0

I need to compare two double values in Matlab and check if they are equal. Now the two compared values are displayed to the user, so he can check the printed result, if necessary.

Now I need to know: Is it possible to compare the two double values so that they are equal, if their decimal representation (using 15 significant digits) is equal? For performance reasons, I would prefer not to compare the resulting strings.

For example the two hexadecimal values 3fd04b2bcf617348 and 3fd04b2bcf617359 represent the same displayed number and should therefore be treated equal, whereas 3fd04b2bcf617348 and 3fd04b2bcf617347 have different decimal representations and should be treated as different, even if their difference is lower:

fprintf('eq: %.15g\n', hex2num('3fd04b2bcf617348'), hex2num('3fd04b2bcf617359'))
fprintf('ne: %.15g\n', hex2num('3fd04b2bcf617348'), hex2num('3fd04b2bcf617347'))
walderich
  • 500
  • 1
  • 9
  • 24
  • Are you sure you want to compare the digits? Consider: `0.99999999` and `1.00000`.... – knedlsepp Feb 09 '15 at 15:15
  • Yes, this behaviour is exactly what I want. Especially in your example it is pretty obvious to the user, that the statement `0.999999 == 1.000000` is wrong, even more than `0.936475 == 0.936476`. With "the user" I refer to non-technical users, who do not understand the background of the underlying data. – walderich Feb 10 '15 at 09:00
  • 1
    What I meant is the following: `1.0000000001` will be interpreted as `1.`, but `0.999999999` won't, even though they have both the same distance from `1.`. I see no reason to accept the first but to reject the second. – knedlsepp Feb 10 '15 at 10:23

1 Answers1

1

You can round the values created by hex2num to 15 digits. This is done using the round function.

For MATLAB R2014b and higher, you can specify the precision directly

b = round(a,15);

For older versions, round just rounds to integers, so you will have to do it manually:

b = round(10^15 .* a) ./ 10^15;

If you compare the numbers after rounding, you get the desired behaviour:

a = [ hex2num('3fd04b2bcf617348'), hex2num('3fd04b2bcf617359') ; ...
      hex2num('3fd04b2bcf617348'), hex2num('3fd04b2bcf617347') ];

% Round to 15 digits
b = round(10^15 .* a) ./ 10^15;

% Compare results
abs(b(1,1) - b(1,2)) < 4*eps(b(1,1))
ans = 
     1

abs(b(2,1) - b(2,2)) < 4*eps(b(2,1))
ans = 
     0
hbaderts
  • 14,136
  • 4
  • 41
  • 48
  • Thanks for your quick reply. I already wrote a function which rounds values to arbitrary significant digits. That's why I was surprised that your simple and straightforward approach should work. I didn't consider using eps for comparison, though. But I wonder what the `4` represents? Someone in the linked article describes it as "totally arbitrary number". Unfortunately I found some values which give false positives. Here is one example: `3fead0c6dd554918`, `3fead0c6dd554913`. – walderich Feb 10 '15 at 09:20
  • @wls: If you really want to compare the digits, you will quite likely have to use `strcmp`, as programming the rounding stuff by hand will be prone to error. In reality `double`s should always have some margin of error and in general this approach should be better than comparing some decimal representation. Consider the computation: `x=(116./100.)*100.`, displaying `x` will yield `1.160000000000000e+02`, but still `floor(x)` will equal 115. Don't rely on the printed decimal digits, especially not on 15 digits, when the theoretical maximum is only 17. – knedlsepp Feb 10 '15 at 10:44
  • I totally agree, that this is a problematic topic. Your example also gives me `115.999...` when printing to theoretical maximum digits: `fprintf('%.17g\n', (116/100)*100)`. So do you think it isn't possible to round just like the output algorithm? Wikipedia says that double's have 15.95 significant digits. Isn't it possible to consistently round the remaining 0.95 digits? Can I maybe round the value to 14 significant digits and then compare the last digit without converting the value completely to a string? – walderich Feb 10 '15 at 12:44