简体   繁体   English

Golang将float64转换为int错误

[英]Golang converting float64 to int error

How can I avoid floating point errors when converting float's to int's. 在将float转换为int时,如何避免浮点错误。 For example the following code prints: 0.5499999999999972 when I wound expect it to print 0.55 . 例如,以下代码打印: 0.5499999999999972当我伤口期望它打印0.55

package main

import "fmt"

func main() {
    x := 100.55
    fmt.Println(x - float64(int(x)))    
}

Output:
0.5499999999999972

You need to understand something: 100.55 is a decimal number (presented in decimal radix). 你需要理解一些东西: 100.55是十进制数(以十进制基数表示)。 100.55 in decimal is a finite number and is exactly this: 100.55 . 十进制中的100.55是有限数,恰好是这个: 100.55

Computers in general store numbers in binary representation. 计算机一般以二进制表示存储数字。 The number 100.55 cannot be represented with a finite binary number: 100.55 is an infinite number in binary representation (same reason why 1/3 cannot be represented with a finite decimal number, it is an endless sequence: 0.333333333.... ). 数字100.55不能用有限二进制数表示: 100.55是二进制表示中的无穷数(同样的原因,为什么1/3不能用有限的十进制数表示,它是无穷无尽的序列: 0.333333333.... )。

But Go (like any other language) stores float64 types using the IEEE-754 standard, which is a finite binary representation. 但Go(与任何其他语言一样)使用IEEE-754标准存储float64类型,这是一种有限二进制表示。 A float64 value uses 64 bits in memory to describe the number, of which 53 bits are used to describe the digits and 11 bits are used for the exponent. float64值使用内存中的64位来描述数字,其中53位用于描述数字,11位用于指数。

Now when you "say" this: 现在当你“说”这个:

x := 100.55

It is a short variable declaration which will create a new variable named x and infer its type from the right hand side expression which is a floating point literal, so by the Go spec x 's type will be float64 . 它是一个简短的变量声明 ,它将创建一个名为x的新变量,并从右侧表达式推断其类型,这是一个浮点字面值,因此Go规范x的类型将是float64 The floating point literal will have to be "converted" in order to be represented using 64 bits (by rules specified by IEEE-754 ). 浮点文字必须被“转换”才能用64位表示(由IEEE-754规定的规则)。 And since 100.55 would require infinite bits to be represented precisely in binary radix, by using only 64 bits (53 for the digits) the result will not (cannot) be exactly 100.55 (but a 64-bit binary number in IEEE-754 format that is closest to it), which is: 并且由于100.55将要求无限位以二进制基数精确表示,通过仅使用64位(数字为53),结果将不会(不能)正好为100.55 (但是IEEE-754格式中的64位二进制数字最接近它),这是:

x := 100.55
fmt.Printf("%.50f\n", x)

100.54999999999999715782905695959925651550292968750000

So you are already starting off with a number not being 100.55 . 所以你已经开始使用不是100.55

You subtract 100 from it ( float64(int(x)) will be exactly 100.0 ): 你从中减去100float64(int(x))将正好是100.0 ):

x = x - float64(int(x))
fmt.Printf("%.50f\n", x)

0.54999999999999715782905695959925651550292968750000

What can you do about it? 你能为这个做什么? Nothing really. 真的没什么。 The result you expect ( 0.55 ) is also an infinite number in binary representation, so you can't have an exact number of 0.55 in a variable of type float64 . 您期望的结果( 0.55 )在二进制表示中也是无限数,因此在float64类型的变量中不能具有0.55的精确数。

What you can do is work with the number as normal, but when you print it, round it to decimal places of your choice. 您可以做的是正常使用数字,但是当您打印它时,将其四舍五入到您选择的小数位。 The easiest is to use fmt.Printf() , and specify a format string using the verb %f including the precision: 最简单的方法是使用fmt.Printf() ,并使用动词%f指定格式字符串,包括精度:

fmt.Printf("%.2f\n", x)

Result: 结果:

0.55

Another option is to avoid using floating point numbers. 另一种选择是避免使用浮点数。 Eg if you were to represent USD amounts, you could "multiply" all your values by 100 and represent amounts as cents (1$*100) which is an integer. 例如,如果您要代表美元金额,您可以将所有值“乘以” 100并将金额表示为美分(1 $ * 100),这是一个整数。 Only if you need to print the result as USD, you could print something like 只有当您需要将结果打印为USD时,才能打印出类似的内容

cents := 10055
fmt.Printf("%d.%d $", cents/100, cents%100)

Output: 输出:

100.55 $

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM