Как изменить double с наименьшим приращением - PullRequest
8 голосов
/ 10 октября 2010

Что-то сломано или я не понимаю, что происходит?

static String getRealBinary(double val) {
    long tmp = Double.doubleToLongBits(val);
    StringBuilder sb = new StringBuilder();

    for (long n = 64; --n > 0; tmp >>= 1)
        if ((tmp & 1) == 0)
            sb.insert(0, ('0'));
        else
            sb.insert(0, ('1'));

    sb.insert(0, '[').insert(2, "] [").insert(16, "] [").append(']');
    return sb.toString();
}

public static void main(String[] argv) {
    for (int j = 3; --j >= 0;) {
        double d = j;
        for (int i = 3; --i >= 0;) {
            d += Double.MIN_VALUE;
            System.out.println(d +getRealBinary(d));
        }
    }
}

С выходом:

2.0[1] [00000000000] [000000000000000000000000000000000000000000000000000]
2.0[1] [00000000000] [000000000000000000000000000000000000000000000000000]
2.0[1] [00000000000] [000000000000000000000000000000000000000000000000000]
1.0[0] [11111111110] [000000000000000000000000000000000000000000000000000]
1.0[0] [11111111110] [000000000000000000000000000000000000000000000000000]
1.0[0] [11111111110] [000000000000000000000000000000000000000000000000000]
4.9E-324[0] [00000000000] [000000000000000000000000000000000000000000000000001]
1.0E-323[0] [00000000000] [000000000000000000000000000000000000000000000000010]
1.5E-323[0] [00000000000] [000000000000000000000000000000000000000000000000011]

Ответы [ 5 ]

8 голосов
/ 10 октября 2010

Основная идея заключается в том, чтобы сначала преобразовать double в его длинное представление (используя doubleToLongBits, как вы это сделали в getRealBinary), увеличить это значение на 1 и, наконец, преобразовать новый long обратно в двойное представление, которое оно представляет через longBitsToDouble.

РЕДАКТИРОВАТЬ: Java (начиная с 1.5) обеспечивает Math.ulp(double), который, я полагаю, вы можете использовать для непосредственного вычисления следующего более высокого значения: x + Math.ulp(x).

7 голосов
/ 10 октября 2010

Числа с плавающей запятой не распределены равномерно по числовой строке, как целочисленные типы.Они более плотно упакованы около 0 и очень далеко друг от друга, когда вы приближаетесь к бесконечности.Поэтому нет константы, которую вы можете добавить к числу с плавающей запятой, чтобы перейти к следующему числу с плавающей запятой.

4 голосов
/ 10 октября 2010

Ваш код неверно сформирован. Вы пытаетесь добавить минимальное двойное значение и ожидаете, что результат будет отличаться от исходного значения. Проблема в том, что double.MinValue настолько мало, что результат округляется и не изменяется.

Рекомендуемое чтение: http://en.wikipedia.org/wiki/Machine_epsilon

В статье в Википедии также есть код Java. Эпсилон по определению является наименьшим числом, таким как (X + eps * X! = X), а eps * X называется «относительный-эпсилон»

3 голосов
/ 17 мая 2017

Начиная с Java 1.8 java.lang.Math.nextUp(double) делает именно то, что вы хотите.Существует также напротив java.lang.Math.nextDown(double).

0 голосов
/ 18 сентября 2013

Если вы хотите использовать класс BigDecimal, также существует метод BigDecimal.ulp().

...