Javascript. Увеличение или уменьшение поплавка как можно меньше

В javascipt у меня есть av с плавающей точкой "а", как это:

var a = 5.;

Теперь я хочу новый номер "b", который чуть больше, чем "a". Я мог бы сделать это:

var b = a + 1.e-10;

Но что, если "а" действительно небольшое число?

var a = 5.e-20;
var b = a + 1.e-10;

Теперь "b" на много порядков больше, чем "a".
Также, если я сделаю разницу между "a" и "b" слишком маленькой, большое "a" может привести к тому, что разница будет округлена.

Как сделать число "b" больше, чем любое число "a", но ближе к "a", чем любое другое число, большее, чем "a", или как сделать число "b" меньше, чем " "но" ближе к "а", чем любое другое число, меньшее "а".

Редактировать:
Точнее говоря: я ищу функцию "makeLarger(a)", которая принимает число "a" и возвращает число "b", где "b>a" всегда будет иметь значение true, а "c>a && c

3 ответа

Решение

Если предположить, a является положительным, реальным и достаточно далеким от того, чтобы быть ненормальным (в этом случае больше, чем 1.0020841800044864e-292), то должно работать следующее:

var u = Number.EPSILON/2 + Number.EPSILON*Number.EPSILON;
var b = a + a*u;

Обратите внимание, что b = a * (1+u) не сработает (например, если a = 0.9999999999999998).

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

Таким образом, без потери общности достаточно рассмотреть цифры a в интервале [1.0,2.0). Мы должны гарантировать, что

Machine.EPSILON/2 < a*u < Machine.EPSILON*3/2

так что окончательное добавление будет округлено в правильном направлении (вместо a или 2 шага). Это довольно просто показать, что u определенный выше удовлетворяет этим свойствам.

Спуститься вниз можно

var c = a - a*u;

PS: Еще один вариант, хотя и сложнее доказать, это

var v = 1 - Machine.EPSILON/2;
var b = a / v; # upwards
var c = a * v; # downwards

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

Для субнормалов вы можете просто добавить / вычесть Number.MIN_VALUEТаким образом, комбинируя все это вместе, вы получите:

function nextup(a) {
    var v = 1 - Number.EPSILON/2;
    if (a >= Number.MIN_VALUE / Number.EPSILON) {
        // positive normal
        return (a/v);
    } else if (a > -Number.MIN_VALUE / Number.EPSILON) {
        // subnormal or zero
        return (a+Number.MIN_VALUE);
    } else {
        // negative normal or NaN
        return (a*v);
    }
 }

 function nextdown(a) {
    var v = 1 - Number.EPSILON/2;
    if (a >= Number.MIN_VALUE / Number.EPSILON) {
        // positive normal
        return (a*v);
    } else if (a > -Number.MIN_VALUE / Number.EPSILON) {
        // subnormal or zero
        return (a-Number.MIN_VALUE);
    } else {
        // negative normal or NaN
        return (a/v);
    }
 }

Вы можете использовать подход большого числа - чтобы сохранить ваш номер в виде последовательности его цифр: например, 123... many digits here ...45 как [1, 2, 3, .., 4, 5]

Таким образом, вы можете обрабатывать слишком много чисел и иметь очень высокую точность ваших операций.

Для этого есть несколько js-модулей, например, http://jsfromhell.com/classes/bignumber

Это может быть неортодоксальным, но вы можете сделать следующее:

  1. бросьте число с плавающей точкой в ​​строку, вам не нужно беспокоиться о размере числа (в пределах разумного).
  2. найти индекс десятичной точки.
  3. извлекать значительную группу чисел с конца (здесь требуется настройка - что-то вроде "до первой пары, которая не равна 0 во главе с 9 или еще чем-то")
  4. приведите их к int и увеличьте на 1
  5. замените числа в первой строке на номера во второй в var b
  6. поместите десятичную дробь (по предыдущему индексу), приведите к плавающей точке.

Есть некоторые тонкие настройки, которые нужно решить, но это будет сделано.

Мне не хочется писать код для примера, но это тривиально.

Другие вопросы по тегам