2012-04-13 25 views
12

Tôi đã nhìn thấy một số câu hỏi về mô phỏng và hình ảnh động trong javascript, mà thường liên quan đến tính cạnh huyền:hypotenuse nhanh nhất trong javascript?

hypot = Math.sqrt(x*x + y*y); 

Kể từ tọa độ Descartes là vũ khí của sự lựa chọn trong hầu hết các động cơ, những tính toán này là cần thiết để tìm khoảng cách giữa các cặp điểm, vv Vì vậy, bất kỳ sự tăng tốc nào trong việc tính toán cạnh huyền có thể là một trợ giúp lớn cho nhiều dự án.

Để kết thúc, bạn có thể thấy phương pháp nhanh hơn so với triển khai đơn giản ở trên không? Tôi đã tìm thấy một phép tính xấp xỉ nhanh hơn trong Chrome, nhưng hóa ra lại chậm hơn nhiều trong Firefox, dựa trên this approximation function in SuperCollider.

Chỉnh sửa 2015-08-15: Tôi đã chuyển câu trả lời được chấp nhận thành Math.hypot; Tôi nghi ngờ cách tiếp cận thực dụng hiện nay sẽ là sử dụng Math.hypot hoặc một hàm hypot tổng hợp nếu không có sẵn, và để so sánh với hình vuông (mỗi câu trả lời của sch) nếu điều đó là đủ và Math.hypot không có sẵn.

+3

bạn luôn có thể sử dụng [số 0x5f3759df kỳ diệu] (http://en.wikipedia.org/wiki/Fast_inverse_square_root) – violet313

+1

Đó là cao quý của bạn muốn tăng tốc độ mỗi kịch bản có sử dụng công thức Pythagore. Tuy nhiên, tôi không nghĩ rằng một giải pháp chung tồn tại để làm cho công thức nhanh hơn (nếu không chúng tôi sẽ không sử dụng phiên bản 2.500 tuổi). Thay vì cố gắng làm cho công thức nhanh hơn, hãy cố gắng cấu trúc lại mã của bạn để bạn sử dụng công thức ít hơn, và chỉ sau khi bạn đã chứng minh rằng công thức là nút cổ chai trong hiệu suất mã của bạn. – Kevin

+0

@Kevin: Trong C hoặc một số ngôn ngữ khác với chi phí thấp hơn, thực sự có xấp xỉ làm tăng tốc độ mọi thứ. Liệu tính xấp xỉ có hữu ích hay không phụ thuộc vào độ chính xác cần thiết của một mô hình, nhưng đối với vật lý trò chơi, nó sẽ đáng giá nếu nó làm cho gameplay trở nên linh hoạt hơn. –

Trả lời

1

Trong ECMAScript ES6 bạn có thể sử dụng Math.hypot:

// ES5 support 
 

 
Math.hypot = Math.hypot || function(x, y){ return Math.sqrt(x*x + y*y) } 
 

 
var x = 3, y = 4; 
 

 
document.write(Math.hypot(x, y))

Sửa: Bạn có thể chạy thử nghiệm này trên một tab trống, là 2 triệu hoạt động với cả hai phương pháp, kết quả rất tốt, nhanh hơn 24%.

var i, tmp, x = 55, y = 66, end, ini = performance.now(); 

// Math.sqrt operation 
i = 0; 
ini = performance.now(); 
tmp = 0; 
while(i++ < 2000000){ 
    tmp += Math.sqrt(x*x + y*y) 
} 
end = performance.now(); 
console.log(tmp, "Math.sqrt operation: " + (end - ini) + " ms"); 

// Math.hypot 

i = 0; 
ini = performance.now(); 
tmp = 0; 
while(i++ < 2000000){ 
    tmp += Math.hypot(x, y) 
} 
end = performance.now(); 

console.log(tmp, "Math.hypot: " + (end - ini) + " ms"); 

Note: Trong thử nghiệm này, nó được sử dụng ES6 của Math.hypot.

enter image description here

+0

Ooh, bất kỳ ý tưởng nào về hiệu suất của nó? –

+0

@PhilH Chỉnh sửa, tôi đã thử nghiệm thao tác với Math.sqrt và Math.hypot, bạn có thể thấy nó. Trong thử nghiệm này, chức năng ban đầu của Math.hypot được sử dụng –

+0

'hypot' xuất hiện liên tục chậm hơn trên Chrome 62. Tôi đã cố gắng đặt nó trong một chức năng nghiêm ngặt để giảm thiểu sự can thiệp bên ngoài (https://gist.github.com/anonymous/159187ac9a8d3caf97737cd9cf551c1a), nhưng sqrt vẫn hoạt động nhanh hơn. Có lẽ họ đã thêm một số bảo vệ chống lại tràn/underflow tại một số điểm? – Arthur2e5

13

Thông thường, bạn không cần tính căn bậc hai và hypot^2 = x*x + y*y là đủ. Đây là trường hợp ví dụ nếu bạn muốn so sánh khoảng cách và không cần các giá trị thực tế.

0

Bạn có thể xem xét mức độ bình đẳng của xy. Nếu bằng với bạn có thể tính toán hypotenuse là (x + y)/sqrt(2) trong đó sqrt(2) là hằng số.

Vì vậy, phương pháp này có thể được sử dụng cho trường hợp x = y. Đối với các trường hợp khác, nó có thể được sử dụng với số lần hiển thị tối đa là ~ 41%. Đây là một lỗi lớn. Nhưng khi bạn chỉ định giới hạn lỗi cho phép, bạn có thể sử dụng phương pháp này. Ví dụ: nếu xác định lỗi cho phép đến 5%, bạn có thể nhận được rằng b phải nằm trong khoảng từ 0.515*a đến 1.942*a.

Vì vậy, nếu bạn không cần sự thiếu chính xác về tính toán của mình, bạn có thể cải thiện hiệu suất tính toán với phạm vi giá trị.

Bằng cách tương tự, bạn có thể xem xét mức độ bình đẳng của x hoặc y đến zero. Và với một số tính toán chính xác hypotenuse nhanh hơn cho các trường hợp này.

P.S. Tôi đã đọc về điều này trong một số russian article.

6

Một điểm quan trọng mà nhiều người không biết:

hypot = Math.sqrt(x*x + y*y);

đó làm việc trên lý thuyết, nhưng trong thực tế nó có thể thất bại. Nếu x là quá lớn rằng x * x tràn, mã sẽ tạo ra một kết quả vô hạn.

Dưới đây là cách tính toán sqrt (x x + y y) mà không có rủi ro tràn.

max = maximum(|x|, |y|) 
min = minimum(|x|, |y|) 
r = min/max 
return max*sqrt(1 + r*r) 

Tham chiếu và đầy đủ văn bản: John D.Cook - http://www.johndcook.com/blog/2010/06/02/whats-so-hard-about-finding-a-hypotenuse/

+0

(cộng với một) nó là tốt để đề cập đến vấn đề thực hiện như tính toán tràn vv .. –

+0

cộng với một chi tiết, đảm bảo ít nhất một trong 'x' và' y' là khác không, nếu không kết quả sẽ là 'vô cùng ' –

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