Problem with number precision in version 2017a
1 visualizzazione (ultimi 30 giorni)
Mostra commenti meno recenti
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?
0 Commenti
Risposte (2)
Walter Roberson
il 15 Mag 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 Commenti
Walter Roberson
il 15 Mag 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)
Philip Borghesani
il 15 Mag 2017
Modificato: Philip Borghesani
il 15 Mag 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 Commenti
Walter Roberson
il 15 Mag 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.
Vedere anche
Categorie
Scopri di più su Data Type Conversion in Help Center e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!