2009-05-05 6 views

답변

0

OpenJDK에서 소스 코드를 다운로드하십시오.

0

정확히 모르겠지만 뉴튼의 알고리즘을 마지막 지점에서 찾을 수있을 것 같습니다.

UPD : 구체적인 구현은 구체적인 자바 머신에 달려 있다고합니다. Windows의 경우 표준 연산자 sqrt가있는 어셈블러 구현을 사용하고 있습니다

+0

어셈블러 opcode는 OS에 의존하지 않으므로 Windows와 관련이 없습니다. 그러나 예, JVM은 C 소스의 다양한 주석에 설명 된대로 기본 명령어를 선호합니다. – Joey

30

JDK를 설치하면 표준 라이브러리의 소스 코드가 src.zip 안에 있습니다.

public static native double sqrt(double a); 

은 그래서 정말 그냥 기본 전화 그리고 자바에 의해 다른 플랫폼에서 다르게 구현 될 수 있습니다 다음과 같이 StrictMath.sqrt(double)이 구현 이것은하지만, StrictMath 당신을 도움이되지 않습니다.

그러나 StrictMath 상태의 문서로 :

는 Java 프로그램의 이식성을 유지하기 위해이 패키지에있는 숫자의 일부 기능의 정의는, 기존의 알고리즘과 같은 결과를내는 것이 요구되고 있습니다. 이 알고리즘은 잘 알려진 네트워크 라이브러리 netlib에서 "Freely Distributable Math Library"패키지 fdlibm으로 구할 수 있습니다. C 프로그래밍 언어로 작성된 이러한 알고리즘은 Java 부동 소수점 산술 규칙에 따라 모든 부동 소수점 연산으로 실행되는 것으로 이해해야합니다.

Java math 라이브러리는 fdlibm 버전 5.3과 관련하여 정의됩니다. fdlibm이 acos와 같은 함수에 대해 둘 이상의 정의를 제공하는 경우, "IEEE 754 core function"버전을 사용하십시오 (이름이 문자 e로 시작하는 파일에 있음). fdlibm 의미를 필요로하는 메소드는 sin, cos, tan, asin, acos, atan, exp, log, log10, cbrt, atan2, pow, sinh, cosh, tanh, hypot, expm1 및 log1p입니다.

따라서 fdlibm 소스의 해당 버전을 찾으면 Java에서 사용되는 정확한 구현을 찾을 수 있습니다 (여기에서 사양에서 필수). 내가 OpenJDK 주위에 거짓말을해야하는 일이 있기 때문에

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; 
+1

음. 그것은 거의 너무 단순합니다 :-) –

+0

저는 이것이 가변 길이 루프없이 어떻게 구현되는지 이해하지 못합니다. LOL. 이것에 대한 설명을 어디에서 찾을 수 있는지 알고 있습니까? –

+0

@GershomMaes : 수학 StackExchange 사이트 중 하나에서 알고리즘이 어떻게 작동하는지 물어볼 것입니다. 코멘트는 질문을위한 것이 아닙니다. – Joey

7

입니다. JDK에서

/SRC/주/기본/자바/랭/StrictMath.c :

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

jsqrt는 JDK에 sqrt로 정의됩니다/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 
} 

그리고 __ieee754_sqrt는 JDK에 정의되어/SRC/주/기본/자바/랭/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 (올바른 방법이 연결되기를 바랍니다.)

+0

+ hg 소스에 대한 링크 1 개 – Will

관련 문제