2012-08-02 32 views
2

我正在研究static_casting long double double时gcc和gdb的奇怪行为。我有类似下面的代码:gdb中的C++ static_cast返回与gcc不同的结果

const double xDelta = 60.0; 
int xSplits = 3; 
const long double xStepL = static_cast<long double>(xSplits)/xDelta; 
const double xStep = static_cast<double>(xStepL); 

基本上它分3/60,所以结果应该是0.05。当以简单的double值运行时,xStep的值是0.050000000000000003,所以决定使用12字节的更高精度的long double。上例中xStepL的值为0.05000000000000000000067762635780344。当将此值重新输入到double时,实际上它又是0.050000000000000003。但是,使用gdb检查数值时,它会打印以下内容:

(gdb) p xStep 
$1 = 0.050000000000000003 
(gdb) p static_cast<double>(xStepL) 
$2 = 0.049999999999999996 

任何想法为什么结果不同?我真的希望它成为第二个。任何人都知道如何做到这一点?

顺便说一下,我正在使用GCC 4.3.4和GDB 7.2.50。

+0

'0.05'不能用二进制浮点表示,所以实际值将是'0.050000000000000003'('0x1.999999999999ap-5')或'0.049999999999999996'('0x1.9999999999999p-5')之一。越大的值越接近'0.05'('0x1.9 ... ap-5'),所以你应该更喜欢这个值。 – ecatmur 2012-08-02 13:21:18

+0

该值稍后被乘以并转换为整数作为内存访问的偏移量。不幸的是,在这个特殊情况下(这是一个测试用例和绝对边界),它会产生变化并超出可用内存。 – t1mg 2012-08-02 13:33:00

+0

内存问题的可能解决方案包括测试边界和钳位(但是这会在代码中引入分支),或者在内存块的末尾添加副本 - 但只有在访问权限是只读的情况下才有效。 – 2012-08-03 00:02:53

回答

1

我相信问题是​​没有被调用相同的值。代码中的值用一个更高精度的寄存器值来调用,而从gdb调用的那个将在内存中使用一个长双精度值。我不确定编译器允许这样做的确切位置,但我猜测这是一个 - 所以答案最终可能会与一个elp不同。

+0

“高精度寄存器值”是什么意思?我也尝试了GCCs __float128类型,最后遇到了同样的问题。 – t1mg 2012-08-02 12:58:22

+0

通常使用double计算在更高精度的寄存器中执行,然后在存回内存时切换回低精度。 IIRC过去常常是80位中间值,但现在在64位处理器上可能会有所不同。 – 2012-08-02 13:01:02

2

这看起来像gdb中的错误。

long double投射到double指令是fldt(十字节浮点加载),接着fstpl(8字节浮点存储)。当您执行精度降低的浮点存储时,它将围绕操作数,从0.050000000000000000000677626357803440.050000000000000003。它看起来像gdb是截断操作数,从0.050000000000000000000677626357803440.049999999999999996。在浮点十六进制:

0x1.99999999999999999999ap-5 -> 0x1.999999999999ap-5 (gcc, correct) 
0x1.99999999999999999999ap-5 -> 0x1.9999999999999p-5 (gdb, incorrect) 

Discussion表示,这是最近版本的gdb(50年4月7日)的。

+0

我在一分钟前用Debian Wheezy的7.4.1测试过它,结果相同(错误)。我会尽快得到更新版本的证明。感谢您的回复。 – t1mg 2012-08-02 19:10:15

+0

用gdb的最新版本(7.4.50)进行测试。如果它是一个错误,它不是固定的。这里同样的错误结果。 – t1mg 2012-08-03 07:49:10

相关问题