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

Lex Spoon lex at cc.gatech.edu
Wed Oct 11 23:35:15 UTC 2000


Wow, that was fast!

-Lex



Martin McClure <martin at hand2mouse.com> wrote:
> 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