Skip to content

Instantly share code, notes, and snippets.

@treyharris
Last active July 28, 2019 22:22
Show Gist options
  • Save treyharris/27d62183a573fb8b8f40c8e9a3bc1ce2 to your computer and use it in GitHub Desktop.
Save treyharris/27d62183a573fb8b8f40c8e9a3bc1ce2 to your computer and use it in GitHub Desktop.

Fuzzy matching of any numeric type

In Elisp: Numbers (Comparison of Numbers), a suggested definition of approx-equal is given as:

(defvar fuzz-factor 1.0e-6)
(defun approx-equal (x y)
  (or (= x y)
      (< (/ (abs (- x y))
            (max (abs x) (abs y)))
         fuzz-factor)))

I was breiefly surprised after evaluating this to find that (approx-equal 2 22) returned t. But then I realized the issue: in this case, the (< (/ ... fuzz-factor)) was performing integer division, and here, the result will almost certainly be 0, which is < fuzz-factor.

So here's a naïve attempt to fix this:

(defun approx-equal (fx fy)
  (let ((x (float fx))
      (y (float fy)))
    (or (= x y)
      (< (/ (abs (- x y))
            (max (abs x) (abs y)))
         fuzz-factor))))

It works, but is there a more idiomatic way?

Here's a suggestion from edgar-rft:

(defun approx-equal (x y)
  (or (= x y)
      (< (/ (float (abs (- x y)))
            (max (abs x) (abs y)))
         fuzz-factor)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment