为什么C++对大数进行向上取整并对小数进行向下取整?

4
"

在C++中,“x”和“y”是两个长整型变量,我已经将它们分别赋值为两个不同的数字。

虽然变量类型为长整型,但我已经将小数赋给了这个整数。

因此,我期望它会截断小数部分并仅显示整数部分。

它确实截掉了小数点后面的数字并返回了一个整数。

"

enter image description here

输出:

enter image description here

我本来期望 x 的 floor() 结果以 5 结尾,但它返回了一个以 6 结尾的整数,也就是说它返回了 ceil(x)。但在第二种情况下,它返回了 y 的 floor()。

只有在整数太长的情况下才会出现这种情况。

那么可能的原因是什么呢?

我正在使用 Visual Studio Code 上的 minGW c++17 版本,但在线编译器上也发生了相同的情况。


4
请看浮点数计算有问题吗? - 1201ProgramAlarm
1
我建议您查看 [https://i.imgur.com/Kw2ezSB.png] 图片中不带整数的实际值。 - chris
1个回答

13
每次初始化都需要两次转换,首先将源文本中的十进制数字转换为double,然后再从double转换为long long
让我们先讨论第二个声明。因为2.001是一个double常量,所以十进制源文本2.001必须转换为double。假设您的C实现使用IEEE-754 binary64,则结果为2.000999999999999889865875957184471189975738525390625。然后,在初始化时,此double值被转换为long long。这种转换到整数类型会丢弃小数部分,因此结果为2。
在第一个声明中,当9223372036854775.001转换为double时,结果为9223372036854776。这是因为最接近9223372036854775.001的两个double数分别是9223372036854774和9223372036854776。后者更接近,因此被选择。然后将此double值转换为long long。没有小数部分,因此结果是9223372036854776。

因此,第一次转换会向上舍入,因为它不仅仅是将值转换为最接近的long long值。它首先必须将其四舍五入为最接近的double值。而在该数字的规模下,double格式没有足够的分辨率来表示每个整数。它只表示每隔一个整数:9223372036854770、…772、…774、…776、…778等。因此,9223372036854775不是候选项。


3
一个64位的浮点数格式最多可以表示2^64个数字(实际上更少,因为某些位模式被保留用于特殊含义)。而整数是无穷多的,因此64位无法表示每一个整数。 - Eric Postpischil
2
@Hack06:更具体地说,浮点格式由一个符号、一个在某个基数(通常为2)上具有固定宽度的数字和一个指数组成,表示的值是该数字乘以基数的指数幂。当指数足够大时,其与固定宽度数字的乘积意味着该数字的低位数字被缩放超过1的值,因此它们不能通过单整数增量来递增。 - Eric Postpischil
1
@Hack06:浮点格式的一个例子是一个符号、三个小数位和一个指数。当指数为-4(注意:指数的起始点是任意的),这种格式表示从.0100到.0999的数字。当它为-3时,它表示从.100到.999的数字。当它为-2时,它表示从1.00到9.99的数字。当它为-1时,它表示从10.0到99.9的数字。当它为0时,它表示从100到999的数字。当它为1时,它表示从1000到9990的数字。此时,它无法表示每个整数,因为比例太大了。 - Eric Postpischil
1
@Hack06:floatdouble使用科学计数法。它们被存储为1.0240000486373901 * 2^53。第一部分只能有23位,因此无法精确地按顺序保存每个整数。而能够做到这一点的类型是... long long。您还可以使用定点类型来实现所需的功能,但由于此原因,它们所能容纳的范围要小得多。 - Mooing Duck
3
强烈推荐:https://www.itu.dk/~sestoft/bachelor/IEEE754_article.pdf 这是一篇经典文章。 - Howard Hinnant
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接