A部分) 大家好,我是CS一年级学生。在早期的测验中,有一些花车是双打的。我在提交后发布此内容。所以我认为我没问题,实际上我希望没人关心。
float price1 = 17.96f, price3 = 17.98f;
double price2 = 17.96, price4 = 17.98;
printf("1. 17.96 = %f (as cents:%d)\n", price1, (int)(price1 * 100));
printf("2. 17.96 = %lf (as cents:%d)\n", price2, (int)(price2 * 100));
printf("3. 17.98 = %f (as cents:%d)\n", price3, (int)(price3 * 100));
printf("4. 17.98 = %lf (as cents:%d)\n", price4, (int)(price4 * 100));
输出是
1. 17.96 = 17.959999 (as cents:1795)
2. 17.96 = 17.960000 (as cents:1796)
3. 17.98 = 17.980000 (as cents:1798)
4. 17.98 = 17.980000 (as cents:1798)
问题是为什么 (int)(price1 * 100) 结果是 1795 或 1796。 我将打印格式更改为小数点后 25 位,看看内存中存储的“实数”是多少。 输出结果
1. 17.96 = 17.9599990844726562500000000 (as cents:1795)
2. 17.96 = 17.9600000000000008526512829 (as cents:1796)
3. 17.98 = 17.9799995422363281250000000 (as cents:1798)
4. 17.98 = 17.9800000000000004263256415 (as cents:1798)
我很容易发现Price1小数部分的第7个数字是0,这使得之前的数字是17.959999。这个数字 * 100 然后转换为 INT 确实是 1795。但很快我注意到 Price3(也是一个浮点数)乘以 100 转换为 Int 是 1798 而不是我想象的 1797!在花了很多时间与 ChatGPT 4.0 交谈后(为什么不首先使用 Stackoverflow?caz chatGPT Plus 售价 31.5 加元!我必须让它物有所值!),它告诉我“啊你是对的,你的教授错了 ~”
但我不是一个因为AI做不到就放弃的人。花了将近半天的时间,我得到了一个结论(我不知道对还是错)。参与计算的数字不是“实际存储的数字”,而是使用默认说明符打印的数字,最多可达 6 位十进制数字。所以在计算“Price3 * 100”时,price3不是“17.9799995422363281250000000”而是17.980000。因此,(int) (price3 * 100) 的结果是 1798。
我想确认我的猜测。或者如果可能的话提供一个链接。 (抱歉!今天真的花了很多时间,没有精力去goole了)
B 部分)
我知道这个问题是非常基本的,甚至是愚蠢的。但我还是花了半天多的时间才找到答案(主要是和AI对话),甚至没有得到答案。我知道在这条路上我以后还会面临更多的问题。我知道“首先如何,其次为什么”在这个领域非常重要,基本上我猜的一切。只是因为喜欢把所有事情都弄清楚,并花时间在上面。我知道我无法弄清楚所有事情,未来要学习的东西越来越多。那么有人对这条道路上的新学生有建议吗?
float
和 double
是一些整数乘以 2 的幂。
17.96
和 17.98
不能 完全这样表示。
而是使用附近的可表示数字,该数字位于所需代码浮点常量的上方或下方。
按 100 缩放会产生 额外舍入效应 - 可能会向上一点或向下一点。产品可能是 1796、1798 或略高于或略低于。
C23 可选择提供十进制浮点,最适合解决类似的十进制问题。
在没有清楚了解边缘效应的情况下,不要对浮点计算结果使用像
(int)
这样的粗略转换。
应用
int
转换是有问题的编码,因为轻微的乘积计算会导致 1795 或 1797,因为之前的乘积是 1795.999...1797.999...使用 lround()
会更有意义。
要使用
float
(一个糟糕的主意)扩大货币规模,请乘以 100.0(double
)并使用 llround()
或 lround()
。
要使用
double
将货币缩放为整数,请乘以 100.0L(a long double
)并使用 llroundl()
或 lroundl()
。
额外的精度将有助于解决边缘情况。