Checking Equality with Fractions in Common Lisp

So, I find out that Lisp does fractions, which is great. But why then does this equality check for a NIL return:

* (= 0.2 1/5) NIL 

... until it returns True, if it is first converted to float :

 * (= 0.2 (float 1/5)) T 

I tried in SBCL and CLISP .

Is the implementation incomplete or is there a particular reason or logic for this behavior?

+5
source share
2 answers

Relations in Common Lisp

Note that fractions (which are not a numeric type in Common Lisp) are converted to rational values ​​in Lisp. rational , ratio and integer (and others) are valid numeric types in Common Lisp. If you enter a fraction, it normalizes to rational (integer or ratio).

 CL-USER 16 > 3/9 1/3 CL-USER 17 > 9/9 1 CL-USER 18 > 6/9 2/3 

Numerical comparison

When the float and ratio are compared, the float is converted to rational, and then the exact comparison is performed. See: CLHS, Float Rule, and Rational Contagion .

The relation is not converted to float, but float is converted to rational.

The problem arises because some floats do not translate into the relationships you expect. The main problem is that floating point numbers are not necessarily an exact representation. Converting an inaccurate number into an exact rational number is not required, giving a naively expected result.

Unfortunately, converting 0.2 to a rational number is not necessarily 1/5 , but this:

 CL-USER 7 > (rational 0.2) 13421773/67108864 

But 0.5 is 1/2 .

 CL-USER 8 > (rational 0.5) 1/2 

This is what happens in your examples:

 CL-USER 9 > (= 1/2 (rational 0.5)) T CL-USER 10 > (= 1/5 (rational 0.2)) NIL 

So this is not

 CL-USER 14 > (= 0.2 (float 1/5)) T 

But:

 CL-USER 15 > (= (rational 0.2) 1/5) NIL 

Note that the rational type combines the disjoint subtypes of ratio and integer . So (rational 1.0) can be an integer, not a ratio.

+6
source

specification o = says:

Value = true if all numbers are the same in value; otherwise it is not true.

So far, the spec on real says:

The rational and float types are disjoint subtypes of type real .

In other words, you can compare them because they are both numbers, but they are different because, because the subtypes do not intersect, they are different values.

What you can do is convert them to the same β€œsubset” of numbers, float, and then the comparison will return true.

The reason for this behavior is that float in general have an approximate representation (see comments from @coreump and links), while rational numbers have an exact representation, so it is impractical to compare values ​​that may "look" outwardly the same, but differ in the internal (binary) representation.

+3
source

Source: https://habr.com/ru/post/1232721/


All Articles