Tại sao Math.pow () (đôi khi) không bằng ** trong JavaScript?


118

Tôi vừa phát hiện ra tính năng ECMAScript 7 a**bnhư một sự thay thế cho Math.pow(a,b)( Tài liệu tham khảo MDN ) và xem một cuộc thảo luận trong bài đăng đó , trong đó chúng dường như hoạt động khác nhau. Tôi đã thử nghiệm nó trong Chrome 55 và có thể xác nhận rằng kết quả khác nhau.

Math.pow(99,99) trả lại 3.697296376497263e+197

trong khi

99**99 trả lại 3.697296376497268e+197

Vì vậy, ghi lại sự khác biệt Math.pow(99,99) - 99**99dẫn đến -5.311379928167671e+182.

Cho đến nay, có thể nói, đó chỉ đơn giản là một triển khai khác, nhưng gói nó trong một hàm lại hoạt động khác:

function diff(x) {
  return Math.pow(x,x) - x**x;
}

gọi diff(99)trả lại 0.

Tại sao điều đó lại xảy ra?

Như xszaboj đã chỉ ra, điều này có thể được thu hẹp lại thành vấn đề này:

var x = 99;
x**x - 99**99; // Returns -5.311379928167671e+182

7
Có vẻ như ai đó đã viết lại thuật toán mà họ đã sử dụng và một lỗi dấu phẩy động được tìm thấy. Con số này là khó khăn ...
krillgar

4
@krillgar nghe có vẻ hợp lý, nhưng tại sao lỗi tương tự lại không xảy ra trong một hàm?
Thomas Altmann

3
@AndersonPimentel Liên kết MDN trỏ đến một bảng tương thích .
Álvaro González

7
sự khác biệt là giữa hai điều này: var x = 99; x * * x; và 99 * * 99. Hoặc hàm diff (x) {return 99 * * 99 - (x * * x); }; khác (99). Xin lỗi vì khoảng cách, Comment lọc hai ngôi sao :(
xszaboj

1
@xszaboj đưa mã vào backticks `likethis`để làm cho nó có thể đọc được và cũng tránh đậm / nghiêng vấn đề
phuclv

Câu trả lời:


126

99**99được đánh giá ở thời gian biên dịch ( "liên tục gấp"), và trình biên dịch powthông thường khác với một thời gian chạy . Khi đánh giá **tại thời gian chạy, kết quả giống hệt nhau Math.pow- không có gì lạ vì **thực sự được biên dịch thành một Math.powlệnh gọi:

console.log(99**99);           // 3.697296376497268e+197
a = 99, b = 99;
console.log(a**b);             // 3.697296376497263e+197
console.log(Math.pow(99, 99)); // 3.697296376497263e+197

Thực ra

99 99 = 369729637649726772657187905628805440595668764281741102430259972423552570455277523421410650010128232727940978889548326540119429996769494359451621570193644014418079913999999999999999999999999

vì vậy kết quả đầu tiên là một xấp xỉ tốt hơn, vẫn không xảy ra sự khác biệt như vậy giữa các biểu thức hằng và động.

Hành vi này giống như một lỗi trong V8. Nó đã được báo cáo và hy vọng sẽ sớm được khắc phục.


19
Vì vậy, về cơ bản JS đang cố gắng cải thiện hiệu suất với máy tính 99**99trước? Đây có thể được coi là một lỗi, vì Math.powtạo ra cùng một đầu ra cho các số và biến và **không?
Thomas Altmann

3
@ThomasAltmann: Math.rowluôn là thời gian chạy, việc gấp const chỉ có thể được thực hiện cho các nhà khai thác. Vâng, đó chắc chắn là một lỗi.
georg

11
Một lỗi đã được ghi lại bởi OP ở đây.
James Thorpe

5
Tôi đang sử dụng MS Edge, và tất cả 3 kết quả đều giống nhau: 3.697296376497263e+197, 3.697296376497263e+197, và 3.697296376497263e+197tương ứng. Đó chắc chắn là một lỗi của Chrome.
Nolonar

4
@ThomasAltmann nếu việc gấp liên tục tạo ra giá trị kém hơn so với thời gian chạy thì đó là lỗi. Nếu nó tạo ra giá trị tốt hơn thời gian chạy thì nó có thể bị coi là lỗi hoặc không. Trong trường hợp này, tốt hơn - giá trị chính xác là "... 26772 ...", liên tục gấp tạo ra "... 268" (làm tròn chính xác) và thời gian chạy tạo ra "... 263" (giảm 4+ đơn vị ở vị trí cuối cùng).
hobbs
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.