OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gnu-src/] [newlib-1.18.0/] [newlib-1.18.0-or32-1.0rc1/] [newlib/] [libm/] [mathfp/] [e_hypot.c] - Diff between revs 207 and 345

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 207 Rev 345
 
 
/* @(#)e_hypot.c 5.1 93/09/24 */
/* @(#)e_hypot.c 5.1 93/09/24 */
/*
/*
 * ====================================================
 * ====================================================
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 *
 *
 * Developed at SunPro, a Sun Microsystems, Inc. business.
 * Developed at SunPro, a Sun Microsystems, Inc. business.
 * Permission to use, copy, modify, and distribute this
 * Permission to use, copy, modify, and distribute this
 * software is freely granted, provided that this notice
 * software is freely granted, provided that this notice
 * is preserved.
 * is preserved.
 * ====================================================
 * ====================================================
 */
 */
 
 
/*
/*
FUNCTION
FUNCTION
        <<hypot>>, <<hypotf>>---distance from origin
        <<hypot>>, <<hypotf>>---distance from origin
INDEX
INDEX
        hypot
        hypot
INDEX
INDEX
        hypotf
        hypotf
 
 
ANSI_SYNOPSIS
ANSI_SYNOPSIS
        #include <math.h>
        #include <math.h>
        double hypot(double <[x]>, double <[y]>);
        double hypot(double <[x]>, double <[y]>);
        float hypotf(float <[x]>, float <[y]>);
        float hypotf(float <[x]>, float <[y]>);
 
 
TRAD_SYNOPSIS
TRAD_SYNOPSIS
        double hypot(<[x]>, <[y]>)
        double hypot(<[x]>, <[y]>)
        double <[x]>, <[y]>;
        double <[x]>, <[y]>;
 
 
        float hypotf(<[x]>, <[y]>)
        float hypotf(<[x]>, <[y]>)
        float <[x]>, <[y]>;
        float <[x]>, <[y]>;
 
 
DESCRIPTION
DESCRIPTION
        <<hypot>> calculates the Euclidean distance
        <<hypot>> calculates the Euclidean distance
        @tex
        @tex
        $\sqrt{x^2+y^2}$
        $\sqrt{x^2+y^2}$
        @end tex
        @end tex
        @ifnottex
        @ifnottex
        <<sqrt(<[x]>*<[x]> + <[y]>*<[y]>)>>
        <<sqrt(<[x]>*<[x]> + <[y]>*<[y]>)>>
        @end ifnottex
        @end ifnottex
        between the origin (0,0) and a point represented by the
        between the origin (0,0) and a point represented by the
        Cartesian coordinates (<[x]>,<[y]>).  <<hypotf>> differs only
        Cartesian coordinates (<[x]>,<[y]>).  <<hypotf>> differs only
        in the type of its arguments and result.
        in the type of its arguments and result.
 
 
RETURNS
RETURNS
        Normally, the distance value is returned.  On overflow,
        Normally, the distance value is returned.  On overflow,
        <<hypot>> returns <<HUGE_VAL>> and sets <<errno>> to
        <<hypot>> returns <<HUGE_VAL>> and sets <<errno>> to
        <<ERANGE>>.
        <<ERANGE>>.
 
 
        You can change the error treatment with <<matherr>>.
        You can change the error treatment with <<matherr>>.
 
 
PORTABILITY
PORTABILITY
        <<hypot>> and <<hypotf>> are not ANSI C.  */
        <<hypot>> and <<hypotf>> are not ANSI C.  */
 
 
/* hypot(x,y)
/* hypot(x,y)
 *
 *
 * Method :
 * Method :
 *      If (assume round-to-nearest) z=x*x+y*y
 *      If (assume round-to-nearest) z=x*x+y*y
 *      has error less than sqrt(2)/2 ulp, than
 *      has error less than sqrt(2)/2 ulp, than
 *      sqrt(z) has error less than 1 ulp (exercise).
 *      sqrt(z) has error less than 1 ulp (exercise).
 *
 *
 *      So, compute sqrt(x*x+y*y) with some care as
 *      So, compute sqrt(x*x+y*y) with some care as
 *      follows to get the error below 1 ulp:
 *      follows to get the error below 1 ulp:
 *
 *
 *      Assume x>y>0;
 *      Assume x>y>0;
 *      (if possible, set rounding to round-to-nearest)
 *      (if possible, set rounding to round-to-nearest)
 *      1. if x > 2y  use
 *      1. if x > 2y  use
 *              x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
 *              x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
 *      where x1 = x with lower 32 bits cleared, x2 = x-x1; else
 *      where x1 = x with lower 32 bits cleared, x2 = x-x1; else
 *      2. if x <= 2y use
 *      2. if x <= 2y use
 *              t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
 *              t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
 *      where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
 *      where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
 *      y1= y with lower 32 bits chopped, y2 = y-y1.
 *      y1= y with lower 32 bits chopped, y2 = y-y1.
 *
 *
 *      NOTE: scaling may be necessary if some argument is too
 *      NOTE: scaling may be necessary if some argument is too
 *            large or too tiny
 *            large or too tiny
 *
 *
 * Special cases:
 * Special cases:
 *      hypot(x,y) is INF if x or y is +INF or -INF; else
 *      hypot(x,y) is INF if x or y is +INF or -INF; else
 *      hypot(x,y) is NAN if x or y is NAN.
 *      hypot(x,y) is NAN if x or y is NAN.
 *
 *
 * Accuracy:
 * Accuracy:
 *      hypot(x,y) returns sqrt(x^2+y^2) with error less
 *      hypot(x,y) returns sqrt(x^2+y^2) with error less
 *      than 1 ulps (units in the last place)
 *      than 1 ulps (units in the last place)
 */
 */
 
 
#include "fdlibm.h"
#include "fdlibm.h"
 
 
#ifndef _DOUBLE_IS_32BITS
#ifndef _DOUBLE_IS_32BITS
 
 
#ifdef __STDC__
#ifdef __STDC__
        double hypot(double x, double y)
        double hypot(double x, double y)
#else
#else
        double hypot(x,y)
        double hypot(x,y)
        double x, y;
        double x, y;
#endif
#endif
{
{
        double a=x,b=y,t1,t2,y1,y2,w;
        double a=x,b=y,t1,t2,y1,y2,w;
        __int32_t j,k,ha,hb;
        __int32_t j,k,ha,hb;
 
 
        GET_HIGH_WORD(ha,x);
        GET_HIGH_WORD(ha,x);
        ha &= 0x7fffffff;
        ha &= 0x7fffffff;
        GET_HIGH_WORD(hb,y);
        GET_HIGH_WORD(hb,y);
        hb &= 0x7fffffff;
        hb &= 0x7fffffff;
        if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
        if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
        SET_HIGH_WORD(a,ha);    /* a <- |a| */
        SET_HIGH_WORD(a,ha);    /* a <- |a| */
        SET_HIGH_WORD(b,hb);    /* b <- |b| */
        SET_HIGH_WORD(b,hb);    /* b <- |b| */
        if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
        if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
        k=0;
        k=0;
        if(ha > 0x5f300000) {   /* a>2**500 */
        if(ha > 0x5f300000) {   /* a>2**500 */
           if(ha >= 0x7ff00000) {       /* Inf or NaN */
           if(ha >= 0x7ff00000) {       /* Inf or NaN */
               __uint32_t low;
               __uint32_t low;
               w = a+b;                 /* for sNaN */
               w = a+b;                 /* for sNaN */
               GET_LOW_WORD(low,a);
               GET_LOW_WORD(low,a);
               if(((ha&0xfffff)|low)==0) w = a;
               if(((ha&0xfffff)|low)==0) w = a;
               GET_LOW_WORD(low,b);
               GET_LOW_WORD(low,b);
               if(((hb^0x7ff00000)|low)==0) w = b;
               if(((hb^0x7ff00000)|low)==0) w = b;
               return w;
               return w;
           }
           }
           /* scale a and b by 2**-600 */
           /* scale a and b by 2**-600 */
           ha -= 0x25800000; hb -= 0x25800000;  k += 600;
           ha -= 0x25800000; hb -= 0x25800000;  k += 600;
           SET_HIGH_WORD(a,ha);
           SET_HIGH_WORD(a,ha);
           SET_HIGH_WORD(b,hb);
           SET_HIGH_WORD(b,hb);
        }
        }
        if(hb < 0x20b00000) {   /* b < 2**-500 */
        if(hb < 0x20b00000) {   /* b < 2**-500 */
            if(hb <= 0x000fffff) {      /* subnormal b or 0 */
            if(hb <= 0x000fffff) {      /* subnormal b or 0 */
                __uint32_t low;
                __uint32_t low;
                GET_LOW_WORD(low,b);
                GET_LOW_WORD(low,b);
                if((hb|low)==0) return a;
                if((hb|low)==0) return a;
                t1=0;
                t1=0;
                SET_HIGH_WORD(t1,0x7fd00000);   /* t1=2^1022 */
                SET_HIGH_WORD(t1,0x7fd00000);   /* t1=2^1022 */
                b *= t1;
                b *= t1;
                a *= t1;
                a *= t1;
                k -= 1022;
                k -= 1022;
            } else {            /* scale a and b by 2^600 */
            } else {            /* scale a and b by 2^600 */
                ha += 0x25800000;       /* a *= 2^600 */
                ha += 0x25800000;       /* a *= 2^600 */
                hb += 0x25800000;       /* b *= 2^600 */
                hb += 0x25800000;       /* b *= 2^600 */
                k -= 600;
                k -= 600;
                SET_HIGH_WORD(a,ha);
                SET_HIGH_WORD(a,ha);
                SET_HIGH_WORD(b,hb);
                SET_HIGH_WORD(b,hb);
            }
            }
        }
        }
    /* medium size a and b */
    /* medium size a and b */
        w = a-b;
        w = a-b;
        if (w>b) {
        if (w>b) {
            t1 = 0;
            t1 = 0;
            SET_HIGH_WORD(t1,ha);
            SET_HIGH_WORD(t1,ha);
            t2 = a-t1;
            t2 = a-t1;
            w  = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
            w  = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
        } else {
        } else {
            a  = a+a;
            a  = a+a;
            y1 = 0;
            y1 = 0;
            SET_HIGH_WORD(y1,hb);
            SET_HIGH_WORD(y1,hb);
            y2 = b - y1;
            y2 = b - y1;
            t1 = 0;
            t1 = 0;
            SET_HIGH_WORD(t1,ha+0x00100000);
            SET_HIGH_WORD(t1,ha+0x00100000);
            t2 = a - t1;
            t2 = a - t1;
            w  = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
            w  = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
        }
        }
        if(k!=0) {
        if(k!=0) {
            __uint32_t high;
            __uint32_t high;
            t1 = 1.0;
            t1 = 1.0;
            GET_HIGH_WORD(high,t1);
            GET_HIGH_WORD(high,t1);
            SET_HIGH_WORD(t1,high+(k<<20));
            SET_HIGH_WORD(t1,high+(k<<20));
            return t1*w;
            return t1*w;
        } else return w;
        } else return w;
}
}
 
 
#endif /* defined(_DOUBLE_IS_32BITS) */
#endif /* defined(_DOUBLE_IS_32BITS) */
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.