# Difference between revisions of "Floating Point Compare"

From ErlangCentral Wiki

m (eep, HTML element issue.) | |||

(3 intermediate revisions by 2 users not shown) | |||

Line 5: | Line 5: | ||

== Solution == | == 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: | In these cases, you can use floating-point byte strings to represent and compare numbers: | ||

<code> | <code> | ||

− | 1> | + | 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 | 7201.70 | ||

− | 2> | + | 2> B = 8.0011e-3 * 9.001e5. |

7201.79 | 7201.79 | ||

− | 3> | + | 3> A == B. |

false | false | ||

− | 4> | + | 4> fuzzy_match(A,B,3). |

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

true | true | ||

− | + | 5> fuzzy_match(A,B,4). | |

− | + | ||

− | + | ||

− | + | ||

− | + | ||

false | false | ||

</code> | </code> | ||

Line 41: | Line 27: | ||

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

<code> | <code> | ||

− | + | 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 | true | ||

+ | 6> equal_to_digit(7201,700099999999, 7201.790110000001,2). | ||

+ | false | ||

</code> | </code> | ||

Line 69: | Line 44: | ||

− | [[Category:CookBook]] | + | [[Category:CookBook]][[Category:NumberRecipes]] |

## 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