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 |
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! |
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? 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 ? 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 talking in numerical analysis ignorance...
_,,,^..^,,,_ best, Eliot |
> 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. |
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 > |
On Mon, Apr 23, 2018 at 8:06 PM, David T. Lewis <[hidden email]> wrote: Hi Eliot, 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.
_,,,^..^,,,_ best, Eliot |
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 > |
Hi all, I couldn't resist, and posted a version to the trunk ;)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: |
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 >> >> > >> >> >> > > |
Free forum by Nabble | Edit this page |