为什么显式整数转换未按预期应用

Why explicit Integer conversion doesn't apply as expected

提问人:MarlonB 提问时间:9/19/2023 最后编辑:MarlonB 更新时间:9/20/2023 访问量:126

问:

请注意,我的问题不是“为什么浮点数会失去精度”我知道并非一个数字的所有小数部分都可以以二进制形式存在。真正存储的实际上是“最接近的数字” 占据了所有尾数位空间。

鉴于:

//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 年。

c 浮点精度

评论

4赞 JohnFilleau 9/19/2023
你为什么不问问你的教学人员呢?无论如何,在互联网上询问并进行自己的研究......但是你的教学人员是有报酬来帮助你处理这些事情的。我不明白你为什么要忽略那个资源。
4赞 Ken White 9/19/2023
您的 B 部分问题完全不适合本网站。我们不提供职业、学习、教育或其他建议。这个网站专门用于解决与编程(代码)或使用程序员工具有关的问题。对于A部分,你为什么不问你的导师这个问题?他们得到报酬来教育你,他们的部分工作是使信息清晰,并在信息不明确时提供额外的解释。
5赞 user207421 9/19/2023
了解每个计算机科学家都应该了解的浮点运算知识。
2赞 cafce25 9/19/2023
请不要上传代码/数据/错误的图像。
1赞 cafce25 9/19/2023
我认为你最大的问题是你相信人工智能是真正的人工智能,尽管它的名字和有时看起来它一点也不聪明,LLT所做的只是处理数字并预测下一个单词,你最好问问同学或你的教学人员。

答:

4赞 chux - Reinstate Monica 9/19/2023 #1

常见,是一些整数乘以 2 的幂。参见二元理性floatdouble

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 * 10017.95999908447265625f * 100.0ffloat

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 年。
floatfloatfloatfloatint


C23 可以选择提供十进制浮点数,最适合用于类似的十进制问题。


不要在没有清楚地了解边缘效应的情况下使用浮点计算结果的粗转换。(int)

应用铸件是有问题的编码,因为乘积计算可能会产生 1796 年或 1798 年,因为先前的乘积是 1795.999......1797.999... 使用会更有意义。intlround()


为了很好地使用(一个糟糕的主意)来扩展资金,请乘以 100.0 (a) 并使用 或 。floatdoublellround()lround()

要将货币使用成整数,请乘以 100.0L (a ) 并使用 或 。doublelong doublellroundl()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 * 10017.96f * 100.0ffloat17.96f * 100.0double

评论

0赞 MarlonB 9/20/2023
Hi, thanks for answering my question. I've known that floating numbers stored in the system are not actually the numbers themselves unless their fractional part is 1/2^n. So I changed the print format up to 25 decimal places to check the " nearest number". 17.96f = 17.9599990844726562500000000 (as cents:1795) 17.98f = 17.9799995422363281250000000 (as cents:1798) . after * 100 then explicitly convert to Int , first one rounded down to 1795 , second didn't round down to 1797 . That's what I can't figure. I asked my school instructor she couldn't tell. So I think 7th decimal number decide it
0赞 MarlonB 9/20/2023
and I am also confused about this part Recall 17.96f * 100 is not the same as math 17.96 * 100, but 1.795999908447265625f * 100.0f (which is 179.5999908447265625), and then that product is rounded to the nearest float: 179.59998779296875. 17.96f x100 is 1.795999908447265625f * 100.0f , why it's not 17.95999908447265625f x 100f? and I think 100 does not matter whether it's 100.0f (as a float) or 100 (as Int) It won't impact the result because the "fractional part " is 0 which makes it perfectly stored in the mantissa bit space.
0赞 chux - Reinstate Monica 9/20/2023
@MarlonB That's what I can't figure --> What is ? Math wise, the product is , yet that is not representable as a . The closest is . Converting that to an is .17.979999542236328125f * 1001797.9999542236328125floatfloat1798.0fint1798
0赞 chux - Reinstate Monica 9/20/2023
@MarlonB Re: and I am also confused ...: clerical error fixed in answer.
0赞 MarlonB 9/20/2023
Thanks for your supplementary explanation. now I finally understand that.