在哪里可以找到Java的Square Root函数的源代码?

时间:2009-05-05 14:47:58

标签: java math.sqrt

我知道Math.sqrt调用StrictMath.sqrt(double a) 我想查看用于计算它的实际代码。

4 个答案:

答案 0 :(得分:30)

安装JDK时,可以在src.zip中找到标准库的源代码。但是,StrictMathStrictMath.sqrt(double)无效,因为public static native double sqrt(double a); 的实施方式如下:

StrictMath

所以它实际上只是一个本机调用,并且可能在Java的不同平台上以不同的方式实现。

但是,正如netlib所述的文档:

  

为了帮助确保Java程序的可移植性,此程序包中某些数字函数的定义要求它们产生与某些已发布算法相同的结果。这些算法可以从着名的网络库fdlibm获得,作为“Freely Distributable Math Library”fdlibm包。然后,这些以C编程语言编写的算法应理解为遵循Java浮点算法规则的所有浮点运算。

     

Java数学库是根据fdlibm 5.3版定义的。其中fdlibm为函数提供了多个定义(例如acos),请使用“IEEE 754核心函数”版本(驻留在名称以字母e开头的文件中)。需要fdlibm语义的方法是sin,cos,tan,asin,acos,atan,exp,log,log10,cbrt,atan2,pow,sinh,cosh,tanh,hypot,expm1和log1p。

因此,通过查找fdlibm源的适当版本,您还应该找到Java使用的确切实现(并且此处的规范强制要求)。

static const double one = 1.0, tiny=1.0e-300; double z; int sign = (int) 0x80000000; unsigned r, t1, s1, ix1, q1; int ix0, s0, q, m, t, i; ix0 = __HI(x); /* high word of x */ ix1 = __LO(x); /* low word of x */ /* take care of Inf and NaN */ if ((ix0 & 0x7ff00000) == 0x7ff00000) { return x*x+x; /* sqrt(NaN) = NaN, sqrt(+inf) = +inf, sqrt(-inf) = sNaN */ } /* take care of zero */ if (ix0 <= 0) { if (((ix0&(~sign)) | ix1) == 0) { return x; /* sqrt(+-0) = +-0 */ } else if (ix0 < 0) { return (x-x) / (x-x); /* sqrt(-ve) = sNaN */ } } /* normalize x */ m = (ix0 >> 20); if (m == 0) { /* subnormal x */ while (ix0==0) { m -= 21; ix0 |= (ix1 >> 11); ix1 <<= 21; } for (i=0; (ix0&0x00100000)==0; i++) { ix0 <<= 1; } m -= i-1; ix0 |= (ix1 >> (32-i)); ix1 <<= i; } m -= 1023; /* unbias exponent */ ix0 = (ix0&0x000fffff)|0x00100000; if (m&1) { /* odd m, double x to make it even */ ix0 += ix0 + ((ix1&sign) >> 31); ix1 += ix1; } m >>= 1; /* m = [m/2] */ /* generate sqrt(x) bit by bit */ ix0 += ix0 + ((ix1 & sign)>>31); ix1 += ix1; q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ r = 0x00200000; /* r = moving bit from right to left */ while (r != 0) { t = s0 + r; if (t <= ix0) { s0 = t+r; ix0 -= t; q += r; } ix0 += ix0 + ((ix1&sign)>>31); ix1 += ix1; r>>=1; } r = sign; while (r != 0) { t1 = s1+r; t = s0; if ((t<ix0) || ((t == ix0) && (t1 <= ix1))) { s1 = t1+r; if (((t1&sign) == sign) && (s1 & sign) == 0) { s0 += 1; } ix0 -= t; if (ix1 < t1) { ix0 -= 1; } ix1 -= t1; q1 += r; } ix0 += ix0 + ((ix1&sign) >> 31); ix1 += ix1; r >>= 1; } /* use floating add to find out rounding direction */ if((ix0 | ix1) != 0) { z = one - tiny; /* trigger inexact flag */ if (z >= one) { z = one+tiny; if (q1 == (unsigned) 0xffffffff) { q1=0; q += 1; } } else if (z > one) { if (q1 == (unsigned) 0xfffffffe) { q+=1; } q1+=2; } else q1 += (q1&1); } } ix0 = (q>>1) + 0x3fe00000; ix1 = q 1>> 1; if ((q&1) == 1) ix1 |= sign; ix0 += (m <<20); __HI(z) = ix0; __LO(z) = ix1; return z; 使用的实现

{{1}}

答案 1 :(得分:7)

由于我碰巧有OpenJDK,我会在这里展示它的实现。

在jdk / src / share / native / java / lang / StrictMath.c中:

JNIEXPORT jdouble JNICALL
Java_java_lang_StrictMath_sqrt(JNIEnv *env, jclass unused, jdouble d)
{
    return (jdouble) jsqrt((double)d);
}

jsqrt在jdk / src / share / native / java / lang / fdlibm / src / w_sqrt.c中定义为sqrt(名称通过预处理器更改):

#ifdef __STDC__
        double sqrt(double x)           /* wrapper sqrt */
#else
        double sqrt(x)                  /* wrapper sqrt */
        double x;
#endif
{
#ifdef _IEEE_LIBM
        return __ieee754_sqrt(x);
#else
        double z;
        z = __ieee754_sqrt(x);
        if(_LIB_VERSION == _IEEE_ || isnan(x)) return z;
        if(x<0.0) {
            return __kernel_standard(x,x,26); /* sqrt(negative) */
        } else
            return z;
#endif
}

__ieee754_sqrt在jdk / src / share / native / java / lang / fdlibm / src / e_sqrt.c中定义为:

#ifdef __STDC__
static  const double    one     = 1.0, tiny=1.0e-300;
#else
static  double  one     = 1.0, tiny=1.0e-300;
#endif

#ifdef __STDC__
        double __ieee754_sqrt(double x)
#else
        double __ieee754_sqrt(x)
        double x;
#endif
{
        double z;
        int     sign = (int)0x80000000;
        unsigned r,t1,s1,ix1,q1;
        int ix0,s0,q,m,t,i;

        ix0 = __HI(x);                  /* high word of x */
        ix1 = __LO(x);          /* low word of x */

    /* take care of Inf and NaN */
        if((ix0&0x7ff00000)==0x7ff00000) {
            return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
                                           sqrt(-inf)=sNaN */
        }
    /* take care of zero */
        if(ix0<=0) {
            if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
            else if(ix0<0)
                return (x-x)/(x-x);             /* sqrt(-ve) = sNaN */
        }
    /* normalize x */
        m = (ix0>>20);
        if(m==0) {                              /* subnormal x */
            while(ix0==0) {
                m -= 21;
                ix0 |= (ix1>>11); ix1 <<= 21;
            }
            for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
            m -= i-1;
            ix0 |= (ix1>>(32-i));
            ix1 <<= i;
        }
        m -= 1023;      /* unbias exponent */
        ix0 = (ix0&0x000fffff)|0x00100000;
        if(m&1){        /* odd m, double x to make it even */
            ix0 += ix0 + ((ix1&sign)>>31);
            ix1 += ix1;
        }
        m >>= 1;        /* m = [m/2] */

    /* generate sqrt(x) bit by bit */
        ix0 += ix0 + ((ix1&sign)>>31);
        ix1 += ix1;
        q = q1 = s0 = s1 = 0;   /* [q,q1] = sqrt(x) */
        r = 0x00200000;         /* r = moving bit from right to left */

        while(r!=0) {
            t = s0+r;
            if(t<=ix0) {
                s0   = t+r;
                ix0 -= t;
                q   += r;
            }
            ix0 += ix0 + ((ix1&sign)>>31);
            ix1 += ix1;
            r>>=1;
        }

        r = sign;
        while(r!=0) {
            t1 = s1+r;
            t  = s0;
            if((t<ix0)||((t==ix0)&&(t1<=ix1))) {
                s1  = t1+r;
                if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
                ix0 -= t;
                if (ix1 < t1) ix0 -= 1;
                ix1 -= t1;
                q1  += r;
            }
            ix0 += ix0 + ((ix1&sign)>>31);
            ix1 += ix1;
            r>>=1;
        }

    /* use floating add to find out rounding direction */
        if((ix0|ix1)!=0) {
            z = one-tiny; /* trigger inexact flag */
            if (z>=one) {
                z = one+tiny;
                if (q1==(unsigned)0xffffffff) { q1=0; q += 1;}
                else if (z>one) {
                    if (q1==(unsigned)0xfffffffe) q+=1;
                    q1+=2;
                } else
                    q1 += (q1&1);
            }
        }
        ix0 = (q>>1)+0x3fe00000;
        ix1 =  q1>>1;
        if ((q&1)==1) ix1 |= sign;
        ix0 += (m <<20);
        __HI(z) = ix0;
        __LO(z) = ix1;
        return z;
}

文件中有大量的注释解释了所使用的方法,我省略了(半)简洁。 Here's the file in Mercurial(我希望这是链接到它的正确方法)。

答案 2 :(得分:0)

从OpenJDK下载源代码。

答案 3 :(得分:0)

我不确切知道,但我认为你会在终点找到牛顿算法。

UPD:评论说具体实现取决于具体的java机器。对于Windows,它可能使用汇编程序实现,其中标准运算符sqrt存在