NaN does not operate symmetrically with integer classes

1 view (last 30 days)
If you are working with the integer classes, and you mix a NaN into arithmetic calculations with the data, then the result differs depending on whether the NaN appears in the first operation or if the NaN is encountered afterwards. At least on R2014a that is.
X = {NaN, uint8(2), uint8(3), uint8(4)};
T = perms(X);
total = @(A,B,C,D) A+B+C+D;
for K = 1 : size(T,1); result{K} = total(T{K,1},T{K,2},T{K,3},T{K,4}); end
[result(:),T]
ans =
[0] [ 4] [ 3] [ 2] [NaN]
[2] [ 4] [ 3] [NaN] [ 2]
[0] [ 4] [ 2] [ 3] [NaN]
[3] [ 4] [ 2] [NaN] [ 3]
[5] [ 4] [NaN] [ 2] [ 3]
[5] [ 4] [NaN] [ 3] [ 2]
[0] [ 3] [ 4] [ 2] [NaN]
[2] [ 3] [ 4] [NaN] [ 2]
[0] [ 3] [ 2] [ 4] [NaN]
[4] [ 3] [ 2] [NaN] [ 4]
[6] [ 3] [NaN] [ 2] [ 4]
[6] [ 3] [NaN] [ 4] [ 2]
[0] [ 2] [ 3] [ 4] [NaN]
[4] [ 2] [ 3] [NaN] [ 4]
[0] [ 2] [ 4] [ 3] [NaN]
[3] [ 2] [ 4] [NaN] [ 3]
[7] [ 2] [NaN] [ 4] [ 3]
[7] [ 2] [NaN] [ 3] [ 4]
[6] [NaN] [ 3] [ 2] [ 4]
[6] [NaN] [ 3] [ 4] [ 2]
[7] [NaN] [ 2] [ 3] [ 4]
[7] [NaN] [ 2] [ 4] [ 3]
[5] [NaN] [ 4] [ 2] [ 3]
[5] [NaN] [ 4] [ 3] [ 2]
It took me time to understand this table, and I had to do further tests to be sure. The first column is the result of the addition of the other 4 columns in that order, A+B+C+D . The operations are done starting from the left. If the NaN is not encountered in A or B then the NaN effectively "resets" the chain of additions to 0, so the result of the additions is whatever appears after that point. However, if the NaN occurs in the initial operation A+B in either position, then the result is 0 for that operation so the addition is whatever appears after the A+B point.
>> nan + int8(1) + int8(-5) + int8(-3)
ans =
-8
Entire first operation is affected, giving 0 for the pair so int8(1) is not contributing anything and the result is what is to the right of it
>> int8(0) + nan + int8(1) + int8(-5) + int8(-3)
ans =
-7
The first operation is affected, giving 0 for the first pair, but this is effectively the same as the case where the nan is encountered further on, with the nan resetting the total to 0 where it is encountered.
The operation of nan on items that are of single or double precision is well defined: of those were single or double items instead of uint8 or int8, then the nan would have propagated and the result would nan. But I do not recall seeing the result of combining nan and the integer classes documented.
I can come up with an explanation based upon pairwise operations and left-to-right evaluation. I would not say that it is wrong, just that it is unexpected . I was convinced for a while that it must be doing the operations right to left, until I tested further and found that it was just apparently asymmetric.

Accepted Answer

Steven Lord
Steven Lord on 31 Aug 2015
Scalar integer plus scalar double results in a scalar integer. This is explained in the documentation for the integer types.
"For all binary operations in which one operand is an array of integer data type (except 64-bit integers) and the other is a scalar double, MATLAB computes the operation using elementwise double-precision arithmetic, and then converts the result back to the original integer data type."
Since that sentence talks about the arithmetic operations AND conversion into an integer data type, let's talk about conversion. When dealing with values that are too large or too small to fit in an int8, INT8 will saturate a value that's too large at intmax('int8') and one that's too small at intmin('int8'). But NaN is neither too large nor too small; instead, it's a square peg that can't fit in the round hole that is INT8. [All the possible bit patterns are used for numbers between intmin and intmax, none were reserved for integer NaN.]
So what is int8(NaN)? Unfortunately, it appears there's one conversion operation that's not defined on that documentation page, and that is int8(NaN). [I vaguely remember asking the documentation staff to add that; I'll have to check what happened to that request.] As you can check, int8(NaN) is int8(0).
int8(4) + NaN
= int8(4+NaN)
= int8(NaN)
= int8(0)
and
NaN + int8(4)
= int8(NaN+4)
= int8(NaN)
= int8(0)

More Answers (0)

Community Treasure Hunt

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

Start Hunting!