16

Obviously, float comparison is always tricky. I have a lot of assert-check in my (scientific) code, so very often I have to check for equality of sums to one, and similar issues.

Is there a quick-and easy / best-practice way of performing those checks?

The easiest way I can think of is to build a custom function for fixed tolerance float comparison, but that seems quite ugly to me. I'd prefer a built-in solution, or at least something that is extremely clear and straightforward to understand.

nbro
  • 15,395
  • 32
  • 113
  • 196
zuiqo
  • 1,149
  • 1
  • 10
  • 23

5 Answers5

11

I think it's most likely going to have to be a function you write yourself. I use three things pretty constantly for running computational vector tests so to speak:

Maximum absolute error

return max(abs(result(:) - expected(:))) < tolerance

This calculates maximum absolute error point-wise and tells you whether that's less than some tolerance.

Maximum excessive error count

return sum( (abs(result(:) - expected(:))) < tolerance )

This returns the number of points that fall outside your tolerance range. It's also easy to modify to return percentage.

Root mean squared error

return norm(result(:) - expected(:)) < rmsTolerance

Since these and many other criteria exist for comparing arrays of floats, I would suggest writing a function which would accept the calculation result, the expected result, the tolerance and the comparison method. This way you can make your checks very compact, and it's going to be much less ugly than trying to explain what it is that you're doing in comments.

Phonon
  • 12,549
  • 13
  • 64
  • 114
  • 4
    Using `eps` for tolerance is usually a good idea. Also, R2013a and onward has assertEqual statements within the unit testing framework that will help. – Jonas May 23 '14 at 09:12
  • Indeed, but sometimes it may not be enough, given that you may have lost precision several times in course of some calculations. – Phonon May 23 '14 at 09:32
  • Thanks, eps() sounds like a good idea. I was actually hoping for some kind of assertEqual outside of the unit test framework. – zuiqo May 23 '14 at 09:42
10

Any fixed tolerance will fail if you put in very large or very small numbers, simplest solution is to use eps to get the double precision:

abs(A-B)<eps(A)*4

The 4 is a totally arbitrary number, which is sufficient in most cases.

Daniel
  • 36,610
  • 3
  • 36
  • 69
5

Don't know any special build in solution. Maybe something with using eps function?

For example as you probably know this will give False (i.e. 0) as a result:

>> 0.1 + 0.1 + 0.1 == 0.3

ans =

     0

But with eps you could do the following and the result is as expected:

>> (0.1+0.1+0.1) - 0.3  < eps     

ans =

     1
Marcin
  • 215,873
  • 14
  • 235
  • 294
  • 2
    You should pass the order of magnitude to `eps`, since `eps(10000)` is larger than `eps(1)`, the default. – Jonas May 23 '14 at 09:12
0

I have had good experience with xUnit, a unit test framework for Matlab. After installing it, you can use:

  • assertVectorsAlmostEqual(a,b) (checks for normwise closeness between vectors; configurable absolute/relative tolerance and sane defaults)
  • assertElementsAlmostEqual(a,b) (same check, but elementwise on every single entry -- so [1 1e-12] and [1 -1e-9] will compare equal with the former but not with the latter).

They are well-tested, fast to use and clear enough to read. The function names are quite long, but with any decent editor (or the Matlab one) you can write them as assertV<tab>.

Federico Poloni
  • 668
  • 8
  • 24
-2

For those who understand both MATLAB and Python (NumPy), it would maybe be useful to check the code of the following Python functions, which do the job:

numpy.allclose(a, b, rtol=1e-05, atol=1e-08)
numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)
Magnilex
  • 11,584
  • 9
  • 62
  • 84
aquercia
  • 1
  • 3
  • 1
    This question is regarding MATLAB, not Python `numpy`. Read the question title and the tags carefully. Moreover, this is probably not constructive for those who are not familiar with Python and `numpy`, so checking the implementations of these is rather useless. – rayryeng May 07 '15 at 17:59
  • My experience is that many people use both matlab and python, so to those people it is useful to do code cross check – aquercia May 07 '15 at 18:30
  • From my experience on StackOverflow, a lot of people who answer MATLAB questions here do not know Python. I'm probably one of the few here that know both relatively well at the same time, and given my perspective, this answer is not useful. It's up to you on whether or not you want to leave it, but I'm gonna leave my downvote. It's not that I don't think your answer is technically correct, but it's because you have placed an answer in a question whose tags are not compatible. – rayryeng May 07 '15 at 18:52
  • 2
    However, if you **translated** the equivalent `numpy` code into MATLAB, then that is a very useful answer, and I'd be inclined to upvote. This way, not only do you point out what `numpy` already has, but you're giving us a way to do this in MATLAB. – rayryeng May 07 '15 at 18:57