为什么将float64转换为int会导致值增加1?

huangapple go评论91阅读模式
英文:

Why does conversion from float64 to int cause the value to increase by 1?

问题

630948893921274879float64类型转换为int时,我期望的结果是630948893921274879。然而,实际结果是630948893921274880,比期望值多了1。

造成这种情况的原因是浮点数的精度限制。在计算机中,浮点数的表示是有限的,无法准确地表示所有的实数。当一个浮点数被转换为整数时,它会被截断为最接近的整数。在这种情况下,630948893921274879的浮点表示与630948893921274880更接近,因此转换结果为后者。

这是由于浮点数的内部表示方式和计算机处理浮点数运算的方式所导致的。如果需要更精确的结果,可以考虑使用其他方法或数据类型来处理这种转换。

英文:

When converting 630948893921274879 of type float64 to an int, I would expect the result to be 630948893921274879. However, the actual result is 630948893921274880, which is 1 greater.

What is the reason for that?

import (
	"fmt"
)

func main() {
	var p float64 = 630948893921274879
	fmt.Println(int(p))   // 630948893921274880
	fmt.Printf("%f\n", p) // 630948893921274880.000000
}

https://play.golang.org/p/gbXKCkZ6_rF

答案1

得分: 6

630948893921274879比最大的整数float64可以编码的值要大,而不需要四舍五入。 "浮点数"(即浮点数)的工作方式与科学计数法相同。它们存储一定数量的有效数字,然后将其乘以某个二的幂。630948893921274879需要比float64可以容纳的有效数字更多,因此它会四舍五入为最接近的可表示值。

如果您需要处理这么大的整数,您需要始终使用整数进行计算。您不能转换为浮点数值。

英文:

630948893921274879 is larger than the largest integer float64 can encode without rounding. The way "floats" (i.e. floating point numbers) work is identical to scientific notation. They store a certain number of significant digits, and then they multiply it by some power of two. 630948893921274879 requires more significant digits than float64 can hold, so it gets rounded to the nearest value it can represent.

If you need to work with integers this large, you need to work in integers the whole time. You cannot convert to floating point values.

答案2

得分: 5

float64不能比int64“免费”地变得“更大”。它在精度和范围之间进行权衡。

在某个大小之后,整数只能表示到最接近的2。当你变得更大时,你最终会跳过每4个,然后是每8个,依此类推。

英文:

float64 doesn't get to go "bigger" than int64 "for free". It trades off precision and range.

After a certain magnitude, integers are only representable to the closest 2. As you go even bigger, you eventually skip every 4, then every 8, and so on.

答案3

得分: 4

你的浮点数无法存储为630948893921274879,而是最接近的数值630948893921274880。以2为底取对数,lg(630948893921274879)介于59和60之间。因此,数字之间的间隔为2^(59-52) = 2^7 = 128。这意味着在2^59和2^60之间的任何数字都会被四舍五入为最接近的128的倍数。

解释:一个浮点数(不仅仅是64位)不是一个数字,而是三个数字相乘。对于64位浮点数:第一个数字是符号,长度为1位。第二个数字是指数,长度为11位。最后一个数字是尾数(也称为尾数、分数和其他一些名称),长度为52位。最后一个数字可以表示为 -1^sign * 2^exponent * 1.significand。1.significand的值介于1和(几乎)2之间。这意味着每当达到2的倍数时,指数将增加,尾数将重置。由于指数增加,所得到的数字的精度将减少一半,因为尾数的最小增量现在将变为原来的两倍。你的数字恰好处于尾数最小变化导致增加128的点上;因此,你的数字将被四舍五入为最接近的128的倍数。因此,造成问题的不是将float64转换为int,而是float64本身。

英文:

Your float cannot be stored as 630948893921274879, but rather the closest analog, 630948893921274880. Taking the log of base 2, lg(630948893921274879) is between 59 and 60. As such, the spacing between numbers is 2^(59-52) = 2^7 = 128. That means any number between 2^59 and 2^60 will be rounded to the nearest multiple of 128.

Explanation: A float (any size, not just 64) is not one number, but 3 numbers multiplied together. For a 64 bit float: The first number is the sign, 1 bit long. The second number is the exponent, 11 bits long. The final number is the significand (AKA mantissa, fraction, and a few other names), 52 bits long. The final number is then -1^sign * 2^exponent * 1.significand. 1.significand will equal a number between 1 and (almost) 2. This means, every time you get to a multiple of 2, the exponent will increase and the significand will reset. Since the exponent increases, the accuracy of the numbers you get will decrease by half, as the most minor increase in significand will now be twice as large. Your number just happens to be at the point where the smallest change in the significand results in an increase of 128; because of this, your number will be rounded to the nearest multiple of 128. As such, it is not the conversion of float64 to int that is causing the issue, but float64 itself.

huangapple
  • 本文由 发表于 2021年7月7日 01:51:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/68275294.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定