On Tue, Sep 26, 2017 at 01:27:52PM +0200, Jan Stary wrote:

> I picked sin() as an example while trying to walk though the implementation
> of (pieces of) libm.  If someone has the time for it, I have some questions.
> 
> I understand the implementation originaly stems from Sun's libm of 1993.
> (As does that of FreeBSD and NetBSD.) It has been tweaked over the years,
> but the code that actually computes the values is mostly untouched.
> 
> s_sin.c normalizes the argument to [-pi/4, +pi/4].
> This is how |x| <= pi/4 is tested:
> 
>       GET_HIGH_WORD(ix,x);
>       ix &= 0x7fffffff;
>       if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
> 
> Why is it done like that? Is it faster or more portable
> or in any way better that comparing the value itself to M_PI_4?
> (Or was it, in 1993?)

The code is written in a way to use as little as fp ops as possible.

> 
> For Inf and NaN arguments, NaN is returned as follows:
> 
>       /* sin(Inf or NaN) is NaN */
>       else if (ix>=0x7ff00000) return x-x;
> 
> Again, why the integer conversion? Would
> 
>       else if (isinf(x) || isnan(x))
> 
> be slower? Less portable?

These functions were not generally available when the code was
written. iirc these were only standarized in C99.

> 
> Also, is "return x-x" just a fast/clever way to return NaN
> for x being Inf _or_ NaN, preferable to return nan("")?

Same as above.

        -Otto


> 
> I have other questions in k_sin.c and elsewhere, but I'll stop here.
> Please see my naive diff below. I tried this on amd64, macppc and armv7;
> regress/lib/libm/fpaccuracy results in zero difference. The only
> other thing I tried is "sox -n out.raw synth 10 sin" which also gives
> the same result. (That's hardly "testing" of course.)
> 
> Surely I am missing something elementary.
> I'll be glad for any insight.
> 
>       Thank you for your time
> 
>               Jan
> 
> 
> Index: s_sin.c
> ===================================================================
> RCS file: /cvs/src/lib/libm/src/s_sin.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 s_sin.c
> --- s_sin.c   12 Sep 2016 19:47:02 -0000      1.11
> +++ s_sin.c   26 Sep 2017 08:54:03 -0000
> @@ -50,17 +50,12 @@ double
>  sin(double x)
>  {
>       double y[2],z=0.0;
> -     int32_t n, ix;
> +     int32_t n;
>  
> -    /* High word of x. */
> -     GET_HIGH_WORD(ix,x);
> -
> -    /* |x| ~< pi/4 */
> -     ix &= 0x7fffffff;
> -     if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
> -
> -    /* sin(Inf or NaN) is NaN */
> -     else if (ix>=0x7ff00000) return x-x;
> +     if (-M_PI_4 < x && x < M_PI_4)
> +             return __kernel_sin(x,z,0);
> +     else if (isinf(x) || isnan(x))
> +             return nan("");
>  
>      /* argument reduction needed */
>       else {

Reply via email to