如何无损地将双精度转换为字符串并返回八度 [英] How to lossless convert a double to string and back in Octave
问题描述
将双精度值保存到字符串时会损失一些精度.即使您使用非常多的数字,转换也可能不可逆,即如果您将双精度 x
转换为字符串 sx
然后再转换回来,您将得到一个数字 x'
可能不等于 x
.这可能会导致一些问题,例如在检查一组测试中的差异时.一种可能性是使用二进制形式(例如本机二进制形式或 HDF5),但我想将数字存储在文本文件中,因此我需要转换为字符串.我有一个可行的解决方案,但我问是否有一些标准或更好的解决方案.
When saving a double to a string there is some loss of precision. Even if you use a very large number of digits the conversion may not be reversible, i.e. if you convert a double x
to a string sx
and then convert back you will get a number x'
which may not be bitwise equal to x
. This may cause some problem for instance when checking for differences in a battery of tests. One possibility is to use binary form (for instance the native Binary form, or HDF5) but I want to store the number in a text file, so I need a conversion to a string. I have a working solution but I ask if there is some standard for this or a better solution.
在 C/C++ 中,您可以将 double 转换为诸如 char*
之类的整数类型,然后使用 printf("%02x",c[j])
.然后例如 PI 将被转换为长度为 16 的字符串:54442d18400921fb
.问题在于,如果您阅读六进制,您将不知道它是哪个数字.所以我会对一些组合感兴趣,例如 pi -> 3.14{54442d18400921fb}
.第一部分是数字的(可能是低精度)十进制表示(通常我会使用 "%g"
输出转换),大括号中的字符串是无损的十六进制表示.
In C/C++ you could cast the double to some integer type like char*
and then convert each byte to an hexa of length 2 with printf("%02x",c[j])
. Then for instance PI would be converted to a string of length 16: 54442d18400921fb
. The problem with this is that if you read the hexa you don get any idea of which number it is. So I would be interested in some mix for instance pi -> 3.14{54442d18400921fb}
. The first part is a (probably low precision) decimal representation of the number (typically I would use a "%g"
output conversion) and the string in braces is the lossless hexadecimal representation.
我将代码作为答案传递
推荐答案
按照帖子中已经提出的想法,我写了以下功能,似乎有效.
Following the ideas already suggested in the post I wrote the following functions, that seem to work.
function s = dbl2str(d);
z = typecast(d,"uint32");
s = sprintf("%.3g{%08x%08x}\n",d,z);
endfunction
function d = str2dbl(s);
k1 = index(s,"{");
k2 = index(s,"}");
## Check that there is a balanced {} or not at all
assert((k1==0) == (k2==0));
if k1>0; assert(k2>k1); endif
if (k1==0);
## If there is not {hexa} part convert with loss
d = str2double(s);
else
## Convert lossless
ss = substr(s,k1+1,k2-k1-1);
z = uint32(sscanf(ss,"%8x",2));
d = typecast(z,"double");
endif
endfunction
那我有
>> spi=dbl2str(pi)
spi = 3.14{54442d18400921fb}
>> pi2 = str2dbl(spi)
pi2 = 3.1416
>> pi2-pi
ans = 0
>> snan = dbl2str(NaN)
snan = NaN{000000007ff80000}
>> nan1 = str2dbl(snan)
nan1 = NaN
进一步的改进是使用其他类型的编码,例如实例 Base64(如@CrisLuengo 在评论中所建议的那样)将二进制部分的长度从 16 字节减少到 11 字节.
A further improvement would be to use other type of enconding, for instance Base64 (as suggested by @CrisLuengo in a comment) that would reduce the length of the binary part from 16 to 11 bytes.
这篇关于如何无损地将双精度转换为字符串并返回八度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!