On 12 August 2013 07:29, Irek Szczesniak <[email protected]> wrote:
> On Mon, Aug 12, 2013 at 1:16 AM, Roland Mainz <[email protected]>
> wrote:
>> On Mon, Aug 12, 2013 at 12:28 AM, Roland Mainz <[email protected]>
>> wrote:
>> [Removing [email protected]]
>>> On Mon, Aug 12, 2013 at 12:14 AM, Roland Mainz <[email protected]>
>>> wrote:
>>>> On Sun, Aug 11, 2013 at 10:57 PM, Roland Mainz <[email protected]>
>>>> wrote:
>>>>> On Sun, Aug 11, 2013 at 6:15 PM, Cedric Blancher
>>>>> <[email protected]> wrote:
>>>>>> On 11 August 2013 10:43, Tina Harriott <[email protected]>
>>>>>> wrote:
>>>>>>> On Wed, Jul 24, 2013 at 7:28 PM, Glenn Fowler <[email protected]>
>>>>>>> wrote:
>>>>>>>> On Wed, 24 Jul 2013 19:02:39 +0200 Tina Harriott wrote:
>>>> [snip]
>>>>>>> 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 ?
>>>>
>>>> Attached (as "astksh20130807_short_float_nextafter001.diff.txt") is a
>>>> _prototype_ patch which shows how it would look like:
>>>> -- snip --
>>>> $ ksh -c 'typeset -s -E x=4 ; print $(( x=nextafter(x,5) ))'
>>>> 4.0000004768371582
>>>> $ ksh -c 'typeset -E x=4 ; print $(( x=nextafter(x,5) ))'
>>>> 4.00000000000000089
>>>> $ ksh -c 'typeset -l -E x=4 ; print $(( x=nextafter(x,5) ))'
>>>> 4 # this is not exactly 4 but it is so a tiny step away from 4 that
>>>> normal %f output doesn't recognise it
>>>> -- snip --
>>>>
>>>> * ToDo:
>>>> - Add |nexttoward()| support
>>>> - Add defines for type size (|float|, |double|, |long double|)
>>>> - Add error code in case if one of the { |float|, |double|, |long
>>>> double| }-variants is missing
>>>> - Somehow make the code look better
>>>>
>>>> Comments/rants/feedback welcome...
>>>
>>> Grumpf... attached (as
>>> "astksh20130807_short_float_nextafter002.diff.txt") is a fixed
>>> patch... the previous one used |double| in case that the datatype of
>>> the arguments couldn't be obtained... the patch corrects this and adds
>>> support for |nexttoward()| ...
>>
>> More thought about this:
>> src/cmd/ksh93/data/math.tab could return all three variants (for {
>> |float|, |double|, |long double| }) and |fun| in |arith_exec()| would
>> be a pointer to an array of these three variants. That would make the
>> support for |float| and |double| generic and remove all the
>> |if()|/|switch()| mess from the "hot" codepath...
>
> That is IMO the only solution which covers *all* corner cases, i.e. if
> an overflow/underflow or creation of subnormal numbers in a math
> function happens. Smaller datatypes mean you'll hit the limits earlier
> than for larger datatypes and not all float/double functions behave
> like doing the same operation with a long double datatype and then
> cast the result to the requested datatype.
Irek, I looked at this. Using a wider datatype and then cast to the
narrower datatype yields an error only in the last bit:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
int main()
{
long double al;
double a;
double al_d;
long double r;
a = tan(-0.001);
al = tanl(-0.001);
al_d = al;
r = fabs(a-al_d);
printf("diff=%a\n", r);
return 0;
}
> gcc -g x.c
> ./a.out
diff=0x0.0000000000001p-1022
This test however doesn't cover exceptional conditions: float will
overflow much faster than a double, a condition which affects pow(),
and hypot() will behave differently for subnormal inputs of different
types because the classification of subnormal depends on the width of
the datatype. Storing results from a narrow datatype (i.e. float,
double) in a long double however is OK again because no information is
lost in that direction.
Therefore I agree with you that all math functions should only be used
with the appropriate datatypes.
Tina
--
Tina Harriott - Women in Mathematics
Contact: [email protected]
_______________________________________________
ast-developers mailing list
[email protected]
http://lists.research.att.com/mailman/listinfo/ast-developers