Почему два числа, которые отличные, оцениваются, как будь равен в Javascript?

Первоначальный вопрос: Why пахал two different numbers equal in язык сценариев JavaScript?

Я играл немного с консолью и мне случилось демонстрировать следующее:

var num1 = 0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
var num2 =  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
console.log(num1 == num2)

И меня удивило, что действительно это сравнение оценивается как истинная (они могут тестировать ее в консоли).

Почему происходит это? Ясно, что это различные числа (у второго есть цифра меньше, чем первый; если удается добавить F второго или 0 к первому, сравнение уже фальшивое, но тем временем, истинная).

27
задан 06.09.2019, 18:04
3 ответа

Все числа в языке сценариев JavaScript представляют внутри как числа плавающей точки двойной точности (видеть §4.3.19 в спецификации), Это означает, что один может представлять точно любое число между 0 и 9007199254740992 (шестнадцатеричный 0x20000000000000, или то, что является тем же самым 2^53). То же самое происходит для отрицательных чисел: идут от 0 до-9007199254740992. Если один тестирует добавлять 1 (или уменьшать 1 для негативов) догадывается, что число, которое остается, - то же самое, но если один пробует добавлять 2, он догадывается, что число меняется. Это, из-за как это mantisa в стандарте IEEE754.

Наблюдайте:

console.log(9007199254740992 === 9007199254740993)

Добавляя другую F к второму числу (когда ты это представил в hexa, ты меняешь не только mantisa но также экспонент (число - 4 команды превосходящий другой), и поэтому да он оценивает отлично.

начиная с vesion ECMAScript 2015 я включаюсь постоянная величина, чтобы получать самое большое безопасное число* Number. MAX_SAFE_INTEGER, кроме Number.isSafeInteger ()

32
ответ дан 03.12.2019, 23:21
  • 1
    Очень хороший, спасибо за вклад –  César 06.12.2015, 17:59
  • 2
    Превосходный explicaci и # 243; n, ясная и прямая. Спасибо за вклад. –  user991 07.12.2015, 16:34
  • 3
    Тогда ¿ nú морские окуни над 9007199254740992 теряют precisió n? ¿ они не являются точными - приближения? –  E-Rick 09.09.2019, 18:15

Не требуются столькие '0's и 'F's. В действительности равенство начинается с только 14 '0's и 'включенный F's с оператором ===

0x100000000000000 === 0xFFFFFFFFFFFFFF

Она explicaciГіn простой, в действительности эти два nГєmeros равны и следовательно она comparaciГіn она правильна таким же образом как следующее равенство tambiГ©n производит true

1 === 1.0

Просто - два различных способа выражать того же самого тому же самому nГєmero

Оба шестнадцатеричных представления evalГєan nГєmero, что может быть показанным просто выполняя в консоли

0x100000000000000
0xFFFFFFFFFFFFFF

, Что evalГєa оба в:

 72057594037927940
 72057594037927940

В случае ее versiГіn со многими '0's или 'F's оба выражения evalГєan в sgte nГєmero:

1.3407807929942597e+154
20
ответ дан 03.12.2019, 23:21
  • 1
    Этот ответ быть и # 237; в совершенную, если он давал мотив реальные , которых эти n и # 250; морские окуни, что не равны, eval и # 250; в как будь равен: Совсем n и # 250; морской окунь в JS представляется посредством IEEE754 и следовательно нет precisi и # 243; n достаточный, чтобы отличать их. –  Darkhogg 07.12.2015, 15:45
  • 2
    Не верно, что мотив, из-за которого 1 === 1.0 - те же самые, из-за которых это сравнение равно. Нижележащий механизм другой для сравнения в вопросе. Для сравнения в данном ответе, взамен, представление точно плавающая - ТО ЖЕ САМОЕ в обоих случаях. –  Luis Masuelli 07.12.2015, 16:44

Когда ты представляешь любое Число плавающей точки с двойной точностью IEEE754 внутри, имеется что-то как:

0111 1111 1111 2222
2222 2222 2222 2222
2222 2222 2222 2222
2222 2222 2222 2222

Где (0) - бит знака (0=positivo, 1=negativo), (1) биты выразителя, и (2) биты matisa.

Если в языке сценариев JavaScript ты сравниваешь 0.5 == 5 * 0.1 ты будешь получать true даже, когда у этой операции есть неточность, характерная для плавающих точек (а именно: у тебя будет что-то из ошибки). Много языков (язык сценариев JavaScript между ними) терпят некую ошибку в последнем бите сравнения в mantisa (просвет, в того же выразителя и тот же знак).

Нормальное состоит в том, что схема плавающей точки сохраняет экспонент как число между 1024 и-1023 (или по крайней мере так должны понимать), в то время как mantisa должен понимать как число между 0 и 0.111111..., чтобы давать число как 0.1b * 2 ^ 12 то, что он равняется тому, чтобы вычислять 0.5 * 4096 в десятичном основании. mantisa, таким образом, всегда будет являться несовершеннолетним в 1 и будет сохранять таким образом что первая цифра (в бинарном основании) - 1. Для того, чтобы это произошло, делается процесс, названный стандартизацию, в котором мы скроллируем экспонент такие столько необходимых чисел как "запятые", давайте хотеть двинуть в числе до того, чтобы мочь вооружать mantisa, первая дробная цифра которого в бинарном была 1 (что часто не может делаться, и отражается это видя, что выразитель, в бинарном, 000 0000 0000 и не возможно "загружаться" больше). Таким образом, каждый раз, когда выразитель не был 000 0000 0000 число устроится для того, чтобы mantisa начался с 0.1 (бинарный) и, таким образом, избыточно (неэффективно) хранить этот 1 (0 перед точкой никогда он не хранится). Следовательно, наш mantisa всегда позволит нам сохранять в цифре больше и из-за этого нам может удаваться представить 2^53 точно, (вместо 2^52 из-за того, что имеем 52 цифры в mantisa).

Давайте видеть сейчас, что у числа 0xFF... есть 13 букв F или, в бинарном, 52 бита длиной. Так только с нами случается, что число могло бы сохранять как (позитив) (+52) (1111... 52 "одни"), но в действительности из-за этого "сдвига" 1, который приходит "подразумеваемо", первый 1 не сохраняет. Число переходит к тому, чтобы сохранять как (делая сдвиг для выразителя в бинарном, конечно):

0100 0011 0010 1111
1111 1111 1111 1111
1111 1111 1111 1111
1111 1111 1111 1110

(el exponente 1075 es, en realidad, el 52, pero sumado el límite para los exponentes negativos, que es 1023)

Другое число - один, непрерывный 52 нулями. Обычно он был бы: (позитив) (+53) (10000... в общем количестве 51 "нуле"). Снова, как mantisa начинается с 0.1 (потому что мы можем нормализовать эти числа) мы уберегаемся первый один.

0100 0011 0100 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000

(el exponente 1076 en realidad es 53, por el mismo motivo)

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

Тогда mantisa 100000... и 011111... (с соответствующими подразумеваемые одни) будут, чтобы "быть похожим" и иметь этого малыша "epsilon" различия, которым они смогут сравниваться, как будь равен.

Заметь относительно mantisa и представления точно плавающая: Концептуально mantisa всегда меньше в 1. Если хочется представлять большее число, нужно беременеть используя экспоненты. Примеры:

  • 0.5 представляется как 0.5 * 2 ^ 0 (считая правильный порядок предшествования операторов в математике).
  • 1 не представляется как 1 * 2 ^ 0 так как mantisa - строго несовершеннолетний в 1, а следовательно он должен представляться как 0.5 * 2 ^ 1.
  • 65, которых в бинарном представлении 1000001, будет сохраняться как (65/128) * 2 ^ 7.

Эти числа представятся следующего способа (нужно помнить: как числа - normalizables, первый "1" подразумеваемый):

0011 1111 1111 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000

(el exponente 1023 corresponde a 0, con una mantisa con valor 0.1 siendo el 1 implícito).

0100 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000

(el exponente 1024 corresponde a 1, con una mantisa con valor 0.1 siendo el primer 1 implícito).

и

0100 0000 0110 0000
0100 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000    

(el exponente 1030 corresponde a 7, con una mantisa que en binario se expresaría 0.1000001, y como el primer 1 es implícito, se guarda como 0000 0100 0000...)

Заметь Относительно выразителей: Точности большего количества десятичных положений могут добиваться используя отрицательные экспоненты (между-1 и-1023): Выразители могут поверните как будто это были положительные числа, но в действительности у них есть "перемещение" (названный bias, оригинально) 1023 (это означает, что выразитель, который кажется 000 0000 0001 в действительности соответствует в 2^ (-1022)). Это переводя в силы в основании 10, самого меньшего возможного выразителя-308 (считая также, где остается mantisa, потому что число - один не нормализованный). Самое меньшее положительное число оказывается:

0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0001

что: (1 * 2^-52) * 2^-1023 ввиду-52 из-за mantisa (у которого только что есть 1 в конце концов) и-1023 из-за выразителя. Последний один заканчивается положением: 1 * 2^ (-1075), что приближается к счастливому 10 ^ -308.

Самый низкий выразитель 000 0000 0000 соответствующий (-1023). Однако в этой стоимости mantisas не считают подразумеваемым первый 1. С другой стороны, хотя самый большой выразитель может представляться как 111 1111 1111, в действительности он не используется как выразитель, а чтобы представлять общие псевдочисла плавающей точки:

0111 1111 1111 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000

соответствуй в +Infinity, пока:

1111 1111 1111 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000

corresesponde в-Infinity, и любой главный файл с mantisa, отличным от 0, как:

?111 1111 1111 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0001

соответствует to NaN (not в number; идеальное представление для оказанные, что они не могут давать числа, как log(-1) или 0/0). Первый бит (бит знака) неуместный в этих случаях.

12
ответ дан 03.12.2019, 23:21