doutang2017 2016-03-17 06:13
浏览 925
已采纳

Golang将float64转换为int错误

How can I avoid floating point errors when converting float's to int's. For example the following code prints: 0.5499999999999972 when I wound expect it to print 0.55.

package main

import "fmt"

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

Output:
0.5499999999999972
  • 写回答

1条回答 默认 最新

  • dongzhang5006 2016-03-17 08:30
    关注

    You need to understand something: 100.55 is a decimal number (presented in decimal radix). 100.55 in decimal is a finite number and is exactly this: 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....).

    But Go (like any other language) stores float64 types using the IEEE-754 standard, which is a finite binary representation. 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.

    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. The floating point literal will have to be "converted" in order to be represented using 64 bits (by rules specified by 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:

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

    So you are already starting off with a number not being 100.55.

    You subtract 100 from it (float64(int(x)) will be exactly 100.0):

    x = x - float64(int(x))
    fmt.Printf("%.50f
    ", 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.

    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("%.2f
    ", x)
    

    Result:

    0.55
    

    Another option is to avoid using floating point numbers. E.g. 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. Only if you need to print the result as USD, you could print something like

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

    Output:

    100.55 $
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥15 绘制多分类任务的roc曲线时只画出了一类的roc,其它的auc显示为nan
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?