Автор оригинала: FreeCodeCamp Community Member.
Кристоф Мишель
Я всегда думал, что новый оператор ES6 Exponentiation x ** y был таким же, как Math.pow (x, y) Отказ
Действительно, это то, что Спецификация говорит о Математика :
12.6.4 – Применение ** Оператор утверждает, что результат является Зависимый от внедрения – Но все равно не должно быть несоответствие между ** и Math.pow Отказ
Однако, оценивая следующее в текущем движке V8 JS (Chrome/Node) в этом:
console.log('1.35 ** 92', 1.35 ** 92) // 978828715394.7672console.log('Math.pow(1.35, 92)', Math.pow(1.35, 92)) // 978828715394.767Оператор Exponentiation ** Возвращает более точное приближение.
Но это не единственная странная странность с оператором Exponentiation: давайте попробуем оценить то же самое с переменными ( repl ) – это не должно иметь никакого значения:
const exponent = 92;console.log(`1.35 ** exponent`, 1.35 ** exponent) // 978828715394.767console.log('1.35 ** 92', 1.35 ** 92) // 978828715394.7672console.log(`Math.pow(1.35, exponent)`, Math.pow(1.35, exponent)) // 978828715394.767console.log('Math.pow(1.35, 92)', Math.pow(1.35, 92)) // 978828715394.767Но это делает: 1.35 ** 92 отличается от 1.35 ** экспонент Отказ
Так что, кажется, здесь происходит, что компилятор обрабатывает код JS 1.35 ** 92 который уже постоянный сложенный
Это имеет смысл, так как V8 действительно компилирует машинный код.
V8 увеличивает производительность, составив JavaScript на родной машинный код перед его выполнением, по сравнению с выполнением Bytecode или интерпретации его.
V8 работает, сначала интерпретируя код JS со своими Переводчик зажигания. Это делает второй пробег с Turbofan Compiler Оптимизация .. Машинный код Отказ
Турбофан сейчас делает постоянная складная. Его алгоритм Exponentiation имеет лучшую точность, чем алгоритм Exponentiation jit Compiler (зажигание).
Если вы попробуете то же самое в других двигателях JS, как Firefox’s Spidermonkey. Результатом является последовательное значение 978828715394.767 Среди всех вычислений.
Это ошибка?
Я бы так сказал, хотя это не было серьезным в моем коде. Но это все еще не следит за спецификацией, который говорит Математика и ** должен привести к тому же величине.
Если вы транспилите код с Babel, x ** y переводится на Math.pow (x, y) , который снова приводит к расхождениям между транспортированным и непереданным кодом. Как мы видели, Math.pow (1.35, 92) это не Быть оптимизированным (только операторы кажутся оптимизированными V8). Поэтому 1.35 ** 92 Результаты в разном коде, когда транспортирован до ES5 Отказ
Используя эту ошибку и игнорируя любые практики чистого кода, мы можем написать приятную функцию, чтобы определить, запускаем ли мы на Chrome (если вы не транспортируете свой код?):
function isChrome() { return 1.35 ** 92 !== Math.pow(1.35, 92)}Все еще более читаемый, чем строки агента пользователя. ?
Первоначально опубликовано в cmichel.io
Оригинал: “https://www.freecodecamp.org/news/i-found-a-bug-in-v8s-exponentiation-operator-dcddfa5b8482/”