我在哪里可以找到 Java 平方根函数的源代码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/825221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Where can I find the source code for Java's Square Root function?
提问by
I know that Math.sqrt
calls StrictMath.sqrt(double a)
.
我知道Math.sqrt
那叫 StrictMath.sqrt(double a)
.
Method signature in StrictMath
class:
StrictMath
类中的方法签名:
public static native double sqrt(double a);
I was wanting to look at the actual implementation codeused to calculate it.
我想查看用于计算它的实际实现代码。
回答by Mnementh
Download the sourcecode from the OpenJDK.
从 OpenJDK 下载源代码。
回答by Roman
I don't know exactly but I think you'll find Newton's algorithm at the end point.
我不知道确切,但我认为你会在终点找到牛顿算法。
UPD: as comments say concrete implementation depends on concrete java machine. For windows it's probably using assembler implementation, where the standard operator sqrt exists
UPD:正如评论所说,具体实现取决于具体的 java 机器。对于 Windows,它可能使用汇编器实现,其中存在标准运算符 sqrt
回答by Joey
When you install a JDK the source code of the standard library can be found inside src.zip
. This won't help you for StrictMath
, though, as StrictMath.sqrt(double)
is implemented as follows:
当您安装 JDK 时,可以在其中找到标准库的源代码src.zip
。StrictMath
但是,这对您没有帮助,具体StrictMath.sqrt(double)
实现如下:
public static native double sqrt(double a);
So it's really just a native call and might be implemented differently on different platforms by Java.
所以它实际上只是一个本地调用,可能会在不同的平台上由 Java 以不同的方式实现。
However, as the documentation of StrictMath
states:
但是,正如文件StrictMath
所述:
To help ensure portability of Java programs, the definitions of some of the numeric functions in this package require that they produce the same results as certain published algorithms. These algorithms are available from the well-known network library
netlib
as the package "Freely Distributable Math Library," fdlibm. These algorithms, which are written in the C programming language, are then to be understood as executed with all floating-point operations following the rules of Java floating-point arithmetic.The Java math library is defined with respect to fdlibm version 5.3. Where fdlibm provides more than one definition for a function (such as acos), use the "IEEE 754 core function" version (residing in a file whose name begins with the letter e). The methods which require fdlibm semantics are sin, cos, tan, asin, acos, atan, exp, log, log10, cbrt, atan2, pow, sinh, cosh, tanh, hypot, expm1, and log1p.
为了帮助确保 Java 程序的可移植性,此包中某些数字函数的定义要求它们产生与某些已发布算法相同的结果。这些算法可以从著名的网络库中
netlib
作为“自由分发数学库”包 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。
So by finding the appropriate version of the fdlibm
source, you should also find the exact implementation used by Java (and mandated by the specification here).
因此,通过找到fdlibm
源代码的适当版本,您还应该找到 Java 使用的确切实现(并由此处的规范强制执行)。
The implementation used by fdlibm
is
使用的实现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 (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;
回答by Michael Myers
Since I happen to have OpenJDKlying around, I'll show its implementation here.
因为我碰巧有OpenJDK,所以我将在这里展示它的实现。
In jdk/src/share/native/java/lang/StrictMath.c:
在 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
is defined as sqrt
in jdk/src/share/native/java/lang/fdlibm/src/w_sqrt.c (the name is changed through the preprocessor):
jsqrt
被定义为sqrt
在JDK / SRC /共享/天然的/爪哇/郎/ fdlibm / SRC / w_sqrt.c(名字通过预处理器改变):
#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
}
And __ieee754_sqrt
is defined in jdk/src/share/native/java/lang/fdlibm/src/e_sqrt.c as:
并__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;
}
There are copious comments in the file explaining the methods used, which I have omitted for (semi-) brevity. Here's the file in Mercurial(I hope this is the right way to link to it).
文件中有大量注释解释了所使用的方法,为了(半)简洁起见,我省略了这些注释。这是 Mercurial 中的文件(我希望这是链接到它的正确方法)。