Problem with number precision in version 2017a

2 views (last 30 days)
I am trying to convert a TXT file with xy values into CSV by using the following command:
dlmwrite(file_name,A, 'delimiter', ',', 'precision','%.16g');
Some numbers are not converted correctly. For example, 9187.89 is converted to 9187.88999999999 or 9189.97 to 9189.96999999999. When I am not using the precision argument, I loose the decimal part for values over 10000. I noticed this problem after I upgraded from matlab 2016b to 2017a. I also noticed that this problem is happening only to X values between 8000-9999. The full range of X values is 2000-21000.
Any suggestions please? How can I keep the numbers as they are and avoid any change in precision?

Answers (2)

Walter Roberson
Walter Roberson on 15 May 2017
"Some numbers are not converted correctly. For example, 9187.89 is converted to 9187.88999999999"
That is correct conversion. MATLAB uses IEEE 754 binary floating point double for numbers unless told otherwise. There is no way to represent 1/10 exactly in finite binary, just the same way that there is no way to represent 1/3 exactly in finite decimal numbers.
The closest representable IEEE 754 number to 9187.89 is 9187.889999999999417923390865325927734375 with hex representation '40c1f1f1eb851eb8' . The next representable number, '40c1f1f1eb851eb9' in hex, is decimal 9187.890000000001236912794411182403564453125 which is roughly twice as far away from 918789/100 as the other number.
  3 Comments
Walter Roberson
Walter Roberson on 15 May 2017
The #1 trick is to adjust your expectations. Floating point numbers are not stored in decimal, so most numbers that you enter in decimal format will not be stored exactly the way you expect.
Alternately, you could enter all of your numbers as strings and convert them using sym() and do the calculations symbolically. For example, sym('9187.89')
Or, you could store your numbers as integers and a base 10 multiplier and keep track of the multiplier as you go through your calculations, and then when you go to print them out, construct a string out of the integer and insert the decimal point into the string at the appropriate location. For example, [918789 -2] to mean 918798 * 10^(-2)
Mazen Bahadi
Mazen Bahadi on 15 May 2017
Thank you for the suggestions. I will try them and see which one will yield a better result.

Sign in to comment.


Philip Borghesani
Philip Borghesani on 15 May 2017
Edited: Philip Borghesani on 15 May 2017
If all your data is in the range you specified with only 2 decimal digits of precision then try:
dlmwrite(file_name,A, 'delimiter', ',', 'precision',7)
Or I prefer:
dlmwrite(file_name,A, 'delimiter', ',', 'precision','%8.2f')
Ether will perform the rounding you expect.
  3 Comments
Walter Roberson
Walter Roberson on 15 May 2017
"Isn't there a function that just take the number as it is and put it in a CSV file without going through the floating point representation issue?"
No. Decimal numbers are represented in binary floating point. If you have a statement like
A = 9187.89;
then as soon as the statement executes, the actual value stored in A will be 9187.889999999999417923390865325927734375
If your data is all coming directly from a text file, then you might be able to store it as string instead of as number, and write out the strings. This can only work if you are not doing any calculation with the numbers.
Mazen Bahadi
Mazen Bahadi on 17 May 2017
Thank you, I will try this option too.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!