Tôi đã thực hiện một số thử nghiệm với C++
hypot()
và Java
Math.hypot
. Cả hai dường như chậm hơn đáng kể so với sqrt(a*a + b*b)
. Đó có phải là do độ chính xác cao hơn không? Phương pháp nào để tính toán sử dụng chức năng lạm dụng hypot
? Đáng ngạc nhiên là tôi không thể tìm thấy bất kỳ dấu hiệu nào về hiệu suất kém trong tài liệu.Tại sao hàm hypot() quá chậm?
Trả lời
Đây không phải là chức năng sqrt đơn giản. Bạn nên kiểm tra liên kết này để thực hiện các thuật toán: http://www.koders.com/c/fid7D3C8841ADC384A5F8DE0D081C88331E3909BF3A.aspx
Nó có khi vòng lặp để kiểm tra tụ
/* Slower but safer algorithm due to Moler and Morrison. Never
produces any intermediate result greater than roughly the
larger of X and Y. Should converge to machine-precision
accuracy in 3 iterations. */
double r = ratio*ratio, t, s, p = abig, q = asmall;
do {
t = 4. + r;
if (t == 4.)
break;
s = r/t;
p += 2. * s * p;
q *= s;
r = (q/p) * (q/p);
} while (1);
EDIT (Update từ JM):
Here là bản gốc Moler còn-Morrison giấy, và here là một sự theo dõi tốt đẹp do Dubrulle.
Sẽ rất hay để cung cấp cho ví dụ trong trường hợp hàm này tốt hơn phương thức 'sqrt'. – schnaader
@schnaader - đọc trang được liên kết, lý do là đúng ở đầu (phiên bản ngắn, phương pháp ngây thơ có thể tràn khi không nên) – Nir
Điều này quan trọng đối với các giá trị rất lớn của x và y. Ví dụ: nếu x và y là x^2 + y^2 lớn hơn MAX_DOUBLE, phiên bản sqrt (x^2 + y^2) sẽ không thành công. Tuy nhiên, vì phương pháp này không bao giờ tạo ra một giá trị lớn hơn nhiều so với x hoặc y, nên nó phải an toàn trong những tình huống đó. – pfhayes
Đây là một thực hiện nhanh hơn, mà kết quả là cũng gần gũi hơn với java.lang.Math.hypot: (NB: để thực hiện Delorie của, cần thêm xử lý NaN và + vô cực đầu vào)
private static final double TWO_POW_450 = Double.longBitsToDouble(0x5C10000000000000L);
private static final double TWO_POW_N450 = Double.longBitsToDouble(0x23D0000000000000L);
private static final double TWO_POW_750 = Double.longBitsToDouble(0x6ED0000000000000L);
private static final double TWO_POW_N750 = Double.longBitsToDouble(0x1110000000000000L);
public static double hypot(double x, double y) {
x = Math.abs(x);
y = Math.abs(y);
if (y < x) {
double a = x;
x = y;
y = a;
} else if (!(y >= x)) { // Testing if we have some NaN.
if ((x == Double.POSITIVE_INFINITY) || (y == Double.POSITIVE_INFINITY)) {
return Double.POSITIVE_INFINITY;
} else {
return Double.NaN;
}
}
if (y-x == y) { // x too small to substract from y
return y;
} else {
double factor;
if (x > TWO_POW_450) { // 2^450 < x < y
x *= TWO_POW_N750;
y *= TWO_POW_N750;
factor = TWO_POW_750;
} else if (y < TWO_POW_N450) { // x < y < 2^-450
x *= TWO_POW_750;
y *= TWO_POW_750;
factor = TWO_POW_N750;
} else {
factor = 1.0;
}
return factor * Math.sqrt(x*x+y*y);
}
}
http://steve.hollasch.net/cgindex/math/pythag-root.txt
cho thấy triển khai nhanh hơn bằng sqrt() là bậc hai so với khối cho Moler & Morrison, với cùng một đặc điểm tràn.
Tôi đã tìm thấy Math.hypot() rất chậm. Tôi tìm thấy tôi có thể mã một phiên bản java nhanh chóng bằng cách sử dụng cùng một thuật toán tạo ra kết quả giống hệt nhau. Điều này có thể được sử dụng để thay thế nó.
/**
* <b>hypot</b>
* @param x
* @param y
* @return sqrt(x*x +y*y) without intermediate overflow or underflow.
* @Note {@link Math#hypot} is unnecessarily slow. This returns the identical result to
* Math.hypot with reasonable run times (~40 nsec vs. 800 nsec).
* <p>The logic for computing z is copied from "Freely Distributable Math Library"
* fdlibm's e_hypot.c. This minimizes rounding error to provide 1 ulb accuracy.
*/
public static double hypot(double x, double y) {
if (Double.isInfinite(x) || Double.isInfinite(y)) return Double.POSITIVE_INFINITY;
if (Double.isNaN(x) || Double.isNaN(y)) return Double.NaN;
x = Math.abs(x);
y = Math.abs(y);
if (x < y) {
double d = x;
x = y;
y = d;
}
int xi = Math.getExponent(x);
int yi = Math.getExponent(y);
if (xi > yi + 27) return x;
int bias = 0;
if (xi > 510 || xi < -511) {
bias = xi;
x = Math.scalb(x, -bias);
y = Math.scalb(y, -bias);
}
// translated from "Freely Distributable Math Library" e_hypot.c to minimize rounding errors
double z = 0;
if (x > 2*y) {
double x1 = Double.longBitsToDouble(Double.doubleToLongBits(x) & 0xffffffff00000000L);
double x2 = x - x1;
z = Math.sqrt(x1*x1 + (y*y + x2*(x+x1)));
} else {
double t = 2 * x;
double t1 = Double.longBitsToDouble(Double.doubleToLongBits(t) & 0xffffffff00000000L);
double t2 = t - t1;
double y1 = Double.longBitsToDouble(Double.doubleToLongBits(y) & 0xffffffff00000000L);
double y2 = y - y1;
double x_y = x - y;
z = Math.sqrt(t1*y1 + (x_y*x_y + (t1*y2 + t2*y))); // Note: 2*x*y <= x*x + y*y
}
if (bias == 0) {
return z;
} else {
return Math.scalb(z, bias);
}
}
- 1. Tại sao hàm lubridate quá chậm khi so sánh với.POSIXct?
- 2. Tại sao numpy.array quá chậm?
- 3. Tại sao "htmlspecialchars" quá chậm?
- 4. Tại sao ngẫu nhiên.choice quá chậm?
- 5. Tại sao plyr lại quá chậm?
- 6. Tại sao PostgreSQL quá chậm trên Windows?
- 7. Tại sao MySQL trong Node.js quá chậm?
- 8. Tại sao vải Tk lại quá chậm?
- 9. Tại sao tải lên quá chậm?
- 10. Tại sao pypy của deque quá chậm?
- 11. Tại sao putImageData lại quá chậm?
- 12. tại sao ruby scanf quá chậm?
- 13. Tại sao quá trình xây dựng Titanium lại quá chậm?
- 14. tại sao các cuộc gọi hàm trong vòng lặp Perl quá chậm?
- 15. Tại sao jQuery.ready được đề xuất khi quá chậm?
- 16. Tại sao javascript chậm trong?
- 17. Tại sao cấu hình quá chậm trong MSYS?
- 18. Tại sao thời gian khởi động IronPython quá chậm?
- 19. Tại sao trình gỡ lỗi của tôi quá chậm?
- 20. Tại sao git log --cherry-pick quá chậm?
- 21. Tại sao biểu thức Haskell này lại quá chậm?
- 22. Tại sao các vectơ đóng hộp quá chậm?
- 23. Tại sao jQuery Ajax quá chậm trên IE7?
- 24. Tại sao DateTime.Now DateTime.UtcBây giờ quá chậm/tốn kém
- 25. CodedUI: Tại sao tìm kiếm một ô quá chậm?
- 26. Tại sao Eclipse quá chậm khi khởi động?
- 27. Tại sao ứng dụng PyQt khởi động quá chậm?
- 28. Tại sao kết nối với máy chủ MySQL quá chậm?
- 29. Tại sao cuộc gọi mongodb của tôi lại quá chậm?
- 30. tại sao âm mưu với Matplotlib quá chậm?
'chậm hơn đáng kể' là gì? Bạn có thể định lượng giá trị này không? Bạn đã sử dụng một hồ sơ? Bạn đã chạy thử bao nhiêu lần? Bạn có thể mô tả thử nghiệm của mình (DOE) không? – linuxuser27
Trong Java nó chậm hơn một hệ số ~ 7, trong C++ ~ 10. Chúng tôi thấy rằng độc lập với đồng nghiệp của tôi khi thử nghiệm một trong những vấn đề lập trình cho cuộc thi lập trình sắp tới tại một trường đại học. – Leonid
@ linuxuser27: và hai người upvoted bình luận của mình, kiểm tra Ravi Gummadi +9 upvoted câu trả lời cho giác ngộ. – SyntaxT3rr0r