直接将 double 结果分配给 int 时的精度损失/舍入差异
Precision loss / rounding difference when directly assigning double result to an int
在这种情况下,从 double 转换为 int 是否按预期执行是有原因的:
double value = 45.33;
double multResult = (double) value*100.0; // assign to double
int convert = multResult; // assign to int
printf("convert = %d\n", convert); // prints 4533 as expected
但在这种情况下不是:
double value = 45.33;
int multResultInt = (double) value*100.0; // assign directly to int
printf("multResultInt = %d\n", multResultInt); // prints 4532??
在我看来应该没有区别。在第二种情况下,结果在转换为 int 之前仍然首先存储为 double,除非我不理解强制转换和硬分配之间的一些区别。
两者之间确实没有区别,但是当涉及到浮点计算时,编译器习惯于采取一些自由。例如,编译器可以自由使用 更高 的计算中间结果精度,但更高仍然意味着不同,因此结果可能会有所不同。
一些编译器提供开关以始终放弃额外精度并将所有中间结果转换为规定的浮点数(比如 64 位双精度数)。但是,这会使代码变慢。
具体来说,数字45.33
不能用浮点值精确表示(用二进制表示时是周期数,需要无限位数)。当乘以 100
这个值 可能是 你没有得到一个整数,但非常接近(略低于或略高于)。
int
转换或转换使用截断和非常接近 4533
的东西执行,但下面将变为 4532
,当上面变为 4533
时;即使差异非常小,比如 1E-300
.
为避免出现问题,请务必解决数字准确性问题。如果您进行的计算依赖于浮点数的精确值,那么您使用了错误的工具。
@6502 给了你理论,这里是如何用实验来看待事物
double v = 45.33;
int x = v * 100.0;
printf("x=%d v=%.20lf v100=%.20lf\n", x, v, v * 100.0 );
在我的机器上,这会打印
x=4533 v=45.32999999999999829470 v100=4533.00000000000000000000
当编码为 64 位 IEEE-754 浮点数时,值 45.33
没有精确表示。由于编码精度有限,v
的实际值略低于预期值。
那么为什么乘以 100.0
可以解决某些机器上的问题?一种可能性是乘法以 80 位精度完成,然后四舍五入以适应 64 位结果。当转换为 64 位时,80 位数字 4532.999...
将四舍五入为 4533
。
在你的机器上,乘法显然是用 64 位精度完成的,我希望 v100
将打印为 4532.999...
。
在这种情况下,从 double 转换为 int 是否按预期执行是有原因的:
double value = 45.33;
double multResult = (double) value*100.0; // assign to double
int convert = multResult; // assign to int
printf("convert = %d\n", convert); // prints 4533 as expected
但在这种情况下不是:
double value = 45.33;
int multResultInt = (double) value*100.0; // assign directly to int
printf("multResultInt = %d\n", multResultInt); // prints 4532??
在我看来应该没有区别。在第二种情况下,结果在转换为 int 之前仍然首先存储为 double,除非我不理解强制转换和硬分配之间的一些区别。
两者之间确实没有区别,但是当涉及到浮点计算时,编译器习惯于采取一些自由。例如,编译器可以自由使用 更高 的计算中间结果精度,但更高仍然意味着不同,因此结果可能会有所不同。
一些编译器提供开关以始终放弃额外精度并将所有中间结果转换为规定的浮点数(比如 64 位双精度数)。但是,这会使代码变慢。
具体来说,数字45.33
不能用浮点值精确表示(用二进制表示时是周期数,需要无限位数)。当乘以 100
这个值 可能是 你没有得到一个整数,但非常接近(略低于或略高于)。
int
转换或转换使用截断和非常接近 4533
的东西执行,但下面将变为 4532
,当上面变为 4533
时;即使差异非常小,比如 1E-300
.
为避免出现问题,请务必解决数字准确性问题。如果您进行的计算依赖于浮点数的精确值,那么您使用了错误的工具。
@6502 给了你理论,这里是如何用实验来看待事物
double v = 45.33;
int x = v * 100.0;
printf("x=%d v=%.20lf v100=%.20lf\n", x, v, v * 100.0 );
在我的机器上,这会打印
x=4533 v=45.32999999999999829470 v100=4533.00000000000000000000
当编码为 64 位 IEEE-754 浮点数时,值 45.33
没有精确表示。由于编码精度有限,v
的实际值略低于预期值。
那么为什么乘以 100.0
可以解决某些机器上的问题?一种可能性是乘法以 80 位精度完成,然后四舍五入以适应 64 位结果。当转换为 64 位时,80 位数字 4532.999...
将四舍五入为 4533
。
在你的机器上,乘法显然是用 64 位精度完成的,我希望 v100
将打印为 4532.999...
。