[Bug?] Converting Float to Fraction

Richard A. O'Keefe ok at cs.otago.ac.nz
Tue Feb 25 01:05:02 UTC 2003

```Bill Spight <bspight at pacbell.net> wrote:
Suppose we want to test whether a number is an integer.

As he discovered, "is an integer" is ambiguous.

2 asFraction isInteger is false.

I note that the ANSI standard says in section 5.6.2.15 that
#asFraction "Answer(s) a fraction that reasonably approximates the
receiver.  if the recevier is an integral value, the result may be
<integer>."

So (1) I would have expected 2 asFraction to be 2, not 2/1, and
(2) the answer is only supposed to "reasonably approximate" the
is integral anyway.

2 asFraction reduced isInteger is true.

Fine. The latter looks like our test.

No.  As noted above, (2.00....01 asFraction reduced) could perfectly
well be an integer even though 2.00....01 is not integral.  It so happens
that Squeak has #asApproximateFraction and #asTrueFraction (would be clearer
if named #asExactFraction) and #asFraction calls the latter, but other
Smalltalks may for good reason prefer the former.

However,

2.0 asFraction reduced isInteger

brings up the debugger. The reason is that

2.0 asFraction isInteger

is true. It should be false, right?

Nope.  The ANSI standard clearly allows (but does not require) this.

(OTOH, if it should be true, then shouldn't Integer>>asFraction

I would have expected it to.

In ANSI Smalltalk, the simplest way to test whether a number is integral
would seem to be

x fractionPart isZero

This works in Squeak.  Of course it is necessary to probe exceptional cases:

Float infinity fractionPart => 0.0
So Float infinity fractionPart isZero => true

Do we regard infinity as integral or not?  All sufficiently large
floating-point numbers are integral, so I suppose there's a limit
argument that says it should be.  By the way, since we are allow
to ask for (Float infinity), why are we forbidden to get it the
normal IEEE way (1.0/0.0)?

Float nan fractionPart => NaN
So Float nan fractionPart isZero => false

I think it's clear that NaN is not integral, so this is the right result.

Using fractionPart has the advantage of NOT converting floating point numbers
to big fractions; the only intermediate result is just another Float.

```