[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 22.214.171.124 that
#asFraction "Answer(s) a fraction that reasonably approximates the
receiver. if the recevier is an integral value, the result may be
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
receiver, so couldn't be relied on to tell whether the receiver
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.
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
return the receiver?)
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.
More information about the Squeak-dev