是的,我知道,对双精度值进行按位运算似乎是个坏主意,但我确实需要它。
你不需要阅读我的问题的下一段,只是为了你们的好奇:
我实际上尝试了 Mozilla Tamarin(Actionscript 虚拟机)的特殊模块。在其中,任何对象都为其类型保留前 3 位(例如,双精度为 7)。这些位降低了原始数据类型(仅 29 位等)的精度。对于我的模组,我需要将此区域扩大 2 位。这意味着,例如,当您添加 2 个双精度时,您需要将最后 5 位设置为零,进行数学运算,然后将它们重置为结果。这么多为什么^^
现在回到代码。这是一个最小的例子,它显示了一个非常相似的问题:
double *d = new double;
*d = 15.25;
printf("float: %f\n", *d);
//forced hex output of double
printf("forced bitwise of double: ");
unsigned char * c = (unsigned char *) d;
int i;
for (i = sizeof (double)-1; i >=0 ; i--) {
printf ("%02X ", c[i]);
}
printf ("\n");
//cast to long long-pointer, so that bitops become possible
long long * l = (long long*)d;
//now the bitops:
printf("IntHex: %016X, float: %f\n", *l, *(double*)l); //this output is wrong!
*l = *l | 0x07;
printf("last 3 bits set to 1: %016X, float: %f\n", *l, *d);//this output is wrong!
*l = *l | 0x18;
printf("2 bits more set to 1: %016X, float: %f\n", *l, *d);//this output is wrong!
在 VisualStudio2008 中运行时,第一个输出是正确的。第二个。3rd 对十六进制和浮点表示都产生 0,这显然是错误的。十六进制和浮点数的第 4 和第 5 也为零,但修改后的位显示在十六进制值中。所以我想,也许类型转换在这里搞砸了。所以还有2个输出:
printf("float2: %f\n", *(double*)(long long*)d); //almost right
printf("float3: %f\n", *d); //almost right
好吧,他们显示 15.25,但它应该是 15.2500000000000550670620214078。所以我想,嘿,这只是输出中的精度问题。让我们进一步修改一下:
*l = *l |= 0x10000000000;
printf("float4: %f\n", *d);
同样,输出是 15.25(0000),而不是 15.2519531250000550670620214078。奇怪的是,另一个强制的十六进制输出(见上面的代码)根本没有修改 d 。所以我修改了一下,并意识到第 31 位(0x80000000)是我可以手动设置的最后一个。和神圣的钼,它实际上对输出有影响(15.250004)!
所以,虽然我有点迷路,但还是有很多困惑。printf 坏了吗?我在这里有大/小端混乱吗?我是否不小心创建了某种缓冲区溢出?
如果有人有兴趣,在原来的问题(狨猴的事情,见上文)它几乎是相反的。在那里,最后三位已经设置(代表双精度)。将它们设置为零可以正常工作(这是原始实现)。将 2 更多设置为零具有与上述相同的效果(整体值被降至零)。顺便说一句,这不是特定于输出的,而且数学运算似乎也适用于那些底值(这样获得的 2 个值的 mul 会导致 0)。
任何帮助,将不胜感激。问候。