2.9999999999999999 >>.5?

Я слышал, что вы можете смещать номер на 5. вместо использования Math.floor(). Я решил проверить его пределы, чтобы убедиться, что это подходящая замена, поэтому я проверил следующие значения и получил следующие результаты в Google Chrome:


2.5 >> .5 == 2;
2.9999 >> .5 == 2;
2.999999999999999 >> .5 == 2;  // 15 9s
2.9999999999999999 >> .5 == 3;  // 16 9s

После некоторых попыток я узнал, что наивысшее возможное значение двух, которое при сдвиге справа на 0,5 даст 2, равно 2.9999999999999997779553950749686919152736663818359374999999 ¯ (с 9 повторами) в Chrome и Firefox. Число равно 2.9999999999999997779 ¯ в IE.

Мой вопрос: каково значение числа .0000000000000007779553950749686919152736663818359374? Это очень странное число, и это действительно вызвало мое любопытство.

Я пытался найти ответ или хотя бы какой-то образец, но я думаю, что моя проблема заключается в том, что я действительно не понимаю побитную операцию. Я понимаю идею в принципе, но переключение бит-последовательности на .5 не имеет для меня никакого смысла. Любая помощь приветствуется.

Для записи последовательность странных цифр изменяется с помощью 2 ^ x. Максимально возможные значения следующих чисел, которые по-прежнему усекаются должным образом:

for 0: 0.9999999999999999444888487687421729788184165954589843749¯
for 1: 1.9999999999999999888977697537484345957636833190917968749¯
for 2-3: x+.99999999999999977795539507496869191527366638183593749¯
for 4-7: x+.9999999999999995559107901499373838305473327636718749¯
for 8-15: x+.999999999999999111821580299874767661094665527343749¯
...and so forth

Ответ 1

На самом деле, вы просто заканчиваете выполнение floor() в первом операнде без каких-либо операций с плавающей запятой. Поскольку сдвиговые операции с левым сдвигом и правым сдвигом имеют смысл только с целыми операндами, механизм JavaScript сначала преобразует два операнда в целые числа:

2.999999 >> 0.5

становится:

Math.floor(2.999999) >> Math.floor(0.5)

Что в свою очередь:

2 >> 0

Смещение на 0 бит означает "не делать сдвига", и поэтому вы попадаете в первый операнд, просто обрезанный до целого числа.

Исходный код SpiderMonkey имеет:

switch (op) {
  case JSOP_LSH:
  case JSOP_RSH:
    if (!js_DoubleToECMAInt32(cx, d, &i)) // Same as Math.floor()
        return JS_FALSE;
    if (!js_DoubleToECMAInt32(cx, d2, &j)) // Same as Math.floor()
        return JS_FALSE;
    j &= 31;
    d = (op == JSOP_LSH) ? i << j : i >> j;
    break;

Ваше видение "округления" с определенными номерами связано с тем, что движок JavaScript не может обрабатывать десятичные цифры за пределами определенной точности, и поэтому ваш номер заканчивается округлением до следующего целого числа. Попробуйте это в своем браузере:

alert(2.999999999999999);

Вы получите 2.999999999999999. Теперь попробуйте добавить еще один 9:

alert(2.9999999999999999);

Вы получите 3.

Ответ 2

Это, возможно, самая худшая идея, которую я когда-либо видел. Его единственная возможная цель для существующего - выиграть обернутый кодовый конкурс. Нет никакого значения для длинных номеров, которые вы разместили, - это артефакт базовой реализации с плавающей запятой, отфильтрованный через бога, знает сколько промежуточных слоев. Бит-сдвиг на дробное число байтов является безумным, и я удивлен, что он не вызывает исключения, но этот Javascript всегда готов переопределить "безумный".

Если бы я был вами, я бы избегал использования этой "функции". Его единственное значение является возможной основной причиной необычного условия ошибки. Используйте Math.floor() и пожалейте следующего программиста, который будет поддерживать код.


Подтверждая пару подозрений, которые я испытывал при чтении вопроса:

  • Правое смещение любого дробного числа x с помощью любого дробного числа y будет просто обрезать x, давая тот же результат, что и Math.floor(), в то же время тщательно запутывая читателя.
  • 2.999999999999999777955395074968691915... просто самое большое число, которое можно отличить от "3". Попробуйте оценить его самостоятельно - если вы добавите что-нибудь к нему, оно будет оцениваться до 3. Это артефакт реализации плавающей запятой браузера и локальной системы.

Ответ 3

Если вы хотите углубиться, прочитайте "Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой": http://docs.sun.com/source/806-3568/ncg_goldberg.html

Ответ 4

Я не думаю, что ваша правильная смена важна. Вы просто выходите за пределы константы с плавающей запятой двойной точности.

В Chrome:

var x = 2.999999999999999777955395074968691915273666381835937499999;
var y = 2.9999999999999997779553950749686919152736663818359375;

document.write("x=" + x);
document.write(" y=" + y);

Распечатывается: x = 2.9999999999999996 y = 3

Ответ 5

Попробуйте этот javascript: Оповещение (parseFloat ( "2,9999999999999997779553950749686919152736663818359374999999" ));

Затем попробуйте следующее: Оповещение (parseFloat ( "2,9999999999999997779553950749686919152736663818359375" ));

То, что вы видите, - это простая неточность с плавающей запятой. Для получения дополнительной информации об этом см. Это, например: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems.

Основная проблема заключается в том, что самое близкое к тому, что значение с плавающей запятой может получить представление второго числа, больше или равно 3, тогда как закрытие того, что поплавок может получить до первого числа, строго меньше трех.

Что касается того, почему правое смещение на 0,5 вообще делает что-либо здравомыслящим, кажется, что 0,5 просто преобразуется в int (0) заранее. Тогда исходный поплавок (2.999...) преобразуется в int путем усечения, как обычно.

Ответ 6

Я предполагаю, что вы получите те же результаты, просто указав значения в int.

Ответ 7

Оператор правого сдвига действует только на целые (обе стороны). Таким образом, сдвиг вправо на .5 бит должен быть точно эквивалентен сдвигу вправо на 0 бит. И левая сторона преобразуется в целое число перед операцией shift, что делает то же самое, что и Math.floor().

Ответ 8

Я подозреваю, что преобразование 2.9999999999999997779553950749686919152736663818359374999999 в его двоичное представление будет просветляющим. Вероятно, это всего лишь 1 бит отличается от истины 3.

Ответ 9

Я подозреваю, что конвертация 2.9999999999999997779553950749686919152736663818359374999999 для него двоичное представление было бы просвещенным. Вероятно, это всего лишь 1 бит от истины 3.

Хорошо, но не сигары. Поскольку число FP с двойной точностью имеет 53 бита, последний номер FP до 3 фактически (точный): 2.999999999999999555910790149937383830547332763671875

Но почему 2,9999999999999997779553950749686919152736663818359375

(и это точно, а не 49999...!)

который выше, чем последний отображаемый блок? Завершают. Процедура преобразования (String to number) просто правильно запрограммирована для округления ввода следующего числа с плавающей запятой.

2,999999999999999555910790149937383830547332763671875

....... (значения между, увеличение) → округление вниз

2,9999999999999997779553950749686919152736663818359375

....... (значения между, увеличение) → округлить до 3

3

Вход преобразования должен использовать полную точность. Если число равно половине между эти два числа fp (что равно 2.9999999999999997779553950749686919152736663818359375) округление зависит от установленных флагов. Округление по умолчанию округлое до четного, что означает, что число будет округлено до следующего четного числа.

Теперь

3 = 11. (двоичный)

2.999... = 10.11111111111...... (двоичный)

Все биты установлены, число всегда нечетное. Это означает, что точное число будет округлено, поэтому вы получаете странный период... 49999, потому что он должен быть меньше, чем точная половина, которую можно отличить от 3.

Ответ 10

И чтобы добавить к Джону ответ, шансы на это более результативны, чем Math.floor, исчезающе малы.

Я не знаю, использует ли JavaScript числа с плавающей запятой или какую-то библиотеку с бесконечной точностью, но в любом случае вы собираетесь обходить ошибки при такой операции, даже если она довольно хорошо определена.

Ответ 11

Следует отметить, что число ".0000000000000007779553950749686919152736663818359374" вполне возможно Epsilon, определяемое как "наименьшее число E такое что (1 + E) > 1."