gpt4 book ai didi

通过 long long 指针对 double 进行 C++ 按位操作会中断输出

转载 作者:行者123 更新时间:2023-11-27 23:22:42 26 4
gpt4 key购买 nike

是的,我知道,对 double 值进行按位运算似乎是个坏主意,但我确实需要它。

我的问题你不需要阅读下一段,只是为了你们的好奇:

我实际上尝试了 Mozilla Tamarin(Actionscript 虚拟机)的特殊模组。其中,任何对象都为其类型保留前 3 位(例如,double 为 7)。这些位降低了原始数据类型的精度(int 只有 29 位等)。对于我的模组,我需要将这个区域扩展 2 位。这意味着,例如,当您添加 2 个 double 时,您需要将最后 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,这显然是错误的。十六进制和 float 的第 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 坏了吗?我在这里有大/小端困惑吗?我是不是不小心造成了某种缓冲区溢出?

如果有人感兴趣,在最初的问题(狨猴问题,见上文)中,它几乎是相反的。在那里,最后三位已经设置(代表 double )。将它们设置为零可以正常工作(这是原始实现)。将 2 more 设置为零与上面的效果相同(总值降低为零)。顺便说一句,这不是特定于输出的,而且数学操作似乎也适用于那些底值(获得的 2 个值的乘积,结果为 0)。

如有任何帮助,我们将不胜感激。问候。

最佳答案

well, they show 15.25, but it should be 15.2500000000000550670620214078

默认情况下,%f 显示 6 位精度,因此您看不到差异。您还需要使用 ll 修饰符指定第一个参数是 long long 而不是 int;否则,它可能会打印垃圾。如果您修复该问题并使用更高的精度,例如 %.30f,您应该会看到预期的结果:

printf("last 3 bits set to 1: %016llX, float: %.30f\n", *l, *d);
printf("2 bits more set to 1: %016llX, float: %.30f\n", *l, *d);

last 3 bits set to 1: 0000000000000007, float: 15.250000000000012434497875801753
2 bits more set to 1: 000000000000001F, float: 15.250000000000055067062021407764

lets modify a bit further up:

*l = *l |= 0x10000000000;
printf("float4: %f\n", *d);

你有一个流氓 = 给出未定义的行为,所以这个值可能会或可能不会被修改(程序可能会或可能不会崩溃,打电话出去吃披萨,或者毁灭宇宙) .此外,如果您的编译器不兼容 C++11,则整型文字的类型可能不会大于 long,它可能只有 32 位;在这种情况下,它将(可能)变为零。

修复这些问题(在我的情况下,按原样使用您的代码),我得到了预期的结果:

*l = *l | 0x10000000000LL;  // just one assignment, and "LL" to force "long long"
printf("float4: %f\n", *d);


float4: 15.251953

Here是一个示范。

关于通过 long long 指针对 double 进行 C++ 按位操作会中断输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11685702/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com