[squeak-dev] The Inbox: Kernel-dtl.1166.mcz
Nicolas Cellier
nicolas.cellier.aka.nice at gmail.com
Thu Apr 26 07:54:45 UTC 2018
2018-04-26 9:53 GMT+02:00 Nicolas Cellier <
nicolas.cellier.aka.nice at gmail.com>:
> Also note that in base 2, we know the unit of least precision
> So we could stop the loop when precision reaches half ulp, or
>
> bitLimit := 1 - self ulp exponent.
> [frac = 0 and: [denom1 highBit > bitLimit or: [...]] whileFalse: [...]
>
>
Err, I forgot to tell the aim: get a relative precision
> 2018-04-26 9:45 GMT+02:00 Nicolas Cellier <nicolas.cellier.aka.nice@
> gmail.com>:
>
>> Here is the version that i use in VW (SYSBUG-FloatConversion in cincom
>> public store)
>>
>> asApproximateFraction
>> "Answer a Rational number--Integer or Fraction--representing the
>> receiver.
>> This conversion uses the continued fraction method to approximate
>> a floating point number."
>>
>> | num1 denom1 num2 denom2 int frac newD temp limit |
>> num1 := self asFraction. "use exact arithmetic"
>> frac := num1 fractionPart. "The fractional part of self"
>> int := num1 truncated. "The integer part of self"
>> num1 := int. "The first of two alternating numerators"
>> denom1 := 1. "The first of two alternating denominators"
>> num2 := 1. "The second numerator"
>> denom2 := 0. "The second denominator--will update"
>> limit := self class precision + 7 // 8 + 1.
>> [frac = 0 or: [denom1 digitLength > limit or: [(self coerce:
>> (Fraction numerator: num1 denominator: denom1)) = self]]]
>> whileFalse:
>> ["repeat while the fractional part is not zero"
>> newD := frac reciprocal. "Take reciprocal of the
>> fractional part"
>> int := newD truncated. "get the integer part of this"
>> frac := newD fractionPart. "and save the fractional part
>> for next time"
>> temp := num2. "Get old numerator and save it"
>> num2 := num1. "Set second numerator to first"
>> num1 := num1 * int + temp. "Update first numerator"
>> temp := denom2. "Get old denominator and save
>> it"
>> denom2 := denom1. "Set second denominator to first"
>> denom1 := int * denom1 + temp. "Update first
>> denominator"].
>> "If fractional part is zero, return the first ratio"
>> denom1 = 1
>> ifTrue: ["Am i really an Integer?"
>> ^num1"Yes, return Integer result"]
>> ifFalse: ["Otherwise return Fraction result"
>> ^Fraction numerator: num1 denominator: denom1]
>>
>> Note that I use self asFraction (asTrueFraction) and then perform all
>> operations in Integer arithmetic.
>> #digitLength is the number of bytes like in Squeak.
>>
>> For user-defined controlled precision like aimed by Eliot, we could use
>> #decimalDigitLength and seed it by default with something like
>> #decimalPrecision in Squeak.
>> #decimalPrecision does not exist yet but could be (self class precision *
>> 2 ln / 10 ln) rounded - or simply 15 or 16.
>> Note that it's an absolute precision, not a relative precision which is
>> used.
>>
>> Also note that we could rewrite the iteration like this:
>> num1 := num2 + ((num2 := num1) * int).
>> den1 := den2 + ((den2 := den1) * int).
>>
>> 2018-04-26 4:48 GMT+02:00 <commits at source.squeak.org>:
>>
>>> David T. Lewis uploaded a new version of Kernel to project The Inbox:
>>> http://source.squeak.org/inbox/Kernel-dtl.1166.mcz
>>>
>>> ==================== Summary ====================
>>>
>>> Name: Kernel-dtl.1166
>>> Author: dtl
>>> Time: 25 April 2018, 10:48:38.572237 pm
>>> UUID: 43d80609-fbc5-40a1-9d49-37d2c4f0b306
>>> Ancestors: Kernel-dtl.1165
>>>
>>> In calculation of asApproximateFraction, the digit count for
>>> floatPrecision should be
>>> an integer, so do not convert it with asFlloat.
>>>
>>> Allows the following to be resolved without infinite loop on comparison
>>> to Float infinity:
>>> ((FloatArray new: 1) at: 1 put: 1 / 3; at: 1)
>>> asApproximateFractionFloatPrecision: 10000
>>>
>>> =============== Diff against Kernel-dtl.1165 ===============
>>>
>>> Item was changed:
>>> ----- Method: Float>>asApproximateFractionAtOrder:floatPrecision: (in
>>> category 'converting') -----
>>> asApproximateFractionAtOrder: maxOrder floatPrecision: decimalPlaces
>>> "Answer a Fraction approximating the receiver. This conversion
>>> uses the
>>> continued fraction method to approximate a floating point
>>> number. If maxOrder
>>> is zero, use maximum order. Assume that I am a float with
>>> decimalPlaces of
>>> meaningful accuracy, regardless of the precision of my internal
>>> representation."
>>>
>>> | num1 denom1 num2 denom2 int frac newD temp order
>>> floatPrecision |
>>> num1 := self asInteger. "The first of two alternating numerators"
>>> denom1 := 1. "The first of two alternating
>>> denominators"
>>> num2 := 1. "The second numerator"
>>> denom2 := 0. "The second denominator--will update"
>>> int := num1. "The integer part of self"
>>> frac := self fractionPart. "The fractional part of
>>> self"
>>> order := maxOrder = 0 ifTrue: [-1] ifFalse: [maxOrder].
>>> + floatPrecision := 10 raisedTo: decimalPlaces.
>>> - floatPrecision := (10 raisedTo: decimalPlaces) asFloat.
>>> [frac = 0 or: [order = 0] ]
>>> whileFalse:
>>> ["repeat while the fractional part is not zero
>>> and max order is not reached"
>>> order := order - 1.
>>> newD := 1.0 / frac. "Take
>>> reciprocal of the fractional part"
>>> int := newD asInteger. "get the integer
>>> part of this"
>>> frac := newD fractionPart. "and save the
>>> fractional part for next time"
>>> temp := num2. "Get old
>>> numerator and save it"
>>> num2 := num1. "Set
>>> second numerator to first"
>>> num1 := num1 * int + temp. "Update first
>>> numerator"
>>> temp := denom2. "Get old
>>> denominator and save it"
>>> denom2 := denom1. "Set
>>> second denominator to first"
>>> denom1 := int * denom1 + temp. "Update
>>> first denominator"
>>> floatPrecision < denom1
>>> ifTrue:
>>> ["Is ratio past float
>>> precision? If so, pick which
>>> of the two ratios to use"
>>> num2 = 0.0
>>> ifTrue: ["Is second
>>> denominator 0?"
>>> ^
>>> Fraction numerator: num1 denominator: denom1].
>>> ^ Fraction numerator: num2
>>> denominator: denom2]].
>>> "If fractional part is zero, return the first ratio"
>>> denom1 = 1
>>> ifTrue: ["Am I really an Integer?"
>>> ^ num1 "Yes, return Integer result"]
>>> ifFalse: ["Otherwise return Fraction result"
>>> ^ Fraction numerator: num1 denominator:
>>> denom1]!
>>>
>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20180426/f821d597/attachment.html>
More information about the Squeak-dev
mailing list
|