Problem with number precision in version 2017a

1 Ansicht (letzte 30 Tage)
Mazen Bahadi
Mazen Bahadi am 14 Mai 2017
Kommentiert: Mazen Bahadi am 17 Mai 2017
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?

Antworten (2)

Walter Roberson
Walter Roberson am 15 Mai 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 Kommentare
Walter Roberson
Walter Roberson am 15 Mai 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 am 15 Mai 2017
Thank you for the suggestions. I will try them and see which one will yield a better result.

Melden Sie sich an, um zu kommentieren.


Philip Borghesani
Philip Borghesani am 15 Mai 2017
Bearbeitet: Philip Borghesani am 15 Mai 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 Kommentare
Walter Roberson
Walter Roberson am 15 Mai 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 am 17 Mai 2017
Thank you, I will try this option too.

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Data Type Conversion finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by