Deleting an Element Modifies Other Elements

1 回表示 (過去 30 日間)
Mohammad Abu Laila
Mohammad Abu Laila 2020 年 7 月 25 日
編集済み: John D'Errico 2020 年 7 月 25 日
I was having an issue in my code. However, I narrowed it down to this issue. In my code, I delete the first element of an array and compare it with another array. When the arrays are supposed to be identical, some of the elements of the first array will get modified somehow.
Here is an example code.
a=1:0.1:2;
a(1)=[];
b=1.1:0.1:2;
eq=isequal(a,b);
c=a-b;
d=c/eps;
The output of the code is:
eq =
logical
0
c =
1.0e-15 *
0 -0.2220 0 -0.2220 0 0 0 0 0 0
d =
0 -1 0 -1 0 0 0 0 0 0
I cannot pinpoint the origin of this issue. However, as can be seen from the array d, the values of some of the elements the array a are shifted by a value of eps, i.e. the floating-point relative accuracy. In addition, the shift of values does not happen at the same indices. It will be random as the original elements of the array a are declared differently. If the code is modified as follows:
a=1e-3:1e-4:2e-3;
a(1)=[];
b=1.1e-3:1e-4:2e-3;
eq=isequal(a,b);
c=a-b;
d=c/eps;
And the output is:
eq =
logical
0
c =
1.0e-18 *
0 0 -0.2168 -0.2168 0 0 0 0 0 0
d =
1.0e-03 *
0 0 -0.9766 -0.9766 0 0 0 0 0 0
Here a shift of eps, with relative to the 1e-3 range, happened in the 3rd and 4th elements not the 2nd and 4th elements as in the previous example. Does somebody know how to mitigate this issue?

回答 (2 件)

John D'Errico
John D'Errico 2020 年 7 月 25 日
編集済み: John D'Errico 2020 年 7 月 25 日
No. You are coming to a conclusion based on the wrong assumptions. It is NOT that deleting an element modifies other elements.
a = 1:0.1:2;
>> b = 1.1:0.1:2;
>> a(3)
ans =
1.2
>> b(2)
ans =
1.2
Are they the same? They look to be the same.
a(3) == b(2)
ans =
logical
0
But MATLAB knows they are not the same. I did not need to delete an element. In fact, they were computed using different floating point operations to arrive at the result.
sprintf('%0.55f',a(3))
ans =
'1.1999999999999999555910790149937383830547332763671875000'
sprintf('%0.55f',b(2))
ans =
'1.2000000000000001776356839400250464677810668945312500000'
It turns out they differ by one bit down at the level of the least significant bits. In a "binary" form, we could write the expansion for a(3) and b(2) as
a(3): '1.0011001100110011001100110011001100110011001100110011'
b(2): '1.0011001100110011001100110011001100110011001100110100'
You can read those binary expansionas as if
a(3) = a + 1/8 + 1/16 + 1/128 + 1/256 + ...
so we would have a(3) as the expression:
a(3) == sum(2.^[0 -3 -4 -7 -8 -11 -12 -15 -16 -19 -20 -23 -24 -27 -28 -31 -32 -35 -36 -39 -40 -43 -44 -47 -48 -51 -52])
So in fact, if we increment a(3) by the least significant bit, we will see a double carry in binary, and get exactly b(2). So It truly is a 1 bit difference between those values.
a(3) + 2^-52 == b(2)
ans =
logical
1
What you need to learn is that the number 1.2 (edited: typo originally said 1/2) is NOT exactly representable in a binary form. Just like the decimal form of the fraction 1/3 is in fact an infinitely repeating decimal. So 1.2, when represented in binary, is an infinitely repeating binary form. You should be able to see the pattern above. The pattern '0011' repeats infinitely often.
This is even discussed in the MATLAB FAQ as I recall, but this is a behavior that will be found in any language that uses a floating point binary form (The IEEE standard) to represent numbers. It would happen even if we were internally representing the numbers in decimal form, since as I said before, then we would have the problem that fractions like 1/3 are not exactly representable.
How do problems arise? Suppose you want to represent all numbers as decimals. I'll arbitrarily pick 5 digit deimal expansions. So we would have
a = 1/3 = 0.33333
Correct? What is 2/3? The best approximation for 2.3 would be
b = 2/3 = 0.66667
But then we clearly have
a + a = 2*a = 0.66666
So 2*a ~= b. Likewise, 3*a = a + a + a should be 1. Instead, it would be 0.99999, which is not 1. Close, but not 1.
This is, as I said, a fundamental limitation of any floating point storage form. There will always be numbers which will not be storable in an exact form. Whenever you are forced to store numbers in a finite number of digits or bits, whatever, you will also see contradictions arise, where a number is not exactly what you think it is.
  2 件のコメント
Steven Lord
Steven Lord 2020 年 7 月 25 日
What you need to learn is that the number 1/2 is NOT exactly representable in a binary form.
Did you mean 1/10 here or 1.2?
John D'Errico
John D'Errico 2020 年 7 月 25 日
編集済み: John D'Errico 2020 年 7 月 25 日
oops, lol. Actually, I intended to write 1.2, not 1/2.
The keys . amd / are right next to each other on the keyboard. Just fat fingers on my part.

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


madhan ravi
madhan ravi 2020 年 7 月 25 日
a=sym(1e-3:1e-4:2e-3);
a(1)=[];
b=sym(1.1e-3:1e-4:2e-3);
  2 件のコメント
Mohammad Abu Laila
Mohammad Abu Laila 2020 年 7 月 25 日
Why should the array be converted to a symbolic array?
What is the cause of the of the original problem?
madhan ravi
madhan ravi 2020 年 7 月 25 日
Click on the tag floating-point to see lots of discussions there.

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

カテゴリ

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

製品


リリース

R2020a

Community Treasure Hunt

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

Start Hunting!

Translated by