为啥c ++将大数字四舍五入到上限,将小数四舍五入到下限[重复]
Posted
技术标签:
【中文标题】为啥c ++将大数字四舍五入到上限,将小数四舍五入到下限[重复]【英文标题】:why c++ is rounding of big numbers to ceil and small numbers to floor [duplicate]为什么c ++将大数字四舍五入到上限,将小数四舍五入到下限[重复] 【发布时间】:2020-10-22 07:31:09 【问题描述】:"x","y" 是 c++ 中的两个 long long 类型变量,我为其分配了两个不同的数字。
变量类型是 long long 但我已将小数分配给整数。
所以我希望它会修剪小数部分并仅显示整数部分。
它去掉小数点后的数字并返回一个整数。
输出:
我期待 x 的 floor(),但它返回了一些以 6 而不是 5 结尾的整数,我的意思是它返回了 ceil(x)。但在第二种情况下,它返回了 floor(y)。
只有当整数太长时才会发生。
那么可能的原因是什么?
我在 Visual Studio 代码上使用 minGW c++17 版本.. 但在线编译器也在发生同样的情况。
【问题讨论】:
见Is floating point math broken?。 我建议examining the actual value you get 在图片中不带整数。 【参考方案1】:每次初始化都涉及两次转换,首先从源文本中的十进制数字到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和92233720368。 .然后这个double
值被转换为long long
。没有小数部分,所以结果就是 9223372036854776。
因此,第一次转换会向上取整,因为它不是简单地转换为最接近的 long long
值。它首先必须四舍五入到最接近的double
值。而且,在该数字的范围内,double
格式没有足够的分辨率来表示每个整数。它仅表示每隔一个整数:9223372036854770、…772、…774、…776、…778 等等。所以 9223372036854775 不是候选人。
【讨论】:
@Hack06:64 位浮点格式最多可以表示 2^64 个数字(实际上更少,因为某些位模式是为特殊含义而保留的)。有无穷多个整数。因此,64位是无法表示每一个整数的。 @Hack06:更具体地说,浮点格式由一个符号、一个以某个底数(通常为 2)为固定宽度的数字和一个指数组成,表示的值是乘以的数字由底提高到指数的幂。当指数足够大时,它与固定宽度数字的乘积意味着该数字的低位被缩放到超过 1 的值,因此它们不能以单整数增量递增。 @Hack06:浮点格式的一个例子是一个符号、三个十进制数字和一个指数。当指数为 -4 时(注意:指数的起点是任意的),此格式表示从 .0100 到 .0999 的数字。当它为 -3 时,它表示从 0.100 到 0.999 的数字。为-2 时,表示从 1.00 到 9.99 的数字。当它为-1 时,它表示从 10.0 到 99.9 的数字。为0时表示100到999之间的数字,为1时表示1000到9990之间的数字。此时不能表示每一个整数,因为比例尺太大。 @Hack06:float
和 double
使用科学记数法。它存储为 1.0240000486373901 * 2^53。第一部分只能有 23 位,因此它不能按顺序精确地保存每个整数。 做的类型是...long long
。你也可以用定点类型做你想做的事,但是它们的范围比浮点类型小很多。
@Hack06:强烈推荐:itu.dk/~sestoft/bachelor/IEEE754_article.pdf这是经典。以上是关于为啥c ++将大数字四舍五入到上限,将小数四舍五入到下限[重复]的主要内容,如果未能解决你的问题,请参考以下文章