Erlang Central

# Difference between revisions of "Floating Point Compare"

From ErlangCentral Wiki

## Problem

You want to compare two floating-point numbers and know if they are equal. Unfortunately, floating-point arithmetic is not precise so very few results will match exactly. Consequently, we usually want to compare floating point values up to a certain number of decimal places.

## Solution

Implement a "fuzzy match" on two real numbers where the difference is below some epsilon threshhold.

In these cases, you can use floating-point byte strings to represent and compare numbers:

```1> Aval = 8.001e-3 * 9.001e5.
7201.70
2> Bval = 8.0011e-3 * 9.001e5.
7201.79
3> Aval == Bval.
false
4> ABin = << Aval/float >>.
<<64,188,33,179,57,192,235,237>>
5> BBin = << Bval/float >>.
<<64,188,33,202,68,166,34,63>>
6> << ABinTest:3/binary, ARest:5/binary >> = ABin.
<<64,188,33,179,57,192,235,237>>
7> ABinTest.
<<64,188,33>>
8> << BBinTest:3/binary, BRest:5/binary >> = BBin.
<<64,188,33,202,68,166,34,63>>
9> BBinTest.
<<64,188,33>>
10> BinTest == BinTest2.
true
11> << ABinTest2:4/binary, ARest2:4/binary >> = ABin.
<<64,188,33,179,57,192,235,237>>
12> << BBinTest2:4/binary, BRest2:4/binary >> = BBin.
<<64,188,33,202,68,166,34,63>>
13> ABinTest2 == BBinTest2.
false
```

Another option is to convert the numbers into strings and then compare the portions of the numbers of interest:

```14> [Nsa]=io_lib:format("~.12f", [Aval]).
["7201.700099999999"]
15> [NSB]=io_lib:format("~.12f", [Bval]).
["7201.790110000001"]
16> string:substr(NSAa, 1, 6) == string:substr(NSB, 1, 6).
true
```

A final thought:

```20> Equal_to_digit = fun(Digit, Numa, Numb) ->
20> [N_a] = io_lib:format("~.12f", [Numa]),
20> [N_b] = io_lib:format("~.12f", [Numb]),
20> string:substr(N_a, 1, Digit) == string:substr(N_b,1,Digit) end.
#Fun<erl_eval.18.83214871>
21> Equal_to_digit(6, Aval, Bval).
true
```

Note: Some error handling would obviously be necessary to handle cases where the digits are insufficient for the match.