我正在创建一个程序,提取双数字的二进制/字节数据并将其转换为十六进制。然后需要应用反向:将十六进制转换回字节,以便它可以再次用作double。
这是我正在调查项目的内容。其背后的想法是“根据我的主管的说法,通过以ASCII格式保存双值而不是保存其字节值,可能会丢失一些准确性”。这些值将被保存并读取数千次,因此原始双精度值的准确性非常重要。
就个人而言,我没有看到问题。例如,我有以下代码从内存中提取double的字节,并将其转换为十六进制。
string double_to_hex_string(double d)
{
unsigned char *buffer = (unsigned char*)&d;
int bufferSize = sizeof(double);
char converted[bufferSize *2];
int j = 0;
for(int i = bufferSize - 1; i >= 0 ; --i)
{
sprintf(&converted[j*2], "%02X", buffer[i]);
++j;
}
string hex_string(converted);
return hex_string;
}
双值0.61在内存中表示为0.60999(重新出现)。但是,这两个值都会产生相同的十六进制值 - 因为这些数字是相同的,只能以一种方式表示。这是我的想法,但无论如何我都被告知要进行调查。
我的主要问题是在类型之间进行转换 - 尤其是从字符串十六进制转换为双精度值。我在互联网上使用了大量代码而没有理解字节的表示方式。我目前的理解是:
存储在内存中的double类型(或任何其他类型)的数值范围为0 - 255.因此,无符号字符是保存这些字节值(一个字节)的合理方式。
这些char值只是8位整数。并且可以很容易地转换为十六进制。
为了转换回来,我对步骤的猜测是(正好相反):
将字符串中的每对十六进制值转换为unsigned char。
将这些char收集到一个数组中。
将字符数组转换为double(不知何故)。
如果有任何指导,我将不胜感激 - 尤其是我在转换过程中可能忽略的任何内容,以及对我在上述文本中所作陈述的任何更正。
答案 0 :(得分:2)
好的,有些答案。让我们假设,为了论证,这是关于double的最常见定义,即64位IEE 754标准。
由于这些方法的工作方式,可以精确地以十进制表示双精度变量的值。例如,您可以将2 ^ 200存储在一个中,并且您可以准确地将其写为具有61位数的十进制数。没有人这样做,但相信我,这是可能的。
当恶化进入的时候,当你试图将东西存储在一个无法用其格式表达的双精度时,例如1/7。最接近的近似值是从小数点后面的16位正确数字开始的数字,但如果您认为其余数字无关紧要,那么您就错了。只将那些16位数字(即数字.1428571428571428)写入文件,并将其读回,将导致与之前略有不同的数字,这与1/7相差不多。
所以,是的,如果您必须将数字写入文件并重新读入,请不要这样做。如果不能简单地将“本机”字节内容写入二进制文件,则使用16位十六进制数字是一种有效的替代方法 干得好。如果我们再次假设该double是8个字节,则不需要可变长度缓冲区,也不需要循环。
string double_to_hex_string(double d)
{
char converted[17];
sprintf(converted, "%016llX", *((uint64_t*)&d));
return std::string(converted);
}
顺便说一下,
双值0.61在内存中表示为0.60999(重新出现)。
不完全正确,只有14个九重复。 (之后,还有其他数字。)如果有无数个9,那将是0.61的精确表示! 其余的假设都没问题。