[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
       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.

	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
	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 mailing list