Tôi biết rằng Math.sqrt gọi StrictMath.sqrt (double a) Tôi muốn xem mã thực tế được sử dụng để tính toán nó.Tôi có thể tìm mã nguồn cho chức năng Square Root của Java ở đâu?
Trả lời
Tải xuống mã nguồn từ OpenJDK.
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
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
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
là
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;
Mmmm. Nó gần như quá đơn giản :-) –
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? –
@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
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
}
Và __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ó).
cộng một cho liên kết tới nguồn trong hg – Will
- 1. Tôi có thể tìm mã nguồn của gitk ở đâu?
- 2. Tôi có thể tìm mã nguồn Flex ở đâu?
- 3. Tôi có thể tìm mã nguồn JDK 1.5 ở đâu?
- 4. Tôi có thể tìm mã nguồn C++ ở đâu?
- 5. Tôi có thể tìm nguồn cho System.Web.Optimization ở đâu?
- 6. Tôi có thể tìm mã nguồn của tiện ích Unix ở đâu?
- 7. Tôi có thể tìm hiểu thêm về chức năng dịch thuật của PyPy ở đâu?
- 8. Tôi có thể tìm mã nguồn cho .net CLR và C# ở đâu?
- 9. Tôi có thể tìm tài liệu cho BlueZ ở đâu?
- 10. Bạn có thể tìm mã gốc trong JDK ở đâu?
- 11. Tôi có thể tìm các bản triển khai gốc của các chức năng này ở đâu?
- 12. Tôi có thể tìm phần mềm trực quan hóa mã nguồn mở tốt ở đâu?
- 13. Mã nguồn cho trình biên dịch java ở đâu?
- 14. Tôi có thể xem mã nguồn của JDK của Mặt trời ở đâu?
- 15. Tôi có thể tìm mã mẫu iPad ở đâu
- 16. Tôi có thể tìm các thuật toán đóng gói thùng 2d mã nguồn mở ở đâu?
- 17. Tôi có thể tìm mã nguồn cuộc gọi hệ thống ở đâu?
- 18. Tôi có thể tìm mã nguồn cho tất cả các thư viện chuẩn của C ở đâu?
- 19. Mã nguồn PHP cho các chức năng sẵn có
- 20. Tôi có thể tìm danh sách mã lỗi SQLException cho MySQL ở đâu?
- 21. mã nguồn cho thư viện chuẩn trong ocaml ở đâu?
- 22. Tôi có thể tìm GACUtil ở đâu?
- 23. Tôi có thể tìm hướng dẫn cho Clang ở đâu?
- 24. Tôi có thể tìm nguồn gốc cho lọ lõi lò xo ở đâu?
- 25. Tôi có thể tìm appcmd.exe cho IIS Express ở đâu?
- 26. Tôi có thể xác định nội dung cho một chức năng riêng tư ở đâu?
- 27. tôi có thể lấy mã nhị phân GCC ở đâu?
- 28. Tôi có thể tải xuống mã nguồn của "OpenGL" ở đâu?
- 29. Tôi có thể tìm hiểu về chuỗi JNDI ở đâu?
- 30. Tôi có thể tìm lớp C# cho "Chia sẻ bí mật của Shamir" ở đâu?
Tôi nghĩ rằng Intel có chỉ dẫn sqrt - điều này có đúng không? – Marichyasana