2009-05-05 38 views

Trả lời

0

Tải xuống mã nguồn từ OpenJDK.

0

Tôi không biết chính xác nhưng tôi nghĩ bạn sẽ tìm thấy thuật toán của Newton ở điểm cuối.

UPD: như ý kiến ​​nói rằng việc triển khai cụ thể phụ thuộc vào máy java cụ thể. Đối với các cửa sổ, có thể sử dụng trình biên dịch thực thi, nơi toán tử chuẩn sqrt tồn tại

+0

Các opcode mã hóa không phụ thuộc vào hệ điều hành, do đó không có liên quan gì đến Windows. Nhưng có, JVM sẽ ưu tiên một hướng dẫn gốc như được nêu chi tiết trong các nhận xét khác nhau của nguồn C. – Joey

30

Khi bạn cài đặt JDK, mã nguồn của thư viện chuẩn có thể tìm thấy bên trong src.zip. Điều này sẽ không giúp bạn cho StrictMath, tuy nhiên, như StrictMath.sqrt(double) được thực hiện như sau:

public static native double sqrt(double a); 

Vì vậy, nó thực sự chỉ là một cuộc gọi mẹ đẻ và có thể được thực hiện khác nhau trên các nền tảng khác nhau bằng Java.

Tuy nhiên, như các tài liệu hướng dẫn của StrictMath trạng thái:

Để giúp đảm bảo tính di động của các chương trình Java, các định nghĩa của một số các chức năng số trong gói này yêu cầu họ xuất trình kết quả tương tự như thuật toán được công bố cụ thể. Các thuật toán này có sẵn từ thư viện mạng nổi tiếng netlib làm gói "Thư viện toán phân phối tự do", fdlibm. Các thuật toán này, được viết bằng ngôn ngữ lập trình C, sau đó được hiểu là được thực thi với tất cả các phép toán dấu phẩy động theo các quy tắc của số học dấu chấm động Java.

Thư viện toán học Java được định nghĩa liên quan đến fdlibm phiên bản 5.3. Trong đó fdlibm cung cấp nhiều hơn một định nghĩa cho một hàm (chẳng hạn như acos), sử dụng phiên bản "IEEE 754 core function" (nằm trong một tệp có tên bắt đầu bằng chữ cái e). Các phương thức yêu cầu ngữ nghĩa fdlibm là sin, cos, tan, asin, acos, atan, exp, log, log10, cbrt, atan2, pow, sinh, cosh, tanh, hypot, expm1 và log1p.

Vì vậy, bằng cách tìm phiên bản thích hợp của nguồn fdlibm, bạn cũng nên tìm cách triển khai chính xác được sử dụng bởi Java (và bắt buộc theo đặc tả tại đây).

Việc thực hiện được sử dụng bởi 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

Mmmm. Nó gần như quá đơn giản :-) –

+0

Tôi chỉ không hiểu làm thế nào điều này được thực hiện mà không có vòng biến chiều dài lol. Bạn có biết nơi để tìm một lời giải thích cho điều này? –

+0

@GershomMaes: Tôi có thể hỏi về cách thuật toán hoạt động trên một trong các trang web StackExchange toán học. Nhận xét không dành cho câu hỏi. – Joey

7

Kể từ khi tôi tình cờ có OpenJDK nằm xung quanh, tôi sẽ thực hiện nó ở đây.

Trong jdk/src/share/mẹ đẻ/java/lang/StrictMath.c:

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

jsqrt được định nghĩa là sqrt trong jdk/src/share/mẹ đẻ/java/lang/fdlibm/src/w_sqrt.c (tên được thay đổi thông qua tiền xử lý):

#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 được định nghĩa trong jdk/src/share/mẹ đẻ/java/lang/fdlibm/src/e_sqrt.c là:

#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; 
} 

Có các nhận xét phong phú trong tệp giải thích các phương pháp được sử dụng mà tôi đã bỏ qua (bán) ngắn gọn. Here's the file in Mercurial (Tôi hy vọng đây là cách phù hợp để liên kết với nó).

+0

cộng một cho liên kết tới nguồn trong hg – Will

Các vấn đề liên quan