[FIX] Fraction>>asFloat returns infinity if numerator and denominator both very large

Martin McClure martin at hand2mouse.com
Wed Oct 11 16:23:09 UTC 2000


Okay, I've got a fix that works pretty well under all the conditions 
I've tried. If anybody sees any way to make this better, let me know. 
This fix incorporates bits of the suggestions quoted below.

-Martin

The proposed fix:

'From Squeak2.8 of 13 June 2000 [latest update: #2359] on 10 October 
2000 at 11:02:43 pm'!

!Fraction methodsFor: 'converting' stamp: 'mrm 10/10/2000 22:58'!
asFloat
	"Answer a Float that closely approximates the value of the receiver.
	Ideally, answer the Float that most closely approximates the 
receiver, but
	I'm not quite sure it quite achieves that in all cases."

	| nScaleBits dScaleBits nScaled dScaled |

	"Scale the numerator by throwing away all but the
	top 8 digits (57 to 64 significant bits) then making that a Float.
	This keeps all of the precision of a Float (53 significand bits) but
	guarantees that we do not exceed the range representable as a Float
	(about 2 to the 1024th)"

	nScaleBits _ 8 * ((numerator digitLength - 8) max: 0).
	nScaled _ (numerator bitShift: nScaleBits negated) asFloat.

	"Scale the denominator the same way."
	dScaleBits _ 8 * ((denominator digitLength - 8) max: 0).
	dScaled _ (denominator bitShift: dScaleBits negated) asFloat.

	"Divide the scaled numerator and denominator to make the 
right mantissa, then
	scale to correct the exponent."
	^ (nScaled / dScaled) timesTwoPower: (nScaleBits - dScaleBits).
! !





At 5:13 PM -0400 10/9/00, Lex Spoon wrote:
>Writing the code so that you get 1.0 out of it is challenging, but it
>would surely be nice.  Any numerics experts around?  I think you could
>get a decent answer by:
>
>	1. Right-shift each number until you only have as many digits as a
>Float can represent.  Remember the amount each numbers was shifted.
>
>	2. Divide the numbers.
>
>	3. Shift the result, as needed.
>

Yep, that's the approach I ended up taking.

At 6:49 PM -0500 10/9/00, Tim Olson wrote:
>Here's one solution:
>
>
>----
>'From Squeak2.8 of 13 June 2000 [latest update: #2359] on 9 October 2000
>at 6:45:29 pm'!
>
>!Fraction methodsFor: 'converting' stamp: 'tao 10/9/2000 18:39'!
>asFloat
>	"Answer a Float that represents the same value as does the receiver."
>
>	| nf df scaleFactor |
>	nf _ numerator asFloat.
>	df _ denominator asFloat.
>	nf isInfinite ifTrue:
>		["scale to possibly remove infinities"
>		scaleFactor _ 2 raisedToInteger: ((denominator 
>digitLength * 8 - 52)
>max: 0).
>		nf _ (numerator / scaleFactor) rounded asFloat.
>		df _ (denominator / scaleFactor) rounded asFloat.
>		^ nf / df].
>	df isInfinite ifTrue:
>		["scale to possibly represent as denorm"
>		scaleFactor _ 2 raisedToInteger: 53.
>		df _ (denominator / scaleFactor) rounded asFloat.
>		^ nf / scaleFactor asFloat / df].
>	^ nf / df
>! !
>----

This code looks like it would produce the right answer for my test 
case, but I don't think it would deal well with 'infinite' numerators 
combined with smaller denominators. For example:

   ((10 raisedToInteger: 309) + 1 / 10) asFloat

should return 1.0e308, but this code returns Infinity. The scale 
factor is it uses is 1 because the denominator is small, but the 
denominator is large enough to put the Fraction's value within the 
Float representable range.

It seemed better to scale the numerator and denominator separately.





More information about the Squeak-dev mailing list