Deleting an Element Modifies Other Elements

2 visualizaciones (últimos 30 días)
Mohammad Abu Laila
Mohammad Abu Laila el 25 de Jul. de 2020
Editada: John D'Errico el 25 de Jul. de 2020
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?

Respuestas (2)

John D'Errico
John D'Errico el 25 de Jul. de 2020
Editada: John D'Errico el 25 de Jul. de 2020
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 comentarios
Steven Lord
Steven Lord el 25 de Jul. de 2020
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 el 25 de Jul. de 2020
Editada: John D'Errico el 25 de Jul. de 2020
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.

Iniciar sesión para comentar.


madhan ravi
madhan ravi el 25 de Jul. de 2020
a=sym(1e-3:1e-4:2e-3);
a(1)=[];
b=sym(1.1e-3:1e-4:2e-3);
  2 comentarios
Mohammad Abu Laila
Mohammad Abu Laila el 25 de Jul. de 2020
Why should the array be converted to a symbolic array?
What is the cause of the of the original problem?
madhan ravi
madhan ravi el 25 de Jul. de 2020
Click on the tag floating-point to see lots of discussions there.

Iniciar sesión para comentar.

Productos


Versión

R2020a

Community Treasure Hunt

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

Start Hunting!

Translated by