On Sun, Aug 11, 2013 at 6:15 PM, Cedric Blancher <cedric.blanc...@gmail.com> wrote: > On 11 August 2013 10:43, Tina Harriott <tina.harriott.m...@gmail.com> wrote: >> On Wed, Jul 24, 2013 at 7:28 PM, Glenn Fowler <g...@research.att.com> wrote: >>> >>> On Wed, 24 Jul 2013 19:02:39 +0200 Tina Harriott wrote: >>>> Here's one of my little tough problems which I am unable to solve >>>> myself, even after looking at the source code of ast-ksh. The problem >>>> below requires a good understanding how floating point numbers are >>>> implemented in computers. >>> >>>> I'm trying to prototype code and like to iterate over a small, linear >>>> area by using the C library function nextafter() to step forward the >>>> smallest possible distance between each step, and print the number of >>>> iterations needed to cover the distance between 4 and 4.000000000001: >>>> ksh -c 'float v ; integer iter ; for ((iter=0,v=4 ; v < 4.000000000001 >>>> && iter < 10000000; v=nextafter(v,4.000000000001))) ; do >>>> ((iter++));done;print $iter ' >>>> 2305843 >>> >>>> The result 2305843 is correct. >>> >>>> However, if I use typeset -E (or just typeset) to declare the variable >>>> v the loop runs forever, or in this case until it hits iter < 10000000 >>>> which I added as safeguard later: >>>> ksh -c 'typeset -E v ; integer iter ; for ((iter=0,v=4 ; v < >>>> 4.000000000001 && iter < 10000000; v=nextafter(v,4.000000000001))) ; >>>> do ((iter++));done;print $iter ' >>>> 10000000 >>> >>>> Can anyone explain this? >>> >>> float is an alias >>> this shows the alias definition >>> type float >>> which is >>> typeset -lE >>> this documents -l >>> typeset --?l >>> >>> so for your example >>> typeset -E >>> gave you a double v and >>> typeset -lE >>> would give you a "long double" v >> >> But why does nextafter() misbehave if I want to use a datatype smaller >> than "long double"? Accuracy is a good thing, but in this case we >> iterate too fine-grained, meaning the code should iterate over the >> smallest possible steps of a double, but not over the smallest >> possible steps of a long double. > > Does anyone have a good idea how to fix this in ksh?
Grumpf... yes. Technically I feared that day may come when |nextafter()| and |nexttoward()| were added in ksh93... ;-/ The issue is more or less like this: Both |nextafter(f|l|)\(\)| and |nexttoward(f|l|)\(\)| step over the smallest possible quantity for the specific { |float|, |double|, |long double| }-datatype and therefore (for example) using |nextafterl()| (intended for |long double|) for a |float| doesn't work because it does so small steps that they cannot be represented in a |float| ... that causes the endless loop in Tina's example. The fix would be to "remember" the datatype (e.g. { |float|, |double|, |long double| }) for a given variable and pass that down to |arith_exec()| and call the specific version of |nextafter()| and |nexttoward()| for that datatype, for example: - variables declared via typeset -s -E/-X should use |nextafterf()|/|nexttowardf()| - variables declared via typeset -E/-X should use |nextafter()|/|nexttoward()| - variables declared via typeset -l -E/-X should use |nextafterl()|/|nexttowardl()| ... if the platforms libc/libm do not have a matching |nextafter(f|l|)\(\)|/|nexttoward(f|l|)\(\)| variant for the input datatype then the "function not found"-error should be thrown. Note that we do _not_ have to change the logic for all math functions... AFAIK |nextafter()| and |nexttoward()| are the only exceptions which require special handling... Glenn: What do you think ? ---- Bye, Roland -- __ . . __ (o.\ \/ /.o) roland.ma...@nrubsig.org \__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer /O /==\ O\ TEL +49 641 3992797 (;O/ \/ \O;) _______________________________________________ ast-users mailing list ast-users@lists.research.att.com http://lists.research.att.com/mailman/listinfo/ast-users