Erlang Central

Difference between revisions of "Floating Point Compare"

From ErlangCentral Wiki

(Actually implement the "fuzzy match".)
m (eep, HTML element issue.)
Line 10: Line 10:
 
<code>
 
<code>
 
fuzzy_match(A,B,L) ->
 
fuzzy_match(A,B,L) ->
     <<AT:L/binary, _/binary>> = <<A/float>>,
+
     &lt;&lt;AT:L/binary, _/binary>> = &lt;&lt;A/float>>,
     <<BT:L/binary, _/binary>> = <<B/float>>,
+
     &lt;&lt;BT:L/binary, _/binary>> = &lt;&lt;B/float>>,
 
     AT == BT.
 
     AT == BT.
 
1> A = 8.001e-3 * 9.001e5.
 
1> A = 8.001e-3 * 9.001e5.

Revision as of 15:49, 24 September 2006

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:

fuzzy_match(A,B,L) ->
    <<AT:L/binary, _/binary>> = <<A/float>>,
    <<BT:L/binary, _/binary>> = <<B/float>>,
    AT == BT.
1> A = 8.001e-3 * 9.001e5.
7201.70
2> B = 8.0011e-3 * 9.001e5.
7201.79
3> A == B.
false
4> fuzzy_match(A,B,3).
true
5> fuzzy_match(A,B,4).
false

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

equal_to_digit(A,B,D) ->
    [As0,Bs0] = io_lib:fwrite("~.*f~.*f", [D+1,A-trunc(A),D+1,B-trunc(B)]),
    As = string:substr(As0,1,D+2), Bs = string:substr(Bs0,1,D+2),
    As == Bs.
5> equal_to_digit(7201.700099999999, 7201.790110000001,1).
true
6> equal_to_digit(7201,700099999999, 7201.790110000001,2).
false

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

See Also

Volume 2, Section 4.2.2 of The Art of Computer Programming