C 如何从无符号整数中检索精确的双精度值(精度)

C how to retrieve exact double value (precision) from a unsigned integer

我有一个校验和,我正在尝试对其进行逆向工程,我已经知道如何在知道最初用于创建校验和的原始初始值后保持校验和生成。

到目前为止我知道校验和是使用双数据类型数学方程生成的。

计算出的校验和的最终值是一个无符号整数,但在此之前它会从 double 转换为 unsigned long long aka (unsigned __int64)。

我想做的是将一个无符号整数恢复为双数据类型的相同值,以进行下一步撤消校验和以检索原始初始值。

在计算校验和时,这里是它以双精度数据类型生成的值。 3083570000.3115764 创建校验和 0xB7CB8B50

我不认为这是一个有损对话,所以即使它从 8 字节双倍转换回 4 字节整数校验和,也没有真正丢失任何东西。为什么?因为 double 值总是通过乘以 4294967295.0 创建的,我认为这只是为了消除尾随的 4 个字节,有点像移位。

所以我要检索的 double 值必须除以 4294967295.0 才能准确地将原始双精度值恢复到最后一位。

问题是我无法正确除法,因为它不是 100% 准确到最后一个小数点。我知道浮点数学不是 100% 准确的 IEEE 浮点废话,但我不在乎关于这一点,我只是想按照最初创建它的方式来扭转它。

产出 假设原始校验和为 0.71794958809146792
0.71794958809146792 * 4294967295.0 = 3083570000.3115761849416764
数据包中发送的答案是 0xb7cb8b50

如果我手动将无符号整数 0xb7cb8b50 转换为 unsigned __int64 它应该看起来像这样 0x00000000b7cb8b50

原始的 double 在代码中的生成方式应该是这样的,我在将它附加到数据包之前使用了相同的密钥来重新创建相同的条件来首先生成校验和,它应该是这样的
Real ANSWER = 3083570000.3115764

所以
0x00000000b7cb8b50 should equals = 3083570000.3115764 double

我的反向代码是这样的

unsigned int checksum = 0xb7cb8b50;
double test1 = (double)(unsigned __int64)checksum;
double test2 = double(checksum);
double test3 = static_cast<double>(checksum);
double test4 = *((double*)(void*)&checksum);

上面的代码有几个小数位是错误的。

test1 returns = 3083570000.0000000
test2 returns = 3083570000.0000000
test3 returns = 3083570000.0000000
test4 returns = 1.523486003547e-314#DEN

如何获得额外的,.3115764也是我的问题。

double 数字的小数部分(小数点后)在分配给整数时会丢失。

进行逆向操作(将结果int赋值给double),小数部分为0,所以无法恢复[=11的原始值=] 数.

在以下代码的输出中可以看出 double 值是如何存储在内存中的(最重要的 32 位不为 0):

double initial = 0.71794958809146792 * 4294967295.0;
uint64_t rawValue = *(uint64_t*)&initial;
uint32_t checksum = (uint32_t)initial;
printf("initial: %f 0x%llx\n", initial, rawValue);
printf("after:   %u 0x%x\n", checksum, checksum);
// Prints
// initial: 3083570000.311576 0x41e6f9716a09f86f
// after:   3083570000 0xb7cb8b50

尝试将原始 int 值转换为 double(如 *((double*)(void*)&checksum))是不正确的操作,它甚至可能访问不属于 checksum 的内存(if int size if 4 bytes).

有关 double 表示的更多信息,请访问:

https://en.wikipedia.org/wiki/Double-precision_floating-point_format