[squeak-dev] asApproximateFraction[AtOrder:]

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Thu Apr 26 13:12:32 UTC 2018


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 <lewis at mail.msen.com>:

> 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 <lewis at mail.msen.com>
> 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 (sam at rfc1149.net, 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
>
> >
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20180426/98a6a246/attachment.html>


More information about the Squeak-dev mailing list