Чому Math.pow () (іноді) не дорівнює ** у JavaScript?


118

Щойно я виявив функцію ECMAScript 7 a**bяк альтернативу Math.pow(a,b)( MDN Reference ) і натрапив на обговорення в цьому пості , в якому вони, мабуть, поводяться по-різному. Я перевірив це в Chrome 55 і можу підтвердити, що результати відрізняються.

Math.pow(99,99) повертає 3.697296376497263e+197

тоді як

99**99 повертає 3.697296376497268e+197

Таким чином, реєстрація різниці Math.pow(99,99) - 99**99призводить до -5.311379928167671e+182.

Поки що можна було сказати, що це просто інша реалізація, але вбудовування її у функцію знову поводиться інакше:

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

дзвінки diff(99)повертаються 0.

Чому це відбувається?

Як вказував xszaboj , це може бути звужене до цієї проблеми:

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

7
Здається, що хтось переписав алгоритм, який вони використовували, і виявлена помилка з плаваючою комою . Числа важкі ...
krillgar

4
@krillgar здається розумним, але чому тоді ця функція не відбувається в функції?
Томас Альтманн

3
@AndersonPimentel Посилання MDN вказує на таблицю сумісності .
Альваро Гонсалес

7
різниця між цими двома: var x = 99; х * * х; і 99 * * 99. Або функція diff (x) {return 99 * * 99 - (x * * x); }; розл. (99). Вибачте за інтервал, Коментар фільтрує дві зірки :(
xszaboj

1
@xszaboj помістив код в основу, `likethis`щоб зробити його читабельним, а також уникнути сміливої ​​/ курсивної проблеми
phuclv

Відповіді:


126

99**99буде оцінено під час компіляції ( «постійного складання»), а також компілятор powпідпрограма відрізняється від виконання одного . Оцінюючи **час виконання, результати ідентичні Math.pow- недарма, оскільки **насправді складається на Math.powвиклик:

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

Насправді

99 99 = 36972963764972677265718790562880544059566876428174110243025997242355257045527752342141065001012823272794097888954832654011942999676949435945162157019364401441807999907999907997337337337337337337337337337337337337337684684684684684684684684687687687687 018 012 262 262 26 27, 30, 30, 30, 30, 33'97, 3990, 399, 490, 419, 390

тому перший результат є кращим наближенням, все ж така розбіжність між постійними та динамічними виразами не повинна мати місце.

Така поведінка схожа на помилку у V8. Про це повідомляється і, сподіваємось, незабаром виправлять.


19
То в основному JS намагається покращити продуктивність 99**99заздалегідь з обчисленнями ? Чи можна це вважати помилкою, оскільки Math.powстворює однаковий вихід для чисел та змінних, а **ні?
Томас Алтманн

3
@ThomasAltmann: Math.rowзавжди виконується, складання const може бути зроблено лише для операторів. Так, це безумовно помилка.
georg

11
Помилка була зареєстрована , тут виглядають речі ОП.
Джеймс Торп

5
Я використовую MS Грань, і все 3 результати однакові: 3.697296376497263e+197, 3.697296376497263e+197, і 3.697296376497263e+197відповідно. Це, безумовно, помилка Chrome.
Нолонар

4
@ThomasAltmann, якщо постійне складання дає гірше значення, ніж імпульс виконання, то це помилка. Якщо він дає кращі значення, ніж час виконання, то це може бути або не вважатися помилкою. У цьому випадку краще - правильне значення "... 26772 ...", постійне складання створює "... 268" (правильно округлене), а час виконання створює "... 263" (вимкнено на 4+ одиниці в останньому місці).
варення
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.