2009-08-07 3 views
19

Я занимаюсь высокоточными научными вычислениями. В поисках лучшего представления различных эффектов, я продолжаю придумывать причины, чтобы получить следующий более высокий (или более низкий) номер двойной точности. По сути, я хочу добавить один из наименее значимых бит во внутреннее представление двойника.следующий более высокий/нижний номер IEEE двойной точности

Сложность в том, что формат IEEE не является полностью однородным. Если бы кто-то использовал низкоуровневый код и фактически добавлял один из наименее значимых бит, результирующий формат мог бы не быть следующим доступным двойным. Например, это может быть номер специального случая, например PositiveInfinity или NaN. Существуют также суб нормальные значения, которые я не утверждаю, чтобы понять, но которые, похоже, имеют определенные битовые шаблоны, отличные от «нормального» шаблона.

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

Я действительно не понимаю, почему IEEE не указала функцию для получения следующего более высокого или более низкого значения. Я не могу быть единственным, кому это нужно.

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

+2

IEEE-754 * указал * такие функции - 'nextUp' и' nextDown', как требуется в разделе 5.3.1 пересмотренного стандарта (2008), и более раннюю функцию 'nextafter', рекомендованную оригиналом (1985) стандарт и требуется на C99. –

ответ

1

Я не уверен, что следую вашей проблеме. Разумеется, стандарт IEEE составляет полностью однородный? Например, посмотрите на эту выдержку из wikipedia article для чисел с двойной точностью.

3ff0 0000 0000 0000 = 1 
3ff0 0000 0000 0001 = 1.0000000000000002, the next higher number > 1 
3ff0 0000 0000 0002 = 1.0000000000000004 

Что не так, просто увеличивая наименьший значащий бит в двоичном или шестнадцатеричном представлении?

Что касается специальных чисел (бесконечность, NaN и т. Д.), Они четко определены и их очень мало. Пределы также определены.

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

+0

Будет ли это работать в тех случаях, когда экспоненту придется увеличивать? –

+0

Моя цель - сделать это чисто, желательно от C#, но, если придется, я опустится до уровня бит. Проблема в том, что стандарт IEEE не находится в общественном достоянии, и я не могу его купить. Стандарт определяет битовые шаблоны для случая, который вы показываете, но также и для всех необычных номеров (таких как суб-нормали). Не нужно знать полную информацию обо всех форматах чисел для выполнения этой задачи. Но если вы перевернете биты самостоятельно, вам придется. Что, если «следующий» номер является субнормальным? Если вы не знаете все правила, вы НЕ МОЖЕТЕ попасть туда! –

+1

@Mark T: Хорошо, теперь я понимаю вашу проблему. Я не понял, что стандарт не был доступен (удивительно)! Ниже приведены реализации ряда функций, включая dnxtaft.f, который возвращает следующее значение с плавающей запятой в направлении x. Может быть, это поможет? http://www.math.utah.edu/~beebe/software/ieee/ –

12

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

  • если у вас есть доступ к достойной математической библиотеке C99, вы можете использовать nextafter (и его поплавок и длинные двойные варианты, nextafterf и nextafterl); или семейства nexttoward (которые в качестве второго аргумента занимают длинный двойной).

  • если вы пишете Fortran, то есть nearest присущий доступны

Если вы не можете получить доступ к ним прямо с вашего языка, вы можете также посмотреть на то, как они реализуются в свободном доступе, например как this one.

2

Да, есть способ. В C#:

 public static double getInc (double d) 
     { 
       // Check for special values 
       if (double.IsPositiveInfinity(d) || double.IsNegativeInfinity(d)) 
        return d; 
       if (double.IsNaN(d)) 
        return d; 

       // Translate the double into binary representation 
       ulong bits = (ulong)BitConverter.DoubleToInt64Bits(d); 
       // Mask out the mantissa bits 
       bits &= 0xfff0000000000000L; 
       // Reduce exponent by 52 bits, so subtract 52 from the mantissa. 
       // First check if number is great enough. 
       ulong testWithoutSign = bits & 0x7ff0000000000000L; 
       if (testWithoutSign > 0x0350000000000000L) 
        bits -= 0x0350000000000000L; 
       else 
        bits = 0x0000000000000001L; 
       return BitConverter.Int64BitsToDouble((long)bits); 
} 

можно складывать и вычитать Увеличение.

+0

Это не " t компиляции, и я не думаю, что вы правильно используете метод «BitConverter.DoubleToInt64Bits» правильно в любом случае. Если вы хотите получить байтовое представление числа, вы должны использовать «BitConverter.GetBytes» (но тогда вам нужно убедиться, что вы увеличиваете или уменьшаете экспоненту, если необходимо). –

+0

Он не компилируется, потому что C# не позволяет смешивать ulong/long константы и переменные (что глупо для операторов бит). И вы ошибались, метод BitConverter действительно возвращает внутреннюю структуру байтов двойника в формате IEEE. –

5

Как говорит Торстен С., это может быть сделано с классом BitConverter, но его метод предполагает, что метод DoubleToInt64Bits возвращает внутреннюю структуру байтов double, которой он не является. Целое число, возвращаемое этим методом, фактически возвращает число представляемых удвоений между 0 и вашим. То есть наименьший положительный двойной - 1, следующий наибольший двойной - 2 и т. д. и т. д. Отрицательные числа начинаются с long.MinValue и уходят от 0d.

Так что вы можете сделать что-то вроде этого:

public static double NextDouble(double value) { 

    // Get the long representation of value: 
    var longRep = BitConverter.DoubleToInt64Bits(value); 

    long nextLong; 
    if (longRep >= 0) // number is positive, so increment to go "up" 
     nextLong = longRep + 1L; 
    else if (longRep == long.MinValue) // number is -0 
     nextLong = 1L; 
    else // number is negative, so decrement to go "up" 
     nextLong = longRep - 1L; 

    return BitConverter.Int64BitsToDouble(nextLong); 
} 

Это не занимается Infinity и NaN,, но вы можете проверить те, и бороться с ними, как вам нравится, если вы беспокоитесь об этом.

+0

Я вижу, что вы используете мой код, потому что аргумент является значением, но BitConverter.DoubleToInt64Bits получает «d» в качестве аргумента. У меня были оговорки о простом добавлении одного, потому что формат IEEE разделяет экспоненту и значимость, но поскольку он имеет скрытый бит , ваша функция на самом деле нормально, насколько я могу видеть. –

6

Большинство языков имеют встроенные или библиотечные функции для получения следующего или предыдущего одноточечного (32-разрядного) и/или двухточечного (64-разрядного) номера.

Для пользователей 32-разрядной и 64-разрядной арифметики с плавающей запятой, разумное понимание основных конструкций очень полезно для предотвращения некоторых опасностей с ними. Стандарт IEEE применяется единообразно, но все же оставляет ряд деталей до исполнителей. Следовательно, универсальное решение платформы, основанное на бит-манипуляциях представлений машинных слов, может быть проблематичным и может зависеть от таких вопросов, как endian и т. Д. Хотя понимание всех подробностей о том, как оно может или должно работать на уровне бит, может продемонстрировать интеллектуальное мастерство, все же лучше использовать внутреннее или библиотечное решение, предназначенное для каждой платформы и имеющее универсальный API на поддерживаемых платформах.

Я заметил решения для C# и C++. Вот некоторые для Java:

Math.nextUp:

общественности статической двойной NextUp (двойной d):

  • Возвращает значение с плавающей запятой, примыкающий к д в направлении положительной бесконечности. Этот метод семантически эквивалентен nextAfter (d, Double.POSITIVE_INFINITY); однако реализация nextUp может работать быстрее, чем ее эквивалент nextAfter.

Особые случаи:

  • Если аргумент является NaN, то результат будет NaN.
  • Если аргумент является положительной бесконечностью, результат будет положительным. бесконечность.
  • Если аргумент равен нулю, то результатом является Double.MIN_VALUE

Параметры:

  • д - начиная с плавающей запятой значение

Возвращает:

  • Смежное значение с плавающей запятой ближе к положительной бесконечности.

общественность статического поплавок NextUp (флоят е):

  • Возвращает значение с плавающей запятой, примыкающего к F в направлении положительной бесконечности. Этот метод семантически эквивалентен nextAfter (f, Float.POSITIVE_INFINITY); однако реализация nextUp может работать быстрее, чем ее эквивалент nextAfter.

Особые случаи:

  • Если аргумент является NaN, то результат будет NaN.
  • Если аргумент является положительной бесконечностью, результат будет положительным. бесконечность.
  • Если аргумент равен нулю, то результатом является Float.MIN_VALUE

Параметры:

  • е - начиная с плавающей запятой значение

Возвращает:

  • Смежное значение с плавающей запятой ближе к положительной бесконечности.

Следующие два являются более сложными в использовании. Однако направление к нулю или к положительной или отрицательной бесконечности представляется более вероятным и полезным. Другое использование - увидеть промежуточное значение между двумя значениями. Можно определить, сколько существует между двумя значениями с помощью цикла и счетчика. Кроме того, похоже, они, наряду со следующими методами, могут быть полезны для приращения/уменьшения для циклов.

Math.nextAfter:

общественность статического двойной nextAfter (двойной старт, двусторонних)

  • Возвращает число с плавающей точкой, смежное с первым аргументом в направления второй аргумент. Если оба аргумента сравниваются как , то возвращается второй аргумент.

Особые случаи:

  • Если какой-либо аргумент является NaN, то возвращается NaN.
  • Если оба аргумента обозначены нулями, направление возвращается без изменений (что подразумевается требованием возврата второго аргумента, если аргументы сравниваются как равные).
  • Если начало равно ± Double.MIN_VALUE и направление имеет такое значение, что результат должен иметь меньшую величину, после чего возвращается ноль с тем же значком , как и начало.
  • Если начало бесконечно и направление имеет такое значение, что результат должен иметь меньшую величину, Double.MAX_VALUE с тем же знаком , когда возвращается начало.
  • Если начало равно ± Double.MAX_VALUE, а направление имеет значение , так что результат должен иметь большую величину, бесконечность с тот же знак, что и в начале.

Параметры:

  • старт - начальное значение с плавающей запятой
  • направление - значение, указывающее, какие из соседей начать или начать должны быть возвращены

Возврат:

  • С плавающей точкой рядом с пуском в направлении направлении.

открытого статическое (начало с плавающей точкой, двойного направления) флоит nextAfter

  • Возвращает число с плавающей точкой, смежное с первым аргументом в направление второго аргумента. Если оба аргумента сравниваются как , то приравнивается значение, эквивалентное второму аргументу.

Особые случаи:

  • Если какой-либо аргумент является NaN, то возвращается NaN.
  • Если оба аргумента совпадают с нулями, возвращается значение, эквивалентное направлению .
  • Если начало равно ± Float.MIN_VALUE, а направление имеет такое значение, что результат должен иметь меньшую величину, после чего возвращается ноль с тем же значком , как и начало.
  • Если начало бесконечно и направление имеет такое значение, что результат должен иметь меньшую величину Float.MAX_VALUE с тем же знаком , когда возвращается начало.
  • Если начало равно ± Float.MAX_VALUE, а направление имеет такое значение , что результат должен иметь большую величину, бесконечность с таким же значком , когда возвращается начало.

Параметры:

  • старт - начальное значение с плавающей запятой
  • направление - значение, указывающее, какие из соседей начать или начать должны быть возвращены

Возврат:

  • Число с плавающей запятой, смежное с началом в направление направления.
1

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

Для значений, близких к широкому диапазону десятичных значений, которые могут представлять двойники, могут быть 1 или -1, эпсилон будет равен нулю или очень, очень мало. Для значений, которые постепенно продвигаются к + или - бесконечности или нулю, epsilon начнет расти. При значениях, очень близких к нулю или бесконечности, epsilon будет очень большим, поскольку доступные двоичные представления для десятичных значений в этих диапазонах очень и очень разрежены.