Why does adding 0 to the end of float literal change how it rounds (possible GCC bug)?(为什么在浮点文字的末尾添加 0 会改变它的舍入方式(可能是 GCC 错误)?)
问题描述
我在我的 x86 VM(32 位)上发现了以下程序:
I discovered on my x86 VM (32 bit) that the following program:
#include <stdio.h>
void foo (long double x) {
int y = x;
printf("(int)%Lf = %d
", x, y);
}
int main () {
foo(.9999999999999999999728949456878623891498136799780L);
foo(.999999999999999999972894945687862389149813679978L);
return 0;
}
产生以下输出:
(int)1.000000 = 1
(int)1.000000 = 0
Ideone 也会产生这种行为.
编译器做了什么来允许这种情况发生?
What is the compiler doing to allow this to happen?
我在追查为什么下面的程序没有像我预期的那样产生 0
时发现了这个常量(使用 19 个 9
产生了 0
我预计):
I found this constant as I was tracking down why the following program didn't produce 0
as I expected (using 19 9
s produced the 0
I expected):
int main () {
long double x = .99999999999999999999L; /* 20 9's */
int y = x;
printf("%d
", y);
return 0;
}
当我试图计算结果从预期变为意外时的值时,我得出了这个问题所涉及的常数.
As I tried to compute the value at which the result switches from expected to unexpected, I arrived at the constant this question is about.
推荐答案
您的问题是您的平台上的 long double
精度不足以存储精确值 0.99999999999999999999.这意味着必须将它的值转换为可表示的值(这种转换发生在程序的翻译过程中,而不是在运行时).
Your problem is that long double
on your platform has insufficient precision to store the exact value 0.99999999999999999999. This means that the value of that must be converted to a representable value (this conversion happens during translation of your program, not at runtime).
这种转换可以生成最接近的可表示值,也可以生成下一个更大或更小的可表示值.选择是实现定义的,因此您的实现应该记录它正在使用的.您的实现似乎使用 x87 样式的 80 位 long double
,并且正在四舍五入到最接近的值,导致 x
中存储的值为 1.0.
This conversion can generate either the nearest representable value, or the next greater or smaller representable value. The choice is implementation-defined, so your implementation should document which it is using. It seems that your implementation uses x87-style 80bit long double
, and is rounding to the nearest value, resulting in a value of 1.0 stored in x
.
使用 long double
的假定格式(尾数为 64 位),小于 1.0 的最高可表示数字是十六进制:
With the assumed format for long double
(with 64 mantissa bits), the highest representable number less than 1.0 is, in hexadecimal:
0x0.ffffffffffffffff
这个值和下一个更高的可表示数字 (1.0) 之间的正好中间的数字是:
The number exactly halfway between this value and the next higher representable number (1.0) is:
0x0.ffffffffffffffff8
你很长的常数 0.9999999999999999999728949456878623891498136799780 等于:
Your very long constant 0.9999999999999999999728949456878623891498136799780 is equal to:
0x0.ffffffffffffffff7fffffffffffffffffffffffa1eb2f0b64cf31c113a8ec...
如果舍入到最接近的值,显然应该向下舍入,但您似乎已经达到编译器使用的浮点表示的某些限制,或者舍入错误.
which should obviously be rounded down if rounding to nearest, but you appear to have reached some limit of the floating point representation your compiler is using, or a rounding bug.
这篇关于为什么在浮点文字的末尾添加 0 会改变它的舍入方式(可能是 GCC 错误)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:为什么在浮点文字的末尾添加 0 会改变它的舍入方式(可能是 GCC 错误)?
基础教程推荐
- C++ 程序在执行 std::string 分配时总是崩溃 2022-01-01
- 调用std::Package_TASK::Get_Future()时可能出现争用情况 2022-12-17
- 运算符重载的基本规则和习语是什么? 2022-10-31
- C++,'if' 表达式中的变量声明 2021-01-01
- 您如何将 CreateThread 用于属于类成员的函数? 2021-01-01
- 如何在 C++ 中处理或避免堆栈溢出 2022-01-01
- 设计字符串本地化的最佳方法 2022-01-01
- 什么是T&&(双与号)在 C++11 中是什么意思? 2022-11-04
- 如何定义双括号/双迭代器运算符,类似于向量的向量? 2022-01-01
- C++ 标准:取消引用 NULL 指针以获取引用? 2021-01-01