当bitSize参数使用32时,Golang strconv.ParseFloat无法正确解析字符串

qmelpv7a  于 12个月前  发布在  Go
关注(0)|答案(2)|浏览(86)

为什么转换后的float64变量的值是1.5900000333786011.59看起来足够小,可以装入32位:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    str := `1.59`
    float, err := strconv.ParseFloat(str, 32)
    if err != nil {
        fmt.Println("err: ", err)
    }
    fmt.Printf("%T -> %+v\n", float, float)
}

Go playground link

l2osamch

l2osamch1#

这是32位变量的精度问题。这不是Go的问题。查看以下URL。
IEEE 754 - Wikipedia
Single-precision floating-point format - Wikipedia
你会明白在这段C代码中1.59会发生什么。

#include <stdio.h>

int
main(int argc, char* argv[]) {
  float f = 1.59;
  if (f == 1.59) {
    puts("float: equal!");
  } else {
    puts("float: not equal!");
  }

  double d = 1.59;
  if (d == 1.59) {
    puts("double: equal!");
  } else {
    puts("double: not equal!");
  }
  return 0;
}

http://ideone.com/WobYbU
1.590000033378601在32位变量中是1.59。因此,您可以将值转换为float 32。即float 32(1.590000033378601)

package main

import (
    "fmt"
    "strconv"
)

func main() {
    str := `1.59`
    f64, err := strconv.ParseFloat(str, 32)
    if err != nil {
        fmt.Println("err: ", err)
    }
    f32 := float32(f64)
    fmt.Printf("%T -> %+v\n", f32, f32)
}

Go Playground

更新

在大多数计算机上,浮点值存储为以下元素。

  • 符号(零或一)
  • 系数(Coefficient)
  • 指数

例如,表示0.75为+1.1 x 2^-1
+是符号,.1是有效数,-1是指数。这是像下面这样存储在32位内存空间。

Sign                                 Significand
+-+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
  +-+-+-+-+-+-+-+-+
      Exponent

例如,0.75的存储方式如下

0-01111110-10000000000000000000000

     +- Significand
     |
+ 1[.1] x 2 ^ -1
|         |    |
+- Sign   |    +- Exponent
          |
          +------ Base
  • 1.1 x 2^-1 = 1 x 2^0 + 1 x 2^-1 x 2 ^-1 = 0.75
    由于浮点值如上所述表示,因此数学值和计算机值之间是不同的。这是精度问题。
wbgh16ku

wbgh16ku2#

十进制数1.59看起来很短,但这只是因为我们使用的是十进制数系统
当计算机试图用二进制科学记数法a * 2^b)表示相同的数字时,它需要更多的小数位:1.1001011100001010001111010111000010100011110101110001 * 2^0
如果将该值舍入为32位,将其存储在float32类型的变量中,然后打印为decimal,则得到1.59,但将相同的舍入值存储在float64变量中并打印为decimal,则得到1.590000033378601
函数strconv.ParseFloat返回float64,但由于您指定了32位精度,因此应该在使用之前将值转换为float32。

相关问题