I have the following values that I run through the atan2 function:
a(77:78,:)
ans =
-0.250000000000000 0 -0.950000000000000
-0.260000000000000 0 -0.950000000000000
when I put the above array through the atan2 function, the first value is positive and the second is negative,
atan2(a(77:78,2),a(77:78,3))
ans =
3.141592653589793
-3.141592653589793
If I type in each value of the second row of data by hand, the result is differnt for the atan2 function (it is positive):
atan2(0,-0.95)
ans =
3.141592653589793
If I build a test matrix, manually inputing the values, the atan2 results are both positive.
test = [-0.25, 0 , -0.95; -0.26, 0 , -0.95]
test =
-0.250000000000000 0 -0.950000000000000
-0.260000000000000 0 -0.950000000000000
>> atan2(test(1,2),test(1,3))
ans =
3.141592653589793
>> atan2(test(2,2),test(2,3))
ans =
3.141592653589793
Question: Why are the values of atan2 function positive and negative in the first case but then both positive when I type out the values?
Aside: If done separately:
atan2(a(77,2),a(77,3))
ans =
3.141592653589793
>> atan2(a(78,2),a(78,3))
ans =
-3.141592653589793
Thank you

 Accepted Answer

Stephen23
Stephen23 on 25 Nov 2020
Edited: Stephen23 on 25 Nov 2020
The reason is a little arcane: negative zero:
The other answers and comments are wrong: this has nothing to do with floating point error or "almost zero" values.
The second column values are exactly zero, and we know that the value is exactly zero because in both long and short format only the exact value zero is displayed as one single digit "0", just as all of your examples show.
So what is the catch?
The catch is simply the IEEE 754 defines two zeros, a positive zero and a negative zero. Same value, different signs. Some (but not all) operations retain the sign when operating on them.
One of your zeros is negative and one is positive, but unfortunately MATLAB** displays them without the sign:
Y = [0;-0] % positive and negative zero!
Y = 2×1
0 0
X = [-0.95;-0.95]; % these values are not really relevant
atan2(Y,X)
ans = 2×1
3.1416 -3.1416
Here is a useful trick to detect if a zero is positive or negative (simply displaying it doesn't work):
Y % they look the same ... but are they?
Y = 2×1
0 0
sign(1./Y) % no!
ans = 2×1
1 -1
Negative zeros can be generated by some arithmetic operations, or perhaps by converting data from text. If you want to remove negative zeros from an array without changing the sign of the other data, just add zero:
Z = [-0,-2,+0,3]
Z = 1×4
0 -2 0 3
sign(1./Z)
ans = 1×4
-1 -1 1 1
Z = 0+Z % remove negative zeros
Z = 1×4
0 -2 0 3
sign(1./Z)
ans = 1×4
1 -1 1 1
** for what it's worth, Octave does display the sign.

8 Comments

What are other way to generate negative 0?
1/(-Inf)
V = [-0, -0e23, 0*-1, 1/-Inf, -0+-0, sscanf('-0','%f'), hex2num('8000000000000000')]
V = 1×7
0 0 0 0 0 0 0
sign(1./V)
ans = 1×7
-1 -1 -1 -1 -1 -1 -1
Bruno Luong
Bruno Luong on 25 Nov 2020
Edited: Bruno Luong on 25 Nov 2020
one more by seeting the sign bit
>> z=typecast(uint8([0 0 0 0 0 0 0 128]),'double')
z =
0
>> sign(1/z)
ans =
-1
Vice versa this sign bit gives another way to test a floating scalar x is negative
b = typecast(x,'uint8');
negative = bitand(b(end),128)~=1
Bruno Luong
Bruno Luong on 25 Nov 2020
Edited: Bruno Luong on 25 Nov 2020
So the "fix" for OP question is
a(a(:,2)==0,2) = 0;
atan2(a(xxx,2),a(xxx,3)) % xxx are row indices
Here's are a few others, started in this thread
>> x = [0.1 -0.1];
>> y = round(x)
y =
0 0
>> format hex
>> y
y =
0000000000000000 8000000000000000
>> fix(x)
ans =
0000000000000000 8000000000000000
>> ceil(x)
ans =
3ff0000000000000 8000000000000000
Upstream in this thread it was stated:
"If you want to remove negative zeros from an array without changing the sign of the other data, just add zero"
Just to be clear, adding zero only impacts the real part of a complex number
>> x = [0+1i*3; -0.1-0.1*1i];
>> x = round(x)
x =
0000000000000000 4008000000000000i
8000000000000000 8000000000000000i
>> x + 0
ans =
0000000000000000 4008000000000000i
0000000000000000 8000000000000000i
Unclear if there is a way to simultaneously "fix" the real and imaginary parts other than:
>> z = complex(real(x)+0,imag(x)+0)
z =
4014000000000000 4008000000000000i
0000000000000000 0000000000000000i
or other similar methods that break out the real and imaginary parts, process them, and then recombine.
>> format hex
>> x = round([0+1i*3; -0.1-0.1*1i])
x =
0000000000000000 4008000000000000i
8000000000000000 8000000000000000i
>> x+complex(0)
ans =
0000000000000000 4008000000000000i
0000000000000000 0000000000000000i
Beside that ATAN2 accepts only real arguments. So not sure this observation is relevant here, and I could't locate the upstream quote.
Paul
Paul on 6 Dec 2020
The upstream quote is in Stephen's original answer.
Wasn't making the observation in the context of ATAN2 alone; was just interested in how to get rid of the negative zero in general.
Adding complex(0) is a much better solution. Thanks for pointing that out.

Sign in to comment.

More Answers (2)

John D'Errico
John D'Errico on 24 Nov 2020

0 votes

What you don't understand is that just because MATLAB displays a number represented to 15 digits, does not mean it is EXACTLY the same thing as what you typed in.
In fact, typically when MATLAB shows a number as -0.950000000000000, you should expect there is more to that number than meets the eye. Anyway, a double precision number cannot represent the number you have written exactly. Just as you cannot represent the fraction 2/3 exactly in any finite number of decimal digits, you cannot represent the decimal number 0.95 as an exact binary representation. This number would be represented by the infinitely repeating string...
'11110011001100110011001100110011001100110011001100110...'
So when you typed in 0.95, you certainly were typing in a DIFFERENT number than you havd stored in the array a. And that is why you get a differnt result. It is not atan2, but the numbers you passed to atan2.

10 Comments

Bradley Hughes
Bradley Hughes on 25 Nov 2020
Edited: Bradley Hughes on 25 Nov 2020
First, I think this answer comes off as kind of condescending ... "What you don't understand"? Really?
Secondly, I think this answer is nonsensical. When you type a number into Matlab, like -.9500000, that's the number. The fact that a rational number like 2/3 is non-terminating, while -.95000 is not, makes for a false analogy.
By the logic you've presented here, NO function would give the same answers when done over and over again. You could try to do ANY function and keep getting different answers, which doesn't happen.
@John
Thank you for the response. Maybe I do not understand, but that is why I am here. I am concerned about what you wrote because my example shows (oversimplifed, but hopefully to the point)
2.000000000/2 = 1.00000000000
2.000000000/2 = -1.00000000000
and what you are saying is that because some extra digits exist that matlab doesn't show, that is why the result is negative.
I even tried using matlab function vpa, but that didn't help.
@Brad, I agree
MATLAB does not not store fractions in decimal. It uses ieee 754 double precision numbers, which are binary rather than decimal. The number 1/10 decimal cannot be exactly represented in binary floating point systems. The numbers that can be exactly represented are 0, together with some extremely small numbers around 10^-304, together with numbers which can be represented as (1+(integer divided by 2^53)) times 2^integer. The scheme can exactly represent integers up to 2^52 but cannot exactly represent 1/10. It can represent fractions that are an integer divided by a power of 2. So it can represent 102/1024 for example. But 1/10 is not m/2^n for any finite integer n m – if it were then 1/10 = m/2^n implies that 2^n = 10*m but 10 factors to 2*5 so you would have to have a number that is only divisible by 2 somehow also be divisible by 5.
@Walter
Thank you, I'm still marinating on what you wrote. Because MATLAB represents fractions in binary, that is why the atan2 functions are showing positive for one answer and negative for another answer.
What I am stuck still though is how can I reproduce this:
atan2(0,-0.9500000000000000000000000000000000000000000000000)
ans =
3.1416
If I am understanding what you wrote, I just need to have more digits on the end, which will cause the answer to flip to a negative?
atan2(b(2),-0.95000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)
ans =
3.1416
Can you recommend a way to reproduce the result from the question?
diff(a(77:78,3))
will give you a nonzero answer, showing you a small numeric difference.
(1+(integer divided by 2^53)) times 2^integer.
The 1 part is talking about the set of "normalized" numbers: numbers whose representation starts with a binary 1, followed by up to 52 bits, and the 2^integer permits the "binary point" (binary equivalent of decimal point) to move along that string of binary digits.
For example, decimal 10 is binary 1010 (8+2), which is binary
1.010 000 000 000 000 000 000 000 000 000 000 000 000 * 2^3
which has an exact representation. Decimal 3.14599609375 is 2^1 + 2^0+1/8+1/64+1/256+1/1024+1/2048 which is binary
1.100 100 101 011 000 000 000 000 000 000 000 000 000 * 2^1
and so has an exact representation.
But 1/10 does not have an exact representation and so 0.95 does not have an exact representation. 0.25 on the other hand does have an exact representation -- but 0.26 does not.
A finite decimal system can represent a (length-limited) subset of (integer)*10^integer such as 95*10^(-2) -> 0.95 . It can exactly represent the fraction A/B only when after being reduced to lowest terms, there is an integer such that B exactly divides 10 to an integer.... which when abs(B) > abs(A) requires that B can be factored into only 2's and 5's. 17/50 for example is fine for decimal as it can be written as 34/100 -> 34 * 10^-2 . But 2/7 cannot be written as a finite decimal.
A finite binary system can represent a (length-limited) subset of (integer)*2^integer such as 1100100101011 * 2^-11 -> 3.14599609375 . It can exactly represent the fraction A/B only when after being reduced to lowest terms, there is a integer such that B exactly divides 2 to the integer... which when abs(B) > abs(A) requires that B can be factor into only 2's. 1/10 cannot be written as finite binary. 2/7 cannot be written as finite binary either.
@Walter
Because I'm pulling the values from sensors, the numbers will be different from above. But the same thing happened:
a(144:145,:)
ans =
-0.6900 0 -0.6400
-0.6800 0 -0.7000
Then applying atans to the set above:
atan2(a(144:145,2),a(144:145,3))
ans =
3.1416
-3.1416
The result is positive for 1 and negative for the other.
When I use look at the difference after setting 'format long'
diff(a(144:145,3))
ans =
-0.060000000000000
If I type in the values by hand:
a(144,:)
ans =
-0.690000000000000 0 -0.640000000000000
>> atan2(0,-0.640000000000000)
ans =
3.141592653589793
>> a(145,:)
ans =
-0.680000000000000 0 -0.700000000000000
>> atan2(0,-0.700000000000000)
ans =
3.141592653589793
Both are positive.
I understand that +pi and -pi are the same thing, but I'm still stuck as to why atan2 is changing its answer from positive to negative.
Thank you for any thoughts
Look at
format long
a(144:145,2)
I suspect the values are not exact 0, and that fact is being hidden by your use of format short
Bruno Luong
Bruno Luong on 25 Nov 2020
Edited: Bruno Luong on 25 Nov 2020
For sure
a(145,2)
is negative (but close to 0)
Stephen23
Stephen23 on 25 Nov 2020
Edited: Stephen23 on 25 Nov 2020
"I suspect the values are not exact 0, and that fact is being hidden by your use of format short"
@Walter Roberson: can you please show a one single example of a non-zero value that is displayed as the single digit "0" (as all of Richard Bag's second-column examples in this thread show). I can't find any:
>> format short
>> [0,eps(0),-eps(0),-0.95]
ans =
0 0.0000 -0.0000 -0.9500
>> format long
>> [0,eps(0),-eps(0),-0.95]
ans =
0 0.000000000000000 -0.000000000000000 -0.950000000000000

Sign in to comment.

Bruno Luong
Bruno Luong on 25 Nov 2020
Edited: Bruno Luong on 25 Nov 2020
Your result
atan2(a(77:78,2),a(77:78,3))
ans =
3.141592653589793
-3.141592653589793
Type single value
a(78,2)
you will see it's actually negative (not exactly 0).
Yes atan2(y,x) has discontinuity at the semi axes { y = 0 } for x < 0.

4 Comments

Did the file get uploaded? I don't seem to see it?
Stephen23
Stephen23 on 25 Nov 2020
Edited: Stephen23 on 25 Nov 2020
"you will see it's actually negative (not exactly 0)."
It is exactly zero. Negative zero in fact.
MATLAB does not display non-zero numbers as the single digit "0", as all of Richard Bag's examples show.
Bruno Luong
Bruno Luong on 25 Nov 2020
Edited: Bruno Luong on 25 Nov 2020
Got you stephen. Good point
Ah, matlab does consider the sign of the 0 in deciding quadrant.

Sign in to comment.

Products

Release

R2020a

Asked:

on 24 Nov 2020

Commented:

on 6 Dec 2020

Community Treasure Hunt

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

Start Hunting!