6

I am trying to compare an array of doubles to a scalar double for equality, but equality is never recognized under certain circumstances. I suspect that this has to do with the way the double is represented (e.g., 1.0 vs 1.00), but I can't figure it out.

For instance, I have generated an array composed of thousands of double values, the last few of which at some instant in time are given by

10.6000
-11.0000
10.2000
22.6000
3.4000

If I test for equality to 10.2 (or 10.2000) by the command array==10.2 (or array=10.2000), I return an array of 0s. If I place the values shown into an array manually (e.g., array=[10.6000 -11.0000 10.2000 22.6000 3.4000]), then the command is successful (i.e., array==10.2 returns 0 0 1 0 0). Could someone please explain why the equality succeeds if I input the values manually, but fails if the array is generated in the context of a program? I am able to rectify the comparison failure by using an approximate rather than an exact comparison (e.g., (array<10.20001) & (array>10.19999)), but this seems unsatisfying.

Edit: The values in the array are generated by iterative addition or subtraction of a constant double (e.g., 0.2). The modulus of this array by 0.2 should therefore be everywhere equal to 0. In fact, the modulus of each element is equal to either 0 or 0.2, as shown below for the above sequence of numbers in the array:

mod(array,0.2)
...
0.2000
     0
0.2000
0.2000
     0

Again, if the values are placed in an array manually and the modulus is taken, the expected value of all 0s is obtained.

user001
  • 1,850
  • 4
  • 27
  • 42

3 Answers3

6

The reason is MATLAB truncated the numbers in the array to preserve only 4 digits after the decimal point when displaying,. That is, the real value of your array may be [10.600000000001, -10.99999999999, ...]. You are right, this is due to the internal representation of floating-point numbers in computer, which may cause tiny errors in the computations.

Personally I think there are two solutions, one is approximate matching like you did, while the other is to round the array up first (say, with this tool from FileExchange), and then do exact matching.

grapeot
  • 1,594
  • 10
  • 21
  • Very helpful. One follow-up question is that my numbers were generated by adding or subtracting a constant amount (e.g., `0.2`) over many cycles in a loop, so mathematically the numbers in the array should equal 0 when modulo 0.2 (`mod(array,0.2)`) is applied. In fact, they are not. They are equal to either 0 or 0.2. Yet of course, when I apply modulo 0.2 to any of the numbers in the array by typing them in manually, the expected value of 0 is given. Could you explain this behavior? Thanks! – user001 Jan 22 '12 at 06:40
  • 1
    This involves how float-point numbers are represented in the computers. An well-known fact is computers use binary rather than decimal. However, there is a problem coming with binary, i.e. a finite fraction, say 0.2 in decimal cannot be represented with finite digits in binary. That is, the binary representation of 0.2 in computer is actually 0.001110011100111..., which is endless. However, MATLAB uses 64 bits to represent a `Single`, which may cause 2^(-65) error. This error is rather tiny, but when there are quite a lot of iterations, it may accumulate. – grapeot Jan 22 '12 at 07:11
  • Wonderful explanation. Thank you so much. – user001 Jan 22 '12 at 07:13
  • 64 bits for a single? Is the value complex? – Ben Voigt Mar 07 '13 at 20:07
2

Something is probably in single precision somewhere, and double elsewhere. The binary representation of e.g. 10.2 in each is different as they terminate after a different number of bits. Thus they are different:

>> if (single(10.2) == 10.2) disp('honk'); end
>> if (single(10.2) == single(10.2)) disp('honk'); end
honk

You'll need to check for equality within some small difference:

 eps = 0.001;
 result = abs(array-10.2) < eps;

You can find the precision used in an array using whos:

>> whos A
  Name      Size            Bytes  Class     Attributes

  A         1x2                 8  single      
Alex
  • 5,863
  • 2
  • 29
  • 46
  • Thanks @Alex. Could you please see my comment under grapeot's post. If I take my array, generated by a series of addition or subtraction of 0.2 (double) in the context of a loop, the modulo of every element in the array is either 0 or 0.2, which makes no sense. I checked the precision of my array using the `whos` command (thanks), and it is double, as is my scalar comparator variable. – user001 Jan 22 '12 at 06:42
  • 1
    0.2 cannot be represented exactly as a binary float (see http://www.h-schmidt.net/FloatApplet/IEEE754.html), it's a continued fraction 0.1001 [1001 ... ]. So adding 0.2 to something might not do exactly what you think. If exactness is important, do your working in the minimum units of your problem, in this case it's probably easiest to work at 10x, and add 2 to numbers then check mod(num,2), then devide by 10 at the end. – Alex Jan 22 '12 at 07:03
  • Thank you very much. The problem is resolved by adding/subtracting 0.25, and this makes sense because 0.25 can be represented exactly as a binary float according to the applet you provided. I suppose the best place to find more information would be an article about floating point representation of numbers. – user001 Jan 22 '12 at 07:12
  • 1
    In my humble opinion, a better way may be to modify your algorithm to avoid error accumulation. It's specially worthwhile to pay attention to in numerical computation. – grapeot Jan 22 '12 at 07:16
  • Thanks @grapeot. Do you mean, as Alex suggested, to scale up to integers (which have exact representations), and scale down at the end? – user001 Jan 22 '12 at 07:18
  • 1
    Yes. Alex's approach is an approach to "avoid error accumulation". By proper scaling, you get exact results in integer field, and only introduce errors in the final division step (note the quotient cannot be represented accurately with finite binary digits). Therefore you can limit the error below 2^(-64), which is way better. – grapeot Jan 22 '12 at 07:23
  • @grapeot: Is there a way to display the entire 64 bits of a matlab double? Thanks. – user001 Jan 22 '12 at 07:29
  • You can try `format long`, which will give you 7 digits for `Single` and 15 digits for `Double`. [Ref](http://www.mathworks.com/help/techdoc/ref/format.html). – grapeot Jan 22 '12 at 07:33
  • You may be interested in [this blog post](http://blogs.mathworks.com/loren/2006/08/23/a-glimpse-into-floating-point-accuracy/). – grapeot Jan 22 '12 at 07:34
1

Create a MATLAB function file that will accept a modulo values (from 3 to 9; that is Z3 to Z9) and will output the least possible value describe by the modulo conditions.

Sample Simulation:

Z = [ 3 4 5 ]; % Modulo Z3, Z4, and Z5

r = [ 2 1 4 ]; % Remainder Values

Least Possible Value is 29.

The Z inputs must be an array matrix ... where in you can type any number from 3 to 9 .... and you can type 3,4,5,6,7,8,9 in any order, in any pairings or groupings ...

The r inputs should be equal to the number of z inputs too...

the output should yield the least possible value though modulo conditions...

alcharvard
  • 11
  • 1