提问人:MarlonB 提问时间:9/19/2023 最后编辑:MarlonB 更新时间:9/20/2023 访问量:126
为什么显式整数转换未按预期应用
Why explicit Integer conversion doesn't apply as expected
问:
请注意,我的问题不是“为什么浮点数会失去精度”我知道并非一个数字的所有小数部分都可以以二进制形式存在。真正存储的实际上是“最接近的数字” 占据了所有尾数位空间。
鉴于:
//This is just an example.
float f1 = 17.96f, f3 = 17.98f;
double d2 = 17.96, d4 = 17.98;
printf("1. 17.96 = %f (as cents:%d)\n", price1, (int)(f1 * 100));
printf("2. 17.96 = %lf (as cents:%d)\n", price2, (int)(d2 * 100));
printf("3. 17.98 = %f (as cents:%d)\n", price3, (int)(f3 * 100));
printf("4. 17.98 = %lf (as cents:%d)\n", price4, (int)(d4 * 100));
输出为
1. 17.96 = 17.959999 (as int:1795)
2. 17.96 = 17.960000 (as int:1796)
3. 17.98 = 17.980000 (as int:1798)
4. 17.98 = 17.980000 (as int:1798)
我将打印格式更改为小数点后第 25 位,以查看内存中存储的“实数”是什么。 结果显示
1. 17.96 = 17.9599990844726562500000000 (as int:1795)
2. 17.96 = 17.9600000000000008526512829 (as int:1796)
3. 17.98 = 17.9799995422363281250000000 (as int:1798)
4. 17.98 = 17.9800000000000004263256415 (as int:1798)
问题是为什么 (int)(f1* 100) 的结果为 1795 而不是 1796,根据“实际存储的数字”是 17.9599990844726562500000000。
但是 (int)(f3 * 100) 的结果是 1798 而不是 1797.而 ''real stored number'' 是 17.9799995422363281250000000。“the”实数 * 100 等于 1797.99995422363281250000000。所以在整数截断之后,它应该是 1797 年,但我得到了 1798 年。
答:
常见,是一些整数乘以 2 的幂。参见二元理性。float
double
17.96
并且不能完全以这种方式表示。17.98
取而代之的是,使用附近的可表示数字,该数字正好高于或正好低于所需的代码浮点常量。
printf("%.52e %.52e\n", 17.96f, 17.98f);
printf("%.52e %.52e\n", 17.96, 17.98);
1.7959999084472656250000000000000000000000000000000000e+01 1.7979999542236328125000000000000000000000000000000000e+01
1.7960000000000000852651282912120223045349121093750000e+01 1.7980000000000000426325641456060111522674560546875000e+01
按 100 缩放会产生额外的舍入效果 - 可能会向上或向下一点。产品可能是 1796、1798 或略高于或略低于。
召回率与数学 17.96 * 100 不同,但是(即 1795.999908447265625),然后将该乘积四舍五入到最接近的值:1795.9998779296875。17.96f * 100
17.95999908447265625f * 100.0f
float
printf("%.52e %.52e\n", 17.96f * 100, 17.98f * 100);
printf("%.52e %.52e\n", 17.96 * 100, 17.98 * 100);
1.7959998779296875000000000000000000000000000000000000e+03 1.7980000000000000000000000000000000000000000000000000e+03
1.7960000000000000000000000000000000000000000000000000e+03 1.7980000000000000000000000000000000000000000000000000e+03
[编辑]
OP 添加了<“的”实数 * 100 等于 1797.99995422363281250000000>
这确实是数学上的明智之举,但它是乘积的乘法。由于 1797.9999542236328125 不能表示为 ,因此结果四舍五入为 1 或 2 附近的 s:1797.9998779296875 或 1798.0。使用 OP 的 FP 舍入模式,它可能四舍五入到最接近值:1798.0。将其转换为 1798 年。float
float
float
float
int
C23 可以选择提供十进制浮点数,最适合用于类似的十进制问题。
不要在没有清楚地了解边缘效应的情况下使用浮点计算结果的粗转换。(int)
应用铸件是有问题的编码,因为乘积计算可能会产生 1796 年或 1798 年,因为先前的乘积是 1795.999......1797.999... 使用会更有意义。int
lround()
为了很好地使用(一个糟糕的主意)来扩展资金,请乘以 100.0 (a) 并使用 或 。float
double
llround()
lround()
要将货币使用成整数,请乘以 100.0L (a ) 并使用 或 。double
long double
llroundl()
lroundl()
额外的精度将有助于处理边缘情况。
printf("%ld %ld\n", lround(17.96f * 100.0), lround(17.98f * 100.0));
printf("%lld %lld\n", llroundl(17.96 * 100.0L), llroundl(17.98 * 100.0L));
1796 1798
1796 1798
注意就像 - 乘法。这与 - 乘法不同。17.96f * 100
17.96f * 100.0f
float
17.96f * 100.0
double
评论
17.979999542236328125f * 100
1797.9999542236328125
float
float
1798.0f
int
1798
评论