Compare numbers within tolerance - which is faster?


#1

Imagine you have a lot (say, tens of thousands) of number pairs a,b to compare - which is faster?

“Pure Python”:

if abs(a-b) < tol: return True

or RhinoCommon:

Import Rhino
if Rhino.RhinoMath.EpsilonEquals(a, b, tol) : return True

I suspect pure Python… but maybe the difference is negligible…

Thx, --Mitch


(David Rutten) #2

Only one way to find out Mitch…


#3

Aww, c’mon, you’re going to make me test it ??? :sweat_smile:

Geez, can’t get away with being lazy here…

– Mitch


(Willem Derks) #4

Here you go:

speedtestcompare.py (629 Bytes)

for 5.000.000 numbers

python : 8.29088592529
EpsilonEquals : 9.48072814941

-Willem


#5

Yep, just finished mine - for a 100K run:
Python: 0.156265
EpsilonEquals : 0.171875

So, minor difference, but measurable…

–Mitch


(Willem Derks) #6

That depends: you say 10% is minor?
That is 6 minutes on an hour or working half a day more per week.

Or since it’s almost weekend 1 gulp extra in a :beer:

-Willem


#7

Nice perspectives! Cheers! Gulp Gulp. (+one extra)


#8

Well, in this case, I figured that even if I ran it a million times, I would only save two seconds, hardly enough time to really enjoy that additional gulp of beer… :smile:

–Mitch


(Menno Deij - van Rijswijk) #9

I added EpsilonEquals to RhinoCommon a while back, and its performance is slightly slower due to the fact that it takes NaN an Infinity into account, as well as floating point representation of numbers whose difference is not well defined due to the details of how they are represented in bits.

I am actually surprised that the difference is so small :slight_smile:


#10

Hello Willem,

do you get different results too when running your script multiple times ? Mine vary between 0.8 and 1 second. It seems that it runs both tests slightly faster by using xrange instead:

python : 3.65004730225
EpsilonEquals : 4.89257049561

I´ve been curious how it compares to vbScript using the code below (not shure if both scripts can be called equivalent):

Option Explicit

Call speedtestcompare()
Sub speedtestcompare()

	Dim numbers(5000000), i, dbltol, start_time, x
	
	For i = 0 To 5000000 : numbers(i) = rnd * i : Next	
    
	dbltol = 0.01
	start_time = timer
    
	For i = 1 To 5000000
		If Abs(numbers(i - 1) - numbers(i)) < dbltol Then
			x = True
		End If
	Next	
    
	Rhino.Print "vbScript: " & timer - start_time
    
End Sub

The result was 1.875 seconds. Can anyone explain why there is such a large difference compared to python or suggest ways to gain more speed?

c.


#11

Yes, I’ve noticed this too - on certain things Python is way slower than VBS. I don’t know if that’s because it has to go through an additional layer of stuff or what…

–Mitch


(Menno Deij - van Rijswijk) #12

For your reference, this is the code that is in RhinoMath.EpsilonEquals.

    /// <summary>
    /// Compare two doubles for equality within some "epsilon" range
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="epsilon"></param>
    /// <returns></returns>
    public static bool EpsilonEquals(double x, double y, double epsilon)
    {
      // IEEE standard says that any comparison between NaN should return false;
      if (double.IsNaN(x) || double.IsNaN(y))
        return false;
      if (double.IsPositiveInfinity(x))
        return double.IsPositiveInfinity(y);
      if (double.IsNegativeInfinity(x))
        return double.IsNegativeInfinity(y);

      // if both are smaller than epsilon, their difference may not be.
      // therefore compare in absolute sense
      if (Math.Abs(x) < epsilon && Math.Abs(y) < epsilon)
      {
        bool result = Math.Abs(x - y) < epsilon;
        return result;
      }

      return (x >= y - epsilon && x <= y + epsilon);
    }