pat*_*oid 3 floating-point precision go
在将float转换为int时,如何避免浮点错误.例如,下面的代码打印出来:0.5499999999999972
当我想要打印时0.55
.
package main
import "fmt"
func main() {
x := 100.55
fmt.Println(x - float64(int(x)))
}
Output:
0.5499999999999972
Run Code Online (Sandbox Code Playgroud)
你需要了解一些东西:100.55
是十进制数(以十进制基数表示).100.55
十进制是一个有限数,正是这样:100.55
.
计算机通常以二进制表示形式存储数字.数字100.55
不能用有限二进制数表示:100.55
是二进制表示中的无穷数(同样的原因1/3
不能用有限的十进制数表示,它是无穷无尽的序列:) 0.333333333....
.
但Go(与任何其他语言一样)float64
使用IEEE-754标准存储类型,IEEE-754标准是有限二进制表示.甲float64
值使用64个比特在存储器来描述的53位被用于描述数字和11位被用于指数的数量,.
现在当你"说"这个:
x := 100.55
Run Code Online (Sandbox Code Playgroud)
它是一个简短的变量声明,它将创建一个名为的新变量,x
并从右侧表达式推断其类型,这是一个浮点文字,因此Go规范x
的类型将是float64
.浮点文字必须被"转换"才能用64位表示(由指定的规则表示IEEE-754
).并且由于100.55
要求无限位以二进制基数精确表示,通过仅使用64位(数字为53),结果将不会(不能)完全100.55
(但是最接近的IEEE-754格式的64位二进制数)它),这是:
x := 100.55
fmt.Printf("%.50f\n", x)
100.54999999999999715782905695959925651550292968750000
Run Code Online (Sandbox Code Playgroud)
所以你已经开始了一个不存在的数字100.55
.
你100
从中减去(float64(int(x))
确切地说100.0
):
x = x - float64(int(x))
fmt.Printf("%.50f\n", x)
0.54999999999999715782905695959925651550292968750000
Run Code Online (Sandbox Code Playgroud)
你能为这个做什么?真的没什么.您期望的结果(0.55
)在二进制表示中也是无限数字,因此您不能0.55
在类型变量中具有精确数字float64
.
您可以做的是正常使用数字,但是当您打印它时,将其四舍五入到您选择的小数位.最简单的方法是使用fmt.Printf()
,并使用%f
包含精度的动词指定格式字符串:
fmt.Printf("%.2f\n", x)
Run Code Online (Sandbox Code Playgroud)
结果:
0.55
Run Code Online (Sandbox Code Playgroud)
另一种选择是避免使用浮点数.例如,如果您要代表美元金额,您可以将所有值"乘以" 100
并将金额表示为美分(1 $*100),这是一个整数.只有当您需要将结果打印为USD时,才能打印出类似的内容
cents := 10055
fmt.Printf("%d.%d $", cents/100, cents%100)
Run Code Online (Sandbox Code Playgroud)
输出:
100.55 $
Run Code Online (Sandbox Code Playgroud)