Как без потерь конвертировать двойной в строку и обратно в октаву - PullRequest
0 голосов
/ 08 декабря 2018

При сохранении double в строку происходит некоторая потеря точности.Даже если вы используете очень большое количество цифр, преобразование может быть необратимым, т. Е. Если вы конвертируете double x в строку sx, а затем конвертируете обратно, вы получите число x', которое не может быть битовымдо x.Это может вызвать некоторые проблемы, например, при проверке различий в батарее тестов.Одна возможность - использовать двоичную форму (например, нативную двоичную форму или HDF5), но я хочу сохранить число в текстовом файле, поэтому мне нужно преобразовать в строку.У меня есть рабочее решение, но я спрашиваю, есть ли какой-то стандарт для этого или лучшее решение.

В C / C ++ вы могли бы привести значение типа double к некоторому целочисленному типу, например char*, а затем преобразовать каждый байт в гекса длины 2 с помощью printf("%02x",c[j]).Тогда, например, PI будет преобразован в строку длиной 16: 54442d18400921fb.Проблема в том, что если вы читаете гекса, вы не понимаете, какое это число.Так что я был бы заинтересован в некотором миксе, например, пи -> 3.14{54442d18400921fb}.Первая часть - это (вероятно, с низкой точностью) десятичное представление числа (обычно я использую выходное преобразование "%g"), а строка в фигурных скобках - это шестнадцатеричное представление без потерь.

РЕДАКТИРОВАТЬ: Я передаю код aswer

1 Ответ

0 голосов
/ 09 декабря 2018

Следуя идеям, уже предложенным в посте, я написал следующие функции, которые, кажется, работают.

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

Еще одним улучшением было бы использование другого типа enconding, например Base64 (как предложено @CrisLuengo в комментарии), который уменьшил быдлина двоичной части от 16 до 11 байт.

...