필터 지우기
필터 지우기

Problem with number precision in version 2017a

조회 수: 2 (최근 30일)
Mazen Bahadi
Mazen Bahadi 2017년 5월 14일
댓글: Mazen Bahadi 2017년 5월 17일
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?

답변 (2개)

Walter Roberson
Walter Roberson 2017년 5월 15일
"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
Walter Roberson
Walter Roberson 2017년 5월 15일
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 2017년 5월 15일
Thank you for the suggestions. I will try them and see which one will yield a better result.

댓글을 달려면 로그인하십시오.


Philip Borghesani
Philip Borghesani 2017년 5월 15일
편집: Philip Borghesani 2017년 5월 15일
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
Walter Roberson
Walter Roberson 2017년 5월 15일
"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 2017년 5월 17일
Thank you, I will try this option too.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Logical에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by