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

时间:2017-07-05 08:44:15

标签: go

为什么转换后的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

2 个答案:

答案 0 :(得分:4)

是32位变量的精度问题。这不是Go的问题。请参阅以下网址。

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。因此,您可以将值与cast一起使用到float32。即float32(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

更新

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

  • 签署(零或一)
  • 重要(系数)
  • 指数

例如,表示0.75是+1.1 x 2^-1

+为Sign,.1为有效,-1为Exponent。这在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

由于浮点值如上所示,因此数学值与计算机的值不同。这是精确问题。

答案 1 :(得分:1)

十进制数1.59看起来很短,但这只是因为我们使用十进制数字系统

当计算机试图用二进制科学记数法a * 2^b)表示相同的数字时,它需要更多的小数位数:1.1001011100001010001111010111000010100011110101110001 * 2^0

如果将此值四舍五入为32位,则将其存储在float32类型的变量中,然后以十进制格式打印,得到1.59,但在float64中存储相同的舍入值变量和打印为十进制,得到1.590000033378601

函数strconv.ParseFloat返回float64,但由于您指定了32位精度,因此您应该在使用之前将值转换为float32。