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