Str2num: exact the same conversion

33 views (last 30 days)
Xiaohan Du
Xiaohan Du on 3 Mar 2018
Commented: Stephen on 4 Mar 2018
Hi all,
Quick question: I have a string like this:
rawStrMod = '0.0000000001, 0.3'
I use str2num to convert it to number,
>> str2num(rawStrMod)
ans =
0.000000000100000 0.300000000000000
It gives me 0.000000000100000, not exactly the same as 0.0000000001. Here I use format long. If I change to format short g, it gives me:
>> format short g
>> str2num(rawStrMod)
ans =
1e-10 0.3
How can I get exactly 0.0000000001?
  2 Comments
Stephen
Stephen on 4 Mar 2018
"How can I get exactly 0.0000000001?"
It is not possible to store 0.0000000001 exactly using binary floating point numbers.

Sign in to comment.

Accepted Answer

Walter Roberson
Walter Roberson on 3 Mar 2018
rawStrMod = '0.0000000001, 0.3';
"It gives me 0.000000000100000, not exactly the same as 0.0000000001."
Ignoring formatting issues, none of the Mathworks toolboxes are able to give you exactly the same as 0.0000000001 . MATLAB is not able to store 0.0000000001 exactly in binary floating point: the closest it can get in binary floating point is 0.00000000010000000000000000364321973154977415791655470655996396089904010295867919921875
The closest Mathworks tool can get is by using the Symbolic Toolbox, for which sym('0.0000000001') gives you something that is closer to 0.0000000001 than you can get without the Symbolic Toolbox, but if you probe hard enough you can prove that sym('0.0000000001') is implemented as a binary ratio whose asymptotic accuracy is bounded by truncations of 10/3 bits per digit of accuracy requested (log2(10) would perhaps be expected but the model turned out to be 10/3: some of the bits are being used for overhead of extended precision values.)
Everything else is just formatting (and perhaps keeping track of sizes). There are only a few formatting options available for default numeric display. For anything else you should be using sprintf() or fprintf() for fine detailed display.
rawStrMod = '0.0000000001, 0.3, 0.0000000001000, 123';
T = regexp(rawStrMod, '\s*,\s*', 'split');
T_numeric = str2double(T);
T_input_digits = cellfun(@length,regexprep(T,{'^[^.]*$', '^.*\.'},{'', ''},'once', 'lineanchors'));
T_data = num2cell( [T_input_digits(:),T_numeric(:)].' );
fprintf('%.*f\n', T_data{:});
Output is
0.0000000001
0.3
0.0000000001000
123
The input was converted to numeric (T_numeric), but the number of decimal places was tracked, and that number is used to format the output.
This code does have a subtle problem:
  • if you have an integer like the 123, then it is entirely reasonable that the output should not contain a decimal place, like happens here, with the number of decimal places being detected to be 0
  • however, if the 123 were instead 123. with no digits following the decimal places, then the number of decimal places would be considered to be 0, and when told to use 0 decimal places, the %f format item does not put in the trailing decimal point, so 123. would print out as 123 with the code as implemented being unable to format 123 on input differently than 123. on input.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!