Conversion of numeric to string in MATLAB

floating-point, matlab, number-formatting, string

Solution

My HPF toolbox also allows you to work with an arbitrary precision of numbers in MATLAB.

In MATLAB, try this:

>> format long g
>> x = 0.280783054
x =
               0.280783054

As you can see, MATLAB writes it out with the digits you have posed. But how does MATLAB really "feel" about that number? What does it store internally? See what sprintf says:

>> sprintf('%.60f',x)
ans =
0.280783053999999976380053112734458409249782562255859375000000

And this is what HPF sees, when it tries to extract that number from the double:

>> hpf(x,60)
ans =
0.280783053999999976380053112734458409249782562255859375000000

The fact is, almost all decimal numbers are NOT representable exactly in floating point arithmetic as a double. (0.5 or 0.375 are exceptions to that rule, for obvious reasons.)

However, when stored in a decimal form with 18 digits, we see that HPF did not need to store the number as a binary approximation to the decimal form.

x = hpf('0.280783054',[18 0])
x =
0.280783054

>> x.mantissa
ans =
  2 8 0 7 8 3 0 5 4 0 0 0 0 0 0 0 0 0

What niels does not appreciate is that decimal numbers are not stored in decimal form as a double. For example what does 0.1 look like internally?

>> sprintf('%.60f',0.1)
ans =
0.100000000000000005551115123125782702118158340454101562500000

As you see, matlab does not store it as 0.1. In fact, matlab stores 0.1 as a binary number, here in effect...

1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + 1/65536 + ...

or if you prefer

2^-4 + 2^-5 + 2^-8 + 2^-9 + 2^-12 + 2^13 + 2^-16 + ...

To represent 0.1 exactly, this would take infinitely many such terms since 0.1 is a repeating number in binary. MATLAB stops at 52 bits. Just like 2/3 = 0.6666666666... as a decimal, 0.1 is stored only as an approximation as a double.

This is why your problem really is completely about precision and the binary form that a double comprises.

As a final edit after chat...

The point is that MATLAB uses a double to represent a number. So it will take in a number with up to 15 decimal digits and be able to spew them out with the proper format setting.

>> format long g
>> eps 
ans = 
2.22044604925031e-16

So for example...

>> x = 1.23456789012345
x =
          1.23456789012345

And we see that MATLAB has gotten it right. But now add one more digit to the end.

>> x = 1.234567890123456
x =
          1.23456789012346

In its full glory, look at x, as MATLAB sees it:

>> sprintf('%.60f',x)
ans =
1.234567890123456024298320699017494916915893554687500000000000

So always beware the last digit of any floating point number. MATLAB will try to round things intelligently, but 15 digits is just on the edge of where you are safe.

Is it necessary to use a tool like HPF or MP to solve such a problem? No, as long as you recognize the limitations of a double. However tools that offer arbitrary precision give you the ability to be more flexible when you need it. For example, HPF offers the use and control of guard digits down in that basement area. If you need them, they are there to save the digits you need from corruption.

Problem

Suppose I want to conver the number `0.011124325465476454` to string in MATLAB. If I hit `mat2str(0.011124325465476454,100)` I get `0.011124325465476453` which differs in the last digit. If I hit `num2str(0.011124325465476454,'%5.25f')` I get `0.0111243254654764530000000` which is padded with undesirable zeros and differs in the last digit (3 should be 4). I need a way to convert numerics with random number of decimals to their EXACT string matches (no zeros padded, no final digit modification). Is there such as way? EDIT: Since I din't have in mind the info about precision that Amro and nrz provided, I am adding some more additional info about the problem. The numbers I actually need to convert come from a C++ program that outputs them to a txt file and they are all of the C++ `double` type. [NOTE: The part that inputs the numbers from the txt file to MATLAB is not coded by me and I'm actually not allowed to modify it to keep the numbers as strings without converting them to numerics. I only have access to this code's "output" which is the numerics I'd like to convert]. So far I haven't gotten numbers with more than 17 decimals (NOTE: consequently the example provided above, with 18 decimals, is not very indicative). Now, if the number has 15 digits eg 0.280783055069002 then `num2str(0.280783055069002,'%5.17f')` or `mat2str(0.280783055069002,17)` returns `0.28078305506900197` which is not the exact number (see last digits). But if I hit `mat2str(0.280783055069002,15)` I get `0.280783055069002` which is correct!!! Probably there a million ways to "code around" the problem (eg create a routine that does the conversion), but isn't there some way using the standard built-in MATLAB's to get desirable results when I input a number with random number of decimals (but no more than 17);

Original source