asApproximateFraction[AtOrder:]

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

asApproximateFraction[AtOrder:]

Eliot Miranda-2
Hi All,

    asApproximateFraction isn't that useful.  It is based on asApproximateFractionAtOrder:, which gives you the best fraction it can find up to order.  e.g.

testContinuedFractions
self assert: (Float pi asApproximateFractionAtOrder: 1) = (22/7).
self assert: (Float pi asApproximateFractionAtOrder: 3) = (355/113)
Here's 32-bit Float 1/3:

((FloatArray new: 1) at: 1 put: 1/3; at: 1) 0.3333333432674408

((FloatArray new: 1) at: 1 put: 1/3; at: 1) asApproximateFraction (11184811/33554432)

That's not what I expected :-).  The problem is that asApproximateFractionAtOrder: is great if you know the number you're dealing with, but if you don't then it'll give you too much information.

[This value comes up in the vm parameters system report page, where 1/3 is the ratio of growth to heap size above which a full GC is performed, i.e. by default every time a scavenge causes the heap grows by 1/3 from the last time a full GC was performed, the system will do a full GC.  It would be great to report this as 1/3, not 0.33333298563957214, which is what's emerging from the C code in the VM].

Let's get a feeling for orders; they're effectively negative powers of 10:

(1 to: 20) collect: [:order| | f |
{ order. (f := Float pi asApproximateFractionAtOrder: order). f asFloat. (f asFloat - Float pi) abs}]
{{1 . (22/7) . 3.142857142857143 . 0.0012644892673496777}.
 {2 . (333/106) . 3.141509433962264 . 8.32196275291075e-5}.
 {3 . (355/113) . 3.1415929203539825 . 2.667641894049666e-7}.
 {4 . (103993/33102) . 3.1415926530119025 . 5.778906242426274e-10}.
 {5 . (104348/33215) . 3.141592653921421 . 3.3162805834763276e-10}.
 {6 . (208341/66317) . 3.1415926534674368 . 1.2235634727630895e-10}.
 {7 . (312689/99532) . 3.1415926536189365 . 2.914335439641036e-11}.
 {8 . (833719/265381) . 3.141592653581078 . 8.715250743307479e-12}.
 {9 . (1146408/364913) . 3.141592653591404 . 1.6107115641261771e-12}.
 {10 . (4272943/1360120) . 3.141592653589389 . 4.04121180963557e-13}.
 {11 . (5419351/1725033) . 3.1415926535898153 . 2.220446049250313e-14}.
 {12 . (80143857/25510582) . 3.1415926535897927 . 4.440892098500626e-16}.
 {13 . (245850922/78256779) . 3.141592653589793 . 0.0}.
 {14 . (817696623/260280919) . 3.141592653589793 . 0.0}.
 {15 . (19052873251/6064717916) . 3.141592653589793 . 0.0}.
 {16 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
 {17 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
 {18 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
 {19 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
 {20 . (19870569874/6324998835) . 3.141592653589793 . 0.0}}


More useful would be something like:

asApproximateFractionToEpsilon: epsilon
"Answer a Fraction approximating the receiver. This conversion uses the 
continued fraction method to approximate a floating point number."

1 to: 12 do:
[:order| | fraction |
fraction := self asApproximateFractionAtOrder: order.
(fraction - self) abs <= epsilon ifTrue:
[^fraction]].
^ self asApproximateFractionAtOrder: 0

and then instead of

asApproximateFraction
"Answer a Fraction approximating the receiver. This conversion uses the 
continued fraction method to approximate a floating point number."

^ self asApproximateFractionAtOrder: 0

one could have

asApproximateFraction
"Answer a Fraction approximating the receiver. This conversion uses the 
continued fraction method to approximate a floating point number."

^self asApproximateFractionToEpsilon: 1e-6

And hence

{ 0.0. 0.333. 0.5. 1.0. Float pi . ((FloatArray new: 1) at: 1 put: 1/3; at: 1) } collect:
    [:n| n asApproximateFractionToEpsilon: 1e-6]
{0 . (333/1000) . (1/2) . 1 . (355/113) . (1/3)}

Votes for or against changing asApproximateFraction to use asApproximateFractionToEpsilon:? (asApproximateFraction has no senders into base image)

Suggestions for a selector that would use self asApproximateFractionToEpsilon: 1e-6 (less clumsy than e.g. asUsefulApproximateFraction).

_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: asApproximateFraction[AtOrder:]

timrowledge
Do you normally want your fraction precise to an actual epsilon or to a fraction of the real value?

Actually I guess that you could make a % value by working out the integer part, approximating the epsilon from that and using your method, so go for it. Not that I'm a numerics geek by any stretch.

> On 23-04-2018, at 1:23 PM, Eliot Miranda <[hidden email]> wrote:
>
> Hi All,
>
>     asApproximateFraction isn't that useful.  It is based on asApproximateFractionAtOrder:, which gives you the best fraction it can find up to order.  e.g.
>
> testContinuedFractions
> self assert: (Float pi asApproximateFractionAtOrder: 1) = (22/7).
> self assert: (Float pi asApproximateFractionAtOrder: 3) = (355/113)
>
> Here's 32-bit Float 1/3:
>
> ((FloatArray new: 1) at: 1 put: 1/3; at: 1) 0.3333333432674408
>
> ((FloatArray new: 1) at: 1 put: 1/3; at: 1) asApproximateFraction (11184811/33554432)
>
> That's not what I expected :-).  The problem is that asApproximateFractionAtOrder: is great if you know the number you're dealing with, but if you don't then it'll give you too much information.
>
> [This value comes up in the vm parameters system report page, where 1/3 is the ratio of growth to heap size above which a full GC is performed, i.e. by default every time a scavenge causes the heap grows by 1/3 from the last time a full GC was performed, the system will do a full GC.  It would be great to report this as 1/3, not 0.33333298563957214, which is what's emerging from the C code in the VM].
>
> Let's get a feeling for orders; they're effectively negative powers of 10:
>
> (1 to: 20) collect: [:order| | f |
> { order. (f := Float pi asApproximateFractionAtOrder: order). f asFloat. (f asFloat - Float pi) abs}]
> {{1 . (22/7) . 3.142857142857143 . 0.0012644892673496777}.
>  {2 . (333/106) . 3.141509433962264 . 8.32196275291075e-5}.
>  {3 . (355/113) . 3.1415929203539825 . 2.667641894049666e-7}.
>  {4 . (103993/33102) . 3.1415926530119025 . 5.778906242426274e-10}.
>  {5 . (104348/33215) . 3.141592653921421 . 3.3162805834763276e-10}.
>  {6 . (208341/66317) . 3.1415926534674368 . 1.2235634727630895e-10}.
>  {7 . (312689/99532) . 3.1415926536189365 . 2.914335439641036e-11}.
>  {8 . (833719/265381) . 3.141592653581078 . 8.715250743307479e-12}.
>  {9 . (1146408/364913) . 3.141592653591404 . 1.6107115641261771e-12}.
>  {10 . (4272943/1360120) . 3.141592653589389 . 4.04121180963557e-13}.
>  {11 . (5419351/1725033) . 3.1415926535898153 . 2.220446049250313e-14}.
>  {12 . (80143857/25510582) . 3.1415926535897927 . 4.440892098500626e-16}.
>  {13 . (245850922/78256779) . 3.141592653589793 . 0.0}.
>  {14 . (817696623/260280919) . 3.141592653589793 . 0.0}.
>  {15 . (19052873251/6064717916) . 3.141592653589793 . 0.0}.
>  {16 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {17 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {18 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {19 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {20 . (19870569874/6324998835) . 3.141592653589793 . 0.0}}
>
>
> More useful would be something like:
>
> asApproximateFractionToEpsilon: epsilon
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> 1 to: 12 do:
> [:order| | fraction |
> fraction := self asApproximateFractionAtOrder: order.
> (fraction - self) abs <= epsilon ifTrue:
> [^fraction]].
> ^ self asApproximateFractionAtOrder: 0
>
> and then instead of
>
> asApproximateFraction
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> ^ self asApproximateFractionAtOrder: 0
>
> one could have
>
> asApproximateFraction
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> ^self asApproximateFractionToEpsilon: 1e-6
>
> And hence
>
> { 0.0. 0.333. 0.5. 1.0. Float pi . ((FloatArray new: 1) at: 1 put: 1/3; at: 1) } collect:
>     [:n| n asApproximateFractionToEpsilon: 1e-6]
> {0 . (333/1000) . (1/2) . 1 . (355/113) . (1/3)}
>
> Votes for or against changing asApproximateFraction to use asApproximateFractionToEpsilon:? (asApproximateFraction has no senders into base image)
>
> Suggestions for a selector that would use self asApproximateFractionToEpsilon: 1e-6 (less clumsy than e.g. asUsefulApproximateFraction).
>
> _,,,^..^,,,_
> best, Eliot
>


tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
Spell checkers at maximum!  Fire!



Reply | Threaded
Open this post in threaded view
|

Re: asApproximateFraction[AtOrder:]

Eliot Miranda-2
Hi Tim,

On Mon, Apr 23, 2018 at 1:34 PM, tim Rowledge <[hidden email]> wrote:
Do you normally want your fraction precise to an actual epsilon or to a fraction of the real value?

Actually I guess that you could make a % value by working out the integer part, approximating the epsilon from that and using your method, so go for it. Not that I'm a numerics geek by any stretch.

 So you'd rather see

asApproximateFraction
"Answer a Fraction approximating the receiver. This conversion uses the 
continued fraction method to approximate a floating point number."

^self asApproximateFractionToEpsilon: self abs / 1.0e6

?  Seems to work well:


| them |
them := (1 to: 6) collect: [:po10| (1 / ((10 raisedTo: po10) * 3)) asFloat].
them collect: [:fraction| fraction asApproximateFractionToEpsilon: fraction / 1.0e6] {(1/30) . (1/300) . (1/3000) . (1/30000) . (1/300000) . (1/3000000)}

| them |
them := (1 to: 6) collect: [:po10| (1 / ((10 raisedTo: po10) / 3)) asFloat].
them collect: [:fraction| fraction asApproximateFractionToEpsilon: fraction / 1.0e6]
 {(3/10) . (3/100) . (3/1000) . (3/10000) . (3/100000) . (3/1000000)}

Float classPool associations
select: [:assoc| assoc value isFloat and: [assoc value isFinite and: [assoc value fractionPart ~= 0]]]
thenCollect: [:assoc|
assoc key -> (assoc value asApproximateFractionToEpsilon: assoc value / 1.0e6)] {#Ln2->(1143/1649) . #Halfpi->(355/226) . #ThreePi->(1065/113) . #RadiansPerDegree->(71/4068) . #Epsilon->(1/1000000000000) . #MaxValLn->(16325/23) . #Ln10->(624/271) . #Pi->(355/113) . #Sqrt2->(1393/985) . #Twopi->(710/113) . #E->(1264/465)}
 

So I'm for

asApproximateFraction
       "Answer a Fraction approximating the receiver. This conversion uses the 
       continued fraction method to approximate a floating point number."
 
       ^self asApproximateFractionToEpsilon: (self / 1e6) abs

talking in numerical analysis ignorance...



> On 23-04-2018, at 1:23 PM, Eliot Miranda <[hidden email]> wrote:
>
> Hi All,
>
>     asApproximateFraction isn't that useful.  It is based on asApproximateFractionAtOrder:, which gives you the best fraction it can find up to order.  e.g.
>
> testContinuedFractions
>       self assert: (Float pi asApproximateFractionAtOrder: 1) = (22/7).
>       self assert: (Float pi asApproximateFractionAtOrder: 3) = (355/113)
>       
> Here's 32-bit Float 1/3:
>
> ((FloatArray new: 1) at: 1 put: 1/3; at: 1) 0.3333333432674408
>
> ((FloatArray new: 1) at: 1 put: 1/3; at: 1) asApproximateFraction (11184811/33554432)
>
> That's not what I expected :-).  The problem is that asApproximateFractionAtOrder: is great if you know the number you're dealing with, but if you don't then it'll give you too much information.
>
> [This value comes up in the vm parameters system report page, where 1/3 is the ratio of growth to heap size above which a full GC is performed, i.e. by default every time a scavenge causes the heap grows by 1/3 from the last time a full GC was performed, the system will do a full GC.  It would be great to report this as 1/3, not 0.33333298563957214, which is what's emerging from the C code in the VM].
>
> Let's get a feeling for orders; they're effectively negative powers of 10:
>
> (1 to: 20) collect: [:order| | f |
> { order. (f := Float pi asApproximateFractionAtOrder: order). f asFloat. (f asFloat - Float pi) abs}]
> {{1 . (22/7) . 3.142857142857143 . 0.0012644892673496777}.
>  {2 . (333/106) . 3.141509433962264 . 8.32196275291075e-5}.
>  {3 . (355/113) . 3.1415929203539825 . 2.667641894049666e-7}.
>  {4 . (103993/33102) . 3.1415926530119025 . 5.778906242426274e-10}.
>  {5 . (104348/33215) . 3.141592653921421 . 3.3162805834763276e-10}.
>  {6 . (208341/66317) . 3.1415926534674368 . 1.2235634727630895e-10}.
>  {7 . (312689/99532) . 3.1415926536189365 . 2.914335439641036e-11}.
>  {8 . (833719/265381) . 3.141592653581078 . 8.715250743307479e-12}.
>  {9 . (1146408/364913) . 3.141592653591404 . 1.6107115641261771e-12}.
>  {10 . (4272943/1360120) . 3.141592653589389 . 4.04121180963557e-13}.
>  {11 . (5419351/1725033) . 3.1415926535898153 . 2.220446049250313e-14}.
>  {12 . (80143857/25510582) . 3.1415926535897927 . 4.440892098500626e-16}.
>  {13 . (245850922/78256779) . 3.141592653589793 . 0.0}.
>  {14 . (817696623/260280919) . 3.141592653589793 . 0.0}.
>  {15 . (19052873251/6064717916) . 3.141592653589793 . 0.0}.
>  {16 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {17 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {18 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {19 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {20 . (19870569874/6324998835) . 3.141592653589793 . 0.0}}
>
>
> More useful would be something like:
>
> asApproximateFractionToEpsilon: epsilon
>       "Answer a Fraction approximating the receiver. This conversion uses the
>       continued fraction method to approximate a floating point number."
>
>       1 to: 12 do:
>               [:order| | fraction |
>                fraction := self asApproximateFractionAtOrder: order.
>                (fraction - self) abs <= epsilon ifTrue:
>                       [^fraction]].
>       ^ self asApproximateFractionAtOrder: 0
>
> and then instead of
>
> asApproximateFraction
>       "Answer a Fraction approximating the receiver. This conversion uses the
>       continued fraction method to approximate a floating point number."
>
>       ^ self asApproximateFractionAtOrder: 0
>
> one could have
>
> asApproximateFraction
>       "Answer a Fraction approximating the receiver. This conversion uses the
>       continued fraction method to approximate a floating point number."
>
>       ^self asApproximateFractionToEpsilon: 1e-6
>
> And hence
>
> { 0.0. 0.333. 0.5. 1.0. Float pi . ((FloatArray new: 1) at: 1 put: 1/3; at: 1) } collect:
>     [:n| n asApproximateFractionToEpsilon: 1e-6]
> {0 . (333/1000) . (1/2) . 1 . (355/113) . (1/3)}
>
> Votes for or against changing asApproximateFraction to use asApproximateFractionToEpsilon:? (asApproximateFraction has no senders into base image)
>
> Suggestions for a selector that would use self asApproximateFractionToEpsilon: 1e-6 (less clumsy than e.g. asUsefulApproximateFraction).
>
> _,,,^..^,,,_
> best, Eliot
>


tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
Spell checkers at maximum!  Fire!






--
_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: asApproximateFraction[AtOrder:]

timrowledge


> On 23-04-2018, at 1:59 PM, Eliot Miranda <[hidden email]> wrote:
>
> Hi Tim,
>
> On Mon, Apr 23, 2018 at 1:34 PM, tim Rowledge <[hidden email]> wrote:
> Do you normally want your fraction precise to an actual epsilon or to a fraction of the real value?
>
> Actually I guess that you could make a % value by working out the integer part, approximating the epsilon from that and using your method, so go for it. Not that I'm a numerics geek by any stretch.
>
>  So you'd rather see
>
> asApproximateFraction
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> ^self asApproximateFractionToEpsilon: self abs / 1.0e6
>
> ?  

Seems good to me. It's like the difference between wanting to print numbers to X decimal places vs Y significant digits. I think...

tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
Maintenance free: It's impossible to fix.



Reply | Threaded
Open this post in threaded view
|

Re: asApproximateFraction[AtOrder:]

David T. Lewis
In reply to this post by Eliot Miranda-2
Hi Eliot,

I think that the confusing behavior is is related to the interpretation of single
precision floats in the VM when represented as double precision Float in Squeak.

How about implementing #asApproximateFractionFloatPrecision: to specify the
assumed accuracy of the float when derived from single precision, but represented
in the image as a double precision Squeak float?

Thus:

  (FloatArray new: 1) at: 1 put: 1/3; at: 1 ==> 0.3333333432674408 "single precision float cast from FloatArray to Squeak double precision"

  0.3333333432674408 asApproximateFraction ==> (11184811/33554432) "bad, original default implementation assumes float double precision"

  0.3333333432674408 asApproximateFractionFloatPrecision: 5 ==> (1/3) "better, limit precision when cast from single precision to double"

An implementation is in the inbox in Kernel-dtl.1165.

Note, orignal author for these methods has initials 'st' is, which according to
SqueakMap is Samuel Tardieu ([hidden email], home page https://rfc1149.net/sam.html).
Even for those of us not who may not be interested in numerical methods, I must
highly recommend his references to rfc1149.

Dave


On Mon, Apr 23, 2018 at 01:23:03PM -0700, Eliot Miranda wrote:

> Hi All,
>
>     asApproximateFraction isn't that useful.  It is based on
> asApproximateFractionAtOrder:, which gives you the best fraction it can
> find up to order.  e.g.
>
> testContinuedFractions
> self assert: (Float pi asApproximateFractionAtOrder: 1) = (22/7).
> self assert: (Float pi asApproximateFractionAtOrder: 3) = (355/113)
> Here's 32-bit Float 1/3:
>
> ((FloatArray new: 1) at: 1 put: 1/3; at: 1) 0.3333333432674408
>
> ((FloatArray new: 1) at: 1 put: 1/3; at: 1) asApproximateFraction
> (11184811/33554432)
>
> That's not what I expected :-).  The problem is that
> asApproximateFractionAtOrder: is great if you know the number you're
> dealing with, but if you don't then it'll give you too much information.
>
> [This value comes up in the vm parameters system report page, where 1/3 is
> the ratio of growth to heap size above which a full GC is performed, i.e.
> by default every time a scavenge causes the heap grows by 1/3 from the last
> time a full GC was performed, the system will do a full GC.  It would be
> great to report this as 1/3, not 0.33333298563957214, which is what's
> emerging from the C code in the VM].
>
> Let's get a feeling for orders; they're effectively negative powers of 10:
>
> (1 to: 20) collect: [:order| | f |
> { order. (f := Float pi asApproximateFractionAtOrder: order). f asFloat. (f
> asFloat - Float pi) abs}]
> {{1 . (22/7) . 3.142857142857143 . 0.0012644892673496777}.
>  {2 . (333/106) . 3.141509433962264 . 8.32196275291075e-5}.
>  {3 . (355/113) . 3.1415929203539825 . 2.667641894049666e-7}.
>  {4 . (103993/33102) . 3.1415926530119025 . 5.778906242426274e-10}.
>  {5 . (104348/33215) . 3.141592653921421 . 3.3162805834763276e-10}.
>  {6 . (208341/66317) . 3.1415926534674368 . 1.2235634727630895e-10}.
>  {7 . (312689/99532) . 3.1415926536189365 . 2.914335439641036e-11}.
>  {8 . (833719/265381) . 3.141592653581078 . 8.715250743307479e-12}.
>  {9 . (1146408/364913) . 3.141592653591404 . 1.6107115641261771e-12}.
>  {10 . (4272943/1360120) . 3.141592653589389 . 4.04121180963557e-13}.
>  {11 . (5419351/1725033) . 3.1415926535898153 . 2.220446049250313e-14}.
>  {12 . (80143857/25510582) . 3.1415926535897927 . 4.440892098500626e-16}.
>  {13 . (245850922/78256779) . 3.141592653589793 . 0.0}.
>  {14 . (817696623/260280919) . 3.141592653589793 . 0.0}.
>  {15 . (19052873251/6064717916) . 3.141592653589793 . 0.0}.
>  {16 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {17 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {18 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {19 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {20 . (19870569874/6324998835) . 3.141592653589793 . 0.0}}
>
>
> More useful would be something like:
>
> asApproximateFractionToEpsilon: epsilon
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> 1 to: 12 do:
> [:order| | fraction |
> fraction := self asApproximateFractionAtOrder: order.
> (fraction - self) abs <= epsilon ifTrue:
> [^fraction]].
> ^ self asApproximateFractionAtOrder: 0
>
> and then instead of
>
> asApproximateFraction
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> ^ self asApproximateFractionAtOrder: 0
>
> one could have
>
> asApproximateFraction
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> ^self asApproximateFractionToEpsilon: 1e-6
>
> And hence
>
> { 0.0. 0.333. 0.5. 1.0. Float pi . ((FloatArray new: 1) at: 1 put: 1/3; at:
> 1) } collect:
>     [:n| n asApproximateFractionToEpsilon: 1e-6]
> {0 . (333/1000) . (1/2) . 1 . (355/113) . (1/3)}
>
> Votes for or against changing asApproximateFraction to use
> asApproximateFractionToEpsilon:? (asApproximateFraction has no senders into
> base image)
>
> Suggestions for a selector that would use self
> asApproximateFractionToEpsilon: 1e-6 (less clumsy than e.g.
> asUsefulApproximateFraction).
>
> _,,,^..^,,,_
> best, Eliot

>


Reply | Threaded
Open this post in threaded view
|

Re: asApproximateFraction[AtOrder:]

Eliot Miranda-2


On Mon, Apr 23, 2018 at 8:06 PM, David T. Lewis <[hidden email]> wrote:
Hi Eliot,

I think that the confusing behavior is is related to the interpretation of single
precision floats in the VM when represented as double precision Float in Squeak.

How about implementing #asApproximateFractionFloatPrecision: to specify the
assumed accuracy of the float when derived from single precision, but represented
in the image as a double precision Squeak float?
 
Thanks, David.  This looks good to me.  But I'm no expert here.  If I were to put this into trunk I would modify asApproximateFraction: to send asApproximateFractionAtOrder:floatPrecision: directly.


Thus:

  (FloatArray new: 1) at: 1 put: 1/3; at: 1 ==> 0.3333333432674408 "single precision float cast from FloatArray to Squeak double precision"

  0.3333333432674408 asApproximateFraction ==> (11184811/33554432) "bad, original default implementation assumes float double precision"

  0.3333333432674408 asApproximateFractionFloatPrecision: 5 ==> (1/3) "better, limit precision when cast from single precision to double"

An implementation is in the inbox in Kernel-dtl.1165.

Note, orignal author for these methods has initials 'st' is, which according to
SqueakMap is Samuel Tardieu ([hidden email], home page https://rfc1149.net/sam.html).
Even for those of us not who may not be interested in numerical methods, I must
highly recommend his references to rfc1149.

Dave


On Mon, Apr 23, 2018 at 01:23:03PM -0700, Eliot Miranda wrote:
> Hi All,
>
>     asApproximateFraction isn't that useful.  It is based on
> asApproximateFractionAtOrder:, which gives you the best fraction it can
> find up to order.  e.g.
>
> testContinuedFractions
> self assert: (Float pi asApproximateFractionAtOrder: 1) = (22/7).
> self assert: (Float pi asApproximateFractionAtOrder: 3) = (355/113)
> Here's 32-bit Float 1/3:
>
> ((FloatArray new: 1) at: 1 put: 1/3; at: 1) 0.3333333432674408
>
> ((FloatArray new: 1) at: 1 put: 1/3; at: 1) asApproximateFraction
> (11184811/33554432)
>
> That's not what I expected :-).  The problem is that
> asApproximateFractionAtOrder: is great if you know the number you're
> dealing with, but if you don't then it'll give you too much information.
>
> [This value comes up in the vm parameters system report page, where 1/3 is
> the ratio of growth to heap size above which a full GC is performed, i.e.
> by default every time a scavenge causes the heap grows by 1/3 from the last
> time a full GC was performed, the system will do a full GC.  It would be
> great to report this as 1/3, not 0.33333298563957214, which is what's
> emerging from the C code in the VM].
>
> Let's get a feeling for orders; they're effectively negative powers of 10:
>
> (1 to: 20) collect: [:order| | f |
> { order. (f := Float pi asApproximateFractionAtOrder: order). f asFloat. (f
> asFloat - Float pi) abs}]
> {{1 . (22/7) . 3.142857142857143 . 0.0012644892673496777}.
>  {2 . (333/106) . 3.141509433962264 . 8.32196275291075e-5}.
>  {3 . (355/113) . 3.1415929203539825 . 2.667641894049666e-7}.
>  {4 . (103993/33102) . 3.1415926530119025 . 5.778906242426274e-10}.
>  {5 . (104348/33215) . 3.141592653921421 . 3.3162805834763276e-10}.
>  {6 . (208341/66317) . 3.1415926534674368 . 1.2235634727630895e-10}.
>  {7 . (312689/99532) . 3.1415926536189365 . 2.914335439641036e-11}.
>  {8 . (833719/265381) . 3.141592653581078 . 8.715250743307479e-12}.
>  {9 . (1146408/364913) . 3.141592653591404 . 1.6107115641261771e-12}.
>  {10 . (4272943/1360120) . 3.141592653589389 . 4.04121180963557e-13}.
>  {11 . (5419351/1725033) . 3.1415926535898153 . 2.220446049250313e-14}.
>  {12 . (80143857/25510582) . 3.1415926535897927 . 4.440892098500626e-16}.
>  {13 . (245850922/78256779) . 3.141592653589793 . 0.0}.
>  {14 . (817696623/260280919) . 3.141592653589793 . 0.0}.
>  {15 . (19052873251/6064717916) . 3.141592653589793 . 0.0}.
>  {16 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {17 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {18 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {19 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>  {20 . (19870569874/6324998835) . 3.141592653589793 . 0.0}}
>
>
> More useful would be something like:
>
> asApproximateFractionToEpsilon: epsilon
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> 1 to: 12 do:
> [:order| | fraction |
> fraction := self asApproximateFractionAtOrder: order.
> (fraction - self) abs <= epsilon ifTrue:
> [^fraction]].
> ^ self asApproximateFractionAtOrder: 0
>
> and then instead of
>
> asApproximateFraction
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> ^ self asApproximateFractionAtOrder: 0
>
> one could have
>
> asApproximateFraction
> "Answer a Fraction approximating the receiver. This conversion uses the
> continued fraction method to approximate a floating point number."
>
> ^self asApproximateFractionToEpsilon: 1e-6
>
> And hence
>
> { 0.0. 0.333. 0.5. 1.0. Float pi . ((FloatArray new: 1) at: 1 put: 1/3; at:
> 1) } collect:
>     [:n| n asApproximateFractionToEpsilon: 1e-6]
> {0 . (333/1000) . (1/2) . 1 . (355/113) . (1/3)}
>
> Votes for or against changing asApproximateFraction to use
> asApproximateFractionToEpsilon:? (asApproximateFraction has no senders into
> base image)
>
> Suggestions for a selector that would use self
> asApproximateFractionToEpsilon: 1e-6 (less clumsy than e.g.
> asUsefulApproximateFraction).
>
> _,,,^..^,,,_
> best, Eliot

>





--
_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: asApproximateFraction[AtOrder:]

David T. Lewis
On Wed, Apr 25, 2018 at 06:32:51PM -0700, Eliot Miranda wrote:

> On Mon, Apr 23, 2018 at 8:06 PM, David T. Lewis <[hidden email]> wrote:
>
> > Hi Eliot,
> >
> > I think that the confusing behavior is is related to the interpretation of
> > single
> > precision floats in the VM when represented as double precision Float in
> > Squeak.
> >
> > How about implementing #asApproximateFractionFloatPrecision: to specify
> > the
> > assumed accuracy of the float when derived from single precision, but
> > represented
> > in the image as a double precision Squeak float?
> >
>
> Thanks, David.  This looks good to me.  But I'm no expert here.  If I were
> to put this into trunk I would modify asApproximateFraction: to
> send asApproximateFractionAtOrder:floatPrecision: directly.
>

Oops, emails crossed in the ether. I just committed a small but important fix
to the inbox, and I missed your suggestion.

Should this go to trunk? If so I will add your change when merging.

Dave

>
> > Thus:
> >
> >   (FloatArray new: 1) at: 1 put: 1/3; at: 1 ==> 0.3333333432674408 "single
> > precision float cast from FloatArray to Squeak double precision"
> >
> >   0.3333333432674408 asApproximateFraction ==> (11184811/33554432) "bad,
> > original default implementation assumes float double precision"
> >
> >   0.3333333432674408 asApproximateFractionFloatPrecision: 5 ==> (1/3)
> > "better, limit precision when cast from single precision to double"
> >
> > An implementation is in the inbox in Kernel-dtl.1165.
> >
> > Note, orignal author for these methods has initials 'st' is, which
> > according to
> > SqueakMap is Samuel Tardieu ([hidden email], home page
> > https://rfc1149.net/sam.html).
> > Even for those of us not who may not be interested in numerical methods, I
> > must
> > highly recommend his references to rfc1149.
> >
> > Dave
> >
> >
> > On Mon, Apr 23, 2018 at 01:23:03PM -0700, Eliot Miranda wrote:
> > > Hi All,
> > >
> > >     asApproximateFraction isn't that useful.  It is based on
> > > asApproximateFractionAtOrder:, which gives you the best fraction it can
> > > find up to order.  e.g.
> > >
> > > testContinuedFractions
> > > self assert: (Float pi asApproximateFractionAtOrder: 1) = (22/7).
> > > self assert: (Float pi asApproximateFractionAtOrder: 3) = (355/113)
> > > Here's 32-bit Float 1/3:
> > >
> > > ((FloatArray new: 1) at: 1 put: 1/3; at: 1) 0.3333333432674408
> > >
> > > ((FloatArray new: 1) at: 1 put: 1/3; at: 1) asApproximateFraction
> > > (11184811/33554432)
> > >
> > > That's not what I expected :-).  The problem is that
> > > asApproximateFractionAtOrder: is great if you know the number you're
> > > dealing with, but if you don't then it'll give you too much information.
> > >
> > > [This value comes up in the vm parameters system report page, where 1/3
> > is
> > > the ratio of growth to heap size above which a full GC is performed, i.e.
> > > by default every time a scavenge causes the heap grows by 1/3 from the
> > last
> > > time a full GC was performed, the system will do a full GC.  It would be
> > > great to report this as 1/3, not 0.33333298563957214, which is what's
> > > emerging from the C code in the VM].
> > >
> > > Let's get a feeling for orders; they're effectively negative powers of
> > 10:
> > >
> > > (1 to: 20) collect: [:order| | f |
> > > { order. (f := Float pi asApproximateFractionAtOrder: order). f asFloat.
> > (f
> > > asFloat - Float pi) abs}]
> > > {{1 . (22/7) . 3.142857142857143 . 0.0012644892673496777}.
> > >  {2 . (333/106) . 3.141509433962264 . 8.32196275291075e-5}.
> > >  {3 . (355/113) . 3.1415929203539825 . 2.667641894049666e-7}.
> > >  {4 . (103993/33102) . 3.1415926530119025 . 5.778906242426274e-10}.
> > >  {5 . (104348/33215) . 3.141592653921421 . 3.3162805834763276e-10}.
> > >  {6 . (208341/66317) . 3.1415926534674368 . 1.2235634727630895e-10}.
> > >  {7 . (312689/99532) . 3.1415926536189365 . 2.914335439641036e-11}.
> > >  {8 . (833719/265381) . 3.141592653581078 . 8.715250743307479e-12}.
> > >  {9 . (1146408/364913) . 3.141592653591404 . 1.6107115641261771e-12}.
> > >  {10 . (4272943/1360120) . 3.141592653589389 . 4.04121180963557e-13}.
> > >  {11 . (5419351/1725033) . 3.1415926535898153 . 2.220446049250313e-14}.
> > >  {12 . (80143857/25510582) . 3.1415926535897927 . 4.440892098500626e-16}.
> > >  {13 . (245850922/78256779) . 3.141592653589793 . 0.0}.
> > >  {14 . (817696623/260280919) . 3.141592653589793 . 0.0}.
> > >  {15 . (19052873251/6064717916) . 3.141592653589793 . 0.0}.
> > >  {16 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
> > >  {17 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
> > >  {18 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
> > >  {19 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
> > >  {20 . (19870569874/6324998835) . 3.141592653589793 . 0.0}}
> > >
> > >
> > > More useful would be something like:
> > >
> > > asApproximateFractionToEpsilon: epsilon
> > > "Answer a Fraction approximating the receiver. This conversion uses the
> > > continued fraction method to approximate a floating point number."
> > >
> > > 1 to: 12 do:
> > > [:order| | fraction |
> > > fraction := self asApproximateFractionAtOrder: order.
> > > (fraction - self) abs <= epsilon ifTrue:
> > > [^fraction]].
> > > ^ self asApproximateFractionAtOrder: 0
> > >
> > > and then instead of
> > >
> > > asApproximateFraction
> > > "Answer a Fraction approximating the receiver. This conversion uses the
> > > continued fraction method to approximate a floating point number."
> > >
> > > ^ self asApproximateFractionAtOrder: 0
> > >
> > > one could have
> > >
> > > asApproximateFraction
> > > "Answer a Fraction approximating the receiver. This conversion uses the
> > > continued fraction method to approximate a floating point number."
> > >
> > > ^self asApproximateFractionToEpsilon: 1e-6
> > >
> > > And hence
> > >
> > > { 0.0. 0.333. 0.5. 1.0. Float pi . ((FloatArray new: 1) at: 1 put: 1/3;
> > at:
> > > 1) } collect:
> > >     [:n| n asApproximateFractionToEpsilon: 1e-6]
> > > {0 . (333/1000) . (1/2) . 1 . (355/113) . (1/3)}
> > >
> > > Votes for or against changing asApproximateFraction to use
> > > asApproximateFractionToEpsilon:? (asApproximateFraction has no senders
> > into
> > > base image)
> > >
> > > Suggestions for a selector that would use self
> > > asApproximateFractionToEpsilon: 1e-6 (less clumsy than e.g.
> > > asUsefulApproximateFraction).
> > >
> > > _,,,^..^,,,_
> > > best, Eliot
> >
> > >
> >
> >
> >
>
>
> --
> _,,,^..^,,,_
> best, Eliot

>


Reply | Threaded
Open this post in threaded view
|

Re: asApproximateFraction[AtOrder:]

Nicolas Cellier
Hi all,
I couldn't resist, and posted a version to the trunk ;)
We can have both (un)limited number of iterations and limited precision (it is limited by Float ulp / 2 anyway...).
I kept the default to 10 decimal places, but we can reduce it to 6 if we want to...


2018-04-26 5:03 GMT+02:00 David T. Lewis <[hidden email]>:
On Wed, Apr 25, 2018 at 06:32:51PM -0700, Eliot Miranda wrote:
> On Mon, Apr 23, 2018 at 8:06 PM, David T. Lewis <[hidden email]> wrote:
>
> > Hi Eliot,
> >
> > I think that the confusing behavior is is related to the interpretation of
> > single
> > precision floats in the VM when represented as double precision Float in
> > Squeak.
> >
> > How about implementing #asApproximateFractionFloatPrecision: to specify
> > the
> > assumed accuracy of the float when derived from single precision, but
> > represented
> > in the image as a double precision Squeak float?
> >
>
> Thanks, David.  This looks good to me.  But I'm no expert here.  If I were
> to put this into trunk I would modify asApproximateFraction: to
> send asApproximateFractionAtOrder:floatPrecision: directly.
>

Oops, emails crossed in the ether. I just committed a small but important fix
to the inbox, and I missed your suggestion.

Should this go to trunk? If so I will add your change when merging.

Dave

>
> > Thus:
> >
> >   (FloatArray new: 1) at: 1 put: 1/3; at: 1 ==> 0.3333333432674408 "single
> > precision float cast from FloatArray to Squeak double precision"
> >
> >   0.3333333432674408 asApproximateFraction ==> (11184811/33554432) "bad,
> > original default implementation assumes float double precision"
> >
> >   0.3333333432674408 asApproximateFractionFloatPrecision: 5 ==> (1/3)
> > "better, limit precision when cast from single precision to double"
> >
> > An implementation is in the inbox in Kernel-dtl.1165.
> >
> > Note, orignal author for these methods has initials 'st' is, which
> > according to
> > SqueakMap is Samuel Tardieu ([hidden email], home page
> > https://rfc1149.net/sam.html).
> > Even for those of us not who may not be interested in numerical methods, I
> > must
> > highly recommend his references to rfc1149.
> >
> > Dave
> >
> >
> > On Mon, Apr 23, 2018 at 01:23:03PM -0700, Eliot Miranda wrote:
> > > Hi All,
> > >
> > >     asApproximateFraction isn't that useful.  It is based on
> > > asApproximateFractionAtOrder:, which gives you the best fraction it can
> > > find up to order.  e.g.
> > >
> > > testContinuedFractions
> > > self assert: (Float pi asApproximateFractionAtOrder: 1) = (22/7).
> > > self assert: (Float pi asApproximateFractionAtOrder: 3) = (355/113)
> > > Here's 32-bit Float 1/3:
> > >
> > > ((FloatArray new: 1) at: 1 put: 1/3; at: 1) 0.3333333432674408
> > >
> > > ((FloatArray new: 1) at: 1 put: 1/3; at: 1) asApproximateFraction
> > > (11184811/33554432)
> > >
> > > That's not what I expected :-).  The problem is that
> > > asApproximateFractionAtOrder: is great if you know the number you're
> > > dealing with, but if you don't then it'll give you too much information.
> > >
> > > [This value comes up in the vm parameters system report page, where 1/3
> > is
> > > the ratio of growth to heap size above which a full GC is performed, i.e.
> > > by default every time a scavenge causes the heap grows by 1/3 from the
> > last
> > > time a full GC was performed, the system will do a full GC.  It would be
> > > great to report this as 1/3, not 0.33333298563957214, which is what's
> > > emerging from the C code in the VM].
> > >
> > > Let's get a feeling for orders; they're effectively negative powers of
> > 10:
> > >
> > > (1 to: 20) collect: [:order| | f |
> > > { order. (f := Float pi asApproximateFractionAtOrder: order). f asFloat.
> > (f
> > > asFloat - Float pi) abs}]
> > > {{1 . (22/7) . 3.142857142857143 . 0.0012644892673496777}.
> > >  {2 . (333/106) . 3.141509433962264 . 8.32196275291075e-5}.
> > >  {3 . (355/113) . 3.1415929203539825 . 2.667641894049666e-7}.
> > >  {4 . (103993/33102) . 3.1415926530119025 . 5.778906242426274e-10}.
> > >  {5 . (104348/33215) . 3.141592653921421 . 3.3162805834763276e-10}.
> > >  {6 . (208341/66317) . 3.1415926534674368 . 1.2235634727630895e-10}.
> > >  {7 . (312689/99532) . 3.1415926536189365 . 2.914335439641036e-11}.
> > >  {8 . (833719/265381) . 3.141592653581078 . 8.715250743307479e-12}.
> > >  {9 . (1146408/364913) . 3.141592653591404 . 1.6107115641261771e-12}.
> > >  {10 . (4272943/1360120) . 3.141592653589389 . 4.04121180963557e-13}.
> > >  {11 . (5419351/1725033) . 3.1415926535898153 . 2.220446049250313e-14}.
> > >  {12 . (80143857/25510582) . 3.1415926535897927 . 4.440892098500626e-16}.
> > >  {13 . (245850922/78256779) . 3.141592653589793 . 0.0}.
> > >  {14 . (817696623/260280919) . 3.141592653589793 . 0.0}.
> > >  {15 . (19052873251/6064717916) . 3.141592653589793 . 0.0}.
> > >  {16 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
> > >  {17 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
> > >  {18 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
> > >  {19 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
> > >  {20 . (19870569874/6324998835) . 3.141592653589793 . 0.0}}
> > >
> > >
> > > More useful would be something like:
> > >
> > > asApproximateFractionToEpsilon: epsilon
> > > "Answer a Fraction approximating the receiver. This conversion uses the
> > > continued fraction method to approximate a floating point number."
> > >
> > > 1 to: 12 do:
> > > [:order| | fraction |
> > > fraction := self asApproximateFractionAtOrder: order.
> > > (fraction - self) abs <= epsilon ifTrue:
> > > [^fraction]].
> > > ^ self asApproximateFractionAtOrder: 0
> > >
> > > and then instead of
> > >
> > > asApproximateFraction
> > > "Answer a Fraction approximating the receiver. This conversion uses the
> > > continued fraction method to approximate a floating point number."
> > >
> > > ^ self asApproximateFractionAtOrder: 0
> > >
> > > one could have
> > >
> > > asApproximateFraction
> > > "Answer a Fraction approximating the receiver. This conversion uses the
> > > continued fraction method to approximate a floating point number."
> > >
> > > ^self asApproximateFractionToEpsilon: 1e-6
> > >
> > > And hence
> > >
> > > { 0.0. 0.333. 0.5. 1.0. Float pi . ((FloatArray new: 1) at: 1 put: 1/3;
> > at:
> > > 1) } collect:
> > >     [:n| n asApproximateFractionToEpsilon: 1e-6]
> > > {0 . (333/1000) . (1/2) . 1 . (355/113) . (1/3)}
> > >
> > > Votes for or against changing asApproximateFraction to use
> > > asApproximateFractionToEpsilon:? (asApproximateFraction has no senders
> > into
> > > base image)
> > >
> > > Suggestions for a selector that would use self
> > > asApproximateFractionToEpsilon: 1e-6 (less clumsy than e.g.
> > > asUsefulApproximateFraction).
> > >
> > > _,,,^..^,,,_
> > > best, Eliot
> >
> > >
> >
> >
> >
>
>
> --
> _,,,^..^,,,_
> best, Eliot

>





Reply | Threaded
Open this post in threaded view
|

Re: asApproximateFraction[AtOrder:]

David T. Lewis
Thank you Nicolas!

I moved my two packages from inbox to treated.

Dave

> Hi all,
> I couldn't resist, and posted a version to the trunk ;)
> We can have both (un)limited number of iterations and limited precision
> (it
> is limited by Float ulp / 2 anyway...).
> I kept the default to 10 decimal places, but we can reduce it to 6 if we
> want to...
>
>
> 2018-04-26 5:03 GMT+02:00 David T. Lewis <[hidden email]>:
>
>> On Wed, Apr 25, 2018 at 06:32:51PM -0700, Eliot Miranda wrote:
>> > On Mon, Apr 23, 2018 at 8:06 PM, David T. Lewis <[hidden email]>
>> wrote:
>> >
>> > > Hi Eliot,
>> > >
>> > > I think that the confusing behavior is is related to the
>> interpretation of
>> > > single
>> > > precision floats in the VM when represented as double precision
>> Float
>> in
>> > > Squeak.
>> > >
>> > > How about implementing #asApproximateFractionFloatPrecision: to
>> specify
>> > > the
>> > > assumed accuracy of the float when derived from single precision,
>> but
>> > > represented
>> > > in the image as a double precision Squeak float?
>> > >
>> >
>> > Thanks, David.  This looks good to me.  But I'm no expert here.  If I
>> were
>> > to put this into trunk I would modify asApproximateFraction: to
>> > send asApproximateFractionAtOrder:floatPrecision: directly.
>> >
>>
>> Oops, emails crossed in the ether. I just committed a small but
>> important
>> fix
>> to the inbox, and I missed your suggestion.
>>
>> Should this go to trunk? If so I will add your change when merging.
>>
>> Dave
>>
>> >
>> > > Thus:
>> > >
>> > >   (FloatArray new: 1) at: 1 put: 1/3; at: 1 ==> 0.3333333432674408
>> "single
>> > > precision float cast from FloatArray to Squeak double precision"
>> > >
>> > >   0.3333333432674408 asApproximateFraction ==> (11184811/33554432)
>> "bad,
>> > > original default implementation assumes float double precision"
>> > >
>> > >   0.3333333432674408 asApproximateFractionFloatPrecision: 5 ==>
>> (1/3)
>> > > "better, limit precision when cast from single precision to double"
>> > >
>> > > An implementation is in the inbox in Kernel-dtl.1165.
>> > >
>> > > Note, orignal author for these methods has initials 'st' is, which
>> > > according to
>> > > SqueakMap is Samuel Tardieu ([hidden email], home page
>> > > https://rfc1149.net/sam.html).
>> > > Even for those of us not who may not be interested in numerical
>> methods, I
>> > > must
>> > > highly recommend his references to rfc1149.
>> > >
>> > > Dave
>> > >
>> > >
>> > > On Mon, Apr 23, 2018 at 01:23:03PM -0700, Eliot Miranda wrote:
>> > > > Hi All,
>> > > >
>> > > >     asApproximateFraction isn't that useful.  It is based on
>> > > > asApproximateFractionAtOrder:, which gives you the best fraction
>> it
>> can
>> > > > find up to order.  e.g.
>> > > >
>> > > > testContinuedFractions
>> > > > self assert: (Float pi asApproximateFractionAtOrder: 1) = (22/7).
>> > > > self assert: (Float pi asApproximateFractionAtOrder: 3) =
>> (355/113)
>> > > > Here's 32-bit Float 1/3:
>> > > >
>> > > > ((FloatArray new: 1) at: 1 put: 1/3; at: 1) 0.3333333432674408
>> > > >
>> > > > ((FloatArray new: 1) at: 1 put: 1/3; at: 1) asApproximateFraction
>> > > > (11184811/33554432)
>> > > >
>> > > > That's not what I expected :-).  The problem is that
>> > > > asApproximateFractionAtOrder: is great if you know the number
>> you're
>> > > > dealing with, but if you don't then it'll give you too much
>> information.
>> > > >
>> > > > [This value comes up in the vm parameters system report page,
>> where
>> 1/3
>> > > is
>> > > > the ratio of growth to heap size above which a full GC is
>> performed,
>> i.e.
>> > > > by default every time a scavenge causes the heap grows by 1/3 from
>> the
>> > > last
>> > > > time a full GC was performed, the system will do a full GC.  It
>> would be
>> > > > great to report this as 1/3, not 0.33333298563957214, which is
>> what's
>> > > > emerging from the C code in the VM].
>> > > >
>> > > > Let's get a feeling for orders; they're effectively negative
>> powers
>> of
>> > > 10:
>> > > >
>> > > > (1 to: 20) collect: [:order| | f |
>> > > > { order. (f := Float pi asApproximateFractionAtOrder: order). f
>> asFloat.
>> > > (f
>> > > > asFloat - Float pi) abs}]
>> > > > {{1 . (22/7) . 3.142857142857143 . 0.0012644892673496777}.
>> > > >  {2 . (333/106) . 3.141509433962264 . 8.32196275291075e-5}.
>> > > >  {3 . (355/113) . 3.1415929203539825 . 2.667641894049666e-7}.
>> > > >  {4 . (103993/33102) . 3.1415926530119025 .
>> 5.778906242426274e-10}.
>> > > >  {5 . (104348/33215) . 3.141592653921421 .
>> 3.3162805834763276e-10}.
>> > > >  {6 . (208341/66317) . 3.1415926534674368 .
>> 1.2235634727630895e-10}.
>> > > >  {7 . (312689/99532) . 3.1415926536189365 .
>> 2.914335439641036e-11}.
>> > > >  {8 . (833719/265381) . 3.141592653581078 .
>> 8.715250743307479e-12}.
>> > > >  {9 . (1146408/364913) . 3.141592653591404 .
>> 1.6107115641261771e-12}.
>> > > >  {10 . (4272943/1360120) . 3.141592653589389 .
>> 4.04121180963557e-13}.
>> > > >  {11 . (5419351/1725033) . 3.1415926535898153 .
>> 2.220446049250313e-14}.
>> > > >  {12 . (80143857/25510582) . 3.1415926535897927 .
>> 4.440892098500626e-16}.
>> > > >  {13 . (245850922/78256779) . 3.141592653589793 . 0.0}.
>> > > >  {14 . (817696623/260280919) . 3.141592653589793 . 0.0}.
>> > > >  {15 . (19052873251/6064717916) . 3.141592653589793 . 0.0}.
>> > > >  {16 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>> > > >  {17 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>> > > >  {18 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>> > > >  {19 . (19870569874/6324998835) . 3.141592653589793 . 0.0}.
>> > > >  {20 . (19870569874/6324998835) . 3.141592653589793 . 0.0}}
>> > > >
>> > > >
>> > > > More useful would be something like:
>> > > >
>> > > > asApproximateFractionToEpsilon: epsilon
>> > > > "Answer a Fraction approximating the receiver. This conversion
>> uses
>> the
>> > > > continued fraction method to approximate a floating point number."
>> > > >
>> > > > 1 to: 12 do:
>> > > > [:order| | fraction |
>> > > > fraction := self asApproximateFractionAtOrder: order.
>> > > > (fraction - self) abs <= epsilon ifTrue:
>> > > > [^fraction]].
>> > > > ^ self asApproximateFractionAtOrder: 0
>> > > >
>> > > > and then instead of
>> > > >
>> > > > asApproximateFraction
>> > > > "Answer a Fraction approximating the receiver. This conversion
>> uses
>> the
>> > > > continued fraction method to approximate a floating point number."
>> > > >
>> > > > ^ self asApproximateFractionAtOrder: 0
>> > > >
>> > > > one could have
>> > > >
>> > > > asApproximateFraction
>> > > > "Answer a Fraction approximating the receiver. This conversion
>> uses
>> the
>> > > > continued fraction method to approximate a floating point number."
>> > > >
>> > > > ^self asApproximateFractionToEpsilon: 1e-6
>> > > >
>> > > > And hence
>> > > >
>> > > > { 0.0. 0.333. 0.5. 1.0. Float pi . ((FloatArray new: 1) at: 1 put:
>> 1/3;
>> > > at:
>> > > > 1) } collect:
>> > > >     [:n| n asApproximateFractionToEpsilon: 1e-6]
>> > > > {0 . (333/1000) . (1/2) . 1 . (355/113) . (1/3)}
>> > > >
>> > > > Votes for or against changing asApproximateFraction to use
>> > > > asApproximateFractionToEpsilon:? (asApproximateFraction has no
>> senders
>> > > into
>> > > > base image)
>> > > >
>> > > > Suggestions for a selector that would use self
>> > > > asApproximateFractionToEpsilon: 1e-6 (less clumsy than e.g.
>> > > > asUsefulApproximateFraction).
>> > > >
>> > > > _,,,^..^,,,_
>> > > > best, Eliot
>> > >
>> > > >
>> > >
>> > >
>> > >
>> >
>> >
>> > --
>> > _,,,^..^,,,_
>> > best, Eliot
>>
>> >
>>
>>
>>
>
>