在哪里可以找到Java';s平方根函数?
我知道在哪里可以找到Java';s平方根函数?,java,math.sqrt,Java,Math.sqrt,我知道Math.sqrt调用StrictMath.sqrt(双a) StrictMath类中的方法签名: public static native double sqrt(double a); 我想看看用于计算它的实际实现代码 从OpenJDK下载源代码。我不太清楚,但我想你会在最后找到牛顿算法 UPD:正如评论所说,具体的实现取决于具体的java机器。对于windows,它可能使用汇编程序实现,其中存在标准运算符sqrt安装JDK时,可以在src.zip中找到标准库的源代码。这对stricm
Math.sqrt
调用StrictMath.sqrt(双a)
StrictMath
类中的方法签名:
public static native double sqrt(double a);
我想看看用于计算它的实际实现代码 从OpenJDK下载源代码。我不太清楚,但我想你会在最后找到牛顿算法
UPD:正如评论所说,具体的实现取决于具体的java机器。对于windows,它可能使用汇编程序实现,其中存在标准运算符sqrt安装JDK时,可以在
src.zip
中找到标准库的源代码。这对stricmath
没有帮助,因为stricmath.sqrt(double)
的实现如下:
public static native double sqrt(double a);
因此,它实际上只是一个本机调用,可能在不同的平台上通过Java实现
但是,正如StrictMath的文档所述:
为了帮助确保Java程序的可移植性,此包中某些数值函数的定义要求它们产生与某些已发布算法相同的结果。这些算法可从著名的网络库netlib
中获得,作为“可自由分发的数学库”包。这些算法是用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、hypop、expm1和log1p 因此,通过找到适当版本的
fdlibm
源代码,您还应该找到Java使用的确切实现(这里的规范要求)
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;
static const double one=1.0,tiny=1.0e-300;
双z;
整数符号=(整数)0x8000000;
无符号r,t1,s1,ix1,q1;
intix0,s0,q,m,t,i;
ix0=_HI(x);/*x的高位字*/
ix1=_LO(x);/*低x字*/
/*注意Inf和NaN*/
如果((ix0&0x7ff00000)==0x7ff00000){
返回x*x+x;/*sqrt(NaN)=NaN,
sqrt(+inf)=+inf,
sqrt(-inf)=sNaN*/
}
/*照顾零*/
如果(ix0>20);
如果(m==0){/*次正规x*/
而(ix0==0){
m-=21;
ix0 |=(ix1>>11);ix1=1;/*m=[m/2]*/
/*逐位生成sqrt(x)*/
ix0+=ix0+((ix1和符号)>>31);
ix1+=ix1;
q=q1=s0=s1=0;/*[q,q1]=sqrt(x)*/
r=0x00200000;/*r=从右向左移动位*/
while(r!=0){
t=s0+r;
如果(t>31);
ix1+=ix1;
r> >=1;
}
r=符号;
while(r!=0){
t1=s1+r;
t=s0;
if((t31);
ix1+=ix1;
r>>=1;
}
/*使用浮动加法查找舍入方向*/
如果((ix0 | ix1)!=0){
z=一个-微小;/*触发不精确标志*/
如果(z>=1){
z=一+微小;
如果(q1==(无符号)0xffffffff{
q1=0;
q+=1;
}
}否则,如果(z>1){
如果(q1==(无符号)0xFFFFFE){
q+=1;
}
q1+=2;
}否则
q1+=(q1和1);
}
}
ix0=(q>>1)+0x3fe00000;
ix1=q1>>1;
如果((q&1)=1)ix1 |=符号;
ix0+=(m因为我碰巧有一个空闲时间,所以我将在这里展示它的实现
在jdk/src/share/native/java/lang/stricmath.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
(名称通过预处理器更改):
文件中有大量的注释解释了使用的方法,为了(半)简洁,我省略了这些注释。(我希望这是链接到它的正确方式)。Mmmm。它几乎太简单了:-)我只是不明白在没有变长循环lol的情况下是如何实现的。你知道在哪里可以找到对此的解释吗?@GershomMaes:我可能会问一下该算法在一个mathematics StackExchange网站上是如何工作的。评论不是用来提问的。需要fdlibm语义的方法有sin、cos、tan、asin、acos、atan、exp、log、log10、cbrt、atan2、pow、sinh、cosh、tanh、hypop、expm1和log1p。“-所以sqrt不是其中之一?汇编程序操作码不依赖操作系统,因此与Windows无关。但是,是的,JVM会喜欢C源代码的各种注释中详细说明的本机指令。加上hgI中指向源代码的链接,我认为英特尔有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
}
#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;
}