10

These two long numbers are the same except for the last digit.

test = []; test(1) = 33777100285870080; test(2) = 33777100285870082;

but the last digit is lost when the numbers are put in the array:

unique(test)

ans = 3.3777e+16

How can I prevent this? The numbers are ID codes and losing the last digit is screwing everything up.

  • 2
    are they *just used as ID codes* and *is there no arithmetic operation* done on them? if so storing as a string may be a better option... – RTL Sep 25 '14 at 12:35
  • I tried but I get a similar problem, num2str cuts off the last digit. –  Sep 25 '14 at 12:47
  • 3
    Typing ``eps(test(1))`` returns ``4``. This means the next greater distinguishable number from ``test(1)`` is ``test(1)+4``. You can verify by ``length(unique([test, test(1)+4]))`` returning ``2``. I believe you cannot solve this issue with using default numbers, but rather read (or input) the id as strings. – Nras Sep 25 '14 at 13:03

2 Answers2

13

Matlab uses 64-bit floating point representation by default for numbers. Those have a base-10 16-digit precision (more or less) and your numbers seem to exceed that.

Use something like uint64 to store your numbers:

> test = [uint64(33777100285870080); uint64(33777100285870082)];
> disp(test(1));
   33777100285870080
> disp(test(2));
   33777100285870082

This is really a rounding error, not a display error. To get the correct strings for output purposes, use int2str, because, again, num2str uses a 64-bit floating point representation, and that has rounding errors in this case.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • Running ``num2str(test)`` with your unit64 input returns the desired strings. – Nras Sep 25 '14 at 13:09
  • Just wanted to chime in to say it's not really a rounding error *per se*, it's an intrinsic limit of the floating point representation. The floating point standard cannot represent such a small difference between two numbers of that magnitude. – Dylan Richard Muir Sep 25 '14 at 13:09
  • 64-bit floating-point type can represent exactly integers up to about 2^52. In your case the numbers are slightly larger than that, hence the problem. With one figure less you wouln't have had any problem. Try this for example: `33777100285870082-33777100285870080` (your numbers) gives `0` (wrong). But `3777100285870082-3777100285870080` (remove one figure) gives `2` (correct) – Luis Mendo Sep 25 '14 at 13:33
  • 1
    @Lefti just as long as your id's don't suddenly grow 3 or more digits longer, then this workaround also fails. – Nras Sep 25 '14 at 13:33
  • it should be ok, the ID code is always 17 digits long :) –  Sep 25 '14 at 13:49
  • @Dylan True, the "rounding" I mention, happens when the number is read by Matlab from text and converted into its internal representation. It's more of a "find the closest number that is representable" thing than pure base-10 rounding. – rubenvb Sep 25 '14 at 14:14
2

To add more explanation to @rubenvb's solution, your values are greater than flintmax for IEEE 754 double precision floating-point, i.e, greater than 2^53. After this point not all integers can be exactly represented as doubles. See also this related question.

Community
  • 1
  • 1
horchler
  • 18,384
  • 4
  • 37
  • 73