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

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

安装JDK时,可以在src.zip找到标准库的源代码。 但是,这对StrictMath没有帮助,因为StrictMath.sqrt(double)实现如下:

 public static native double sqrt(double a); 

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

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

为了帮助确保Java程序的可移植性,此程序包中某些数字函数的定义要求它们产生与某些已发布算法相同的结果。 这些算法可以从众所周知的网络库netlib作为“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使用的确切实现(并且此处的规范强制要求)。

fdlibm使用的fdlibm

 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 (xx) / (xx); /* 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> 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; 

因为我碰巧有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 (xx)/(xx); /* 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>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; } 

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

从OpenJDK下载源代码。

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

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