Is precision the reason my code doesn't work ?

1 回表示 (過去 30 日間)
Faez Alkadi
Faez Alkadi 2017 年 9 月 15 日
コメント済み: Walter Roberson 2017 年 9 月 16 日
I have a matrix (as attached) I try to find rows that has a specific number in the 2nd column as N. It works when try N=1 or N=0 and extract the the new data from the original DATA. But when I pick a number from column 2 other than 1 or 0 For example the number in DATA(3044,2) which is (0.123945562585054) the code doesNOT work. I'm wondering if it is the precision or what ? Any help is highly appreciated:
data=[];
N=1;
for j=1:length(DATA);
if DATA(j,2)==N;
data =[data;DATA(j,:)]
else
data=[data];
end
end

採用された回答

Walter Roberson
Walter Roberson 2017 年 9 月 15 日
Yes, precision is the problem. You have to take special steps to be able to see the full precision of a number in order to be able to type it in with enough precision that you can do an exact comparison using "==" like you do.
I recommend that you use https://www.mathworks.com/matlabcentral/fileexchange/22239-num2strexact--exact-version-of-num2str- to look at what the numbers really stored are.
You should consider whether you really want to do exact bit-for-bit comparisons. Any two ways of computing values that are algebraically equivalent can have different round-off, so you should only ever use == to compare values that have been extracted from the same array. Otherwise you should compare with a tolerance.
  4 件のコメント
Faez Alkadi
Faez Alkadi 2017 年 9 月 16 日
編集済み: Faez Alkadi 2017 年 9 月 16 日
I used N=DATA(1470:2) for my code above to extract the data. so matlab would know whatever the value stored for N and work based on that.
the code still doesn't work.
Walter Roberson
Walter Roberson 2017 年 9 月 16 日
編集済み: Walter Roberson 2017 年 9 月 16 日
format long g
will display 15 digits, which is not quite enough to figure out exactly what the stored number is. On OS-X you can use techniques such as
fprintf('%.999g\n', DATA(1470))
to see the entire decimal representation of the number. You can do the same thing on Linux but the conversion gets inaccurate part way through. But on Windows, the Windows libraries just print 0s so you need a routine such as I linked to.
DATA(1470:2) is empty. Perhaps you mean DATA(1470,2) . If you extract a number from an array it is legitimate to use == to compare against members of the array to find out which ones are exactly bit-for-bit equal to it.
You might want to have a look at ismembertol() -- but watch out for the difference between relative tolerance and absolute tolerance.

サインインしてコメントする。

その他の回答 (1 件)

Jan
Jan 2017 年 9 月 16 日
Note that the statement
data=[data];
is simply a confusing waste of time: It uses the operator for concatenating a list of elements [] for one element only and assigns the output to the same variable as the input. 1. omit the unnecessary square brackets and 2. omit the complete line, when it does not perform anything.
The iterative growing of arrays consumes a lot of resources. If the final output contains 1000 rows, Matlab must allocate sum(1:1000) rows to create it: 500'500. A better implementation without a loop and without the iterative growing:
data = DATA(DATA(:, 2) == N, :)
The actual problem of the precision has been explained by Walter already. This might be useful:
match = abs(DATA(:, 2) - N) < 10 * eps(N);
data = DATA(match, :);
The limit might be absolute or relative depending on the meaning of your data. The factor 10 is chosen arbitrarily here also and has to be adjusted.
  3 件のコメント
Jan
Jan 2017 年 9 月 16 日
編集済み: Jan 2017 年 9 月 16 日
Data = round(Data, 4)
Note that this will not solve the precision problem! The elements of Data are still double precision values stored in binary format. Many decimal numbers do not have an exact binary representation, and therefore even the rounded numbers are not guaranteed to have only zeros as trailing digits. Example:
x1 = 0.5347 + 0.0001;
x2 = 0.7323 + 0.0001;
sprintf('%.16g\n', round(x1, 4), round(x2, 4))
% 0.5348000000000001
% 0.7323999999999999
And this is the exact and correct result for double precision data.
x1 == 0.5348 % FALSE !!!
There is no way around using an interval for the comparison when fractional numbers are used. But you can use integer values instead:
Data = round(Data * 10000);
As long as the original Data is smaller than 900'719'925'474 (2^53 / 10000), the results are exactly integers and the comparison works without an interval:
x1 = 0.5347
x2 = x1 + 0.0001
round(x1 * 10000) == 5347 % TRUE
round(x2 * 10000) == 5348 % TRUE
Walter Roberson
Walter Roberson 2017 年 9 月 16 日
For N digits after the decimal place, at most 2^N out of 10^N values have exact binary representation -- for example for 3 decimal places, at most 8 out of 1000 values have exact binary representation.

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeLogical についてさらに検索

Community Treasure Hunt

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

Start Hunting!

Translated by