Approximate equality: Difference between revisions
(→{{header|REXX}}: added the REXX computer programming language for this task.) |
(→{{header|Python}}: flagged as needs improvement, possibly due to a typo in the program (the leading digit was dropped from "100.01").) |
||
Line 72: | Line 72: | ||
=={{header|Python}}== |
=={{header|Python}}== |
||
{{improve|Python| <br> The first number for the 2nd pair of (testvalues) numbers should be: <br> '''100.01''' <br> instead of <br> '''00.01''' <br><br> Please fix the program and update the output, and remove this flagging text.}} |
|||
<lang python>from numpy import sqrt |
<lang python>from numpy import sqrt |
||
from math import isclose |
from math import isclose |
Revision as of 04:23, 2 September 2019
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.
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 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.
Perl 6
Is approximately equal to is a built-in operator in Perl 6. 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.
<lang perl6>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 ≅ π;
}</lang>
- 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
Python
<lang python>from numpy import sqrt from math import isclose
testvalues = [[100000000000000.01,100000000000000.011], [00.01, 100.011],
[10000000000000.001 / 10000.0, 1000000000.0000001000], [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]]
for (x, y) in testvalues:
maybenot = "" if isclose(x, y) else "NOT" print(x, "is", maybenot, "approximately equal to ", y)
</lang>
- Output:
100000000000000.02 is approximately equal to 100000000000000.02 0.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
REXX
<lang rexx>/*REXX program mimics an "approximately equal to" for comparing floating point numbers*/ @.= /*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= 100000000000000003.0 100000000000000004.0 @.9= 3.14159265358979323846 3.14159265358979324 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; numeric digits 15; return x=y /*FP compare.*/ /*──────────────────────────────────────────────────────────────────────────────────────*/ 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</lang>
- 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= 1.00000E+9 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.00000000 B= 2.0 A approximately equal to B? true ═════════════════════════ processing pair 7 ══════════════════════════ A= -2.00000000 B= -2.0 A approximately equal to B? true ═════════════════════════ processing pair 8 ══════════════════════════ A= 100000000000000003.0 B= 100000000000000004.0 A approximately equal to B? true ═════════════════════════ processing pair 9 ══════════════════════════ A= 3.14159265358979323846 B= 3.14159265358979324 A approximately equal to B? true