Если вы попробуете 9n**9n**9n в консоли Chrome, Chrome сломается (напоминает бесконечный цикл). Почему это происходит?

Если вы попробуете 9n**9n**9n в консоли Chrome, Chrome сломается (напоминает бесконечный цикл).

  • В двигателе V8 не хватает реализации для этого случая?

Я имею в виду, что если вы попробуете 9**9**9, он вернет Infinity, что довольно мило.

  • Почему V8 не возвращает Infinity в первом случае?
  • И почему кажется, что он входит в бесконечный цикл?

Я пробовал это и в Firefox, и этой проблемы не существует, потому что в настоящее время в SpiderMonkey нет реализации BigInt.

Спасибо!


person Tiberiu    schedule 28.11.2018    source источник
comment
Просто вопрос, что такое 9n**9n? Является ли n любым числом? Просто для уточнения.   -  person lloydaf    schedule 28.11.2018
comment
BigInt создается добавлением n в конец целочисленного литерала — 10n — или вызовом функции BigInt(). Это из MDN developer.mozilla.org/en- США/документы/Интернет/JavaScript/Справочник/   -  person Tiberiu    schedule 28.11.2018
comment
Я использую Edge только для чтения epubs на своем компьютере. Это очень здорово.   -  person Tiberiu    schedule 28.11.2018
comment
кажется, что хром может доходить до 9n**9n**5n, но длина этого числа также составляет 56349 символов.   -  person Stender    schedule 28.11.2018
comment
Да, это так. Я использую Edge на своем мобильном телефоне через Chrome и Firefox, но для консоли отладки я использую Firefox.   -  person ms2r    schedule 28.11.2018


Ответы (3)


Как уже было сказано, 9n — это BigInt-представление 9.

Оператор ** (мощность) работает справа налево, что приводит к быстрой эскалации результатов:

2n**2n**2n === 2n ** 4n === 16n
3n**3n**3n === 3n ** 27n === 7625597484987n
4n**4n**4n === 4n ** 256n === 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096n

В моей системе это становится довольно медленным с 7n**7n**7n, что занимает около 32 секунд для вычисления печати. В результате получается 695976 цифр, первые 5000 из которых выводятся в консоль.

Я больше не пробовал, но я бы сказал, что это просто пережевывает результат. На вычисление print могут уйти часы или дни (или, возможно, в какой-то момент может даже возникнуть ситуация Out Of Memory).

Обновление:

Я только что попробовал var x = 7n**7n**7n в консоли Chrome, поэтому просто присвоил его переменной, и это закончилось почти мгновенно. Оказывается, преобразование bigint в строку требует времени; печать x.toString().length занимает столько же времени, сколько и печать x или 7n**7n**7n.

Дальнейшие эксперименты выявили другое интересное поведение, см. эти результаты:

// Pure calculation time increases significantly when the exponent grows:
var x = 7n**7n**7n; // ~   1200 ms
var x = 7n**8n**7n; // ~   7000 ms
var x = 7n**7n**8n; // ~  62000 ms
var x = 7n**8n**8n; // ~ 470000 ms

// But it's a different story when the base number is 'simple' in binary terms, e.g. 8n:
var x = 8n**7n**7n; // ~      1 ms
var x = 8n**8n**7n; // ~      1 ms
var x = 8n**7n**8n; // ~      7 ms
var x = 8n**8n**8n; // ~     17 ms

И да, всему есть конец:

var x = 32n**16n**8n;

дает:

VM436:1 Uncaught RangeError: Maximum BigInt size exceeded
at <anonymous>:1:28

Верхний предел в Chrome составляет 1 миллиард бит (1e9 бит), или около 125 МБ. Ссылка: https://github.com/tc39/proposal-bigint/issues./174#issuecomment-437471065

person Peter B    schedule 28.11.2018
comment
Интересно, вернет ли мощная система через какое-то время Бесконечность... стремясь узнать, что скрывается в конце этой дыры. - person Tiberiu; 28.11.2018
comment
Красавчик, спасибо за интерес! Сколько времени потребовалось для последнего расчета (который дает RangeError)? - person Tiberiu; 28.11.2018
comment
Времени нет совсем, использовал "простой" базовый номер (32n) под который оптимизирован движок и тогда он летает. Вероятно, он видит, что можно использовать простой битовый сдвиг, и выдает более 1 миллиарда мест для сдвига. - person Peter B; 28.11.2018
comment
Разработчик V8 здесь. Просто для подтверждения: (1) в BigInts нет бесконечности. Каждая операция возвращает либо конечный BigInt, либо RangeError. (2) Это действительно .toString, который занимает так много времени. См. github.com/tc39/proposal-bigint/issues/166. Попробуйте .toString(16), если вам действительно нужно текстовое представление большого BigInt. - person jmrk; 28.11.2018

Справочная информация:

В JavaScript вы можете использовать суффикс n для создания числа как bigint (просто большие числа). Большие числа имеют разные способы вычисления. Обычно они более «дорогие» для вычисления. Он не использует встроенные методы процессора для вычислений. Вместо этого bigints используют мягкие вычисления.

Описание проблемы:

9n**9n означает 9^9 (9*9*9*9*9*9*9*9*9). Это 387420489. Даже если вы умножите 387420489 само по себе, это действительно большое число. Но **9n означает, что вы хотите вычислить 387420489^9, что действительно очень большое число. Кажется, для хрома требуется слишком много времени для его вычисления или возникает какая-то неизвестная проблема.

По сути, это должна быть ошибка, о которой нужно сообщить. Странным образом зависание браузера не очень удобно для пользователя.

person Adil Aliyev    schedule 28.11.2018
comment
9n**9n**9n такое же, как 9n**(9n**9n), а не (9n**9n)**9n - person tsh; 28.11.2018
comment
Математически говоря да. Но концепция не меняется. В любом случае это очень большое число, которое сложно вычислить для V8. Но поведение странное. Следовательно, это ошибка. - person Adil Aliyev; 28.11.2018
comment
Ничего сложно посчитать (9n**9n)**9n. Он действительно не очень большой. И Chrome сразу отвечает 196627050475552913618075908526912116283103450944214766927315415537966391196809n без проблем. - person tsh; 28.11.2018
comment
Действительно очень маленький. Просто умножьте это само на себя :p - person Adil Aliyev; 28.11.2018

Ответ на вопрос, почему 9**9**9 возвращает Infinity, заключается в том, что переполнение максимального значения не займет много времени (около 2^1024). Он может даже сократить его с помощью **, как видите, если первое число> = 2, а второе число> 1024, тогда это будет бесконечность.

С BigInt он может представлять гораздо большие числа, вот что он пытается сделать. Для достижения «Бесконечности» с BigInt требуется много времени (EDIT: что на самом деле было бы исключением RangeError). Найти 387420489 можно довольно быстро, но 9n**387420489n, где BigInts умножается почти в 400 миллионов раз... это занимает некоторое время.

Операция BigInt намного медленнее, чем обычная операция int. Я ожидаю, что вы можете получить результат (или исключение RangeError), если подождете 20-30 минут, но может быть и намного дольше.

person Garr Godfrey    schedule 28.11.2018
comment
Было бы интересно посмотреть, действительно ли через какое-то время результатом будет Infinity, но боюсь, моя система не способна на этот тест. Он может загореться. :) - person Tiberiu; 28.11.2018
comment
Пояснения: 2^53 — это максимальное целое число, которое может точно представлять двойное число, также известное как Number.MAX_SAFE_INTEGER. Максимальное числовое значение равно 2^1024, также известное как Number.MAX_VALUE. Это не специфично для V8, это связано со спецификацией IEEE 754, которой следуют большинство языков программирования. --- У BigInt нет понятия бесконечности, никакая операция BigInt никогда не вернет бесконечность, потому что все дело в том, чтобы быть точным. Если результат слишком велик для представления, он выдаст RangeError. - person jmrk; 28.11.2018
comment
@jmrk спасибо, я собираюсь обновить ответ. Я думал, что он попытается сохранить целочисленность, но это не имеет смысла после некоторого сна. - person Garr Godfrey; 28.11.2018