Approximate equality: Difference between revisions
m (used numbers instead of bullets in the task's preamble.) |
m (→{{header|Wren}}: Changed to Wren S/H) |
||
(98 intermediate revisions by 38 users not shown) | |||
Line 1: | Line 1: | ||
{{ |
{{task}} |
||
Sometimes, when testing whether the solution to a task (for example, here on Rosetta Code) is correct, the |
Sometimes, when testing whether the solution to a task (for example, here on Rosetta Code) is correct, the |
||
Line 23: | Line 23: | ||
:# 10000000000000.001 <big>/</big> 10000.0, 1000000000.0000001000 |
:# 10000000000000.001 <big>/</big> 10000.0, 1000000000.0000001000 |
||
:# 0.001, 0.0010000001 |
:# 0.001, 0.0010000001 |
||
:# 0.000000000000000000000101, 0.0 |
|||
:# sqrt(2) * sqrt(2), 2.0 |
:# sqrt(2) * sqrt(2), 2.0 |
||
:# -sqrt(2) * sqrt(2), -2.0 |
:# -sqrt(2) * sqrt(2), -2.0 |
||
:# 3.14159265358979323846, 3.14159265358979324 |
:# 3.14159265358979323846, 3.14159265358979324 |
||
<br/> |
<br/> |
||
Answers should be true for the first example and false in the second, so that just rounding the numbers to a fixed number of decimals should not be enough. Otherwise answers may vary and still be correct. See the Python code for one type of solution. |
|||
Answers should be similar to the Python code example, except for the fifth case, which may well vary depending on how your function handles comparison with (exactly) 0.0. |
|||
<br><br> |
<br><br> |
||
__TOC__ |
__TOC__ |
||
=={{header|Ada}}== |
|||
<syntaxhighlight lang="ada"> |
|||
with Ada.Text_IO; use Ada.Text_IO; |
|||
with Ada.Numerics.Generic_Elementary_Functions; |
|||
procedure Main is |
|||
type Real is digits 18; |
|||
package Real_Funcs is new Ada.Numerics.Generic_Elementary_Functions(Real); |
|||
use Real_Funcs; |
|||
package Real_IO is new Ada.Text_IO.Float_IO(Real); |
|||
use Real_IO; |
|||
function Approx_Equal (Left : Real; Right : Real) return Boolean is |
|||
-- Calculate an epsilon value based upon the magnitude of the |
|||
-- maximum value of the two parameters |
|||
eps : Real := Real'Max(Left, Right) * 1.0e-9; |
|||
begin |
|||
if left > Right then |
|||
return Left - Right < eps; |
|||
else |
|||
return Right - Left < eps; |
|||
end if; |
|||
end Approx_Equal; |
|||
Type Index is (Left, Right); |
|||
type Pairs_List is array (Index) of Real; |
|||
type Pairs_Table is array(1..8) of Pairs_List; |
|||
Table : Pairs_Table; |
|||
begin |
|||
Table := ((100000000000000.01, 100000000000000.011), |
|||
(100.01, 100.011), |
|||
(10000000000000.001 / 10000.0, 1000000000.0000001000), |
|||
(0.001, 0.0010000001), |
|||
(0.000000000000000000000101, 0.0), |
|||
(sqrt(2.0) * sqrt(2.0), 2.0), |
|||
(-sqrt(2.0) * sqrt(2.0), -2.0), |
|||
(3.14159265358979323846, 3.14159265358979324)); |
|||
for Pair of Table loop |
|||
Put(Item => Pair(Left), Exp => 0, Aft => 16, Fore => 6); |
|||
Put(" "); |
|||
Put(Item => Pair(Right), Exp => 0, Aft => 16, Fore => 6); |
|||
Put_Line(" " & Boolean'Image(Approx_Equal(Pair(Left), Pair(Right)))); |
|||
end loop; |
|||
end Main; |
|||
</syntaxhighlight> |
|||
{{Output}} |
|||
<pre> |
|||
100000000000000.0100000000000000 100000000000000.0110000000000000 TRUE |
|||
100.0100000000000000 100.0110000000000000 FALSE |
|||
1000000000.0000001000000000 1000000000.0000001000000000 TRUE |
|||
0.0010000000000000 0.0010000001000000 FALSE |
|||
0.0000000000000000 0.0000000000000000 FALSE |
|||
2.0000000000000000 2.0000000000000000 TRUE |
|||
-2.0000000000000000 -2.0000000000000000 FALSE |
|||
3.1415926535897932 3.1415926535897932 TRUE |
|||
</pre> |
|||
=={{header|ALGOL 68}}== |
|||
{{Trans|Kotlin}} |
|||
<syntaxhighlight lang="algol68">BEGIN # test REAL values for approximate equality # |
|||
# returns TRUE if value is approximately equal to other, FALSE otherwide # |
|||
PROC approx equals = ( REAL value, REAL other, REAL epsilon )BOOL: ABS ( value - other ) < epsilon; |
|||
# shows the result of testing a for approximate equality with b # |
|||
PROC test = ( REAL a, b )VOID: |
|||
BEGIN |
|||
REAL epsilon = 1e-18; |
|||
print( ( a, ", ", b, " => ", IF approx equals( a, b, epsilon ) THEN "true" ELSE "false" FI, newline ) ) |
|||
END # test # ; |
|||
# task test cases # |
|||
test( 100000000000000.01, 100000000000000.011 ); |
|||
test( 100.01, 100.011 ); |
|||
test( 10000000000000.001 / 10000.0, 1000000000.0000001000); |
|||
test( 0.001, 0.0010000001 ); |
|||
test( 0.000000000000000000000101, 0.0 ); |
|||
test( sqrt( 2 ) * sqrt( 2 ), 2.0 ); |
|||
test( - sqrt( 2 ) * sqrt( 2 ), -2.0 ); |
|||
test( 3.14159265358979323846, 3.14159265358979324 ) |
|||
END</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
+1.00000000000000e +14, +1.00000000000000e +14 => true |
|||
+1.00010000000000e +2, +1.00011000000000e +2 => false |
|||
+1.00000000000000e +9, +1.00000000000000e +9 => false |
|||
+1.00000000000000e -3, +1.00000010000000e -3 => false |
|||
+1.01000000000000e -22, +0.00000000000000e +0 => true |
|||
+2.00000000000000e +0, +2.00000000000000e +0 => false |
|||
-2.00000000000000e +0, -2.00000000000000e +0 => false |
|||
+3.14159265358979e +0, +3.14159265358979e +0 => true |
|||
</pre> |
|||
=={{header|AWK}}== |
|||
<syntaxhighlight lang="awk"> |
|||
# syntax: GAWK -f APPROXIMATE_EQUALITY.AWK |
|||
# converted from C# |
|||
BEGIN { |
|||
epsilon = 1 |
|||
while (1 + epsilon != 1) { |
|||
epsilon /= 2 |
|||
} |
|||
printf("epsilon = %18.16g\n\n",epsilon) |
|||
main("100000000000000.01","100000000000000.011") |
|||
main("100.01","100.011") |
|||
main("10000000000000.001"/"10000.0","1000000000.0000001000") |
|||
main("0.001","0.0010000001") |
|||
main("0.000000000000000000000101","0.0") |
|||
main(sqrt(2.0)*sqrt(2.0),"2.0") |
|||
main(-sqrt(2.0)*sqrt(2.0),"-2.0") |
|||
main("3.14159265358979323846","3.14159265358979324") |
|||
exit(0) |
|||
} |
|||
function main(a,b, tmp) { |
|||
tmp = abs(a - b) < epsilon |
|||
printf("%d %27s %s\n",tmp,a,b) |
|||
} |
|||
function abs(x) { if (x >= 0) { return x } else { return -x } } |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
epsilon = 1.110223024625157e-016 |
|||
1 100000000000000.01 100000000000000.011 |
|||
0 100.01 100.011 |
|||
0 1e+009 1000000000.0000001000 |
|||
0 0.001 0.0010000001 |
|||
1 0.000000000000000000000101 0.0 |
|||
0 2 2.0 |
|||
0 -2 -2.0 |
|||
1 3.14159265358979323846 3.14159265358979324 |
|||
</pre> |
|||
=={{header|C}}== |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="c">#include <math.h> |
|||
#include <stdbool.h> |
|||
#include <stdio.h> |
|||
bool approxEquals(double value, double other, double epsilon) { |
|||
return fabs(value - other) < epsilon; |
|||
} |
|||
void test(double a, double b) { |
|||
double epsilon = 1e-18; |
|||
printf("%f, %f => %d\n", a, b, approxEquals(a, b, epsilon)); |
|||
} |
|||
int main() { |
|||
test(100000000000000.01, 100000000000000.011); |
|||
test(100.01, 100.011); |
|||
test(10000000000000.001 / 10000.0, 1000000000.0000001000); |
|||
test(0.001, 0.0010000001); |
|||
test(0.000000000000000000000101, 0.0); |
|||
test(sqrt(2.0) * sqrt(2.0), 2.0); |
|||
test(-sqrt(2.0) * sqrt(2.0), -2.0); |
|||
test(3.14159265358979323846, 3.14159265358979324); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000.015625, 100000000000000.015625 => 1 |
|||
100.010000, 100.011000 => 0 |
|||
1000000000.000000, 1000000000.000000 => 0 |
|||
0.001000, 0.001000 => 0 |
|||
0.000000, 0.000000 => 1 |
|||
2.000000, 2.000000 => 0 |
|||
-2.000000, -2.000000 => 0 |
|||
3.141593, 3.141593 => 1</pre> |
|||
=={{header|C sharp|C#}}== |
|||
<syntaxhighlight lang="csharp">using System; |
|||
public static class Program |
|||
{ |
|||
public static void Main() { |
|||
Test(100000000000000.01, 100000000000000.011); |
|||
Test(100.01, 100.011); |
|||
Test(10000000000000.001 / 10000.0, 1000000000.0000001000); |
|||
Test(0.001, 0.0010000001); |
|||
Test(0.000000000000000000000101, 0.0); |
|||
Test(Math.Sqrt(2) * Math.Sqrt(2), 2.0); |
|||
Test(-Math.Sqrt(2) * Math.Sqrt(2), -2.0); |
|||
Test(3.14159265358979323846, 3.14159265358979324); |
|||
void Test(double a, double b) { |
|||
const double epsilon = 1e-18; |
|||
WriteLine($"{a}, {b} => {a.ApproxEquals(b, epsilon)}"); |
|||
} |
|||
} |
|||
public static bool ApproxEquals(this double value, double other, double epsilon) => Math.Abs(value - other) < epsilon; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
100000000000000.02, 100000000000000.02 => True |
|||
100.01, 100.011 => False |
|||
1000000000.0000002, 1000000000.0000001 => False |
|||
0.001, 0.0010000001 => False |
|||
1.01E-22, 0 => True |
|||
2.0000000000000004, 2 => False |
|||
-2.0000000000000004, -2 => False |
|||
3.141592653589793, 3.141592653589793 => True</pre> |
|||
=={{header|C++}}== |
|||
{{trans|C}} |
|||
<syntaxhighlight lang="cpp">#include <iomanip> |
|||
#include <iostream> |
|||
#include <cmath> |
|||
bool approxEquals(double a, double b, double e) { |
|||
return fabs(a - b) < e; |
|||
} |
|||
void test(double a, double b) { |
|||
constexpr double epsilon = 1e-18; |
|||
std::cout << std::setprecision(21) << a; |
|||
std::cout << ", "; |
|||
std::cout << std::setprecision(21) << b; |
|||
std::cout << " => "; |
|||
std::cout << approxEquals(a, b, epsilon) << '\n'; |
|||
} |
|||
int main() { |
|||
test(100000000000000.01, 100000000000000.011); |
|||
test(100.01, 100.011); |
|||
test(10000000000000.001 / 10000.0, 1000000000.0000001000); |
|||
test(0.001, 0.0010000001); |
|||
test(0.000000000000000000000101, 0.0); |
|||
test(sqrt(2.0) * sqrt(2.0), 2.0); |
|||
test(-sqrt(2.0) * sqrt(2.0), -2.0); |
|||
test(3.14159265358979323846, 3.14159265358979324); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000.015625, 100000000000000.015625 => 1 |
|||
100.010000000000005116, 100.01099999999999568 => 0 |
|||
1000000000.00000023842, 1000000000.00000011921 => 0 |
|||
0.00100000000000000002082, 0.00100000010000000005492 => 0 |
|||
1.0099999999999999762e-22, 0 => 1 |
|||
2.00000000000000044409, 2 => 0 |
|||
-2.00000000000000044409, -2 => 0 |
|||
3.141592653589793116, 3.141592653589793116 => 1</pre> |
|||
=={{header|Common Lisp}}== |
|||
This solution compares the normalized (i.e. between 0.5 and 1 on implementations which use binary floating point) significands of the floating point numbers, correcting each significand by half the difference in the exponents so that the corrected numbers used for comparison have the same difference in order of magnitude as the original numbers and are stable when the order of the arguments is changed. Unlike the metric of comparing the difference to some fraction of the numbers' size, this approach only requires two floating point operations (the subtraction and comparison at the end), and more directly maps to the fundamental issue which leads to the need for floating-point comparisons, i.e. the limited precision of the significand. |
|||
<syntaxhighlight lang="lisp"> |
|||
(defun approx-equal (float1 float2 &optional (threshold 0.000001)) |
|||
"Determine whether float1 and float2 are equal; THRESHOLD is the |
|||
maximum allowable difference between normalized significands of floats |
|||
with the same exponent. The significands are scaled appropriately |
|||
before comparison for floats with different exponents." |
|||
(multiple-value-bind (sig1 exp1 sign1) (decode-float float1) |
|||
(multiple-value-bind (sig2 exp2 sign2) (decode-float float2) |
|||
(let ((cmp1 (float-sign sign1 (scale-float sig1 (floor (- exp1 exp2) 2)))) |
|||
(cmp2 (float-sign sign2 (scale-float sig2 (floor (- exp2 exp1) 2))))) |
|||
(< (abs (- cmp1 cmp2)) threshold))))) |
|||
</syntaxhighlight> |
|||
=={{header|D}}== |
|||
{{trans|C#}} |
|||
<syntaxhighlight lang="d">import std.math; |
|||
import std.stdio; |
|||
auto approxEquals = (double a, double b, double epsilon) => abs(a - b) < epsilon; |
|||
void main() { |
|||
void test(double a, double b) { |
|||
double epsilon = 1e-18; |
|||
writefln("%.18f, %.18f => %s", a, b, a.approxEquals(b, epsilon)); |
|||
} |
|||
test(100000000000000.01, 100000000000000.011); |
|||
test(100.01, 100.011); |
|||
test(10000000000000.001 / 10000.0, 1000000000.0000001000); |
|||
test(0.001, 0.0010000001); |
|||
test(0.000000000000000000000101, 0.0); |
|||
test(sqrt(2.0) * sqrt(2.0), 2.0); |
|||
test(-sqrt(2.0) * sqrt(2.0), -2.0); |
|||
test(3.14159265358979323846, 3.14159265358979324); |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000.015620000000000000, 100000000000000.015620000000000000 => true |
|||
100.010000000000005110, 100.010999999999995680 => false |
|||
1000000000.000000119100000000, 1000000000.000000119100000000 => true |
|||
0.001000000000000000, 0.001000000100000000 => false |
|||
0.000000000000000000, 0.000000000000000000 => true |
|||
2.000000000000000000, 2.000000000000000000 => true |
|||
-2.000000000000000000, -2.000000000000000000 => true |
|||
3.141592653589793116, 3.141592653589793116 => true</pre> |
|||
=={{header|Delphi}}== |
|||
{{libheader| System.SysUtils}} |
|||
{{libheader| System.Math}} |
|||
The Delphi has a Math.SameValue function for compare, but all float operations use by default Extended (High precision), we need use double cast for every operation, like division, multiply and square tree. |
|||
<syntaxhighlight lang="delphi"> |
|||
program Approximate_Equality; |
|||
{$APPTYPE CONSOLE} |
|||
uses |
|||
System.SysUtils, |
|||
System.Math; |
|||
const |
|||
EPSILON: Double = 1E-18; |
|||
procedure Test(a, b: Double; Expected: Boolean); |
|||
var |
|||
result: Boolean; |
|||
const |
|||
STATUS: array[Boolean] of string = ('FAIL', 'OK'); |
|||
begin |
|||
result := SameValue(a, b, EPSILON); |
|||
Write(a, ' ', b, ' => ', result, ' '^I); |
|||
writeln(Expected, ^I, STATUS[Expected = result]); |
|||
end; |
|||
begin |
|||
Test(100000000000000.01, 100000000000000.011, True); |
|||
Test(100.01, 100.011, False); |
|||
Test(double(10000000000000.001) / double(10000.0), double(1000000000.0000001000), |
|||
False); |
|||
Test(0.001, 0.0010000001, False); |
|||
Test(0.000000000000000000000101, 0.0, True); |
|||
Test(double(Sqrt(2)) * double(Sqrt(2)), 2.0, False); |
|||
Test(-double(Sqrt(2)) * double(Sqrt(2)), -2.0, false); |
|||
Test(3.14159265358979323846, 3.14159265358979324, True); |
|||
Readln; |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1.00000000000000E+0014 1.00000000000000E+0014 => TRUE TRUE OK |
|||
1.00010000000000E+0002 1.00011000000000E+0002 => FALSE FALSE OK |
|||
1.00000000000000E+0009 1.00000000000000E+0009 => FALSE FALSE OK |
|||
1.00000000000000E-0003 1.00000010000000E-0003 => FALSE FALSE OK |
|||
1.01000000000000E-0022 0.00000000000000E+0000 => TRUE TRUE OK |
|||
2.00000000000000E+0000 2.00000000000000E+0000 => FALSE FALSE OK |
|||
-2.00000000000000E+0000 -2.00000000000000E+0000 => FALSE FALSE OK |
|||
3.14159265358979E+0000 3.14159265358979E+0000 => TRUE TRUE OK |
|||
</pre> |
|||
=={{header|Factor}}== |
=={{header|Factor}}== |
||
The <code>~</code> word takes three arguments: the two values to be compared, and an epsilon value representing the allowed distance between the two values. A positive epsilon performs an absolute distance test, an epsilon of zero performs an exact comparison, and a negative epsilon performs a relative distance test (as required by this task). |
The <code>~</code> word takes three arguments: the two values to be compared, and an epsilon value representing the allowed distance between the two values. A positive epsilon performs an absolute distance test, an epsilon of zero performs an exact comparison, and a negative epsilon performs a relative distance test (as required by this task). |
||
{{works with|Factor|0.99 development version 2019-07-10}} |
{{works with|Factor|0.99 development version 2019-07-10}} |
||
< |
<syntaxhighlight lang="factor">USING: formatting generalizations kernel math math.functions ; |
||
100000000000000.01 100000000000000.011 |
100000000000000.01 100000000000000.011 |
||
Line 47: | Line 393: | ||
[ 2dup -1e-15 ~ "%+47.30f %+47.30f -1e-15 ~ : %u\n" printf ] |
[ 2dup -1e-15 ~ "%+47.30f %+47.30f -1e-15 ~ : %u\n" printf ] |
||
2 8 mnapply</ |
2 8 mnapply</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 58: | Line 404: | ||
-2.000000000000000444089209850063 -2.000000000000000000000000000000 -1e-15 ~ : t |
-2.000000000000000444089209850063 -2.000000000000000000000000000000 -1e-15 ~ : t |
||
+3.141592653589793115997963468544 +3.141592653589793115997963468544 -1e-15 ~ : t |
+3.141592653589793115997963468544 +3.141592653589793115997963468544 -1e-15 ~ : t |
||
</pre> |
|||
=={{header|Forth}}== |
|||
{{works with|GForth | 0.7.9_20211014}} |
|||
Genuine Forth word : |
|||
f~ ( r1 r2 r3 – flag ) float-ext “f-proximate” |
|||
ANS Forth medley for comparing r1 and r2 for equality: r3>0: f~abs; r3=0: bitwise comparison; r3<0: |
|||
<syntaxhighlight lang="forth"> |
|||
: test-f~ ( f1 f2 -- ) |
|||
1e-18 \ epsilon |
|||
f~ \ AproximateEqual |
|||
if ." True" else ." False" then |
|||
; |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
100000000000000.01e 100000000000000.011e test-f~ True |
|||
100.01e 100.011e test-f~ False |
|||
10000000000000.001e 10000.0e f/ 1000000000.0000001000e test-f~ False |
|||
0.001e 0.0010000001e test-f~ False |
|||
0.000000000000000000000101e 0.0e test-f~ True |
|||
2.0e fdup fsqrt fswap fsqrt f* 2.0e test-f~ False |
|||
2.0e fdup fsqrt fnegate fswap fsqrt f* -2.0e test-f~ False |
|||
3.14159265358979323846e 3.14159265358979324e test-f~ True |
|||
</pre> |
|||
=={{header|Fortran}}== |
|||
Compare against the Python function documented at https://www.python.org/dev/peps/pep-0485/#proposed-implementation, |
|||
and with the discussion at https://stackoverflow.com/questions/5595425/what-is-the-best-way-to-compare-floats-for-almost-equality-in-python# |
|||
<syntaxhighlight lang="fortran">program main |
|||
implicit none |
|||
integer :: i |
|||
double precision, allocatable :: vals(:) |
|||
vals = [ 100000000000000.01d0, 100000000000000.011d0, & |
|||
& 100.01d0, 100.011d0, & |
|||
& 10000000000000.001d0/10000d0, 1000000000.0000001000d0, & |
|||
& 0.001d0, 0.0010000001d0, & |
|||
& 0.000000000000000000000101d0, 0d0, & |
|||
& sqrt(2d0)*sqrt(2d0), 2d0, & |
|||
& -sqrt(2d0)*sqrt(2d0), -2d0, & |
|||
& 3.14159265358979323846d0, 3.14159265358979324d0 ] |
|||
do i = 1, size(vals)/2 |
|||
print '(ES30.18, A, ES30.18, A, L)', vals(2*i-1), ' == ', vals(2*i), ' ? ', eq_approx(vals(2*i-1), vals(2*i)) |
|||
end do |
|||
contains |
|||
logical function eq_approx(a, b, reltol, abstol) |
|||
!! is a approximately equal b? |
|||
double precision, intent(in) :: a, b |
|||
!! values to compare |
|||
double precision, intent(in), optional :: reltol, abstol |
|||
!! relative and absolute error thresholds. |
|||
!! defaults: epsilon, smallest non-denormal number |
|||
double precision :: rt, at |
|||
rt = epsilon(1d0) |
|||
at = tiny(1d0) |
|||
if (present(reltol)) rt = reltol |
|||
if (present(abstol)) at = abstol |
|||
eq_approx = abs(a - b) .le. max(rt * max(abs(a), abs(b)), at) |
|||
return |
|||
end function |
|||
end program</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 1.000000000000000156E+14 == 1.000000000000000156E+14 ? T |
|||
1.000100000000000051E+02 == 1.000109999999999957E+02 ? F |
|||
1.000000000000000238E+09 == 1.000000000000000119E+09 ? T |
|||
1.000000000000000021E-03 == 1.000000100000000055E-03 ? F |
|||
1.009999999999999976E-22 == 0.000000000000000000E+00 ? F |
|||
2.000000000000000444E+00 == 2.000000000000000000E+00 ? T |
|||
-2.000000000000000444E+00 == -2.000000000000000000E+00 ? T |
|||
3.141592653589793116E+00 == 3.141592653589793116E+00 ? T</pre> |
|||
=={{header|FreeBASIC}}== |
|||
{{trans|AWK}} |
|||
<syntaxhighlight lang="freebasic">#include "string.bi" |
|||
Dim Shared As Double epsilon = 1 |
|||
Sub eq_approx(a As Double,b As Double) |
|||
Dim As Boolean tmp = Abs(a - b) < epsilon |
|||
Print Using "& & &";tmp;a;b |
|||
End Sub |
|||
While (1 + epsilon <> 1) |
|||
epsilon /= 2 |
|||
Wend |
|||
Print "epsilon = "; Format(epsilon, "0.000000000000000e-00") |
|||
Print |
|||
eq_approx(100000000000000.01, 100000000000000.011) |
|||
eq_approx(100.01, 100.011) |
|||
eq_approx(10000000000000.001/10000.0, 1000000000.0000001000) |
|||
eq_approx(0.001, 0.0010000001) |
|||
eq_approx(0.000000000000000000000101, 0.0) |
|||
eq_approx(Sqr(2)*Sqr(2), 2.0) |
|||
eq_approx(-Sqr(2)*Sqr(2), -2.0) |
|||
eq_approx(3.14159265358979323846, 3.14159265358979324) |
|||
Sleep</syntaxhighlight> |
|||
=={{header|FutureBasic}}== |
|||
<syntaxhighlight lang="futurebasic"> |
|||
local fn DoublesAreApproxEqual( val1 as double, val2 as double, epsilon as double ) as CFStringRef |
|||
CFStringRef result = @"false" |
|||
if ( fn fabs( val1 - val2 ) < epsilon ) then result = @"true" |
|||
end fn = result |
|||
void local fn DoIt |
|||
long i |
|||
double epsilon = 1e-18, values(15) |
|||
values(0) = 100000000000000.01 : values(1) = 100000000000000.011 |
|||
values(2) = 100.01 : values(3) = 100.011 |
|||
values(4) = 10000000000000.001 / 10000.0 : values(5) = 1000000000.0000001000 |
|||
values(6) = 0.001 : values(7) = 0.0010000001 |
|||
values(8) = 0.000000000000000000000101 : values(9) = 0.0 |
|||
values(10) = fn sqrt(2) * fn sqrt(2) : values(11) = 2.0 |
|||
values(12) = -fn sqrt(2) * fn sqrt(2) : values(13) = -2.0 |
|||
values(14) = 3.14159265358979323846 : values(15) = 3.14159265358979324 |
|||
for i = 0 to 14 step 2 |
|||
print values(i)@", "values(i+1)@" "fn DoublesAreApproxEqual( values(i), values(i+1), epsilon ) |
|||
next |
|||
end fn |
|||
fn DoIt |
|||
HandleEvents |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
100000000000000, 100000000000000 true |
|||
100.01, 100.011 false |
|||
1000000000, 1000000000 false |
|||
0.001, 0.0010000001 false |
|||
1.01e-22, 0 true |
|||
2, 2 false |
|||
-2, -2 false |
|||
3.141592653589793, 3.141592653589793 true |
|||
</pre> |
</pre> |
||
=={{header|Go}}== |
=={{header|Go}}== |
||
Go's float64 type is limited to 15 or 16 digits of precision. As there are some numbers in this task which have more digits than this I've used big.Float instead. |
Go's float64 type is limited to 15 or 16 digits of precision. As there are some numbers in this task which have more digits than this I've used big.Float instead. |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 116: | Line 612: | ||
fmt.Printf("% 21.19g %s %- 21.19g\n", pair[0], s, pair[1]) |
fmt.Printf("% 21.19g %s %- 21.19g\n", pair[0], s, pair[1]) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 130: | Line 626: | ||
3.141592653589793239 ≈ 3.14159265358979324 |
3.141592653589793239 ≈ 3.14159265358979324 |
||
</pre> |
</pre> |
||
=={{header|Groovy}}== |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="groovy">class Approximate { |
|||
private static boolean approxEquals(double value, double other, double epsilon) { |
|||
return Math.abs(value - other) < epsilon |
|||
} |
|||
private static void test(double a, double b) { |
|||
double epsilon = 1e-18 |
|||
System.out.printf("%f, %f => %s\n", a, b, approxEquals(a, b, epsilon)) |
|||
} |
|||
static void main(String[] args) { |
|||
test(100000000000000.01, 100000000000000.011) |
|||
test(100.01, 100.011) |
|||
test(10000000000000.001 / 10000.0, 1000000000.0000001000) |
|||
test(0.001, 0.0010000001) |
|||
test(0.000000000000000000000101, 0.0) |
|||
test(Math.sqrt(2.0) * Math.sqrt(2.0), 2.0) |
|||
test(-Math.sqrt(2.0) * Math.sqrt(2.0), -2.0) |
|||
test(3.14159265358979323846, 3.14159265358979324) |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000.020000, 100000000000000.020000 => true |
|||
100.010000, 100.011000 => false |
|||
1000000000.000000, 1000000000.000000 => true |
|||
0.001000, 0.001000 => false |
|||
0.000000, 0.000000 => true |
|||
2.000000, 2.000000 => false |
|||
-2.000000, -2.000000 => false |
|||
3.141593, 3.141593 => true</pre> |
|||
=={{header|Haskell}}== |
|||
<syntaxhighlight lang="haskell">class (Num a, Ord a, Eq a) => AlmostEq a where |
|||
eps :: a |
|||
infix 4 ~= |
|||
(~=) :: AlmostEq a => a -> a -> Bool |
|||
a ~= b = or [ a == b |
|||
, abs (a - b) < eps * abs(a + b) |
|||
, abs (a - b) < eps ] |
|||
instance AlmostEq Int where eps = 0 |
|||
instance AlmostEq Integer where eps = 0 |
|||
instance AlmostEq Double where eps = 1e-14 |
|||
instance AlmostEq Float where eps = 1e-5</syntaxhighlight> |
|||
Examples |
|||
<pre>λ> 0.000001 == (0 :: Float) |
|||
False |
|||
λ> 0.000001 ~= (0 :: Float) |
|||
True |
|||
λ> 0.000001 ~= (0 :: Double) |
|||
False |
|||
λ> (\x -> sqrt x * sqrt x == x) $ (2 :: Float) |
|||
False |
|||
λ> (\x -> sqrt x * sqrt x ~= x) $ (2 :: Float) |
|||
True |
|||
λ> (\x -> sqrt x * sqrt x == x) $ (2 :: Double) |
|||
False |
|||
λ> (\x -> sqrt x * sqrt x ~= x) $ (2 :: Double) |
|||
True</pre> |
|||
Assignment |
|||
<syntaxhighlight lang="haskell">test :: [(Double, Double)] |
|||
test = [(100000000000000.01, 100000000000000.011) |
|||
,(100.01, 100.011) |
|||
,(10000000000000.001 / 10000.0, 1000000000.0000001000) |
|||
,(0.001, 0.0010000001) |
|||
,(0.000000000000000000000101, 0.0) |
|||
,(sqrt 2 * sqrt 2, 2.0) |
|||
,(-sqrt 2 * sqrt 2, -2.0) |
|||
,(3.141592653589793, 3.141592653589794) |
|||
,(3.141592653589, 3.141592653589794)] |
|||
-- requires import Text.Printf |
|||
main = mapM_ runTest test |
|||
where |
|||
runTest (a, b) = do |
|||
printf "%f == %f %v\n" a b (show $ a==b) :: IO () |
|||
printf "%f ~= %f %v\n\n" a b (show $ a~=b)</syntaxhighlight> |
|||
<pre>λ> main |
|||
100000000000000.02 == 100000000000000.02 True |
|||
100000000000000.02 ~= 100000000000000.02 True |
|||
100.01 == 100.011 False |
|||
100.01 ~= 100.011 False |
|||
1000000000.0000002 == 1000000000.0000001 False |
|||
1000000000.0000002 ~= 1000000000.0000001 True |
|||
0.001 == 0.0010000001 False |
|||
0.001 ~= 0.0010000001 False |
|||
0.000000000000000000000101 == 0.0 False |
|||
0.000000000000000000000101 ~= 0.0 True |
|||
2.0000000000000004 == 2.0 False |
|||
2.0000000000000004 ~= 2.0 True |
|||
-2.0000000000000004 == -2.0 False |
|||
-2.0000000000000004 ~= -2.0 True |
|||
3.141592653589793 == 3.141592653589794 False |
|||
3.141592653589793 ~= 3.141592653589794 True |
|||
3.141592653589 == 3.141592653589794 False |
|||
3.141592653589 ~= 3.141592653589794 False</pre> |
|||
=={{header|J}}== |
|||
Attributed to Ken Iverson, inventor of APL and of course his final dialect, j, |
|||
"In an early talk Ken was explaining the advantages of tolerant comparison. A member of the audience asked incredulously, “Surely you don’t mean that when A=B and B=C, A may not equal C?” Without skipping a beat, Ken replied, “Any carpenter knows that!” and went on to the next question." |
|||
J includes a "customization" conjunction ( !. ) that delivers variants of some verbs. Comparisons are tolerant by default, and their tolerance can be customized to some level. Specifying =!.0 specifies "no tolerance". Specifying a tolerance of 1e_8 is a domain error because that's no longer math. Write your own verb if you need this. |
|||
<syntaxhighlight lang="text"> |
|||
NB. default comparison tolerance matches the python result |
|||
".;._2]0 :0 |
|||
100000000000000.01 = 100000000000000.011 |
|||
100.01 = 100.011 |
|||
(10000000000000.001 % 10000.0) = 1000000000.0000001000 |
|||
0.001 = 0.0010000001 |
|||
0.000000000000000000000101 = 0.0 |
|||
(= ([: *~ %:)) 2 NB. sqrt(2)*sqrt(2) |
|||
((= -)~ ([: (* -) %:)) 2 NB. -sqrt(2) * sqrt(2), -2.0 |
|||
3.14159265358979323846 = 3.14159265358979324 |
|||
) |
|||
1 0 1 0 0 1 1 1 |
|||
NB. tolerance of 1e_12 matches the python result |
|||
".;._2]0 :0[CT=:1e_12 |
|||
100000000000000.01 =!.CT 100000000000000.011 |
|||
100.01 =!.CT 100.011 |
|||
(10000000000000.001 % 10000.0) =!.CT 1000000000.0000001000 |
|||
0.001 =!.CT 0.0010000001 |
|||
0.000000000000000000000101 =!.CT 0.0 |
|||
(=!.CT ([: *~ %:)) 2 NB. sqrt(2)*sqrt(2) |
|||
((=!.CT -)~ ([: (* -) %:)) 2 NB. -sqrt(2) * sqrt(2), -2.0 |
|||
3.14159265358979323846 =!.CT 3.14159265358979324 |
|||
) |
|||
1 0 1 0 0 1 1 1 |
|||
NB. tight tolerance |
|||
".;._2]0 :0[CT=:1e_18 |
|||
100000000000000.01 =!.CT 100000000000000.011 |
|||
100.01 =!.CT 100.011 |
|||
(10000000000000.001 % 10000.0) =!.CT 1000000000.0000001000 |
|||
0.001 =!.CT 0.0010000001 |
|||
0.000000000000000000000101 =!.CT 0.0 |
|||
(=!.CT ([: *~ %:)) 2 NB. sqrt(2)*sqrt(2) |
|||
((=!.CT -)~ ([: (* -) %:)) 2 NB. -sqrt(2) * sqrt(2), -2.0 |
|||
3.14159265358979323846 =!.CT 3.14159265358979324 |
|||
) |
|||
1 0 0 0 0 0 0 1 |
|||
2 (=!.1e_8) 9 |
|||
|domain error |
|||
| 2(= !.1e_8)9 |
|||
</syntaxhighlight> |
|||
=={{header|Java}}== |
|||
{{trans|Kotlin}} |
|||
<syntaxhighlight lang="java">public class Approximate { |
|||
private static boolean approxEquals(double value, double other, double epsilon) { |
|||
return Math.abs(value - other) < epsilon; |
|||
} |
|||
private static void test(double a, double b) { |
|||
double epsilon = 1e-18; |
|||
System.out.printf("%f, %f => %s\n", a, b, approxEquals(a, b, epsilon)); |
|||
} |
|||
public static void main(String[] args) { |
|||
test(100000000000000.01, 100000000000000.011); |
|||
test(100.01, 100.011); |
|||
test(10000000000000.001 / 10000.0, 1000000000.0000001000); |
|||
test(0.001, 0.0010000001); |
|||
test(0.000000000000000000000101, 0.0); |
|||
test(Math.sqrt(2.0) * Math.sqrt(2.0), 2.0); |
|||
test(-Math.sqrt(2.0) * Math.sqrt(2.0), -2.0); |
|||
test(3.14159265358979323846, 3.14159265358979324); |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000.020000, 100000000000000.020000 => true |
|||
100.010000, 100.011000 => false |
|||
1000000000.000000, 1000000000.000000 => false |
|||
0.001000, 0.001000 => false |
|||
0.000000, 0.000000 => true |
|||
2.000000, 2.000000 => false |
|||
-2.000000, -2.000000 => false |
|||
3.141593, 3.141593 => true</pre> |
|||
=={{header|jq}}== |
|||
{{trans|Lobster}} |
|||
<syntaxhighlight lang="jq"># Return whether the two numbers `a` and `b` are close. |
|||
# Closeness is determined by the `epsilon` parameter - |
|||
# the numbers are considered close if the difference between them |
|||
# is no more than epsilon * max(abs(a), abs(b)). |
|||
def isclose(a; b; epsilon): |
|||
((a - b) | fabs) <= (([(a|fabs), (b|fabs)] | max) * epsilon); |
|||
def lpad($len; $fill): tostring | ($len - length) as $l | ($fill * $l)[:$l] + .; |
|||
def lpad: lpad(20; " "); |
|||
# test values |
|||
def tv: [ |
|||
{x: 100000000000000.01, y: 100000000000000.011 }, |
|||
{x: 100.01, y: 100.011 }, |
|||
{x: (10000000000000.001 / 10000.0), y: 1000000000.0000001000 }, |
|||
{x: 0.001, y: 0.0010000001 }, |
|||
{x: 0.000000000000000000000101, y: 0.0 }, |
|||
{x: ((2|sqrt) * (2|sqrt)), y: 2.0 }, |
|||
{x: (-(2|sqrt) * (2|sqrt)), y: -2.0 }, |
|||
{x: 3.14159265358979323846, y: 3.14159265358979324 } |
|||
] |
|||
; |
|||
tv[] | "\(.x|lpad) \(if isclose(.x; .y; 1.0e-9) then " ≈ " else " ≉ " end) \(.y|lpad)" |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
Using jq 1.6: |
|||
<syntaxhighlight lang="sh"> 100000000000000.02 ≈ 100000000000000.02 |
|||
100.01 ≉ 100.011 |
|||
1000000000.0000002 ≈ 1000000000.0000001 |
|||
0.001 ≉ 0.0010000001 |
|||
1.01e-22 ≉ 0 |
|||
2.0000000000000004 ≈ 2 |
|||
-2.0000000000000004 ≈ -2 |
|||
3.141592653589793 ≈ 3.141592653589793</syntaxhighlight> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
Julia has an infix operator, ≈, which corresponds to Julia's buitin isapprox() function. |
Julia has an infix operator, ≈, which corresponds to Julia's buitin isapprox() function. |
||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang="julia">testvalues = [[100000000000000.01, 100000000000000.011], |
||
[100.01, 100.011], |
|||
[10000000000000.001 / 10000.0, 1000000000.0000001000], |
[10000000000000.001 / 10000.0, 1000000000.0000001000], |
||
[0.001, |
[0.001, 0.0010000001], |
||
[ |
[0.000000000000000000000101, 0.0], |
||
[ |
[sqrt(2) * sqrt(2), 2.0], |
||
[ |
[-sqrt(2) * sqrt(2), -2.0], |
||
[3.14159265358979323846, 3.14159265358979324]] |
|||
for (x, y) in testvalues |
for (x, y) in testvalues |
||
println(rpad(x, 21), " ≈ ", lpad(y, 22), ": ", x ≈ y) |
println(rpad(x, 21), " ≈ ", lpad(y, 22), ": ", x ≈ y) |
||
end |
end |
||
</ |
</syntaxhighlight>{{out}} |
||
<pre> |
<pre> |
||
1.0000000000000002e14 ≈ 1.0000000000000002e14: true |
1.0000000000000002e14 ≈ 1.0000000000000002e14: true |
||
Line 150: | Line 886: | ||
1.0000000000000002e9 ≈ 1.0000000000000001e9: true |
1.0000000000000002e9 ≈ 1.0000000000000001e9: true |
||
0.001 ≈ 0.0010000001: false |
0.001 ≈ 0.0010000001: false |
||
1.01e- |
1.01e-22 ≈ 0.0: false |
||
2.0000000000000004 ≈ 2.0: true |
2.0000000000000004 ≈ 2.0: true |
||
-2.0000000000000004 ≈ -2.0: true |
-2.0000000000000004 ≈ -2.0: true |
||
1.0e17 ≈ 1.0e17: true |
|||
3.141592653589793 ≈ 3.141592653589793: true |
3.141592653589793 ≈ 3.141592653589793: true |
||
</pre> |
</pre> |
||
=={{header| |
=={{header|Kotlin}}== |
||
{{trans|C#}} |
|||
<syntaxhighlight lang="scala">import kotlin.math.abs |
|||
import kotlin.math.sqrt |
|||
fun approxEquals(value: Double, other: Double, epsilon: Double): Boolean { |
|||
return abs(value - other) < epsilon |
|||
} |
|||
fun test(a: Double, b: Double) { |
|||
val epsilon = 1e-18 |
|||
println("$a, $b => ${approxEquals(a, b, epsilon)}") |
|||
} |
|||
fun main() { |
|||
test(100000000000000.01, 100000000000000.011) |
|||
test(100.01, 100.011) |
|||
test(10000000000000.001 / 10000.0, 1000000000.0000001000) |
|||
test(0.001, 0.0010000001) |
|||
test(0.000000000000000000000101, 0.0) |
|||
test(sqrt(2.0) * sqrt(2.0), 2.0) |
|||
test(-sqrt(2.0) * sqrt(2.0), -2.0) |
|||
test(3.14159265358979323846, 3.14159265358979324) |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1.0000000000000002E14, 1.0000000000000002E14 => true |
|||
100.01, 100.011 => false |
|||
1.0000000000000002E9, 1.0000000000000001E9 => false |
|||
0.001, 0.0010000001 => false |
|||
1.01E-22, 0.0 => true |
|||
2.0000000000000004, 2.0 => false |
|||
-2.0000000000000004, -2.0 => false |
|||
3.141592653589793, 3.141592653589793 => true</pre> |
|||
=={{header|Lobster}}== |
|||
{{trans|Rust}} |
|||
<syntaxhighlight lang="lobster"> |
|||
// Return whether the two numbers `a` and `b` are close. |
|||
// Closeness is determined by the `epsilon` parameter - |
|||
// the numbers are considered close if the difference between them |
|||
// is no more than epsilon * max(abs(a), abs(b)). |
|||
// |
|||
def isclose(a, b, epsilon): |
|||
return abs(a - b) <= max(abs(a), abs(b)) * epsilon |
|||
let tv = [ |
|||
xy { 100000000000000.01, 100000000000000.011 }, |
|||
xy { 100.01, 100.011 }, |
|||
xy { 10000000000000.001 / 10000.0, 1000000000.0000001000 }, |
|||
xy { 0.001, 0.0010000001 }, |
|||
xy { 0.000000000000000000000101, 0.0 }, |
|||
xy { sqrt(2.0) * sqrt(2.0), 2.0 }, |
|||
xy { -sqrt(2.0) * sqrt(2.0), -2.0 }, |
|||
xy { 3.14159265358979323846, 3.14159265358979324 } |
|||
] |
|||
for(tv) t: |
|||
print concat_string([string(t.x), if isclose(t.x, t.y, 1.0e-9): """ ≈ """ else: """ ≉ """, string(t.y)], "") |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
100000000000000.0 ≈ 100000000000000.0 |
|||
100.01 ≉ 100.011 |
|||
1000000000.0 ≈ 1000000000.0 |
|||
0.001 ≉ 0.0010000001 |
|||
0.0 ≉ 0.0 |
|||
2.0 ≈ 2.0 |
|||
-2.0 ≈ -2.0 |
|||
3.14159265359 ≈ 3.14159265359 |
|||
</pre> |
|||
=={{header|Lua}}== |
|||
{{trans|C}} |
|||
<syntaxhighlight lang="lua">function approxEquals(value, other, epsilon) |
|||
return math.abs(value - other) < epsilon |
|||
end |
|||
function test(a, b) |
|||
local epsilon = 1e-18 |
|||
print(string.format("%f, %f => %s", a, b, tostring(approxEquals(a, b, epsilon)))) |
|||
end |
|||
function main() |
|||
test(100000000000000.01, 100000000000000.011); |
|||
test(100.01, 100.011) |
|||
test(10000000000000.001 / 10000.0, 1000000000.0000001000) |
|||
test(0.001, 0.0010000001) |
|||
test(0.000000000000000000000101, 0.0) |
|||
test(math.sqrt(2.0) * math.sqrt(2.0), 2.0) |
|||
test(-math.sqrt(2.0) * math.sqrt(2.0), -2.0) |
|||
test(3.14159265358979323846, 3.14159265358979324) |
|||
end |
|||
main()</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000.020000, 100000000000000.020000 => true |
|||
100.010000, 100.011000 => false |
|||
1000000000.000000, 1000000000.000000 => false |
|||
0.001000, 0.001000 => false |
|||
0.000000, 0.000000 => true |
|||
2.000000, 2.000000 => false |
|||
-2.000000, -2.000000 => false |
|||
3.141593, 3.141593 => true</pre> |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">ClearAll[CloseEnough] |
|||
CloseEnough[a_, b_, tol_] := Chop[a - b, tol] == 0 |
|||
numbers = { |
|||
{100000000000000.01, 100000000000000.011}, |
|||
{100.01, 100.011}, |
|||
{10000000000000.001/10000.0, 1000000000.0000001000}, |
|||
{0.001, 0.0010000001}, |
|||
{0.000000000000000000000101, 0.0}, |
|||
{Sqrt[2.0] Sqrt[2.0], 2.0}, {-Sqrt[2.0] Sqrt[2.0], -2.0}, |
|||
{3.14159265358979323846, 3.14159265358979324} |
|||
}; |
|||
(*And@@Flatten[Map[MachineNumberQ,numbers,{2}]]*) |
|||
{#1, #2, CloseEnough[#1, #2, 10^-9]} & @@@ numbers // Grid</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1.*10^14 1.0000000000000001*10^14 True |
|||
100.01 100.011 False |
|||
1.*10^9 1.000000000000000100*10^9 False |
|||
0.001 0.001 True |
|||
1.01*10^-22 0. True |
|||
2. 2. True |
|||
-2. -2. True |
|||
3.1415926535897932385 3.1415926535897932 True</pre> |
|||
=={{header|Nim}}== |
|||
To compare the floating point values, we use a relative tolerance. |
|||
In order to display the values “a” and “b” as provided, without any rounding, we transmit them as strings to a comparison procedure which compute the floating point values. If the first value “a” is provided as an operation, we use a comparison procedure which accepts the computed value of “a” as second parameter. Here, “b” is never provided as an operation and can always be transmitted as a string. |
|||
<syntaxhighlight lang="nim">from math import sqrt |
|||
import strformat |
|||
import strutils |
|||
const Tolerance = 1e-10 |
|||
proc `~=`(a, b: float): bool = |
|||
## Check if "a" and "b" are close. |
|||
## We use a relative tolerance to compare the values. |
|||
result = abs(a - b) < max(abs(a), abs(b)) * Tolerance |
|||
proc compare(a, b: string) = |
|||
## Compare "a" and "b" transmitted as strings. |
|||
## Values are computed using "parseFloat". |
|||
let r = a.parseFloat() ~= b.parseFloat() |
|||
echo fmt"{a} ~= {b} is {r}" |
|||
proc compare(a: string; avalue: float; b: string) = |
|||
## Compare "a" and "b" transmitted as strings. |
|||
## The value of "a" is transmitted and not computed. |
|||
let r = avalue ~= b.parseFloat() |
|||
echo fmt"{a} ~= {b} is {r}" |
|||
compare("100000000000000.01", "100000000000000.011") |
|||
compare("100.01", "100.011") |
|||
compare("10000000000000.001 / 10000.0", 10000000000000.001 / 10000.0, "1000000000.0000001000") |
|||
compare("0.001", "0.0010000001") |
|||
compare("0.000000000000000000000101", "0.0") |
|||
compare("sqrt(2) * sqrt(2)", sqrt(2.0) * sqrt(2.0), "2.0") |
|||
compare("-sqrt(2) * sqrt(2)", -sqrt(2.0) * sqrt(2.0), "-2.0") |
|||
compare("3.14159265358979323846", "3.14159265358979324")</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000.01 ~= 100000000000000.011 is true |
|||
100.01 ~= 100.011 is false |
|||
10000000000000.001 / 10000.0 ~= 1000000000.0000001000 is true |
|||
0.001 ~= 0.0010000001 is false |
|||
0.000000000000000000000101 ~= 0.0 is false |
|||
sqrt(2) * sqrt(2) ~= 2.0 is true |
|||
-sqrt(2) * sqrt(2) ~= -2.0 is true |
|||
3.14159265358979323846 ~= 3.14159265358979324 is true</pre> |
|||
=={{header|OCaml}}== |
|||
<syntaxhighlight lang="ocaml">let approx_eq v1 v2 epsilon = |
|||
Float.abs (v1 -. v2) < epsilon |
|||
let test a b = |
|||
let epsilon = 1e-18 in |
|||
Printf.printf "%g, %g => %b\n" a b (approx_eq a b epsilon) |
|||
let () = |
|||
test 100000000000000.01 100000000000000.011; |
|||
test 100.01 100.011; |
|||
test (10000000000000.001 /. 10000.0) 1000000000.0000001000; |
|||
test 0.001 0.0010000001; |
|||
test 0.000000000000000000000101 0.0; |
|||
test ((sqrt 2.0) *. (sqrt 2.0)) 2.0; |
|||
test (-. (sqrt 2.0) *. (sqrt 2.0)) (-2.0); |
|||
test 3.14159265358979323846 3.14159265358979324; |
|||
;; |
|||
</syntaxhighlight> |
|||
=={{header|Pascal}}== |
|||
{{works with|Extended Pascal}} |
|||
The constants <tt>minReal</tt>, <tt>maxReal</tt> and <tt>epsReal</tt> are defined by the ISO standard 10206 (“Extended Pascal”). |
|||
However, their specific values are “implementation defined”, i. e. it is up to the compiler vendors to assign concrete values to them. |
|||
<syntaxhighlight lang="pascal">program approximateEqual(output); |
|||
{ |
|||
\brief determines whether two `real` values are approximately equal |
|||
\param x a reference value |
|||
\param y the value to compare with \param x |
|||
\return true if \param x is equal or approximately equal to \param y |
|||
} |
|||
function equal(protected x, y: real): Boolean; |
|||
function approximate: Boolean; |
|||
function d(protected x: real): integer; |
|||
begin |
|||
d := trunc(ln(abs(x) + minReal) / ln(2)) + 1 |
|||
end; |
|||
begin |
|||
approximate := abs(x - y) <= epsReal * (maxReal / (d(x) + d(y))) |
|||
end; |
|||
begin |
|||
equal := (x = y) or_else (x * y >= 0.0) and_then approximate |
|||
end; |
|||
{ --- auxilliary routines ---------------------------------------------- } |
|||
procedure test(protected x, y: real); |
|||
const |
|||
{ ANSI escape code for color coding } |
|||
CSI = chr(8#33) + '['; |
|||
totalMinimumWidth = 40; |
|||
postRadixDigits = 24; |
|||
begin |
|||
write(x:totalMinimumWidth:postRadixDigits, '':1, CSI, '1;3'); |
|||
if equal(x, y) then |
|||
begin |
|||
if x = y then |
|||
begin |
|||
write('2m≅') |
|||
end |
|||
else |
|||
begin |
|||
write('5m≆') |
|||
end |
|||
end |
|||
else |
|||
begin |
|||
write('1m≇') |
|||
end; |
|||
writeLn(CSI, 'm', '':1, y:totalMinimumWidth:postRadixDigits) |
|||
end; |
|||
{ === MAIN ============================================================= } |
|||
var |
|||
n: integer; |
|||
x: real; |
|||
begin |
|||
{ Variables were used to thwart compile-time evaluation done } |
|||
{ by /some/ compilers potentially confounding the results. } |
|||
n := 2; |
|||
x := 100000000000000.01; |
|||
test(x, 100000000000000.011); |
|||
test(100.01, 100.011); |
|||
test(x / 10000.0, 1000000000.0000001000); |
|||
test(0.001, 0.0010000001); |
|||
test(0.000000000000000000000101, 0.0); |
|||
x := sqrt(n); |
|||
test(sqr(x), 2.0); |
|||
test((-x) * x, -2.0); |
|||
test(3.14159265358979323846, 3.14159265358979324) |
|||
end.</syntaxhighlight> |
|||
{{out}} |
|||
100000000000000.015625000000000000000000 ≅ 100000000000000.015625000000000000000000 |
|||
100.010000000000005115907697 ≆ 100.010999999999995679900167 |
|||
10000000000.000001907348632812500000 ≆ 1000000000.000000119209289550781250 |
|||
0.001000000000000000020817 ≇ 0.001000000100000000054917 |
|||
0.000000000000000000000101 ≇ 0.000000000000000000000000 |
|||
2.000000000000000444089210 ≆ 2.000000000000000000000000 |
|||
-2.000000000000000444089210 ≆ -2.000000000000000000000000 |
|||
3.141592653589793115997963 ≅ 3.141592653589793115997963 |
|||
The shown output was generated by a <tt>program</tt> compiled by the GPC (GNU Pascal Compiler). |
|||
Due to technical limitations it was not possible to reproduce 100.01 ≆ 100.011 as requested by the task specification. |
|||
The computer had an IEEE-754-compliant FPU with 80-bit precision. |
|||
Note that Pascal’s <tt>write</tt>/<tt>writeLn</tt>/<tt>writeStr</tt> routines (the last one is only available in Extended Pascal) produce ''rounded'' representations. |
|||
=={{header|Perl}}== |
|||
Passes task tests, but use the module <code>Test::Number::Delta</code> for anything of real importance. |
|||
<syntaxhighlight lang="perl">use strict; |
|||
use warnings; |
|||
sub is_close { |
|||
my($a,$b,$eps) = @_; |
|||
$eps //= 15; |
|||
my $epse = $eps; |
|||
$epse++ if sprintf("%.${eps}f",$a) =~ /\./; |
|||
$epse++ if sprintf("%.${eps}f",$a) =~ /\-/; |
|||
my $afmt = substr((sprintf "%.${eps}f", $a), 0, $epse); |
|||
my $bfmt = substr((sprintf "%.${eps}f", $b), 0, $epse); |
|||
printf "%-5s %s ≅ %s\n", ($afmt eq $bfmt ? 'True' : 'False'), $afmt, $bfmt; |
|||
} |
|||
for ( |
|||
[100000000000000.01, 100000000000000.011], |
|||
[100.01, 100.011], |
|||
[10000000000000.001 / 10000.0, 1000000000.0000001000], |
|||
[0.001, 0.0010000001], |
|||
[0.000000000000000000000101, 0.0], |
|||
[sqrt(2) * sqrt(2), 2.0], |
|||
[-sqrt(2) * sqrt(2), -2.0], |
|||
[100000000000000003.0, 100000000000000004.0], |
|||
[3.14159265358979323846, 3.14159265358979324] |
|||
) { |
|||
my($a,$b) = @$_; |
|||
is_close($a,$b); |
|||
} |
|||
print "\nTolerance may be adjusted.\n"; |
|||
my $real_pi = 2 * atan2(1, 0); |
|||
my $roman_pi = 22/7; |
|||
is_close($real_pi,$roman_pi,$_) for <10 3>;</syntaxhighlight> |
|||
{{out}} |
|||
<pre>True 100000000000000.0 ≅ 100000000000000.0 |
|||
False 100.0100000000000 ≅ 100.0109999999999 |
|||
True 1000000000.000000 ≅ 1000000000.000000 |
|||
False 0.001000000000000 ≅ 0.001000000100000 |
|||
True 0.000000000000000 ≅ 0.000000000000000 |
|||
True 2.000000000000000 ≅ 2.000000000000000 |
|||
True -2.000000000000000 ≅ -2.000000000000000 |
|||
True 10000000000000000 ≅ 10000000000000000 |
|||
True 3.141592653589793 ≅ 3.141592653589793 |
|||
Tolerance may be adjusted. |
|||
False 3.141592653 ≅ 3.142857142 |
|||
True 3.14 ≅ 3.14</pre> |
|||
=={{header|Phix}}== |
|||
Traditionally I have always just used sprintf() to compare floating point atoms in phix.<br> |
|||
This task (imo) is trying to make a general-purpose routine out of code which is best tailored for each and every specific task.<br> |
|||
It proved much harder to get decent-looking output than perform the tests, hence I allowed both the compare (cfmt) and display (dfmt) formats to be overridden.<br> |
|||
I got a different result for test 4 to everyone else, but simply setting the cfmt to "%.10f" got it the NOT.<br> |
|||
Likewise something similar for the trickier/ambiguous test 5, for which "0.000000" is as good as anything I can do, and both now show how to get either a true or false result. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">dfmt</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"%g"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cfmt</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"%g"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">ca</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cfmt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">cb</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cfmt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">eqs</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ca</span><span style="color: #0000FF;">=</span><span style="color: #000000;">cb</span><span style="color: #0000FF;">?</span><span style="color: #008000;">""</span><span style="color: #0000FF;">:</span><span style="color: #008000;">"NOT "</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">da</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dfmt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">db</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dfmt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%30s and\n%30s are %sapproximately equal\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">da</span><span style="color: #0000FF;">,</span><span style="color: #000000;">db</span><span style="color: #0000FF;">,</span><span style="color: #000000;">eqs</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">100000000000000.01</span><span style="color: #0000FF;">,</span><span style="color: #000000;">100000000000000.011</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%.3f"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">100.01</span><span style="color: #0000FF;">,</span><span style="color: #000000;">100.011</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%.3f"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10000000000000.001</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10000.0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000000000.0000001000</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%.10f"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0.001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.0010000001</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%.10f"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- both</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0.001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.0010000001</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%.10f"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%.10f"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- ways</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0.000000000000000000000101</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.0</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%f"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- both</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0.000000000000000000000101</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.0</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%f"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%6f"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- ways</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)*</span><span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span><span style="color: #000000;">2.0</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(-</span><span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)*</span><span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),-</span><span style="color: #000000;">2.0</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">3.14159265358979323846</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.14159265358979324</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%.20f"</span><span style="color: #0000FF;">)</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
|||
64 bit (implied by some of the accuracies specified for this task): |
|||
<pre> |
|||
100000000000000.010 and |
|||
100000000000000.011 are approximately equal |
|||
100.010 and |
|||
100.011 are NOT approximately equal |
|||
1000000000.0000001001 and |
|||
1000000000.0000001000 are approximately equal |
|||
0.0010000000 and |
|||
0.0010000001 are approximately equal |
|||
0.0010000000 and |
|||
0.0010000001 are NOT approximately equal |
|||
0.000000 and |
|||
0.000000 are NOT approximately equal |
|||
0.000000 and |
|||
0.000000 are approximately equal |
|||
2 and |
|||
2 are approximately equal |
|||
-2 and |
|||
-2 are approximately equal |
|||
3.14159265358979323851 and |
|||
3.14159265358979324003 are approximately equal |
|||
</pre> |
|||
32 bit (in fact a couple of them, the first and last pairs, are actually genuinely identical): |
|||
<pre> |
|||
100000000000000.016 and |
|||
100000000000000.016 are approximately equal |
|||
100.010 and |
|||
100.011 are NOT approximately equal |
|||
1000000000.0000002384 and |
|||
1000000000.0000001192 are approximately equal |
|||
0.0010000000 and |
|||
0.0010000001 are approximately equal |
|||
0.0010000000 and |
|||
0.0010000001 are NOT approximately equal |
|||
0.000000 and |
|||
0.000000 are NOT approximately equal |
|||
0.000000 and |
|||
0.000000 are approximately equal |
|||
2 and |
|||
2 are approximately equal |
|||
-2 and |
|||
-2 are approximately equal |
|||
3.1415926535897931 and |
|||
3.1415926535897931 are approximately equal |
|||
</pre> |
|||
=={{header|Processing}}== |
|||
<syntaxhighlight lang="processing">double epsilon = 1e-18D; |
|||
void setup() { |
|||
testIsClose(100000000000000.01D, 100000000000000.011D, epsilon); |
|||
testIsClose(100.01D, 100.011D, epsilon); |
|||
testIsClose(10000000000000.001D / 10000.0D, 1000000000.0000001000D, epsilon); |
|||
testIsClose(0.001D, 0.0010000001D, epsilon); |
|||
testIsClose(0.000000000000000000000101D, 0.0D, epsilon); |
|||
testIsClose(Math.sqrt(2) * Math.sqrt(2), 2.0D, epsilon); |
|||
testIsClose(-Math.sqrt(2) * Math.sqrt(2), -2.0D, epsilon); |
|||
testIsClose(3.14159265358979323846D, 3.14159265358979324D, epsilon); |
|||
exit(); // all done |
|||
} |
|||
boolean isClose(double num1, double num2, double epsilon) { |
|||
return Math.abs(num2 - num1) <= epsilon; |
|||
} |
|||
void testIsClose(double num1, double num2, double epsilon) { |
|||
boolean result = isClose(num1, num2, epsilon); |
|||
if (result) { |
|||
println("True. ", num1, "is close to", num2); |
|||
} else { |
|||
println("False. ", num1, "is not close to", num2); |
|||
} |
|||
}</syntaxhighlight> |
|||
{{Output}} |
|||
<pre> |
|||
True. 1.0000000000000002E14 is close to 1.0000000000000002E14 |
|||
False. 100.01 is not close to 100.011 |
|||
False. 1.0000000000000002E9 is not close to 1.0000000000000001E9 |
|||
False. 0.001 is not close to 0.0010000001 |
|||
True. 1.01E-22 is close to 0.0 |
|||
False. 2.0000000000000004 is not close to 2.0 |
|||
False. -2.0000000000000004 is not close to -2.0 |
|||
True. 3.141592653589793 is close to 3.141592653589793 |
|||
</pre> |
|||
=={{header|Python}}== |
|||
The Python source documentation states: |
|||
<pre> |
|||
math.isclose -> bool |
|||
a: double |
|||
b: double |
|||
* |
|||
rel_tol: double = 1e-09 |
|||
maximum difference for being considered "close", relative to the |
|||
magnitude of the input values |
|||
abs_tol: double = 0.0 |
|||
maximum difference for being considered "close", regardless of the |
|||
magnitude of the input values |
|||
Determine whether two floating point numbers are close in value. |
|||
Return True if a is close in value to b, and False otherwise. |
|||
For the values to be considered close, the difference between them |
|||
must be smaller than at least one of the tolerances. |
|||
-inf, inf and NaN behave similarly to the IEEE 754 Standard. That |
|||
is, NaN is not close to anything, even itself. inf and -inf are |
|||
only close to themselves. |
|||
</pre> |
|||
<syntaxhighlight lang="python">from numpy import sqrt |
|||
from math import isclose |
|||
testvalues = [[100000000000000.01, 100000000000000.011], |
|||
[100.01, 100.011], |
|||
[10000000000000.001 / 10000.0, 1000000000.0000001000], |
|||
[0.001, 0.0010000001], |
|||
[0.000000000000000000000101, 0.0], |
|||
[sqrt(2) * sqrt(2), 2.0], |
|||
[-sqrt(2) * sqrt(2), -2.0], |
|||
[3.14159265358979323846, 3.14159265358979324]] |
|||
for (x, y) in testvalues: |
|||
maybenot = "is" if isclose(x, y) else "is NOT" |
|||
print(x, maybenot, "approximately equal to ", y) |
|||
</syntaxhighlight>{{out}} |
|||
<pre> |
|||
100000000000000.02 is approximately equal to 100000000000000.02 |
|||
100.01 is NOT approximately equal to 100.011 |
|||
1000000000.0000002 is approximately equal to 1000000000.0000001 |
|||
0.001 is NOT approximately equal to 0.0010000001 |
|||
1.01e-22 is NOT approximately equal to 0.0 |
|||
2.0 is approximately equal to 2.0 |
|||
-2.0 is approximately equal to -2.0 |
|||
3.141592653589793 is approximately equal to 3.141592653589793 |
|||
</pre> |
|||
=={{header|R}}== |
|||
The base library has the function all.equal() for this task. However, when the numbers are not equal, rather than return FALSE, it tries to explain the difference. To fix this, we use isTRUE(all.equal(....)) instead. |
|||
<syntaxhighlight lang="rsplus">approxEq <- function(...) isTRUE(all.equal(...)) |
|||
tests <- rbind(c(100000000000000.01, 100000000000000.011), |
|||
c(100.01, 100.011), |
|||
c(10000000000000.001 / 10000.0, 1000000000.0000001000), |
|||
c(0.001, 0.0010000001), |
|||
c(0.000000000000000000000101, 0.0), |
|||
c(sqrt(2) * sqrt(2), 2.0), |
|||
c(-sqrt(2) * sqrt(2), -2.0), |
|||
c(3.14159265358979323846, 3.14159265358979324)) |
|||
results <- mapply(approxEq, tests[, 1], tests[, 2]) |
|||
#All that remains is to print out our results in a presentable way: |
|||
printableTests <- format(tests, scientific = FALSE) |
|||
print(data.frame(x = printableTests[, 1], y = printableTests[, 2], Equal = results, row.names = paste0("Test ", 1:8, ": ")))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> x y Equal |
|||
Test 1: 100000000000000.015625000000000000000000 100000000000000.015625000000000000000000 TRUE |
|||
Test 2: 100.010000000000005115907697 100.010999999999995679900167 FALSE |
|||
Test 3: 1000000000.000000238418579101562500 1000000000.000000119209289550781250 TRUE |
|||
Test 4: 0.001000000000000000020817 0.001000000100000000054917 FALSE |
|||
Test 5: 0.000000000000000000000101 0.000000000000000000000000 TRUE |
|||
Test 6: 2.000000000000000444089210 2.000000000000000000000000 TRUE |
|||
Test 7: -2.000000000000000444089210 -2.000000000000000000000000 TRUE |
|||
Test 8: 3.141592653589793115997963 3.141592653589793115997963 TRUE</pre> |
|||
=={{header|Racket}}== |
|||
In Racket, a number literal with decimal point is considered a flonum, an inexact number which could be either 30 or 62 bits depending on machines. By prefixing the literal with <code>#e</code>, it is now considered an exact, rational number. In this task, we test the approximate equality on both variants: |
|||
<syntaxhighlight lang="racket">#lang racket |
|||
(define (≈ a b [tolerance 1e-9]) |
|||
(<= (abs (/ (- a b) (max a b))) tolerance)) |
|||
(define all-tests |
|||
`(([100000000000000.01 100000000000000.011] |
|||
[100.01 100.011] |
|||
[,(/ 10000000000000.001 10000.0) 1000000000.0000001000] |
|||
[0.001 0.0010000001] |
|||
[0.000000000000000000000101 0.0] |
|||
[,(* (sqrt 2) (sqrt 2)) 2.0] |
|||
[,(* (- (sqrt 2)) (sqrt 2)) -2.0] |
|||
[100000000000000003.0 100000000000000004.0] |
|||
[3.14159265358979323846 3.14159265358979324]) |
|||
([#e100000000000000.01 #e100000000000000.011] |
|||
[#e100.01 #e100.011] |
|||
[,(/ #e10000000000000.001 #e10000.0) #e1000000000.0000001000] |
|||
[#e0.001 #e0.0010000001] |
|||
[#e0.000000000000000000000101 #e0.0] |
|||
[,(* (sqrt 2) (sqrt 2)) #e2.0] |
|||
[,(* (- (sqrt 2)) (sqrt 2)) #e-2.0] |
|||
[100000000000000003 100000000000000004] |
|||
[#e3.14159265358979323846 #e3.14159265358979324]))) |
|||
(define (format-num x) |
|||
(~a (~r x #:precision 30) #:min-width 50 #:align 'right)) |
|||
(for ([tests (in-list all-tests)] [name '("inexact" "exact")]) |
|||
(printf "~a:\n" name) |
|||
(for ([test (in-list tests)]) |
|||
(match-define (list a b) test) |
|||
(printf "~a ~a: ~a\n" (format-num a) (format-num b) (≈ a b))) |
|||
(newline))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
inexact: |
|||
100000000000000.015625000000000000310697263104 100000000000000.015625000000000000310697263104: #t |
|||
100.010000000000005116710235406336 100.010999999999995680439855480832: #f |
|||
1000000000.000000238418579101562504740864 1000000000.000000119209289550781252370432: #t |
|||
0.001000000000000000013287555072 0.001000000100000000093229940736: #f |
|||
0.000000000000000000000101 0: #f |
|||
2.000000000000000444089209850063 2: #t |
|||
-2.000000000000000444089209850063 -2: #t |
|||
100000000000000000 100000000000000000: #t |
|||
3.141592653589793121575456735232 3.141592653589793121575456735232: #t |
|||
exact: |
|||
100000000000000.01 100000000000000.011: #t |
|||
100.01 100.011: #f |
|||
1000000000.0000001 1000000000.0000001: #t |
|||
0.001 0.0010000001: #f |
|||
0.000000000000000000000101 0: #f |
|||
2.000000000000000444089209850063 2: #t |
|||
-2.000000000000000444089209850063 -2: #t |
|||
100000000000000003 100000000000000004: #t |
|||
3.14159265358979323846 3.14159265358979324: #t |
|||
</pre> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|2019.07.1}} |
{{works with|Rakudo|2019.07.1}} |
||
Is approximately equal to is a built-in operator in |
Is approximately equal to is a built-in operator in Raku. Unicode ≅, or the ASCII equivalent: =~=. By default it uses a tolerance of 1e-15 times the order of magnitude of the larger comparand, though that is adjustable by setting the dynamic variable $*TOLERANCE to the desired value. Probably a good idea to localize the changed $*TOLERANCE as it will affect all comparisons within its scope. |
||
Most of the following tests are somewhat pointless in |
Most of the following tests are somewhat pointless in Raku. To a large extent, when dealing with Rational values, you don't really need to worry about "approximately equal to", and all of the test values below, with the exception of <code>sqrt(2)</code>, are Rats by default, and exact. You would have to specifically coerce them to Nums (floating point) to lose the precision. |
||
For example, in |
For example, in Raku, the sum of .1, .2, .3, & .4 is ''identically'' equal to 1. |
||
<lang |
<syntaxhighlight lang="raku" line>say 0.1 + 0.2 + 0.3 + 0.4 === 1.0000000000000000000000000000000000000000000000000000000000000000000000000; # True</syntaxhighlight> |
||
It's also ''approximately'' equal to 1 but... ¯\_(ツ)_/¯ |
It's also ''approximately'' equal to 1 but... ¯\_(ツ)_/¯ |
||
<lang |
<syntaxhighlight lang="raku" line>for |
||
100000000000000.01, 100000000000000.011, |
100000000000000.01, 100000000000000.011, |
||
100.01, 100.011, |
100.01, 100.011, |
||
Line 190: | Line 1,516: | ||
my $*TOLERANCE = .001; |
my $*TOLERANCE = .001; |
||
say 22/7, " ≅ ", π, ": ", 22/7 ≅ π; |
say 22/7, " ≅ ", π, ": ", 22/7 ≅ π; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>100000000000000.01 ≅ 100000000000000.011: True |
<pre>100000000000000.01 ≅ 100000000000000.011: True |
||
Line 206: | Line 1,532: | ||
3.142857 ≅ 3.141592653589793: True</pre> |
3.142857 ≅ 3.141592653589793: True</pre> |
||
=={{header| |
=={{header|ReScript}}== |
||
<syntaxhighlight lang="rescript">let approx_eq = (v1, v2, epsilon) => { |
|||
Traditionally I have always just used sprintf() to compare floating point atoms in phix.<br> |
|||
abs_float (v1 -. v2) < epsilon |
|||
For this task, it proved much harder to get decent-looking output, than it did to perform the tests, and to that end I |
|||
} |
|||
decided to allow the display format (dfmt) to be overidden, when needed, and for the tricker/ambiguous test 5, I also allow the compare format (cfmt) to be overidden, getting ''both'' a true and false result. Likewise I have a different result for test 4 to everyone else, but simply setting the cfmt to "%.8f" would get it the NOT. |
|||
<lang Phix>procedure test(atom a,b, string dfmt="%g", cfmt="%g") |
|||
bool eq = sprintf(cfmt,a)==sprintf(cfmt,b) |
|||
string eqs = iff(eq?"":"NOT "), |
|||
sa = sprintf(dfmt,a), |
|||
sb = sprintf(dfmt,b) |
|||
printf(1,"%30s is %sapproximately equal to %s\n",{sa,eqs,sb}) |
|||
end procedure |
|||
let test = (a, b) => { |
|||
test(100000000000000.01,100000000000000.011,"%.3f") |
|||
let epsilon = 1e-18 |
|||
test(100.01,100.011) |
|||
Printf.printf("%g, %g => %b\n", a, b, approx_eq(a, b, epsilon)) |
|||
test(10000000000000.001/10000.0,1000000000.0000001000,"%.10f") |
|||
} |
|||
test(0.001,0.0010000001,"%.8f") |
|||
test(0.000000000000000000000101,0.0,"%f") |
|||
test(0.000000000000000000000101,0.0,"%f","%6f") |
|||
test(sqrt(2)*sqrt(2),2.0) |
|||
test(-sqrt(2)*sqrt(2),-2.0) |
|||
test(3.14159265358979323846,3.14159265358979324,"%.20f")</lang> |
|||
{{out}} |
|||
64 bit (implied by some of the accuracies specified for this task): |
|||
<pre> |
|||
100000000000000.010 is approximately equal to 100000000000000.011 |
|||
100.01 is NOT approximately equal to 100.011 |
|||
1000000000.0000001001 is approximately equal to 1000000000.0000001000 |
|||
0.00100000000 is approximately equal to 0.0010000001 |
|||
0.000000000000000000000101000 is NOT approximately equal to 0.000000 |
|||
0.000000000000000000000101000 is approximately equal to 0.000000 |
|||
2 is approximately equal to 2 |
|||
-2 is approximately equal to -2 |
|||
3.14159265358979323851 is approximately equal to 3.14159265358979324003 |
|||
</pre> |
|||
32 bit (in fact a couple of them, the first and last pairs, are actually genuinely identical): |
|||
<pre> |
|||
100000000000000.016 is approximately equal to 100000000000000.016 |
|||
100.01 is NOT approximately equal to 100.011 |
|||
1000000000.0000002384 is approximately equal to 1000000000.0000001192 |
|||
0.0010000000 is approximately equal to 0.0010000001 |
|||
0.000000000000000000000101000 is NOT approximately equal to 0.000000 |
|||
0.000000000000000000000101000 is approximately equal to 0.000000 |
|||
2 is approximately equal to 2 |
|||
-2 is approximately equal to -2 |
|||
3.1415926535897931 is approximately equal to 3.1415926535897931 |
|||
</pre> |
|||
{ |
|||
=={{header|Python}}== |
|||
test(100000000000000.01, 100000000000000.011) |
|||
<lang python>from numpy import sqrt |
|||
test(100.01, 100.011) |
|||
from math import isclose |
|||
test(10000000000000.001 /. 10000.0, 1000000000.0000001000) |
|||
test(0.001, 0.0010000001) |
|||
test(0.000000000000000000000101, 0.0) |
|||
test(sqrt(2.0) *. sqrt(2.0), 2.0) |
|||
test(-. sqrt(2.0) *. sqrt(2.0), (-2.0)) |
|||
test(3.14159265358979323846, 3.14159265358979324) |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|REXX}}== |
|||
testvalues = [[100000000000000.01,100000000000000.011], [100.01, 100.011], |
|||
Since the REXX language uses decimal digits (characters) for floating point numbers (and integers), it's just a matter of |
|||
[10000000000000.001 / 10000.0, 1000000000.0000001000], |
|||
<br>choosing the ''number'' of decimal digits for the precision to be used for arithmetic (in this case, fifteen decimal digits). |
|||
[0.001, 0.0010000001], [0.00000000000000000101, 0.0], |
|||
[sqrt(2) * sqrt(2), 2.0], [-sqrt(2) * sqrt(2), -2.0], |
|||
[100000000000000003.0, 100000000000000004.0], |
|||
[3.14159265358979323846, 3.14159265358979324]] |
|||
The choosing of the number of decimal digits is performed via the REXX statement: '''numeric digits ''nnn'' ''' |
|||
for (x, y) in testvalues: |
|||
<syntaxhighlight lang="rexx">/*REXX program mimics an "approximately equal to" for comparing floating point numbers*/ |
|||
maybenot = "is" if isclose(x, y) else "is NOT" |
|||
print(x, maybenot, "approximately equal to ", y) |
|||
</lang>{{out}} |
|||
<pre> |
|||
100000000000000.02 is approximately equal to 100000000000000.02 |
|||
100.01 is NOT approximately equal to 100.011 |
|||
1000000000.0000002 is approximately equal to 1000000000.0000001 |
|||
0.001 is NOT approximately equal to 0.0010000001 |
|||
1.01e-18 is NOT approximately equal to 0.0 |
|||
2.0 is approximately equal to 2.0 |
|||
-2.0 is approximately equal to -2.0 |
|||
1e+17 is approximately equal to 1e+17 |
|||
3.141592653589793 is approximately equal to 3.141592653589793 |
|||
</pre> |
|||
=={{header|REXX}}== |
|||
Since the REXX language uses decimal digits for floating point numbers (and integers), it's just a matter of choosing |
|||
<br>the number of decimal digits for the precision to be used for arithmetic (in this case, fifteen decimal digits). |
|||
<lang rexx>/*REXX program mimics an "approximately equal to" for comparing floating point numbers*/ |
|||
numeric digits 15 /*what other FP hardware normally uses.*/ |
numeric digits 15 /*what other FP hardware normally uses.*/ |
||
@.= /*assign default for the @ array. */ |
@.= /*assign default for the @ array. */ |
||
Line 295: | Line 1,570: | ||
@.6= sqrt(2) * sqrt(2) 2.0 |
@.6= sqrt(2) * sqrt(2) 2.0 |
||
@.7= -sqrt(2) * sqrt(2) '-2.0' |
@.7= -sqrt(2) * sqrt(2) '-2.0' |
||
@.8= |
@.8= 3.14159265358979323846 3.14159265358979324 |
||
/* added ───► */ @.9= 100000000000000003.0 100000000000000004.0 |
|||
end |
end |
||
do j=1 while @.j\=='' /*process CL argument or the array #s. */ |
do j=1 while @.j\=='' /*process CL argument or the array #s. */ |
||
Line 313: | Line 1,588: | ||
numeric form; m.=9; parse value format(x,2,1,,0) 'E0' with g "E" _ .; g=g *.5'e'_ %2 |
numeric form; m.=9; parse value format(x,2,1,,0) 'E0' with g "E" _ .; g=g *.5'e'_ %2 |
||
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/ |
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/ |
||
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/; return g/1</ |
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/; return g/1</syntaxhighlight> |
||
{{out|output|text= when using the internal default inputs:}} |
{{out|output|text= when using the internal default inputs:}} |
||
<pre> |
<pre> |
||
Line 352: | Line 1,627: | ||
═════════════════════════ processing pair 8 ══════════════════════════ |
═════════════════════════ processing pair 8 ══════════════════════════ |
||
A= 3.14159265358979323846 |
|||
A= 100000000000000003.0 |
|||
B= 3.14159265358979324 |
|||
B= 100000000000000004.0 |
|||
A approximately equal to B? true |
A approximately equal to B? true |
||
═════════════════════════ processing pair 9 ══════════════════════════ |
═════════════════════════ processing pair 9 ══════════════════════════ |
||
A= 100000000000000003.0 |
|||
A= 3.14159265358979323846 |
|||
B= 100000000000000004.0 |
|||
B= 3.14159265358979324 |
|||
A approximately equal to B? true |
A approximately equal to B? true |
||
</pre> |
</pre> |
||
=={{header|RPL}}== |
|||
We use here mantissa comparison, which makes that any epsilon can not be close to zero. |
|||
≪ MANT SWAP MANT - ABS 1E-09 < |
|||
≫ ‘'''CLOSE?'''’ STO |
|||
≪ {} { 100000000000000.01 100000000000000.011 |
|||
100.01 100.011 |
|||
≪ 10000000000000.001 10000 / ≫ 1000000000.0000001 |
|||
0.001 0.0010000001 |
|||
0.000000000000000000000101 0 |
|||
≪ 2 √ 2 √ * ≫ 2 |
|||
≪ 2 √ 2 √ * NEG ≫ -2 |
|||
3.14159265358979323846, π } |
|||
1 OVER SIZE '''FOR''' j |
|||
DUP j GET EVAL OVER j 1 + GET EVAL '''CLOSE?''' |
|||
NUM→ "True" "False" IFTE ROT SWAP + SWAP 2 '''STEP''' |
|||
≫ ‘'''TASK'''’ STO |
|||
{{out}} |
|||
<pre> |
|||
1: { "True" "False" "True" "False" "False" "True" "True" "True" } |
|||
</pre> |
|||
=={{header|Ruby}}== |
|||
Most work went into handling weird Float values like NaN and Infinity. |
|||
<syntaxhighlight lang="ruby">require "bigdecimal" |
|||
testvalues = [[100000000000000.01, 100000000000000.011], |
|||
[100.01, 100.011], |
|||
[10000000000000.001 / 10000.0, 1000000000.0000001000], |
|||
[0.001, 0.0010000001], |
|||
[0.000000000000000000000101, 0.0], |
|||
[(2**0.5) * (2**0.5), 2.0], |
|||
[-(2**0.5) * (2**0.5), -2.0], |
|||
[BigDecimal("3.14159265358979323846"), 3.14159265358979324], |
|||
[Float::NAN, Float::NAN,], |
|||
[Float::INFINITY, Float::INFINITY], |
|||
] |
|||
class Numeric |
|||
def close_to?(num, tol = Float::EPSILON) |
|||
return true if self == num |
|||
return false if (self.to_f.nan? or num.to_f.nan?) # NaN is not even close to itself |
|||
return false if [self, num].count( Float::INFINITY) == 1 # Infinity is only close to itself |
|||
return false if [self, num].count(-Float::INFINITY) == 1 |
|||
(self-num).abs <= tol * ([self.abs, num.abs].max) |
|||
end |
|||
end |
|||
testvalues.each do |a,b| |
|||
puts "#{a} #{a.close_to?(b) ? '≈' : '≉'} #{b}" |
|||
end |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000.02 ≈ 100000000000000.02 |
|||
100.01 ≉ 100.011 |
|||
1000000000.0000002 ≈ 1000000000.0000001 |
|||
0.001 ≉ 0.0010000001 |
|||
0.101e-21 ≉ 0.0 |
|||
2.0000000000000004 ≈ 2.0 |
|||
-2.0000000000000004 ≈ -2.0 |
|||
0.314159265358979323846e1 ≈ 3.141592653589793 |
|||
NaN ≉ NaN |
|||
Infinity ≈ Infinity |
|||
</pre> |
|||
=={{header|Rust}}== |
|||
<syntaxhighlight lang="rust">/// Return whether the two numbers `a` and `b` are close. |
|||
/// Closeness is determined by the `epsilon` parameter - |
|||
/// the numbers are considered close if the difference between them |
|||
/// is no more than epsilon * max(abs(a), abs(b)). |
|||
fn isclose(a: f64, b: f64, epsilon: f64) -> bool { |
|||
(a - b).abs() <= a.abs().max(b.abs()) * epsilon |
|||
} |
|||
fn main() { |
|||
fn sqrt(x: f64) -> f64 { x.sqrt() } |
|||
macro_rules! test { |
|||
($a: expr, $b: expr) => { |
|||
let operator = if isclose($a, $b, 1.0e-9) { '≈' } else { '≉' }; |
|||
println!("{:>28} {} {}", stringify!($a), operator, stringify!($b)) |
|||
} |
|||
} |
|||
test!(100000000000000.01, 100000000000000.011); |
|||
test!(100.01, 100.011); |
|||
test!(10000000000000.001/10000.0, 1000000000.0000001000); |
|||
test!(0.001, 0.0010000001); |
|||
test!(0.000000000000000000000101, 0.0); |
|||
test!( sqrt(2.0) * sqrt(2.0), 2.0); |
|||
test!(-sqrt(2.0) * sqrt(2.0), -2.0); |
|||
test!(3.14159265358979323846, 3.14159265358979324); |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 100000000000000.01 ≈ 100000000000000.011 |
|||
100.01 ≉ 100.011 |
|||
10000000000000.001 / 10000.0 ≈ 1000000000.0000001000 |
|||
0.001 ≉ 0.0010000001 |
|||
0.000000000000000000000101 ≉ 0.0 |
|||
sqrt(2.0) * sqrt(2.0) ≈ 2.0 |
|||
-sqrt(2.0) * sqrt(2.0) ≈ -2.0 |
|||
3.14159265358979323846 ≈ 3.14159265358979324</pre> |
|||
=={{header|Scala}}== |
|||
{{Out}}Best seen running in your browser by [https://scastie.scala-lang.org/kxD9xQuIQEGpABXnsE6BiQ Scastie (remote JVM)]. |
|||
<syntaxhighlight lang="scala">object Approximate extends App { |
|||
val (ok, notOk, ε) = ("👌", "❌", 1e-18d) |
|||
private def approxEquals(value: Double, other: Double, epsilon: Double) = |
|||
scala.math.abs(value - other) < epsilon |
|||
private def test(a: BigDecimal, b: BigDecimal, expected: Boolean): Unit = { |
|||
val result = approxEquals(a.toDouble, b.toDouble, ε) |
|||
println(f"$a%40.24f ≅ $b%40.24f => $result%5s ${if (expected == result) ok else notOk}") |
|||
} |
|||
test(BigDecimal("100000000000000.010"), BigDecimal("100000000000000.011"), true) |
|||
test(BigDecimal("100.01"), BigDecimal("100.011"), false) |
|||
test(BigDecimal(10000000000000.001 / 10000.0), BigDecimal("1000000000.0000001000"), false) |
|||
test(BigDecimal("0.001"), BigDecimal("0.0010000001"), false) |
|||
test(BigDecimal("0.000000000000000000000101"), BigDecimal(0), true) |
|||
test(BigDecimal(math.sqrt(2) * math.sqrt(2d)), BigDecimal(2.0), false) |
|||
test(BigDecimal(-Math.sqrt(2) * Math.sqrt(2)), BigDecimal(-2.0), false) |
|||
test(BigDecimal("3.14159265358979323846"), BigDecimal("3.14159265358979324"), true) |
|||
}</syntaxhighlight> |
|||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
Two values can be compared for approximate equality by using the built-in operator '''≅''', available in ASCII as '''=~=''', which does approximate comparison by rounding both operands at '''(PREC>>2)-1''' decimals. However, by default, Sidef uses a floating-point precision of 192 bits. |
Two values can be compared for approximate equality by using the built-in operator '''≅''', available in ASCII as '''=~=''', which does approximate comparison by rounding both operands at '''(PREC>>2)-1''' decimals. However, by default, Sidef uses a floating-point precision of 192 bits. |
||
< |
<syntaxhighlight lang="ruby">[ |
||
100000000000000.01, 100000000000000.011, |
100000000000000.01, 100000000000000.011, |
||
100.01, 100.011, |
100.01, 100.011, |
||
Line 379: | Line 1,779: | ||
].each_slice(2, {|a,b| |
].each_slice(2, {|a,b| |
||
say ("#{a} ≅ #{b}: ", a ≅ b) |
say ("#{a} ≅ #{b}: ", a ≅ b) |
||
})</ |
})</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 398: | Line 1,798: | ||
The Number '''n.round(-k)''' can be used for rounding the number ''n'' to ''k'' decimal places. A positive argument can be used for rounding before the decimal point. |
The Number '''n.round(-k)''' can be used for rounding the number ''n'' to ''k'' decimal places. A positive argument can be used for rounding before the decimal point. |
||
< |
<syntaxhighlight lang="ruby">var a = 100000000000000.01 |
||
var b = 100000000000000.011 |
var b = 100000000000000.011 |
||
# Rounding at 2 and 3 decimal places, respectively |
# Rounding at 2 and 3 decimal places, respectively |
||
say (round(a, -2) == round(b, -2)) # true |
say (round(a, -2) == round(b, -2)) # true |
||
say (round(a, -3) == round(b, -3)) # false</ |
say (round(a, -3) == round(b, -3)) # false</syntaxhighlight> |
||
There is also the built-in '''approx_cmp(a, b, k)''' method, which is equivalent with '''a.round(k) <=> b.round(k)'''. |
There is also the built-in '''approx_cmp(a, b, k)''' method, which is equivalent with '''a.round(k) <=> b.round(k)'''. |
||
< |
<syntaxhighlight lang="ruby">var a = 22/7 |
||
var b = Num.pi |
var b = Num.pi |
||
say ("22/7 ≅ π at 2 decimals: ", approx_cmp(a, b, -2) == 0) |
say ("22/7 ≅ π at 2 decimals: ", approx_cmp(a, b, -2) == 0) |
||
say ("22/7 ≅ π at 3 decimals: ", approx_cmp(a, b, -3) == 0)</ |
say ("22/7 ≅ π at 3 decimals: ", approx_cmp(a, b, -3) == 0)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 421: | Line 1,821: | ||
Additionally, the '''rat_approx''' method can be used for computing a very good rational approximation to a given real value: |
Additionally, the '''rat_approx''' method can be used for computing a very good rational approximation to a given real value: |
||
< |
<syntaxhighlight lang="ruby">say (1.33333333.rat_approx == 4/3) # true |
||
say (zeta(-5).rat_approx == -1/252) # true</ |
say (zeta(-5).rat_approx == -1/252) # true</syntaxhighlight> |
||
Rational approximations illustrated for substrings of PI: |
Rational approximations illustrated for substrings of PI: |
||
< |
<syntaxhighlight lang="ruby">for k in (3..19) { |
||
var r = Str(Num.pi).first(k) |
var r = Str(Num.pi).first(k) |
||
say ("rat_approx(#{r}) = ", Num(r).rat_approx.as_frac) |
say ("rat_approx(#{r}) = ", Num(r).rat_approx.as_frac) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 449: | Line 1,849: | ||
rat_approx(3.14159265358979323) = 1726375805/549522486 |
rat_approx(3.14159265358979323) = 1726375805/549522486 |
||
</pre> |
</pre> |
||
=={{header|Smalltalk}}== |
|||
This compares numbers given the number of ULPs by which they may differ (see wikipedia). |
|||
There are slight differences in how this is named in the various dialects ¹. If required, you have to add a forwarding alias method to Number. |
|||
{{works with|Smalltalk/X}} |
|||
<syntaxhighlight lang="smalltalk">{ #(100000000000000.01 100000000000000.011) . |
|||
#(100.01 100.011) . |
|||
{10000000000000.001 / 10000.0 . 1000000000.0000001000} . |
|||
#(0.001 0.0010000001) . |
|||
#(0.000000000000000000000101 0.0) . |
|||
{ 2 sqrt * 2 sqrt . 2.0} . |
|||
{ 2 sqrt negated * 2 sqrt . -2.0} . |
|||
#(3.14159265358979323846 3.14159265358979324) |
|||
} pairsDo:[:val1 :val2 | |
|||
Stdout printCR: e'{val1} =~= {val2} -> {val1 isAlmostEqualTo:val2 nEpsilon:2}' |
|||
]</syntaxhighlight> |
|||
In CUIS, this method is called <tt>isWithin:floatsFrom:</tt>. |
|||
{{out}} |
|||
<pre>100.01 =~= 100.011 -> false |
|||
1000000000.0 =~= 1000000000.0 -> true |
|||
0.001 =~= 0.0010000001 -> false |
|||
1.01e-22 =~= 0.0 -> true |
|||
2.0 =~= 2.0 -> true |
|||
-2.0 =~= -2.0 -> true |
|||
3.14159265358979 =~= 3.14159265358979 -> true</pre> |
|||
By default, double precision IEEE floats are used. |
|||
=={{header|Swift}}== |
|||
Using the solution proposed as an addition to the Swift standard library in SE-0259. Currently this is not accepted, but is likely to be included in the Swift Numerics module. |
|||
<syntaxhighlight lang="swift">import Foundation |
|||
extension FloatingPoint { |
|||
@inlinable |
|||
public func isAlmostEqual( |
|||
to other: Self, |
|||
tolerance: Self = Self.ulpOfOne.squareRoot() |
|||
) -> Bool { |
|||
// tolerances outside of [.ulpOfOne,1) yield well-defined but useless results, |
|||
// so this is enforced by an assert rathern than a precondition. |
|||
assert(tolerance >= .ulpOfOne && tolerance < 1, "tolerance should be in [.ulpOfOne, 1).") |
|||
// The simple computation below does not necessarily give sensible |
|||
// results if one of self or other is infinite; we need to rescale |
|||
// the computation in that case. |
|||
guard self.isFinite && other.isFinite else { |
|||
return rescaledAlmostEqual(to: other, tolerance: tolerance) |
|||
} |
|||
// This should eventually be rewritten to use a scaling facility to be |
|||
// defined on FloatingPoint suitable for hypot and scaled sums, but the |
|||
// following is good enough to be useful for now. |
|||
let scale = max(abs(self), abs(other), .leastNormalMagnitude) |
|||
return abs(self - other) < scale*tolerance |
|||
} |
|||
@usableFromInline |
|||
internal func rescaledAlmostEqual(to other: Self, tolerance: Self) -> Bool { |
|||
// NaN is considered to be not approximately equal to anything, not even |
|||
// itself. |
|||
if self.isNaN || other.isNaN { return false } |
|||
if self.isInfinite { |
|||
if other.isInfinite { return self == other } |
|||
// Self is infinite and other is finite. Replace self with the binade |
|||
// of the greatestFiniteMagnitude, and reduce the exponent of other by |
|||
// one to compensate. |
|||
let scaledSelf = Self(sign: self.sign, |
|||
exponent: Self.greatestFiniteMagnitude.exponent, |
|||
significand: 1) |
|||
let scaledOther = Self(sign: .plus, |
|||
exponent: -1, |
|||
significand: other) |
|||
// Now both values are finite, so re-run the naive comparison. |
|||
return scaledSelf.isAlmostEqual(to: scaledOther, tolerance: tolerance) |
|||
} |
|||
// If self is finite and other is infinite, flip order and use scaling |
|||
// defined above, since this relation is symmetric. |
|||
return other.rescaledAlmostEqual(to: self, tolerance: tolerance) |
|||
} |
|||
} |
|||
let testCases = [ |
|||
(100000000000000.01, 100000000000000.011), |
|||
(100.01, 100.011), |
|||
(10000000000000.001 / 10000.0, 1000000000.0000001000), |
|||
(0.001, 0.0010000001), |
|||
(0.000000000000000000000101, 0.0), |
|||
(sqrt(2) * sqrt(2), 2.0), |
|||
(-sqrt(2) * sqrt(2), -2.0), |
|||
(3.14159265358979323846, 3.14159265358979324) |
|||
] |
|||
for testCase in testCases { |
|||
print("\(testCase.0), \(testCase.1) => \(testCase.0.isAlmostEqual(to: testCase.1))") |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000.02, 100000000000000.02 => true |
|||
100.01, 100.011 => false |
|||
1000000000.0000002, 1000000000.0000001 => true |
|||
0.001, 0.0010000001 => false |
|||
1.01e-22, 0.0 => false |
|||
2.0000000000000004, 2.0 => true |
|||
-2.0000000000000004, -2.0 => true |
|||
3.141592653589793, 3.141592653589793 => true</pre> |
|||
=={{header|Tcl}}== |
|||
===Using decimal library=== |
|||
Uses tcllib's decimal library. Using a tolerance of 9 significant digits. |
|||
<syntaxhighlight lang="tcl">catch {namespace delete test_almost_equal_decimal} ;# Start with a clean namespace |
|||
namespace eval test_almost_equal_decimal { |
|||
package require Tcl 8.5 ;# required by tcllib |
|||
package require math::decimal ;# from tcllib |
|||
namespace import ::math::decimal::* ;# for: setVariable, fromstr, and compare |
|||
array set yesno {0 Yes -1 No 1 No} ;# For nice output |
|||
# More info here: http://speleotrove.com/decimal/dax3274.html |
|||
# This puts the library into "simplified" mode. Which |
|||
# rounds the "decimal digits" in the coefficient to the |
|||
# number of digits that "precision" is set to. |
|||
setVariable extended 0 |
|||
setVariable precision 9 |
|||
set data { |
|||
{100000000000000.01 100000000000000.011} |
|||
{100.01 100.011} |
|||
{[expr {10000000000000.001 / 10000.0}] 1000000000.0000001000} |
|||
{0.001 0.0010000001} |
|||
{0.000000000000000000000101 0.0} |
|||
{[expr { sqrt(2) * sqrt(2)}] 2.0} |
|||
{[expr {-sqrt(2) * sqrt(2)}] -2.0} |
|||
{3.14159265358979323846 3.14159265358979324} |
|||
} |
|||
set data [subst $data] ;# resolves expressions in the list |
|||
foreach {a b} [join $data] { |
|||
set a_d [fromstr $a] |
|||
set b_d [fromstr $b] |
|||
puts [format "Is %26s ≈ %21s ? %4s." $a $b $yesno([compare $a_d $b_d])] |
|||
} |
|||
} |
|||
</syntaxhighlight>{{out}} |
|||
<pre>Is 100000000000000.01 ≈ 100000000000000.011 ? Yes. |
|||
Is 100.01 ≈ 100.011 ? No. |
|||
Is 1000000000.0000002 ≈ 1000000000.0000001000 ? Yes. |
|||
Is 0.001 ≈ 0.0010000001 ? No. |
|||
Is 0.000000000000000000000101 ≈ 0.0 ? No. |
|||
Is 2.0000000000000004 ≈ 2.0 ? Yes. |
|||
Is -2.0000000000000004 ≈ -2.0 ? Yes. |
|||
Is 3.14159265358979323846 ≈ 3.14159265358979324 ? Yes. |
|||
</pre> |
|||
===Using string manipulation=== |
|||
<syntaxhighlight lang="tcl">catch {namespace delete test_almost_equal_string} ;# Start with a clean namespace |
|||
namespace eval test_almost_equal_string { |
|||
package require Tcl 8.4 ;# ?Maybe earlier? |
|||
array set yesno {1 Yes 0 No} ;# For nice output |
|||
proc isClose {a b {prec 9}} { |
|||
proc toCoeff {n prec} { |
|||
set repr 40 ;# Chosen to be arbitrarily large to handle most cases |
|||
set long [format %0.${repr}f $n] ;# Take out of scientific notation |
|||
set map [string map {. {}} $long] ;# Remove decimal point |
|||
set trim [string trimleft $map 0] ;# Remove leading zeros |
|||
# restore string for comparison |
|||
set len [string length $trim] |
|||
if {$len < $prec} { |
|||
set trim "${trim}[string repeat 0 [expr ($prec+1)-$len]]" |
|||
} |
|||
# Round last decimal place |
|||
set rounded [format %0.f "[string range $trim 0 [expr {$prec-1}]].[string index $trim $prec]"] |
|||
return $rounded |
|||
} |
|||
set a_coeff [toCoeff $a $prec] |
|||
set b_coeff [toCoeff $b $prec] |
|||
return [expr {$a_coeff == $b_coeff}] |
|||
} |
|||
set data { |
|||
{100000000000000.01 100000000000000.011} |
|||
{100.01 100.011} |
|||
{[expr {10000000000000.001 / 10000.0}] 1000000000.0000001000} |
|||
{0.001 0.0010000001} |
|||
{0.000000000000000000000101 0.0} |
|||
{[expr { sqrt(2) * sqrt(2)}] 2.0} |
|||
{[expr {-sqrt(2) * sqrt(2)}] -2.0} |
|||
{3.14159265358979323846 3.14159265358979324} |
|||
} |
|||
set data [subst $data] ;# resolves expressions in the list |
|||
foreach {a b} [join $data] { |
|||
puts [format "Is %26s ≈ %21s ? %4s." $a $b $yesno([isClose $a $b])] |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Is 100000000000000.01 ≈ 100000000000000.011 ? Yes. |
|||
Is 100.01 ≈ 100.011 ? No. |
|||
Is 1000000000.0000002 ≈ 1000000000.0000001000 ? Yes. |
|||
Is 0.001 ≈ 0.0010000001 ? No. |
|||
Is 0.000000000000000000000101 ≈ 0.0 ? No. |
|||
Is 2.0000000000000004 ≈ 2.0 ? Yes. |
|||
Is -2.0000000000000004 ≈ -2.0 ? Yes. |
|||
Is 3.14159265358979323846 ≈ 3.14159265358979324 ? Yes. |
|||
</pre> |
|||
=={{header|Visual Basic .NET}}== |
|||
{{trans|C#}} |
|||
<syntaxhighlight lang="vbnet">Imports System.Runtime.CompilerServices |
|||
Module Module1 |
|||
<Extension()> |
|||
Function ApproxEquals(ByVal value As Double, other As Double, epsilon As Double) |
|||
Return Math.Abs(value - other) < epsilon |
|||
End Function |
|||
Sub Test(a As Double, b As Double) |
|||
Dim epsilon = 1.0E-18 |
|||
Console.WriteLine($"{a}, {b} => {a.ApproxEquals(b, epsilon)}") |
|||
End Sub |
|||
Sub Main() |
|||
Test(100000000000000.02, 100000000000000.02) |
|||
Test(100.01, 100.011) |
|||
Test(10000000000000.002 / 10000.0, 1000000000.0000001) |
|||
Test(0.001, 0.0010000001) |
|||
Test(1.01E-22, 0.0) |
|||
Test(Math.Sqrt(2) * Math.Sqrt(2), 2.0) |
|||
Test(-Math.Sqrt(2) * Math.Sqrt(2), -2.0) |
|||
Test(3.1415926535897931, 3.1415926535897931) |
|||
End Sub |
|||
End Module</syntaxhighlight> |
|||
{{out}} |
|||
<pre>100000000000000, 100000000000000 => True |
|||
100.01, 100.011 => False |
|||
1000000000, 1000000000 => False |
|||
0.001, 0.0010000001 => False |
|||
1.01E-22, 0 => True |
|||
2, 2 => False |
|||
-2, -2 => False |
|||
3.14159265358979, 3.14159265358979 => True</pre> |
|||
=={{header|Wren}}== |
|||
<syntaxhighlight lang="wren">var tol = 1e-16 |
|||
var pairs = [ |
|||
[100000000000000.01, 100000000000000.011], |
|||
[100.01, 100.011], |
|||
[10000000000000.001 / 10000.0, 1000000000.0000001000], |
|||
[0.001, 0.0010000001], |
|||
[0.000000000000000000000101, 0.0], |
|||
[2.sqrt * 2.sqrt, 2.0], |
|||
[-2.sqrt * 2.sqrt, -2.0], |
|||
[3.14159265358979323846, 3.14159265358979324] |
|||
] |
|||
System.print("Approximate equality of test cases for a tolerance of %(tol):") |
|||
var i = 0 |
|||
for (pair in pairs) { |
|||
i = i + 1 |
|||
System.print(" %(i) -> %((pair[0] - pair[1]).abs < tol)") |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Approximate equality of test cases for a tolerance of 1e-16: |
|||
1 -> true |
|||
2 -> false |
|||
3 -> false |
|||
4 -> false |
|||
5 -> true |
|||
6 -> false |
|||
7 -> false |
|||
8 -> true |
|||
</pre> |
|||
=={{header|XPL0}}== |
|||
<syntaxhighlight lang="xpl0">func ApproxEqual(A, B); \Return 'true' if approximately equal |
|||
real A, B; |
|||
real Epsilon; |
|||
[Epsilon:= abs(A) * 1E-15; |
|||
return abs(A-B) < Epsilon; |
|||
]; |
|||
real Data; |
|||
int I; |
|||
[Format(0, 16); |
|||
Data:=[ [100000000000000.01, 100000000000000.011], \should return true |
|||
[100.01, 100.011], \should return false |
|||
[10000000000000.001 / 10000.0, 1000000000.0000001000], |
|||
[0.001, 0.0010000001], |
|||
[0.000000000000000000000101, 0.0], \is undefined |
|||
[sqrt(2.0) * sqrt(2.0), 2.0], |
|||
[-1.0 * sqrt(2.0) * sqrt(2.0), -2.0], \-sqrt doesn't compile! |
|||
[3.14159265358979323846, 3.14159265358979324] ]; |
|||
for I:= 0 to 7 do |
|||
[IntOut(0, I+1); Text(0, ". "); |
|||
RlOut(0, Data(I,0)); ChOut(0, ^ ); RlOut(0, Data(I,1)); |
|||
Text(0, if ApproxEqual(Data(I,0), Data(I,1)) then " true" else " false"); |
|||
CrLf(0); |
|||
]; |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1. 1.0000000000000000E+014 1.0000000000000000E+014 true |
|||
2. 1.0001000000000000E+002 1.0001100000000000E+002 false |
|||
3. 1.0000000000000000E+009 1.0000000000000000E+009 true |
|||
4. 1.0000000000000000E-003 1.0000001000000000E-003 false |
|||
5. 1.0100000000000000E-022 0.0000000000000000E+000 false |
|||
6. 2.0000000000000000E+000 2.0000000000000000E+000 true |
|||
7. -2.0000000000000000E+000 -2.0000000000000000E+000 true |
|||
8. 3.1415926535897900E+000 3.1415926535897900E+000 true |
|||
</pre> |
|||
=={{header|Yabasic}}== |
|||
<syntaxhighlight lang="yabasic">// Rosetta Code problem: http://rosettacode.org/wiki/Approximate_equality |
|||
// by Jjuanhdez, 09/2022 |
|||
epsilon = 1.0 |
|||
while (1 + epsilon <> 1) |
|||
epsilon = epsilon / 2 |
|||
wend |
|||
print "epsilon = ", epsilon |
|||
print |
|||
eq_approx(100000000000000.01, 100000000000000.011) |
|||
eq_approx(100.01, 100.011) |
|||
eq_approx(10000000000000.001/10000.0, 1000000000.0000001000) |
|||
eq_approx(0.001, 0.0010000001) |
|||
eq_approx(0.000000000000000000000101, 0.0) |
|||
eq_approx(sqrt(2)*sqrt(2), 2.0) |
|||
eq_approx(-sqrt(2)*sqrt(2), -2.0) |
|||
eq_approx(3.14159265358979323846, 3.14159265358979324) |
|||
end |
|||
sub eq_approx(a, b) |
|||
tmp = abs(a - b) < epsilon |
|||
print tmp, " ", a, " ", b |
|||
end sub</syntaxhighlight> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
Line 454: | Line 2,204: | ||
and tolerance. If the tolerance is >=0, comparison is absolute. |
and tolerance. If the tolerance is >=0, comparison is absolute. |
||
If tolerance is <0 (and x!=0 and y!=0), the comparison is relative. |
If tolerance is <0 (and x!=0 and y!=0), the comparison is relative. |
||
< |
<syntaxhighlight lang="zkl">testValues:=T( |
||
T(100000000000000.01,100000000000000.011), |
T(100000000000000.01,100000000000000.011), |
||
T(100.01, 100.011), |
T(100.01, 100.011), |
||
Line 470: | Line 2,220: | ||
maybeNot:=( if(x.closeTo(y,tolerance)) " \u2248" else "!\u2248" ); |
maybeNot:=( if(x.closeTo(y,tolerance)) " \u2248" else "!\u2248" ); |
||
println("% 25.19g %s %- 25.19g %g".fmt(x,maybeNot,y, (x-y).abs())); |
println("% 25.19g %s %- 25.19g %g".fmt(x,maybeNot,y, (x-y).abs())); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
Latest revision as of 11:23, 6 November 2023
You are encouraged to solve this task according to the task description, using any language you may know.
Sometimes, when testing whether the solution to a task (for example, here on Rosetta Code) is correct, the difference in floating point calculations between different language implementations becomes significant.
For example, a difference between 32 bit and 64 bit floating point calculations may appear by about the 8th significant digit in base 10 arithmetic.
- Task
Create a function which returns true if two floating point numbers are approximately equal.
The function should allow for differences in the magnitude of numbers, so that, for example,
100000000000000.01 may be approximately equal to 100000000000000.011,
even though 100.01 is not approximately equal to 100.011.
If the language has such a feature in its standard library, this may be used instead of a custom function.
Show the function results with comparisons on the following pairs of values:
- 100000000000000.01, 100000000000000.011 (note: should return true)
- 100.01, 100.011 (note: should return false)
- 10000000000000.001 / 10000.0, 1000000000.0000001000
- 0.001, 0.0010000001
- 0.000000000000000000000101, 0.0
- sqrt(2) * sqrt(2), 2.0
- -sqrt(2) * sqrt(2), -2.0
- 3.14159265358979323846, 3.14159265358979324
Answers should be true for the first example and false in the second, so that just rounding the numbers to a fixed number of decimals should not be enough. Otherwise answers may vary and still be correct. See the Python code for one type of solution.
Ada
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Numerics.Generic_Elementary_Functions;
procedure Main is
type Real is digits 18;
package Real_Funcs is new Ada.Numerics.Generic_Elementary_Functions(Real);
use Real_Funcs;
package Real_IO is new Ada.Text_IO.Float_IO(Real);
use Real_IO;
function Approx_Equal (Left : Real; Right : Real) return Boolean is
-- Calculate an epsilon value based upon the magnitude of the
-- maximum value of the two parameters
eps : Real := Real'Max(Left, Right) * 1.0e-9;
begin
if left > Right then
return Left - Right < eps;
else
return Right - Left < eps;
end if;
end Approx_Equal;
Type Index is (Left, Right);
type Pairs_List is array (Index) of Real;
type Pairs_Table is array(1..8) of Pairs_List;
Table : Pairs_Table;
begin
Table := ((100000000000000.01, 100000000000000.011),
(100.01, 100.011),
(10000000000000.001 / 10000.0, 1000000000.0000001000),
(0.001, 0.0010000001),
(0.000000000000000000000101, 0.0),
(sqrt(2.0) * sqrt(2.0), 2.0),
(-sqrt(2.0) * sqrt(2.0), -2.0),
(3.14159265358979323846, 3.14159265358979324));
for Pair of Table loop
Put(Item => Pair(Left), Exp => 0, Aft => 16, Fore => 6);
Put(" ");
Put(Item => Pair(Right), Exp => 0, Aft => 16, Fore => 6);
Put_Line(" " & Boolean'Image(Approx_Equal(Pair(Left), Pair(Right))));
end loop;
end Main;
- Output:
100000000000000.0100000000000000 100000000000000.0110000000000000 TRUE 100.0100000000000000 100.0110000000000000 FALSE 1000000000.0000001000000000 1000000000.0000001000000000 TRUE 0.0010000000000000 0.0010000001000000 FALSE 0.0000000000000000 0.0000000000000000 FALSE 2.0000000000000000 2.0000000000000000 TRUE -2.0000000000000000 -2.0000000000000000 FALSE 3.1415926535897932 3.1415926535897932 TRUE
ALGOL 68
BEGIN # test REAL values for approximate equality #
# returns TRUE if value is approximately equal to other, FALSE otherwide #
PROC approx equals = ( REAL value, REAL other, REAL epsilon )BOOL: ABS ( value - other ) < epsilon;
# shows the result of testing a for approximate equality with b #
PROC test = ( REAL a, b )VOID:
BEGIN
REAL epsilon = 1e-18;
print( ( a, ", ", b, " => ", IF approx equals( a, b, epsilon ) THEN "true" ELSE "false" FI, newline ) )
END # test # ;
# task test cases #
test( 100000000000000.01, 100000000000000.011 );
test( 100.01, 100.011 );
test( 10000000000000.001 / 10000.0, 1000000000.0000001000);
test( 0.001, 0.0010000001 );
test( 0.000000000000000000000101, 0.0 );
test( sqrt( 2 ) * sqrt( 2 ), 2.0 );
test( - sqrt( 2 ) * sqrt( 2 ), -2.0 );
test( 3.14159265358979323846, 3.14159265358979324 )
END
- Output:
+1.00000000000000e +14, +1.00000000000000e +14 => true +1.00010000000000e +2, +1.00011000000000e +2 => false +1.00000000000000e +9, +1.00000000000000e +9 => false +1.00000000000000e -3, +1.00000010000000e -3 => false +1.01000000000000e -22, +0.00000000000000e +0 => true +2.00000000000000e +0, +2.00000000000000e +0 => false -2.00000000000000e +0, -2.00000000000000e +0 => false +3.14159265358979e +0, +3.14159265358979e +0 => true
AWK
# syntax: GAWK -f APPROXIMATE_EQUALITY.AWK
# converted from C#
BEGIN {
epsilon = 1
while (1 + epsilon != 1) {
epsilon /= 2
}
printf("epsilon = %18.16g\n\n",epsilon)
main("100000000000000.01","100000000000000.011")
main("100.01","100.011")
main("10000000000000.001"/"10000.0","1000000000.0000001000")
main("0.001","0.0010000001")
main("0.000000000000000000000101","0.0")
main(sqrt(2.0)*sqrt(2.0),"2.0")
main(-sqrt(2.0)*sqrt(2.0),"-2.0")
main("3.14159265358979323846","3.14159265358979324")
exit(0)
}
function main(a,b, tmp) {
tmp = abs(a - b) < epsilon
printf("%d %27s %s\n",tmp,a,b)
}
function abs(x) { if (x >= 0) { return x } else { return -x } }
- Output:
epsilon = 1.110223024625157e-016 1 100000000000000.01 100000000000000.011 0 100.01 100.011 0 1e+009 1000000000.0000001000 0 0.001 0.0010000001 1 0.000000000000000000000101 0.0 0 2 2.0 0 -2 -2.0 1 3.14159265358979323846 3.14159265358979324
C
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
bool approxEquals(double value, double other, double epsilon) {
return fabs(value - other) < epsilon;
}
void test(double a, double b) {
double epsilon = 1e-18;
printf("%f, %f => %d\n", a, b, approxEquals(a, b, epsilon));
}
int main() {
test(100000000000000.01, 100000000000000.011);
test(100.01, 100.011);
test(10000000000000.001 / 10000.0, 1000000000.0000001000);
test(0.001, 0.0010000001);
test(0.000000000000000000000101, 0.0);
test(sqrt(2.0) * sqrt(2.0), 2.0);
test(-sqrt(2.0) * sqrt(2.0), -2.0);
test(3.14159265358979323846, 3.14159265358979324);
return 0;
}
- Output:
100000000000000.015625, 100000000000000.015625 => 1 100.010000, 100.011000 => 0 1000000000.000000, 1000000000.000000 => 0 0.001000, 0.001000 => 0 0.000000, 0.000000 => 1 2.000000, 2.000000 => 0 -2.000000, -2.000000 => 0 3.141593, 3.141593 => 1
C#
using System;
public static class Program
{
public static void Main() {
Test(100000000000000.01, 100000000000000.011);
Test(100.01, 100.011);
Test(10000000000000.001 / 10000.0, 1000000000.0000001000);
Test(0.001, 0.0010000001);
Test(0.000000000000000000000101, 0.0);
Test(Math.Sqrt(2) * Math.Sqrt(2), 2.0);
Test(-Math.Sqrt(2) * Math.Sqrt(2), -2.0);
Test(3.14159265358979323846, 3.14159265358979324);
void Test(double a, double b) {
const double epsilon = 1e-18;
WriteLine($"{a}, {b} => {a.ApproxEquals(b, epsilon)}");
}
}
public static bool ApproxEquals(this double value, double other, double epsilon) => Math.Abs(value - other) < epsilon;
}
- Output:
100000000000000.02, 100000000000000.02 => True 100.01, 100.011 => False 1000000000.0000002, 1000000000.0000001 => False 0.001, 0.0010000001 => False 1.01E-22, 0 => True 2.0000000000000004, 2 => False -2.0000000000000004, -2 => False 3.141592653589793, 3.141592653589793 => True
C++
#include <iomanip>
#include <iostream>
#include <cmath>
bool approxEquals(double a, double b, double e) {
return fabs(a - b) < e;
}
void test(double a, double b) {
constexpr double epsilon = 1e-18;
std::cout << std::setprecision(21) << a;
std::cout << ", ";
std::cout << std::setprecision(21) << b;
std::cout << " => ";
std::cout << approxEquals(a, b, epsilon) << '\n';
}
int main() {
test(100000000000000.01, 100000000000000.011);
test(100.01, 100.011);
test(10000000000000.001 / 10000.0, 1000000000.0000001000);
test(0.001, 0.0010000001);
test(0.000000000000000000000101, 0.0);
test(sqrt(2.0) * sqrt(2.0), 2.0);
test(-sqrt(2.0) * sqrt(2.0), -2.0);
test(3.14159265358979323846, 3.14159265358979324);
return 0;
}
- Output:
100000000000000.015625, 100000000000000.015625 => 1 100.010000000000005116, 100.01099999999999568 => 0 1000000000.00000023842, 1000000000.00000011921 => 0 0.00100000000000000002082, 0.00100000010000000005492 => 0 1.0099999999999999762e-22, 0 => 1 2.00000000000000044409, 2 => 0 -2.00000000000000044409, -2 => 0 3.141592653589793116, 3.141592653589793116 => 1
Common Lisp
This solution compares the normalized (i.e. between 0.5 and 1 on implementations which use binary floating point) significands of the floating point numbers, correcting each significand by half the difference in the exponents so that the corrected numbers used for comparison have the same difference in order of magnitude as the original numbers and are stable when the order of the arguments is changed. Unlike the metric of comparing the difference to some fraction of the numbers' size, this approach only requires two floating point operations (the subtraction and comparison at the end), and more directly maps to the fundamental issue which leads to the need for floating-point comparisons, i.e. the limited precision of the significand.
(defun approx-equal (float1 float2 &optional (threshold 0.000001))
"Determine whether float1 and float2 are equal; THRESHOLD is the
maximum allowable difference between normalized significands of floats
with the same exponent. The significands are scaled appropriately
before comparison for floats with different exponents."
(multiple-value-bind (sig1 exp1 sign1) (decode-float float1)
(multiple-value-bind (sig2 exp2 sign2) (decode-float float2)
(let ((cmp1 (float-sign sign1 (scale-float sig1 (floor (- exp1 exp2) 2))))
(cmp2 (float-sign sign2 (scale-float sig2 (floor (- exp2 exp1) 2)))))
(< (abs (- cmp1 cmp2)) threshold)))))
D
import std.math;
import std.stdio;
auto approxEquals = (double a, double b, double epsilon) => abs(a - b) < epsilon;
void main() {
void test(double a, double b) {
double epsilon = 1e-18;
writefln("%.18f, %.18f => %s", a, b, a.approxEquals(b, epsilon));
}
test(100000000000000.01, 100000000000000.011);
test(100.01, 100.011);
test(10000000000000.001 / 10000.0, 1000000000.0000001000);
test(0.001, 0.0010000001);
test(0.000000000000000000000101, 0.0);
test(sqrt(2.0) * sqrt(2.0), 2.0);
test(-sqrt(2.0) * sqrt(2.0), -2.0);
test(3.14159265358979323846, 3.14159265358979324);
}
- Output:
100000000000000.015620000000000000, 100000000000000.015620000000000000 => true 100.010000000000005110, 100.010999999999995680 => false 1000000000.000000119100000000, 1000000000.000000119100000000 => true 0.001000000000000000, 0.001000000100000000 => false 0.000000000000000000, 0.000000000000000000 => true 2.000000000000000000, 2.000000000000000000 => true -2.000000000000000000, -2.000000000000000000 => true 3.141592653589793116, 3.141592653589793116 => true
Delphi
The Delphi has a Math.SameValue function for compare, but all float operations use by default Extended (High precision), we need use double cast for every operation, like division, multiply and square tree.
program Approximate_Equality;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Math;
const
EPSILON: Double = 1E-18;
procedure Test(a, b: Double; Expected: Boolean);
var
result: Boolean;
const
STATUS: array[Boolean] of string = ('FAIL', 'OK');
begin
result := SameValue(a, b, EPSILON);
Write(a, ' ', b, ' => ', result, ' '^I);
writeln(Expected, ^I, STATUS[Expected = result]);
end;
begin
Test(100000000000000.01, 100000000000000.011, True);
Test(100.01, 100.011, False);
Test(double(10000000000000.001) / double(10000.0), double(1000000000.0000001000),
False);
Test(0.001, 0.0010000001, False);
Test(0.000000000000000000000101, 0.0, True);
Test(double(Sqrt(2)) * double(Sqrt(2)), 2.0, False);
Test(-double(Sqrt(2)) * double(Sqrt(2)), -2.0, false);
Test(3.14159265358979323846, 3.14159265358979324, True);
Readln;
end.
- Output:
1.00000000000000E+0014 1.00000000000000E+0014 => TRUE TRUE OK 1.00010000000000E+0002 1.00011000000000E+0002 => FALSE FALSE OK 1.00000000000000E+0009 1.00000000000000E+0009 => FALSE FALSE OK 1.00000000000000E-0003 1.00000010000000E-0003 => FALSE FALSE OK 1.01000000000000E-0022 0.00000000000000E+0000 => TRUE TRUE OK 2.00000000000000E+0000 2.00000000000000E+0000 => FALSE FALSE OK -2.00000000000000E+0000 -2.00000000000000E+0000 => FALSE FALSE OK 3.14159265358979E+0000 3.14159265358979E+0000 => TRUE TRUE OK
Factor
The ~
word takes three arguments: the two values to be compared, and an epsilon value representing the allowed distance between the two values. A positive epsilon performs an absolute distance test, an epsilon of zero performs an exact comparison, and a negative epsilon performs a relative distance test (as required by this task).
USING: formatting generalizations kernel math math.functions ;
100000000000000.01 100000000000000.011
100.01 100.011
10000000000000.001 10000.0 /f 1000000000.0000001000
0.001 0.0010000001
0.000000000000000000000101 0.0
2 sqrt dup * 2.0
2 sqrt dup neg * -2.0
3.14159265358979323846 3.14159265358979324
[ 2dup -1e-15 ~ "%+47.30f %+47.30f -1e-15 ~ : %u\n" printf ]
2 8 mnapply
- Output:
+100000000000000.015625000000000000000000000000 +100000000000000.015625000000000000000000000000 -1e-15 ~ : t +100.010000000000005115907697472721 +100.010999999999995679900166578591 -1e-15 ~ : f +1000000000.000000238418579101562500000000 +1000000000.000000119209289550781250000000 -1e-15 ~ : t +0.001000000000000000020816681712 +0.001000000100000000054917270731 -1e-15 ~ : f +0.000000000000000000000101000000 +0.000000000000000000000000000000 -1e-15 ~ : f +2.000000000000000444089209850063 +2.000000000000000000000000000000 -1e-15 ~ : t -2.000000000000000444089209850063 -2.000000000000000000000000000000 -1e-15 ~ : t +3.141592653589793115997963468544 +3.141592653589793115997963468544 -1e-15 ~ : t
Forth
Genuine Forth word : f~ ( r1 r2 r3 – flag ) float-ext “f-proximate” ANS Forth medley for comparing r1 and r2 for equality: r3>0: f~abs; r3=0: bitwise comparison; r3<0:
: test-f~ ( f1 f2 -- )
1e-18 \ epsilon
f~ \ AproximateEqual
if ." True" else ." False" then
;
- Output:
100000000000000.01e 100000000000000.011e test-f~ True 100.01e 100.011e test-f~ False 10000000000000.001e 10000.0e f/ 1000000000.0000001000e test-f~ False 0.001e 0.0010000001e test-f~ False 0.000000000000000000000101e 0.0e test-f~ True 2.0e fdup fsqrt fswap fsqrt f* 2.0e test-f~ False 2.0e fdup fsqrt fnegate fswap fsqrt f* -2.0e test-f~ False 3.14159265358979323846e 3.14159265358979324e test-f~ True
Fortran
Compare against the Python function documented at https://www.python.org/dev/peps/pep-0485/#proposed-implementation, and with the discussion at https://stackoverflow.com/questions/5595425/what-is-the-best-way-to-compare-floats-for-almost-equality-in-python#
program main
implicit none
integer :: i
double precision, allocatable :: vals(:)
vals = [ 100000000000000.01d0, 100000000000000.011d0, &
& 100.01d0, 100.011d0, &
& 10000000000000.001d0/10000d0, 1000000000.0000001000d0, &
& 0.001d0, 0.0010000001d0, &
& 0.000000000000000000000101d0, 0d0, &
& sqrt(2d0)*sqrt(2d0), 2d0, &
& -sqrt(2d0)*sqrt(2d0), -2d0, &
& 3.14159265358979323846d0, 3.14159265358979324d0 ]
do i = 1, size(vals)/2
print '(ES30.18, A, ES30.18, A, L)', vals(2*i-1), ' == ', vals(2*i), ' ? ', eq_approx(vals(2*i-1), vals(2*i))
end do
contains
logical function eq_approx(a, b, reltol, abstol)
!! is a approximately equal b?
double precision, intent(in) :: a, b
!! values to compare
double precision, intent(in), optional :: reltol, abstol
!! relative and absolute error thresholds.
!! defaults: epsilon, smallest non-denormal number
double precision :: rt, at
rt = epsilon(1d0)
at = tiny(1d0)
if (present(reltol)) rt = reltol
if (present(abstol)) at = abstol
eq_approx = abs(a - b) .le. max(rt * max(abs(a), abs(b)), at)
return
end function
end program
- Output:
1.000000000000000156E+14 == 1.000000000000000156E+14 ? T 1.000100000000000051E+02 == 1.000109999999999957E+02 ? F 1.000000000000000238E+09 == 1.000000000000000119E+09 ? T 1.000000000000000021E-03 == 1.000000100000000055E-03 ? F 1.009999999999999976E-22 == 0.000000000000000000E+00 ? F 2.000000000000000444E+00 == 2.000000000000000000E+00 ? T -2.000000000000000444E+00 == -2.000000000000000000E+00 ? T 3.141592653589793116E+00 == 3.141592653589793116E+00 ? T
FreeBASIC
#include "string.bi"
Dim Shared As Double epsilon = 1
Sub eq_approx(a As Double,b As Double)
Dim As Boolean tmp = Abs(a - b) < epsilon
Print Using "& & &";tmp;a;b
End Sub
While (1 + epsilon <> 1)
epsilon /= 2
Wend
Print "epsilon = "; Format(epsilon, "0.000000000000000e-00")
Print
eq_approx(100000000000000.01, 100000000000000.011)
eq_approx(100.01, 100.011)
eq_approx(10000000000000.001/10000.0, 1000000000.0000001000)
eq_approx(0.001, 0.0010000001)
eq_approx(0.000000000000000000000101, 0.0)
eq_approx(Sqr(2)*Sqr(2), 2.0)
eq_approx(-Sqr(2)*Sqr(2), -2.0)
eq_approx(3.14159265358979323846, 3.14159265358979324)
Sleep
FutureBasic
local fn DoublesAreApproxEqual( val1 as double, val2 as double, epsilon as double ) as CFStringRef
CFStringRef result = @"false"
if ( fn fabs( val1 - val2 ) < epsilon ) then result = @"true"
end fn = result
void local fn DoIt
long i
double epsilon = 1e-18, values(15)
values(0) = 100000000000000.01 : values(1) = 100000000000000.011
values(2) = 100.01 : values(3) = 100.011
values(4) = 10000000000000.001 / 10000.0 : values(5) = 1000000000.0000001000
values(6) = 0.001 : values(7) = 0.0010000001
values(8) = 0.000000000000000000000101 : values(9) = 0.0
values(10) = fn sqrt(2) * fn sqrt(2) : values(11) = 2.0
values(12) = -fn sqrt(2) * fn sqrt(2) : values(13) = -2.0
values(14) = 3.14159265358979323846 : values(15) = 3.14159265358979324
for i = 0 to 14 step 2
print values(i)@", "values(i+1)@" "fn DoublesAreApproxEqual( values(i), values(i+1), epsilon )
next
end fn
fn DoIt
HandleEvents
- Output:
100000000000000, 100000000000000 true 100.01, 100.011 false 1000000000, 1000000000 false 0.001, 0.0010000001 false 1.01e-22, 0 true 2, 2 false -2, -2 false 3.141592653589793, 3.141592653589793 true
Go
Go's float64 type is limited to 15 or 16 digits of precision. As there are some numbers in this task which have more digits than this I've used big.Float instead.
package main
import (
"fmt"
"log"
"math/big"
)
func max(a, b *big.Float) *big.Float {
if a.Cmp(b) > 0 {
return a
}
return b
}
func isClose(a, b *big.Float) bool {
relTol := big.NewFloat(1e-9) // same as default for Python's math.isclose() function
t := new(big.Float)
t.Sub(a, b)
t.Abs(t)
u, v, w := new(big.Float), new(big.Float), new(big.Float)
u.Mul(relTol, max(v.Abs(a), w.Abs(b)))
return t.Cmp(u) <= 0
}
func nbf(s string) *big.Float {
n, ok := new(big.Float).SetString(s)
if !ok {
log.Fatal("invalid floating point number")
}
return n
}
func main() {
root2 := big.NewFloat(2.0)
root2.Sqrt(root2)
pairs := [][2]*big.Float{
{nbf("100000000000000.01"), nbf("100000000000000.011")},
{nbf("100.01"), nbf("100.011")},
{nbf("0").Quo(nbf("10000000000000.001"), nbf("10000.0")), nbf("1000000000.0000001000")},
{nbf("0.001"), nbf("0.0010000001")},
{nbf("0.000000000000000000000101"), nbf("0.0")},
{nbf("0").Mul(root2, root2), nbf("2.0")},
{nbf("0").Mul(nbf("0").Neg(root2), root2), nbf("-2.0")},
{nbf("100000000000000003.0"), nbf("100000000000000004.0")},
{nbf("3.14159265358979323846"), nbf("3.14159265358979324")},
}
for _, pair := range pairs {
s := "≉"
if isClose(pair[0], pair[1]) {
s = "≈"
}
fmt.Printf("% 21.19g %s %- 21.19g\n", pair[0], s, pair[1])
}
}
- Output:
100000000000000.01 ≈ 100000000000000.011 100.01 ≉ 100.011 1000000000.0000001 ≈ 1000000000.0000001 0.001 ≉ 0.0010000001 1.01e-22 ≉ 0 2.000000000000000273 ≈ 2 -2.000000000000000273 ≈ -2 100000000000000003 ≈ 100000000000000004 3.141592653589793239 ≈ 3.14159265358979324
Groovy
class Approximate {
private static boolean approxEquals(double value, double other, double epsilon) {
return Math.abs(value - other) < epsilon
}
private static void test(double a, double b) {
double epsilon = 1e-18
System.out.printf("%f, %f => %s\n", a, b, approxEquals(a, b, epsilon))
}
static void main(String[] args) {
test(100000000000000.01, 100000000000000.011)
test(100.01, 100.011)
test(10000000000000.001 / 10000.0, 1000000000.0000001000)
test(0.001, 0.0010000001)
test(0.000000000000000000000101, 0.0)
test(Math.sqrt(2.0) * Math.sqrt(2.0), 2.0)
test(-Math.sqrt(2.0) * Math.sqrt(2.0), -2.0)
test(3.14159265358979323846, 3.14159265358979324)
}
}
- Output:
100000000000000.020000, 100000000000000.020000 => true 100.010000, 100.011000 => false 1000000000.000000, 1000000000.000000 => true 0.001000, 0.001000 => false 0.000000, 0.000000 => true 2.000000, 2.000000 => false -2.000000, -2.000000 => false 3.141593, 3.141593 => true
Haskell
class (Num a, Ord a, Eq a) => AlmostEq a where
eps :: a
infix 4 ~=
(~=) :: AlmostEq a => a -> a -> Bool
a ~= b = or [ a == b
, abs (a - b) < eps * abs(a + b)
, abs (a - b) < eps ]
instance AlmostEq Int where eps = 0
instance AlmostEq Integer where eps = 0
instance AlmostEq Double where eps = 1e-14
instance AlmostEq Float where eps = 1e-5
Examples
λ> 0.000001 == (0 :: Float) False λ> 0.000001 ~= (0 :: Float) True λ> 0.000001 ~= (0 :: Double) False λ> (\x -> sqrt x * sqrt x == x) $ (2 :: Float) False λ> (\x -> sqrt x * sqrt x ~= x) $ (2 :: Float) True λ> (\x -> sqrt x * sqrt x == x) $ (2 :: Double) False λ> (\x -> sqrt x * sqrt x ~= x) $ (2 :: Double) True
Assignment
test :: [(Double, Double)]
test = [(100000000000000.01, 100000000000000.011)
,(100.01, 100.011)
,(10000000000000.001 / 10000.0, 1000000000.0000001000)
,(0.001, 0.0010000001)
,(0.000000000000000000000101, 0.0)
,(sqrt 2 * sqrt 2, 2.0)
,(-sqrt 2 * sqrt 2, -2.0)
,(3.141592653589793, 3.141592653589794)
,(3.141592653589, 3.141592653589794)]
-- requires import Text.Printf
main = mapM_ runTest test
where
runTest (a, b) = do
printf "%f == %f %v\n" a b (show $ a==b) :: IO ()
printf "%f ~= %f %v\n\n" a b (show $ a~=b)
λ> main 100000000000000.02 == 100000000000000.02 True 100000000000000.02 ~= 100000000000000.02 True 100.01 == 100.011 False 100.01 ~= 100.011 False 1000000000.0000002 == 1000000000.0000001 False 1000000000.0000002 ~= 1000000000.0000001 True 0.001 == 0.0010000001 False 0.001 ~= 0.0010000001 False 0.000000000000000000000101 == 0.0 False 0.000000000000000000000101 ~= 0.0 True 2.0000000000000004 == 2.0 False 2.0000000000000004 ~= 2.0 True -2.0000000000000004 == -2.0 False -2.0000000000000004 ~= -2.0 True 3.141592653589793 == 3.141592653589794 False 3.141592653589793 ~= 3.141592653589794 True 3.141592653589 == 3.141592653589794 False 3.141592653589 ~= 3.141592653589794 False
J
Attributed to Ken Iverson, inventor of APL and of course his final dialect, j, "In an early talk Ken was explaining the advantages of tolerant comparison. A member of the audience asked incredulously, “Surely you don’t mean that when A=B and B=C, A may not equal C?” Without skipping a beat, Ken replied, “Any carpenter knows that!” and went on to the next question."
J includes a "customization" conjunction ( !. ) that delivers variants of some verbs. Comparisons are tolerant by default, and their tolerance can be customized to some level. Specifying =!.0 specifies "no tolerance". Specifying a tolerance of 1e_8 is a domain error because that's no longer math. Write your own verb if you need this.
NB. default comparison tolerance matches the python result
".;._2]0 :0
100000000000000.01 = 100000000000000.011
100.01 = 100.011
(10000000000000.001 % 10000.0) = 1000000000.0000001000
0.001 = 0.0010000001
0.000000000000000000000101 = 0.0
(= ([: *~ %:)) 2 NB. sqrt(2)*sqrt(2)
((= -)~ ([: (* -) %:)) 2 NB. -sqrt(2) * sqrt(2), -2.0
3.14159265358979323846 = 3.14159265358979324
)
1 0 1 0 0 1 1 1
NB. tolerance of 1e_12 matches the python result
".;._2]0 :0[CT=:1e_12
100000000000000.01 =!.CT 100000000000000.011
100.01 =!.CT 100.011
(10000000000000.001 % 10000.0) =!.CT 1000000000.0000001000
0.001 =!.CT 0.0010000001
0.000000000000000000000101 =!.CT 0.0
(=!.CT ([: *~ %:)) 2 NB. sqrt(2)*sqrt(2)
((=!.CT -)~ ([: (* -) %:)) 2 NB. -sqrt(2) * sqrt(2), -2.0
3.14159265358979323846 =!.CT 3.14159265358979324
)
1 0 1 0 0 1 1 1
NB. tight tolerance
".;._2]0 :0[CT=:1e_18
100000000000000.01 =!.CT 100000000000000.011
100.01 =!.CT 100.011
(10000000000000.001 % 10000.0) =!.CT 1000000000.0000001000
0.001 =!.CT 0.0010000001
0.000000000000000000000101 =!.CT 0.0
(=!.CT ([: *~ %:)) 2 NB. sqrt(2)*sqrt(2)
((=!.CT -)~ ([: (* -) %:)) 2 NB. -sqrt(2) * sqrt(2), -2.0
3.14159265358979323846 =!.CT 3.14159265358979324
)
1 0 0 0 0 0 0 1
2 (=!.1e_8) 9
|domain error
| 2(= !.1e_8)9
Java
public class Approximate {
private static boolean approxEquals(double value, double other, double epsilon) {
return Math.abs(value - other) < epsilon;
}
private static void test(double a, double b) {
double epsilon = 1e-18;
System.out.printf("%f, %f => %s\n", a, b, approxEquals(a, b, epsilon));
}
public static void main(String[] args) {
test(100000000000000.01, 100000000000000.011);
test(100.01, 100.011);
test(10000000000000.001 / 10000.0, 1000000000.0000001000);
test(0.001, 0.0010000001);
test(0.000000000000000000000101, 0.0);
test(Math.sqrt(2.0) * Math.sqrt(2.0), 2.0);
test(-Math.sqrt(2.0) * Math.sqrt(2.0), -2.0);
test(3.14159265358979323846, 3.14159265358979324);
}
}
- Output:
100000000000000.020000, 100000000000000.020000 => true 100.010000, 100.011000 => false 1000000000.000000, 1000000000.000000 => false 0.001000, 0.001000 => false 0.000000, 0.000000 => true 2.000000, 2.000000 => false -2.000000, -2.000000 => false 3.141593, 3.141593 => true
jq
# Return whether the two numbers `a` and `b` are close.
# Closeness is determined by the `epsilon` parameter -
# the numbers are considered close if the difference between them
# is no more than epsilon * max(abs(a), abs(b)).
def isclose(a; b; epsilon):
((a - b) | fabs) <= (([(a|fabs), (b|fabs)] | max) * epsilon);
def lpad($len; $fill): tostring | ($len - length) as $l | ($fill * $l)[:$l] + .;
def lpad: lpad(20; " ");
# test values
def tv: [
{x: 100000000000000.01, y: 100000000000000.011 },
{x: 100.01, y: 100.011 },
{x: (10000000000000.001 / 10000.0), y: 1000000000.0000001000 },
{x: 0.001, y: 0.0010000001 },
{x: 0.000000000000000000000101, y: 0.0 },
{x: ((2|sqrt) * (2|sqrt)), y: 2.0 },
{x: (-(2|sqrt) * (2|sqrt)), y: -2.0 },
{x: 3.14159265358979323846, y: 3.14159265358979324 }
]
;
tv[] | "\(.x|lpad) \(if isclose(.x; .y; 1.0e-9) then " ≈ " else " ≉ " end) \(.y|lpad)"
- Output:
Using jq 1.6:
100000000000000.02 ≈ 100000000000000.02
100.01 ≉ 100.011
1000000000.0000002 ≈ 1000000000.0000001
0.001 ≉ 0.0010000001
1.01e-22 ≉ 0
2.0000000000000004 ≈ 2
-2.0000000000000004 ≈ -2
3.141592653589793 ≈ 3.141592653589793
Julia
Julia has an infix operator, ≈, which corresponds to Julia's buitin isapprox() function.
testvalues = [[100000000000000.01, 100000000000000.011],
[100.01, 100.011],
[10000000000000.001 / 10000.0, 1000000000.0000001000],
[0.001, 0.0010000001],
[0.000000000000000000000101, 0.0],
[sqrt(2) * sqrt(2), 2.0],
[-sqrt(2) * sqrt(2), -2.0],
[3.14159265358979323846, 3.14159265358979324]]
for (x, y) in testvalues
println(rpad(x, 21), " ≈ ", lpad(y, 22), ": ", x ≈ y)
end
- Output:
1.0000000000000002e14 ≈ 1.0000000000000002e14: true 100.01 ≈ 100.011: false 1.0000000000000002e9 ≈ 1.0000000000000001e9: true 0.001 ≈ 0.0010000001: false 1.01e-22 ≈ 0.0: false 2.0000000000000004 ≈ 2.0: true -2.0000000000000004 ≈ -2.0: true 3.141592653589793 ≈ 3.141592653589793: true
Kotlin
import kotlin.math.abs
import kotlin.math.sqrt
fun approxEquals(value: Double, other: Double, epsilon: Double): Boolean {
return abs(value - other) < epsilon
}
fun test(a: Double, b: Double) {
val epsilon = 1e-18
println("$a, $b => ${approxEquals(a, b, epsilon)}")
}
fun main() {
test(100000000000000.01, 100000000000000.011)
test(100.01, 100.011)
test(10000000000000.001 / 10000.0, 1000000000.0000001000)
test(0.001, 0.0010000001)
test(0.000000000000000000000101, 0.0)
test(sqrt(2.0) * sqrt(2.0), 2.0)
test(-sqrt(2.0) * sqrt(2.0), -2.0)
test(3.14159265358979323846, 3.14159265358979324)
}
- Output:
1.0000000000000002E14, 1.0000000000000002E14 => true 100.01, 100.011 => false 1.0000000000000002E9, 1.0000000000000001E9 => false 0.001, 0.0010000001 => false 1.01E-22, 0.0 => true 2.0000000000000004, 2.0 => false -2.0000000000000004, -2.0 => false 3.141592653589793, 3.141592653589793 => true
Lobster
// Return whether the two numbers `a` and `b` are close.
// Closeness is determined by the `epsilon` parameter -
// the numbers are considered close if the difference between them
// is no more than epsilon * max(abs(a), abs(b)).
//
def isclose(a, b, epsilon):
return abs(a - b) <= max(abs(a), abs(b)) * epsilon
let tv = [
xy { 100000000000000.01, 100000000000000.011 },
xy { 100.01, 100.011 },
xy { 10000000000000.001 / 10000.0, 1000000000.0000001000 },
xy { 0.001, 0.0010000001 },
xy { 0.000000000000000000000101, 0.0 },
xy { sqrt(2.0) * sqrt(2.0), 2.0 },
xy { -sqrt(2.0) * sqrt(2.0), -2.0 },
xy { 3.14159265358979323846, 3.14159265358979324 }
]
for(tv) t:
print concat_string([string(t.x), if isclose(t.x, t.y, 1.0e-9): """ ≈ """ else: """ ≉ """, string(t.y)], "")
- Output:
100000000000000.0 ≈ 100000000000000.0 100.01 ≉ 100.011 1000000000.0 ≈ 1000000000.0 0.001 ≉ 0.0010000001 0.0 ≉ 0.0 2.0 ≈ 2.0 -2.0 ≈ -2.0 3.14159265359 ≈ 3.14159265359
Lua
function approxEquals(value, other, epsilon)
return math.abs(value - other) < epsilon
end
function test(a, b)
local epsilon = 1e-18
print(string.format("%f, %f => %s", a, b, tostring(approxEquals(a, b, epsilon))))
end
function main()
test(100000000000000.01, 100000000000000.011);
test(100.01, 100.011)
test(10000000000000.001 / 10000.0, 1000000000.0000001000)
test(0.001, 0.0010000001)
test(0.000000000000000000000101, 0.0)
test(math.sqrt(2.0) * math.sqrt(2.0), 2.0)
test(-math.sqrt(2.0) * math.sqrt(2.0), -2.0)
test(3.14159265358979323846, 3.14159265358979324)
end
main()
- Output:
100000000000000.020000, 100000000000000.020000 => true 100.010000, 100.011000 => false 1000000000.000000, 1000000000.000000 => false 0.001000, 0.001000 => false 0.000000, 0.000000 => true 2.000000, 2.000000 => false -2.000000, -2.000000 => false 3.141593, 3.141593 => true
Mathematica/Wolfram Language
ClearAll[CloseEnough]
CloseEnough[a_, b_, tol_] := Chop[a - b, tol] == 0
numbers = {
{100000000000000.01, 100000000000000.011},
{100.01, 100.011},
{10000000000000.001/10000.0, 1000000000.0000001000},
{0.001, 0.0010000001},
{0.000000000000000000000101, 0.0},
{Sqrt[2.0] Sqrt[2.0], 2.0}, {-Sqrt[2.0] Sqrt[2.0], -2.0},
{3.14159265358979323846, 3.14159265358979324}
};
(*And@@Flatten[Map[MachineNumberQ,numbers,{2}]]*)
{#1, #2, CloseEnough[#1, #2, 10^-9]} & @@@ numbers // Grid
- Output:
1.*10^14 1.0000000000000001*10^14 True 100.01 100.011 False 1.*10^9 1.000000000000000100*10^9 False 0.001 0.001 True 1.01*10^-22 0. True 2. 2. True -2. -2. True 3.1415926535897932385 3.1415926535897932 True
Nim
To compare the floating point values, we use a relative tolerance.
In order to display the values “a” and “b” as provided, without any rounding, we transmit them as strings to a comparison procedure which compute the floating point values. If the first value “a” is provided as an operation, we use a comparison procedure which accepts the computed value of “a” as second parameter. Here, “b” is never provided as an operation and can always be transmitted as a string.
from math import sqrt
import strformat
import strutils
const Tolerance = 1e-10
proc `~=`(a, b: float): bool =
## Check if "a" and "b" are close.
## We use a relative tolerance to compare the values.
result = abs(a - b) < max(abs(a), abs(b)) * Tolerance
proc compare(a, b: string) =
## Compare "a" and "b" transmitted as strings.
## Values are computed using "parseFloat".
let r = a.parseFloat() ~= b.parseFloat()
echo fmt"{a} ~= {b} is {r}"
proc compare(a: string; avalue: float; b: string) =
## Compare "a" and "b" transmitted as strings.
## The value of "a" is transmitted and not computed.
let r = avalue ~= b.parseFloat()
echo fmt"{a} ~= {b} is {r}"
compare("100000000000000.01", "100000000000000.011")
compare("100.01", "100.011")
compare("10000000000000.001 / 10000.0", 10000000000000.001 / 10000.0, "1000000000.0000001000")
compare("0.001", "0.0010000001")
compare("0.000000000000000000000101", "0.0")
compare("sqrt(2) * sqrt(2)", sqrt(2.0) * sqrt(2.0), "2.0")
compare("-sqrt(2) * sqrt(2)", -sqrt(2.0) * sqrt(2.0), "-2.0")
compare("3.14159265358979323846", "3.14159265358979324")
- Output:
100000000000000.01 ~= 100000000000000.011 is true 100.01 ~= 100.011 is false 10000000000000.001 / 10000.0 ~= 1000000000.0000001000 is true 0.001 ~= 0.0010000001 is false 0.000000000000000000000101 ~= 0.0 is false sqrt(2) * sqrt(2) ~= 2.0 is true -sqrt(2) * sqrt(2) ~= -2.0 is true 3.14159265358979323846 ~= 3.14159265358979324 is true
OCaml
let approx_eq v1 v2 epsilon =
Float.abs (v1 -. v2) < epsilon
let test a b =
let epsilon = 1e-18 in
Printf.printf "%g, %g => %b\n" a b (approx_eq a b epsilon)
let () =
test 100000000000000.01 100000000000000.011;
test 100.01 100.011;
test (10000000000000.001 /. 10000.0) 1000000000.0000001000;
test 0.001 0.0010000001;
test 0.000000000000000000000101 0.0;
test ((sqrt 2.0) *. (sqrt 2.0)) 2.0;
test (-. (sqrt 2.0) *. (sqrt 2.0)) (-2.0);
test 3.14159265358979323846 3.14159265358979324;
;;
Pascal
The constants minReal, maxReal and epsReal are defined by the ISO standard 10206 (“Extended Pascal”). However, their specific values are “implementation defined”, i. e. it is up to the compiler vendors to assign concrete values to them.
program approximateEqual(output);
{
\brief determines whether two `real` values are approximately equal
\param x a reference value
\param y the value to compare with \param x
\return true if \param x is equal or approximately equal to \param y
}
function equal(protected x, y: real): Boolean;
function approximate: Boolean;
function d(protected x: real): integer;
begin
d := trunc(ln(abs(x) + minReal) / ln(2)) + 1
end;
begin
approximate := abs(x - y) <= epsReal * (maxReal / (d(x) + d(y)))
end;
begin
equal := (x = y) or_else (x * y >= 0.0) and_then approximate
end;
{ --- auxilliary routines ---------------------------------------------- }
procedure test(protected x, y: real);
const
{ ANSI escape code for color coding }
CSI = chr(8#33) + '[';
totalMinimumWidth = 40;
postRadixDigits = 24;
begin
write(x:totalMinimumWidth:postRadixDigits, '':1, CSI, '1;3');
if equal(x, y) then
begin
if x = y then
begin
write('2m≅')
end
else
begin
write('5m≆')
end
end
else
begin
write('1m≇')
end;
writeLn(CSI, 'm', '':1, y:totalMinimumWidth:postRadixDigits)
end;
{ === MAIN ============================================================= }
var
n: integer;
x: real;
begin
{ Variables were used to thwart compile-time evaluation done }
{ by /some/ compilers potentially confounding the results. }
n := 2;
x := 100000000000000.01;
test(x, 100000000000000.011);
test(100.01, 100.011);
test(x / 10000.0, 1000000000.0000001000);
test(0.001, 0.0010000001);
test(0.000000000000000000000101, 0.0);
x := sqrt(n);
test(sqr(x), 2.0);
test((-x) * x, -2.0);
test(3.14159265358979323846, 3.14159265358979324)
end.
- Output:
100000000000000.015625000000000000000000 ≅ 100000000000000.015625000000000000000000 100.010000000000005115907697 ≆ 100.010999999999995679900167 10000000000.000001907348632812500000 ≆ 1000000000.000000119209289550781250 0.001000000000000000020817 ≇ 0.001000000100000000054917 0.000000000000000000000101 ≇ 0.000000000000000000000000 2.000000000000000444089210 ≆ 2.000000000000000000000000 -2.000000000000000444089210 ≆ -2.000000000000000000000000 3.141592653589793115997963 ≅ 3.141592653589793115997963
The shown output was generated by a program compiled by the GPC (GNU Pascal Compiler). Due to technical limitations it was not possible to reproduce 100.01 ≆ 100.011 as requested by the task specification. The computer had an IEEE-754-compliant FPU with 80-bit precision. Note that Pascal’s write/writeLn/writeStr routines (the last one is only available in Extended Pascal) produce rounded representations.
Perl
Passes task tests, but use the module Test::Number::Delta
for anything of real importance.
use strict;
use warnings;
sub is_close {
my($a,$b,$eps) = @_;
$eps //= 15;
my $epse = $eps;
$epse++ if sprintf("%.${eps}f",$a) =~ /\./;
$epse++ if sprintf("%.${eps}f",$a) =~ /\-/;
my $afmt = substr((sprintf "%.${eps}f", $a), 0, $epse);
my $bfmt = substr((sprintf "%.${eps}f", $b), 0, $epse);
printf "%-5s %s ≅ %s\n", ($afmt eq $bfmt ? 'True' : 'False'), $afmt, $bfmt;
}
for (
[100000000000000.01, 100000000000000.011],
[100.01, 100.011],
[10000000000000.001 / 10000.0, 1000000000.0000001000],
[0.001, 0.0010000001],
[0.000000000000000000000101, 0.0],
[sqrt(2) * sqrt(2), 2.0],
[-sqrt(2) * sqrt(2), -2.0],
[100000000000000003.0, 100000000000000004.0],
[3.14159265358979323846, 3.14159265358979324]
) {
my($a,$b) = @$_;
is_close($a,$b);
}
print "\nTolerance may be adjusted.\n";
my $real_pi = 2 * atan2(1, 0);
my $roman_pi = 22/7;
is_close($real_pi,$roman_pi,$_) for <10 3>;
- Output:
True 100000000000000.0 ≅ 100000000000000.0 False 100.0100000000000 ≅ 100.0109999999999 True 1000000000.000000 ≅ 1000000000.000000 False 0.001000000000000 ≅ 0.001000000100000 True 0.000000000000000 ≅ 0.000000000000000 True 2.000000000000000 ≅ 2.000000000000000 True -2.000000000000000 ≅ -2.000000000000000 True 10000000000000000 ≅ 10000000000000000 True 3.141592653589793 ≅ 3.141592653589793 Tolerance may be adjusted. False 3.141592653 ≅ 3.142857142 True 3.14 ≅ 3.14
Phix
Traditionally I have always just used sprintf() to compare floating point atoms in phix.
This task (imo) is trying to make a general-purpose routine out of code which is best tailored for each and every specific task.
It proved much harder to get decent-looking output than perform the tests, hence I allowed both the compare (cfmt) and display (dfmt) formats to be overridden.
I got a different result for test 4 to everyone else, but simply setting the cfmt to "%.10f" got it the NOT.
Likewise something similar for the trickier/ambiguous test 5, for which "0.000000" is as good as anything I can do, and both now show how to get either a true or false result.
with javascript_semantics procedure test(atom a,b, string dfmt="%g", cfmt="%g") string ca = sprintf(cfmt,a), cb = sprintf(cfmt,b), eqs = iff(ca=cb?"":"NOT "), da = sprintf(dfmt,a), db = sprintf(dfmt,b) printf(1,"%30s and\n%30s are %sapproximately equal\n",{da,db,eqs}) end procedure test(100000000000000.01,100000000000000.011,"%.3f") test(100.01,100.011,"%.3f") test(10000000000000.001/10000.0,1000000000.0000001000,"%.10f") test(0.001,0.0010000001,"%.10f") -- both test(0.001,0.0010000001,"%.10f","%.10f") -- ways test(0.000000000000000000000101,0.0,"%f") -- both test(0.000000000000000000000101,0.0,"%f","%6f") -- ways test(sqrt(2)*sqrt(2),2.0) test(-sqrt(2)*sqrt(2),-2.0) test(3.14159265358979323846,3.14159265358979324,"%.20f")
- Output:
64 bit (implied by some of the accuracies specified for this task):
100000000000000.010 and 100000000000000.011 are approximately equal 100.010 and 100.011 are NOT approximately equal 1000000000.0000001001 and 1000000000.0000001000 are approximately equal 0.0010000000 and 0.0010000001 are approximately equal 0.0010000000 and 0.0010000001 are NOT approximately equal 0.000000 and 0.000000 are NOT approximately equal 0.000000 and 0.000000 are approximately equal 2 and 2 are approximately equal -2 and -2 are approximately equal 3.14159265358979323851 and 3.14159265358979324003 are approximately equal
32 bit (in fact a couple of them, the first and last pairs, are actually genuinely identical):
100000000000000.016 and 100000000000000.016 are approximately equal 100.010 and 100.011 are NOT approximately equal 1000000000.0000002384 and 1000000000.0000001192 are approximately equal 0.0010000000 and 0.0010000001 are approximately equal 0.0010000000 and 0.0010000001 are NOT approximately equal 0.000000 and 0.000000 are NOT approximately equal 0.000000 and 0.000000 are approximately equal 2 and 2 are approximately equal -2 and -2 are approximately equal 3.1415926535897931 and 3.1415926535897931 are approximately equal
Processing
double epsilon = 1e-18D;
void setup() {
testIsClose(100000000000000.01D, 100000000000000.011D, epsilon);
testIsClose(100.01D, 100.011D, epsilon);
testIsClose(10000000000000.001D / 10000.0D, 1000000000.0000001000D, epsilon);
testIsClose(0.001D, 0.0010000001D, epsilon);
testIsClose(0.000000000000000000000101D, 0.0D, epsilon);
testIsClose(Math.sqrt(2) * Math.sqrt(2), 2.0D, epsilon);
testIsClose(-Math.sqrt(2) * Math.sqrt(2), -2.0D, epsilon);
testIsClose(3.14159265358979323846D, 3.14159265358979324D, epsilon);
exit(); // all done
}
boolean isClose(double num1, double num2, double epsilon) {
return Math.abs(num2 - num1) <= epsilon;
}
void testIsClose(double num1, double num2, double epsilon) {
boolean result = isClose(num1, num2, epsilon);
if (result) {
println("True. ", num1, "is close to", num2);
} else {
println("False. ", num1, "is not close to", num2);
}
}
- Output:
True. 1.0000000000000002E14 is close to 1.0000000000000002E14 False. 100.01 is not close to 100.011 False. 1.0000000000000002E9 is not close to 1.0000000000000001E9 False. 0.001 is not close to 0.0010000001 True. 1.01E-22 is close to 0.0 False. 2.0000000000000004 is not close to 2.0 False. -2.0000000000000004 is not close to -2.0 True. 3.141592653589793 is close to 3.141592653589793
Python
The Python source documentation states:
math.isclose -> bool a: double b: double * rel_tol: double = 1e-09 maximum difference for being considered "close", relative to the magnitude of the input values abs_tol: double = 0.0 maximum difference for being considered "close", regardless of the magnitude of the input values Determine whether two floating point numbers are close in value. Return True if a is close in value to b, and False otherwise. For the values to be considered close, the difference between them must be smaller than at least one of the tolerances. -inf, inf and NaN behave similarly to the IEEE 754 Standard. That is, NaN is not close to anything, even itself. inf and -inf are only close to themselves.
from numpy import sqrt
from math import isclose
testvalues = [[100000000000000.01, 100000000000000.011],
[100.01, 100.011],
[10000000000000.001 / 10000.0, 1000000000.0000001000],
[0.001, 0.0010000001],
[0.000000000000000000000101, 0.0],
[sqrt(2) * sqrt(2), 2.0],
[-sqrt(2) * sqrt(2), -2.0],
[3.14159265358979323846, 3.14159265358979324]]
for (x, y) in testvalues:
maybenot = "is" if isclose(x, y) else "is NOT"
print(x, maybenot, "approximately equal to ", y)
- Output:
100000000000000.02 is approximately equal to 100000000000000.02 100.01 is NOT approximately equal to 100.011 1000000000.0000002 is approximately equal to 1000000000.0000001 0.001 is NOT approximately equal to 0.0010000001 1.01e-22 is NOT approximately equal to 0.0 2.0 is approximately equal to 2.0 -2.0 is approximately equal to -2.0 3.141592653589793 is approximately equal to 3.141592653589793
R
The base library has the function all.equal() for this task. However, when the numbers are not equal, rather than return FALSE, it tries to explain the difference. To fix this, we use isTRUE(all.equal(....)) instead.
approxEq <- function(...) isTRUE(all.equal(...))
tests <- rbind(c(100000000000000.01, 100000000000000.011),
c(100.01, 100.011),
c(10000000000000.001 / 10000.0, 1000000000.0000001000),
c(0.001, 0.0010000001),
c(0.000000000000000000000101, 0.0),
c(sqrt(2) * sqrt(2), 2.0),
c(-sqrt(2) * sqrt(2), -2.0),
c(3.14159265358979323846, 3.14159265358979324))
results <- mapply(approxEq, tests[, 1], tests[, 2])
#All that remains is to print out our results in a presentable way:
printableTests <- format(tests, scientific = FALSE)
print(data.frame(x = printableTests[, 1], y = printableTests[, 2], Equal = results, row.names = paste0("Test ", 1:8, ": ")))
- Output:
x y Equal Test 1: 100000000000000.015625000000000000000000 100000000000000.015625000000000000000000 TRUE Test 2: 100.010000000000005115907697 100.010999999999995679900167 FALSE Test 3: 1000000000.000000238418579101562500 1000000000.000000119209289550781250 TRUE Test 4: 0.001000000000000000020817 0.001000000100000000054917 FALSE Test 5: 0.000000000000000000000101 0.000000000000000000000000 TRUE Test 6: 2.000000000000000444089210 2.000000000000000000000000 TRUE Test 7: -2.000000000000000444089210 -2.000000000000000000000000 TRUE Test 8: 3.141592653589793115997963 3.141592653589793115997963 TRUE
Racket
In Racket, a number literal with decimal point is considered a flonum, an inexact number which could be either 30 or 62 bits depending on machines. By prefixing the literal with #e
, it is now considered an exact, rational number. In this task, we test the approximate equality on both variants:
#lang racket
(define (≈ a b [tolerance 1e-9])
(<= (abs (/ (- a b) (max a b))) tolerance))
(define all-tests
`(([100000000000000.01 100000000000000.011]
[100.01 100.011]
[,(/ 10000000000000.001 10000.0) 1000000000.0000001000]
[0.001 0.0010000001]
[0.000000000000000000000101 0.0]
[,(* (sqrt 2) (sqrt 2)) 2.0]
[,(* (- (sqrt 2)) (sqrt 2)) -2.0]
[100000000000000003.0 100000000000000004.0]
[3.14159265358979323846 3.14159265358979324])
([#e100000000000000.01 #e100000000000000.011]
[#e100.01 #e100.011]
[,(/ #e10000000000000.001 #e10000.0) #e1000000000.0000001000]
[#e0.001 #e0.0010000001]
[#e0.000000000000000000000101 #e0.0]
[,(* (sqrt 2) (sqrt 2)) #e2.0]
[,(* (- (sqrt 2)) (sqrt 2)) #e-2.0]
[100000000000000003 100000000000000004]
[#e3.14159265358979323846 #e3.14159265358979324])))
(define (format-num x)
(~a (~r x #:precision 30) #:min-width 50 #:align 'right))
(for ([tests (in-list all-tests)] [name '("inexact" "exact")])
(printf "~a:\n" name)
(for ([test (in-list tests)])
(match-define (list a b) test)
(printf "~a ~a: ~a\n" (format-num a) (format-num b) (≈ a b)))
(newline))
- Output:
inexact: 100000000000000.015625000000000000310697263104 100000000000000.015625000000000000310697263104: #t 100.010000000000005116710235406336 100.010999999999995680439855480832: #f 1000000000.000000238418579101562504740864 1000000000.000000119209289550781252370432: #t 0.001000000000000000013287555072 0.001000000100000000093229940736: #f 0.000000000000000000000101 0: #f 2.000000000000000444089209850063 2: #t -2.000000000000000444089209850063 -2: #t 100000000000000000 100000000000000000: #t 3.141592653589793121575456735232 3.141592653589793121575456735232: #t exact: 100000000000000.01 100000000000000.011: #t 100.01 100.011: #f 1000000000.0000001 1000000000.0000001: #t 0.001 0.0010000001: #f 0.000000000000000000000101 0: #f 2.000000000000000444089209850063 2: #t -2.000000000000000444089209850063 -2: #t 100000000000000003 100000000000000004: #t 3.14159265358979323846 3.14159265358979324: #t
Raku
(formerly Perl 6)
Is approximately equal to is a built-in operator in Raku. Unicode ≅, or the ASCII equivalent: =~=. By default it uses a tolerance of 1e-15 times the order of magnitude of the larger comparand, though that is adjustable by setting the dynamic variable $*TOLERANCE to the desired value. Probably a good idea to localize the changed $*TOLERANCE as it will affect all comparisons within its scope.
Most of the following tests are somewhat pointless in Raku. To a large extent, when dealing with Rational values, you don't really need to worry about "approximately equal to", and all of the test values below, with the exception of sqrt(2)
, are Rats by default, and exact. You would have to specifically coerce them to Nums (floating point) to lose the precision.
For example, in Raku, the sum of .1, .2, .3, & .4 is identically equal to 1.
say 0.1 + 0.2 + 0.3 + 0.4 === 1.0000000000000000000000000000000000000000000000000000000000000000000000000; # True
It's also approximately equal to 1 but... ¯\_(ツ)_/¯
for
100000000000000.01, 100000000000000.011,
100.01, 100.011,
10000000000000.001 / 10000.0, 1000000000.0000001000,
0.001, 0.0010000001,
0.000000000000000000000101, 0.0,
sqrt(2) * sqrt(2), 2.0,
-sqrt(2) * sqrt(2), -2.0,
100000000000000003.0, 100000000000000004.0,
3.14159265358979323846, 3.14159265358979324
-> $a, $b {
say "$a ≅ $b: ", $a ≅ $b;
}
say "\nTolerance may be adjusted.";
say 22/7, " ≅ ", π, ": ", 22/7 ≅ π;
{ # Localize the tolerance to only this block
my $*TOLERANCE = .001;
say 22/7, " ≅ ", π, ": ", 22/7 ≅ π;
}
- Output:
100000000000000.01 ≅ 100000000000000.011: True 100.01 ≅ 100.011: False 1000000000.0000001 ≅ 1000000000.0000001: True 0.001 ≅ 0.0010000001: False 0.000000000000000000000101 ≅ 0: True 2.0000000000000004 ≅ 2: True -2.0000000000000004 ≅ -2: True 100000000000000003 ≅ 100000000000000004: True 3.141592653589793226752 ≅ 3.14159265358979324: True Tolerance may be adjusted. 3.142857 ≅ 3.141592653589793: False 3.142857 ≅ 3.141592653589793: True
ReScript
let approx_eq = (v1, v2, epsilon) => {
abs_float (v1 -. v2) < epsilon
}
let test = (a, b) => {
let epsilon = 1e-18
Printf.printf("%g, %g => %b\n", a, b, approx_eq(a, b, epsilon))
}
{
test(100000000000000.01, 100000000000000.011)
test(100.01, 100.011)
test(10000000000000.001 /. 10000.0, 1000000000.0000001000)
test(0.001, 0.0010000001)
test(0.000000000000000000000101, 0.0)
test(sqrt(2.0) *. sqrt(2.0), 2.0)
test(-. sqrt(2.0) *. sqrt(2.0), (-2.0))
test(3.14159265358979323846, 3.14159265358979324)
}
REXX
Since the REXX language uses decimal digits (characters) for floating point numbers (and integers), it's just a matter of
choosing the number of decimal digits for the precision to be used for arithmetic (in this case, fifteen decimal digits).
The choosing of the number of decimal digits is performed via the REXX statement: numeric digits nnn
/*REXX program mimics an "approximately equal to" for comparing floating point numbers*/
numeric digits 15 /*what other FP hardware normally uses.*/
@.= /*assign default for the @ array. */
parse arg @.1 /*obtain optional argument from the CL.*/
if @.1='' | @.1=="," then do; @.1= 100000000000000.01 100000000000000.011
@.2= 100.01 100.011
@.3= 10000000000000.001 / 10000 1000000000.0000001000
@.4= 0.001 0.0010000001
@.5= 0.00000000000000000000101 0.0
@.6= sqrt(2) * sqrt(2) 2.0
@.7= -sqrt(2) * sqrt(2) '-2.0'
@.8= 3.14159265358979323846 3.14159265358979324
/* added ───► */ @.9= 100000000000000003.0 100000000000000004.0
end
do j=1 while @.j\=='' /*process CL argument or the array #s. */
say
say center(' processing pair ' j" ",71,'═') /*display a title for the pair of #s. */
parse value @.j with a b /*extract two values from a pair of #s.*/
say 'A=' a /*display the value of A to the term.*/
say 'B=' b /* " " " " B " " " */
say right('A approximately equal to B?', 65) word("false true", 1 + approxEQ(a,b) )
end /*j*/ /* [↑] right─justify text & true/false*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
approxEQ: procedure; parse arg x,y; return x=y /*floating point compare with 15 digits*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); numeric digits; h=d+6
numeric form; m.=9; parse value format(x,2,1,,0) 'E0' with g "E" _ .; g=g *.5'e'_ %2
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/; return g/1
- output when using the internal default inputs:
═════════════════════════ processing pair 1 ══════════════════════════ A= 100000000000000.01 B= 100000000000000.011 A approximately equal to B? true ═════════════════════════ processing pair 2 ══════════════════════════ A= 100.01 B= 100.011 A approximately equal to B? false ═════════════════════════ processing pair 3 ══════════════════════════ A= 1000000000 B= 1000000000.0000001000 A approximately equal to B? true ═════════════════════════ processing pair 4 ══════════════════════════ A= 0.001 B= 0.0010000001 A approximately equal to B? false ═════════════════════════ processing pair 5 ══════════════════════════ A= 0.00000000000000000000101 B= 0.0 A approximately equal to B? false ═════════════════════════ processing pair 6 ══════════════════════════ A= 2.00000000000000 B= 2.0 A approximately equal to B? true ═════════════════════════ processing pair 7 ══════════════════════════ A= -2.00000000000000 B= -2.0 A approximately equal to B? true ═════════════════════════ processing pair 8 ══════════════════════════ A= 3.14159265358979323846 B= 3.14159265358979324 A approximately equal to B? true ═════════════════════════ processing pair 9 ══════════════════════════ A= 100000000000000003.0 B= 100000000000000004.0 A approximately equal to B? true
RPL
We use here mantissa comparison, which makes that any epsilon can not be close to zero.
≪ MANT SWAP MANT - ABS 1E-09 < ≫ ‘CLOSE?’ STO
≪ {} { 100000000000000.01 100000000000000.011 100.01 100.011 ≪ 10000000000000.001 10000 / ≫ 1000000000.0000001 0.001 0.0010000001 0.000000000000000000000101 0 ≪ 2 √ 2 √ * ≫ 2 ≪ 2 √ 2 √ * NEG ≫ -2 3.14159265358979323846, π } 1 OVER SIZE FOR j DUP j GET EVAL OVER j 1 + GET EVAL CLOSE? NUM→ "True" "False" IFTE ROT SWAP + SWAP 2 STEP ≫ ‘TASK’ STO
- Output:
1: { "True" "False" "True" "False" "False" "True" "True" "True" }
Ruby
Most work went into handling weird Float values like NaN and Infinity.
require "bigdecimal"
testvalues = [[100000000000000.01, 100000000000000.011],
[100.01, 100.011],
[10000000000000.001 / 10000.0, 1000000000.0000001000],
[0.001, 0.0010000001],
[0.000000000000000000000101, 0.0],
[(2**0.5) * (2**0.5), 2.0],
[-(2**0.5) * (2**0.5), -2.0],
[BigDecimal("3.14159265358979323846"), 3.14159265358979324],
[Float::NAN, Float::NAN,],
[Float::INFINITY, Float::INFINITY],
]
class Numeric
def close_to?(num, tol = Float::EPSILON)
return true if self == num
return false if (self.to_f.nan? or num.to_f.nan?) # NaN is not even close to itself
return false if [self, num].count( Float::INFINITY) == 1 # Infinity is only close to itself
return false if [self, num].count(-Float::INFINITY) == 1
(self-num).abs <= tol * ([self.abs, num.abs].max)
end
end
testvalues.each do |a,b|
puts "#{a} #{a.close_to?(b) ? '≈' : '≉'} #{b}"
end
- Output:
100000000000000.02 ≈ 100000000000000.02 100.01 ≉ 100.011 1000000000.0000002 ≈ 1000000000.0000001 0.001 ≉ 0.0010000001 0.101e-21 ≉ 0.0 2.0000000000000004 ≈ 2.0 -2.0000000000000004 ≈ -2.0 0.314159265358979323846e1 ≈ 3.141592653589793 NaN ≉ NaN Infinity ≈ Infinity
Rust
/// Return whether the two numbers `a` and `b` are close.
/// Closeness is determined by the `epsilon` parameter -
/// the numbers are considered close if the difference between them
/// is no more than epsilon * max(abs(a), abs(b)).
fn isclose(a: f64, b: f64, epsilon: f64) -> bool {
(a - b).abs() <= a.abs().max(b.abs()) * epsilon
}
fn main() {
fn sqrt(x: f64) -> f64 { x.sqrt() }
macro_rules! test {
($a: expr, $b: expr) => {
let operator = if isclose($a, $b, 1.0e-9) { '≈' } else { '≉' };
println!("{:>28} {} {}", stringify!($a), operator, stringify!($b))
}
}
test!(100000000000000.01, 100000000000000.011);
test!(100.01, 100.011);
test!(10000000000000.001/10000.0, 1000000000.0000001000);
test!(0.001, 0.0010000001);
test!(0.000000000000000000000101, 0.0);
test!( sqrt(2.0) * sqrt(2.0), 2.0);
test!(-sqrt(2.0) * sqrt(2.0), -2.0);
test!(3.14159265358979323846, 3.14159265358979324);
}
- Output:
100000000000000.01 ≈ 100000000000000.011 100.01 ≉ 100.011 10000000000000.001 / 10000.0 ≈ 1000000000.0000001000 0.001 ≉ 0.0010000001 0.000000000000000000000101 ≉ 0.0 sqrt(2.0) * sqrt(2.0) ≈ 2.0 -sqrt(2.0) * sqrt(2.0) ≈ -2.0 3.14159265358979323846 ≈ 3.14159265358979324
Scala
- Output:
Best seen running in your browser by Scastie (remote JVM).
object Approximate extends App {
val (ok, notOk, ε) = ("👌", "❌", 1e-18d)
private def approxEquals(value: Double, other: Double, epsilon: Double) =
scala.math.abs(value - other) < epsilon
private def test(a: BigDecimal, b: BigDecimal, expected: Boolean): Unit = {
val result = approxEquals(a.toDouble, b.toDouble, ε)
println(f"$a%40.24f ≅ $b%40.24f => $result%5s ${if (expected == result) ok else notOk}")
}
test(BigDecimal("100000000000000.010"), BigDecimal("100000000000000.011"), true)
test(BigDecimal("100.01"), BigDecimal("100.011"), false)
test(BigDecimal(10000000000000.001 / 10000.0), BigDecimal("1000000000.0000001000"), false)
test(BigDecimal("0.001"), BigDecimal("0.0010000001"), false)
test(BigDecimal("0.000000000000000000000101"), BigDecimal(0), true)
test(BigDecimal(math.sqrt(2) * math.sqrt(2d)), BigDecimal(2.0), false)
test(BigDecimal(-Math.sqrt(2) * Math.sqrt(2)), BigDecimal(-2.0), false)
test(BigDecimal("3.14159265358979323846"), BigDecimal("3.14159265358979324"), true)
}
Sidef
Two values can be compared for approximate equality by using the built-in operator ≅, available in ASCII as =~=, which does approximate comparison by rounding both operands at (PREC>>2)-1 decimals. However, by default, Sidef uses a floating-point precision of 192 bits.
[
100000000000000.01, 100000000000000.011,
100.01, 100.011,
10000000000000.001 / 10000.0, 1000000000.0000001000,
0.001, 0.0010000001,
0.000000000000000000000101, 0.0,
sqrt(2) * sqrt(2), 2.0,
-sqrt(2) * sqrt(2), -2.0,
sqrt(-2) * sqrt(-2), -2.0,
cbrt(3)**3, 3,
cbrt(-3)**3, -3,
100000000000000003.0, 100000000000000004.0,
3.14159265358979323846, 3.14159265358979324
].each_slice(2, {|a,b|
say ("#{a} ≅ #{b}: ", a ≅ b)
})
- Output:
100000000000000.01 ≅ 100000000000000.011: false 100.01 ≅ 100.011: false 1000000000.0000001 ≅ 1000000000.0000001: true 0.001 ≅ 0.0010000001: false 0.000000000000000000000101 ≅ 0: false 2 ≅ 2: true -2 ≅ -2: true -2 ≅ -2: true 3 ≅ 3: true -3-7.82914889268316957969274243345625157631318402415e-58i ≅ -3: true 100000000000000003 ≅ 100000000000000004: false 3.14159265358979323846 ≅ 3.14159265358979324: false
The Number n.round(-k) can be used for rounding the number n to k decimal places. A positive argument can be used for rounding before the decimal point.
var a = 100000000000000.01
var b = 100000000000000.011
# Rounding at 2 and 3 decimal places, respectively
say (round(a, -2) == round(b, -2)) # true
say (round(a, -3) == round(b, -3)) # false
There is also the built-in approx_cmp(a, b, k) method, which is equivalent with a.round(k) <=> b.round(k).
var a = 22/7
var b = Num.pi
say ("22/7 ≅ π at 2 decimals: ", approx_cmp(a, b, -2) == 0)
say ("22/7 ≅ π at 3 decimals: ", approx_cmp(a, b, -3) == 0)
- Output:
22/7 ≅ π at 2 decimals: true 22/7 ≅ π at 3 decimals: false
Additionally, the rat_approx method can be used for computing a very good rational approximation to a given real value:
say (1.33333333.rat_approx == 4/3) # true
say (zeta(-5).rat_approx == -1/252) # true
Rational approximations illustrated for substrings of PI:
for k in (3..19) {
var r = Str(Num.pi).first(k)
say ("rat_approx(#{r}) = ", Num(r).rat_approx.as_frac)
}
- Output:
rat_approx(3.1) = 31/10 rat_approx(3.14) = 22/7 rat_approx(3.141) = 245/78 rat_approx(3.1415) = 333/106 rat_approx(3.14159) = 355/113 rat_approx(3.141592) = 355/113 rat_approx(3.1415926) = 86953/27678 rat_approx(3.14159265) = 102928/32763 rat_approx(3.141592653) = 103993/33102 rat_approx(3.1415926535) = 1354394/431117 rat_approx(3.14159265358) = 833719/265381 rat_approx(3.141592653589) = 17925491/5705861 rat_approx(3.1415926535897) = 126312511/40206521 rat_approx(3.14159265358979) = 144029661/45846065 rat_approx(3.141592653589793) = 325994779/103767361 rat_approx(3.1415926535897932) = 903259831/287516534 rat_approx(3.14159265358979323) = 1726375805/549522486
Smalltalk
This compares numbers given the number of ULPs by which they may differ (see wikipedia). There are slight differences in how this is named in the various dialects ¹. If required, you have to add a forwarding alias method to Number.
{ #(100000000000000.01 100000000000000.011) .
#(100.01 100.011) .
{10000000000000.001 / 10000.0 . 1000000000.0000001000} .
#(0.001 0.0010000001) .
#(0.000000000000000000000101 0.0) .
{ 2 sqrt * 2 sqrt . 2.0} .
{ 2 sqrt negated * 2 sqrt . -2.0} .
#(3.14159265358979323846 3.14159265358979324)
} pairsDo:[:val1 :val2 |
Stdout printCR: e'{val1} =~= {val2} -> {val1 isAlmostEqualTo:val2 nEpsilon:2}'
]
In CUIS, this method is called isWithin:floatsFrom:.
- Output:
100.01 =~= 100.011 -> false 1000000000.0 =~= 1000000000.0 -> true 0.001 =~= 0.0010000001 -> false 1.01e-22 =~= 0.0 -> true 2.0 =~= 2.0 -> true -2.0 =~= -2.0 -> true 3.14159265358979 =~= 3.14159265358979 -> true
By default, double precision IEEE floats are used.
Swift
Using the solution proposed as an addition to the Swift standard library in SE-0259. Currently this is not accepted, but is likely to be included in the Swift Numerics module.
import Foundation
extension FloatingPoint {
@inlinable
public func isAlmostEqual(
to other: Self,
tolerance: Self = Self.ulpOfOne.squareRoot()
) -> Bool {
// tolerances outside of [.ulpOfOne,1) yield well-defined but useless results,
// so this is enforced by an assert rathern than a precondition.
assert(tolerance >= .ulpOfOne && tolerance < 1, "tolerance should be in [.ulpOfOne, 1).")
// The simple computation below does not necessarily give sensible
// results if one of self or other is infinite; we need to rescale
// the computation in that case.
guard self.isFinite && other.isFinite else {
return rescaledAlmostEqual(to: other, tolerance: tolerance)
}
// This should eventually be rewritten to use a scaling facility to be
// defined on FloatingPoint suitable for hypot and scaled sums, but the
// following is good enough to be useful for now.
let scale = max(abs(self), abs(other), .leastNormalMagnitude)
return abs(self - other) < scale*tolerance
}
@usableFromInline
internal func rescaledAlmostEqual(to other: Self, tolerance: Self) -> Bool {
// NaN is considered to be not approximately equal to anything, not even
// itself.
if self.isNaN || other.isNaN { return false }
if self.isInfinite {
if other.isInfinite { return self == other }
// Self is infinite and other is finite. Replace self with the binade
// of the greatestFiniteMagnitude, and reduce the exponent of other by
// one to compensate.
let scaledSelf = Self(sign: self.sign,
exponent: Self.greatestFiniteMagnitude.exponent,
significand: 1)
let scaledOther = Self(sign: .plus,
exponent: -1,
significand: other)
// Now both values are finite, so re-run the naive comparison.
return scaledSelf.isAlmostEqual(to: scaledOther, tolerance: tolerance)
}
// If self is finite and other is infinite, flip order and use scaling
// defined above, since this relation is symmetric.
return other.rescaledAlmostEqual(to: self, tolerance: tolerance)
}
}
let testCases = [
(100000000000000.01, 100000000000000.011),
(100.01, 100.011),
(10000000000000.001 / 10000.0, 1000000000.0000001000),
(0.001, 0.0010000001),
(0.000000000000000000000101, 0.0),
(sqrt(2) * sqrt(2), 2.0),
(-sqrt(2) * sqrt(2), -2.0),
(3.14159265358979323846, 3.14159265358979324)
]
for testCase in testCases {
print("\(testCase.0), \(testCase.1) => \(testCase.0.isAlmostEqual(to: testCase.1))")
}
- Output:
100000000000000.02, 100000000000000.02 => true 100.01, 100.011 => false 1000000000.0000002, 1000000000.0000001 => true 0.001, 0.0010000001 => false 1.01e-22, 0.0 => false 2.0000000000000004, 2.0 => true -2.0000000000000004, -2.0 => true 3.141592653589793, 3.141592653589793 => true
Tcl
Using decimal library
Uses tcllib's decimal library. Using a tolerance of 9 significant digits.
catch {namespace delete test_almost_equal_decimal} ;# Start with a clean namespace
namespace eval test_almost_equal_decimal {
package require Tcl 8.5 ;# required by tcllib
package require math::decimal ;# from tcllib
namespace import ::math::decimal::* ;# for: setVariable, fromstr, and compare
array set yesno {0 Yes -1 No 1 No} ;# For nice output
# More info here: http://speleotrove.com/decimal/dax3274.html
# This puts the library into "simplified" mode. Which
# rounds the "decimal digits" in the coefficient to the
# number of digits that "precision" is set to.
setVariable extended 0
setVariable precision 9
set data {
{100000000000000.01 100000000000000.011}
{100.01 100.011}
{[expr {10000000000000.001 / 10000.0}] 1000000000.0000001000}
{0.001 0.0010000001}
{0.000000000000000000000101 0.0}
{[expr { sqrt(2) * sqrt(2)}] 2.0}
{[expr {-sqrt(2) * sqrt(2)}] -2.0}
{3.14159265358979323846 3.14159265358979324}
}
set data [subst $data] ;# resolves expressions in the list
foreach {a b} [join $data] {
set a_d [fromstr $a]
set b_d [fromstr $b]
puts [format "Is %26s ≈ %21s ? %4s." $a $b $yesno([compare $a_d $b_d])]
}
}
- Output:
Is 100000000000000.01 ≈ 100000000000000.011 ? Yes. Is 100.01 ≈ 100.011 ? No. Is 1000000000.0000002 ≈ 1000000000.0000001000 ? Yes. Is 0.001 ≈ 0.0010000001 ? No. Is 0.000000000000000000000101 ≈ 0.0 ? No. Is 2.0000000000000004 ≈ 2.0 ? Yes. Is -2.0000000000000004 ≈ -2.0 ? Yes. Is 3.14159265358979323846 ≈ 3.14159265358979324 ? Yes.
Using string manipulation
catch {namespace delete test_almost_equal_string} ;# Start with a clean namespace
namespace eval test_almost_equal_string {
package require Tcl 8.4 ;# ?Maybe earlier?
array set yesno {1 Yes 0 No} ;# For nice output
proc isClose {a b {prec 9}} {
proc toCoeff {n prec} {
set repr 40 ;# Chosen to be arbitrarily large to handle most cases
set long [format %0.${repr}f $n] ;# Take out of scientific notation
set map [string map {. {}} $long] ;# Remove decimal point
set trim [string trimleft $map 0] ;# Remove leading zeros
# restore string for comparison
set len [string length $trim]
if {$len < $prec} {
set trim "${trim}[string repeat 0 [expr ($prec+1)-$len]]"
}
# Round last decimal place
set rounded [format %0.f "[string range $trim 0 [expr {$prec-1}]].[string index $trim $prec]"]
return $rounded
}
set a_coeff [toCoeff $a $prec]
set b_coeff [toCoeff $b $prec]
return [expr {$a_coeff == $b_coeff}]
}
set data {
{100000000000000.01 100000000000000.011}
{100.01 100.011}
{[expr {10000000000000.001 / 10000.0}] 1000000000.0000001000}
{0.001 0.0010000001}
{0.000000000000000000000101 0.0}
{[expr { sqrt(2) * sqrt(2)}] 2.0}
{[expr {-sqrt(2) * sqrt(2)}] -2.0}
{3.14159265358979323846 3.14159265358979324}
}
set data [subst $data] ;# resolves expressions in the list
foreach {a b} [join $data] {
puts [format "Is %26s ≈ %21s ? %4s." $a $b $yesno([isClose $a $b])]
}
}
- Output:
Is 100000000000000.01 ≈ 100000000000000.011 ? Yes. Is 100.01 ≈ 100.011 ? No. Is 1000000000.0000002 ≈ 1000000000.0000001000 ? Yes. Is 0.001 ≈ 0.0010000001 ? No. Is 0.000000000000000000000101 ≈ 0.0 ? No. Is 2.0000000000000004 ≈ 2.0 ? Yes. Is -2.0000000000000004 ≈ -2.0 ? Yes. Is 3.14159265358979323846 ≈ 3.14159265358979324 ? Yes.
Visual Basic .NET
Imports System.Runtime.CompilerServices
Module Module1
<Extension()>
Function ApproxEquals(ByVal value As Double, other As Double, epsilon As Double)
Return Math.Abs(value - other) < epsilon
End Function
Sub Test(a As Double, b As Double)
Dim epsilon = 1.0E-18
Console.WriteLine($"{a}, {b} => {a.ApproxEquals(b, epsilon)}")
End Sub
Sub Main()
Test(100000000000000.02, 100000000000000.02)
Test(100.01, 100.011)
Test(10000000000000.002 / 10000.0, 1000000000.0000001)
Test(0.001, 0.0010000001)
Test(1.01E-22, 0.0)
Test(Math.Sqrt(2) * Math.Sqrt(2), 2.0)
Test(-Math.Sqrt(2) * Math.Sqrt(2), -2.0)
Test(3.1415926535897931, 3.1415926535897931)
End Sub
End Module
- Output:
100000000000000, 100000000000000 => True 100.01, 100.011 => False 1000000000, 1000000000 => False 0.001, 0.0010000001 => False 1.01E-22, 0 => True 2, 2 => False -2, -2 => False 3.14159265358979, 3.14159265358979 => True
Wren
var tol = 1e-16
var pairs = [
[100000000000000.01, 100000000000000.011],
[100.01, 100.011],
[10000000000000.001 / 10000.0, 1000000000.0000001000],
[0.001, 0.0010000001],
[0.000000000000000000000101, 0.0],
[2.sqrt * 2.sqrt, 2.0],
[-2.sqrt * 2.sqrt, -2.0],
[3.14159265358979323846, 3.14159265358979324]
]
System.print("Approximate equality of test cases for a tolerance of %(tol):")
var i = 0
for (pair in pairs) {
i = i + 1
System.print(" %(i) -> %((pair[0] - pair[1]).abs < tol)")
}
- Output:
Approximate equality of test cases for a tolerance of 1e-16: 1 -> true 2 -> false 3 -> false 4 -> false 5 -> true 6 -> false 7 -> false 8 -> true
XPL0
func ApproxEqual(A, B); \Return 'true' if approximately equal
real A, B;
real Epsilon;
[Epsilon:= abs(A) * 1E-15;
return abs(A-B) < Epsilon;
];
real Data;
int I;
[Format(0, 16);
Data:=[ [100000000000000.01, 100000000000000.011], \should return true
[100.01, 100.011], \should return false
[10000000000000.001 / 10000.0, 1000000000.0000001000],
[0.001, 0.0010000001],
[0.000000000000000000000101, 0.0], \is undefined
[sqrt(2.0) * sqrt(2.0), 2.0],
[-1.0 * sqrt(2.0) * sqrt(2.0), -2.0], \-sqrt doesn't compile!
[3.14159265358979323846, 3.14159265358979324] ];
for I:= 0 to 7 do
[IntOut(0, I+1); Text(0, ". ");
RlOut(0, Data(I,0)); ChOut(0, ^ ); RlOut(0, Data(I,1));
Text(0, if ApproxEqual(Data(I,0), Data(I,1)) then " true" else " false");
CrLf(0);
];
]
- Output:
1. 1.0000000000000000E+014 1.0000000000000000E+014 true 2. 1.0001000000000000E+002 1.0001100000000000E+002 false 3. 1.0000000000000000E+009 1.0000000000000000E+009 true 4. 1.0000000000000000E-003 1.0000001000000000E-003 false 5. 1.0100000000000000E-022 0.0000000000000000E+000 false 6. 2.0000000000000000E+000 2.0000000000000000E+000 true 7. -2.0000000000000000E+000 -2.0000000000000000E+000 true 8. 3.1415926535897900E+000 3.1415926535897900E+000 true
Yabasic
// Rosetta Code problem: http://rosettacode.org/wiki/Approximate_equality
// by Jjuanhdez, 09/2022
epsilon = 1.0
while (1 + epsilon <> 1)
epsilon = epsilon / 2
wend
print "epsilon = ", epsilon
print
eq_approx(100000000000000.01, 100000000000000.011)
eq_approx(100.01, 100.011)
eq_approx(10000000000000.001/10000.0, 1000000000.0000001000)
eq_approx(0.001, 0.0010000001)
eq_approx(0.000000000000000000000101, 0.0)
eq_approx(sqrt(2)*sqrt(2), 2.0)
eq_approx(-sqrt(2)*sqrt(2), -2.0)
eq_approx(3.14159265358979323846, 3.14159265358979324)
end
sub eq_approx(a, b)
tmp = abs(a - b) < epsilon
print tmp, " ", a, " ", b
end sub
zkl
Floats are 64 bit and have the closeTo method, which takes a comparison value and tolerance. If the tolerance is >=0, comparison is absolute. If tolerance is <0 (and x!=0 and y!=0), the comparison is relative.
testValues:=T(
T(100000000000000.01,100000000000000.011),
T(100.01, 100.011),
T(10000000000000.001 / 10000.0, 1000000000.0000001),
T(0.001, 0.0010000001),
T(0.00000000000000000101, 0.0),
T( (2.0).sqrt()*(2.0).sqrt(), 2.0),
T( -(2.0).sqrt()*(2.0).sqrt(), -2.0),
T(100000000000000003.0, 100000000000000004.0),
T(3.14159265358979323846, 3.14159265358979324)
);
tolerance:=-1e-9; // <0 for relative comparison
foreach x,y in (testValues){
maybeNot:=( if(x.closeTo(y,tolerance)) " \u2248" else "!\u2248" );
println("% 25.19g %s %- 25.19g %g".fmt(x,maybeNot,y, (x-y).abs()));
}
- Output:
100000000000000.0156 ≈ 100000000000000.0156 0 100.0100000000000051 !≈ 100.0109999999999957 0.001 1000000000.000000238 ≈ 1000000000.000000119 1.19209e-07 0.001000000000000000021 !≈ 0.001000000100000000055 1e-10 1.010000000000000018e-18 !≈ 0 1.01e-18 2.000000000000000444 ≈ 2 4.44089e-16 -2.000000000000000444 ≈ -2 4.44089e-16 100000000000000000 ≈ 100000000000000000 0 3.141592653589793116 ≈ 3.141592653589793116 0
- Programming Tasks
- Solutions by Programming Task
- Ada
- ALGOL 68
- AWK
- C
- C sharp
- C++
- Common Lisp
- D
- Delphi
- System.SysUtils
- System.Math
- Factor
- Forth
- Fortran
- FreeBASIC
- FutureBasic
- Go
- Groovy
- Haskell
- J
- Java
- Jq
- Julia
- Kotlin
- Lobster
- Lua
- Mathematica
- Wolfram Language
- Nim
- OCaml
- Pascal
- Perl
- Phix
- Processing
- Python
- R
- Racket
- Raku
- ReScript
- REXX
- RPL
- Ruby
- Rust
- Scala
- Sidef
- Smalltalk
- Swift
- Tcl
- Visual Basic .NET
- Wren
- XPL0
- Yabasic
- Zkl