1

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.

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.

EDIT: I pass the code as an aswer

  • @CrisLuengo The question is about whether there are already some built in alternatives (end of first paragraph):) – flawr Dec 08 '18 at 21:25
  • @CrisLuengo: the answer of flawr is right. The code is there and seems working. I use it mainly in exporting and importing data from JSON files. BTW, I think that also in C/C++ there should exist an output conversion (%something) to do this. Another issue is the string length. If you stick to an hexa code then you need 16 chars just for the hexa code. If you use a broader set of chars, for instance (a-z,A-Z,0-9) then you can reduce the 16 chars of the hexa to 11 chars. Then you could have a lossless representation in let's say 20 chars (with the delimiters and the human readable part). – Mario Storti Dec 08 '18 at 23:09
  • @CrisLuengo I see your point now. Thank you for the suggestion, may be it is more useful that way. I will do that. – Mario Storti Dec 08 '18 at 23:11
  • There’s base64 encoding. That goes from 3 bytes to 4. Probably the best you can accomplish in terms of space. – Cris Luengo Dec 08 '18 at 23:11

1 Answers1

1

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

Then I have

>> 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

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.