Oracle плавает против числа - PullRequest
       18

Oracle плавает против числа

13 голосов
/ 02 декабря 2008

Я вижу противоречивые ссылки в документации Oracle . Есть ли разница между тем, как десятичные числа хранятся в типах FLOAT и NUMBER в базе данных?

Как я помню из C, et al, у float есть ограничения точности, которых нет у int. Например, для чисел с плавающей запятой 0,1 (основание 10) приблизительно равно 0.110011001100110011001101 (основание 2), что приблизительно равно 0,100000001490116119384765625 (основание 10). Однако для 'int's 5 (Base 10) - это точно 101 (Base 2).

Вот почему следующее не завершится, как ожидалось в C:

float i;
i = 0;
for (i=0; i != 10; )
{
    i += 0.1
}

Однако я вижу в других местах документации Oracle , что FLOAT был определен как NUMBER. И, насколько я понимаю, реализация Oracle типа NUMBER не сталкивается с той же проблемой, что и с плавающей точкой C.

Итак, что за настоящая история здесь? Отклонился ли Oracle от нормы того, что, как я ожидаю, произойдет с float / FLOATs?

(Я уверен, что это различие в том, что я буду использовать их, но я знаю, что у меня будут вопросы, если 0.1 * 10 выйдет из 1.00000000000000001)

Ответы [ 5 ]

25 голосов
/ 02 декабря 2008

Oracle BINARY_FLOAT хранит данные внутри себя, используя представление с плавающей точкой IEEE 754, как C и многие другие языки. Когда вы извлекаете их из базы данных и обычно сохраняете их в типе данных IEEE 754 на языке хоста, он может скопировать значение без его преобразования.

Принимая во внимание, что тип данных Oracle FLOAT является синонимом типа данных ANSI SQL NUMERIC, который в Oracle называется NUMBER. Это точный числовой тип данных с десятичным масштабированием, который не имеет поведения округления IEEE 754. Но если вы извлекаете эти значения из базы данных и помещаете их в число с плавающей запятой C или Java, вы можете потерять точность на этом этапе.

10 голосов
/ 30 апреля 2009

Oracle BINARY_FLOAT и BINARY_DOUBLE в основном эквивалентны стандарту IEEE 754, но они определенно не хранятся внутри стандартного представления IEEE 754.

Например, BINARY_DOUBLE занимает 9 байт памяти по сравнению с 8 в IEEE. Также двойное число с плавающей точкой -3.0 представляется как 3F-F7-FF-FF-FF-FF-FF-FF, которое, если вы используете реальный IEEE, будет быть C0-08-00-00-00-00-00-00. Обратите внимание, что бит 63 равен 0 в представлении Oracle, в то время как он равен 1 в IEEE (если 's' является знаковым битом, в соответствии с IEEE знак числа равен (-1) ^ s). См. Очень хорошие калькуляторы IEEE 754 на http://babbage.cs.qc.cuny.edu/IEEE-754/

Вы можете легко найти это, если у вас есть столбец BINARY__DOUBLE BD в таблице T с запросом:

выберите BD, DUMP (BD) из T

Теперь все это хорошо и интересно (возможно), но когда кто-то работает в C и получает числовое значение из Oracle (связывая переменную с числовым столбцом любого типа), он обычно получает результат в реальном IEEE. double как поддерживается C. Теперь это значение зависит от всех обычных неточностей IEEE.

Если кто-то хочет сделать точную арифметику, он может сделать это либо в PL / SQL, либо с помощью специальных библиотек C для точной арифметики.

Для собственного объяснения Oracle их числовых типов данных см .: http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#i16209

3 голосов
/ 02 декабря 2008

Число Oracle на самом деле представляет собой десятичное (базовое-10) представление с плавающей запятой ... Float это просто псевдоним для Number и делает то же самое.

если вы хотите, чтобы двоичные числа (base-2) плавали, вам нужно использовать типы данных Oracle BINARY_FLOAT или BINARY_DOUBLE.

текст ссылки

2 голосов
/ 07 августа 2015

Как и упомянутый ранее PLS_INTEGER, типы BINARY_FLOAT и BINARY_DOUBLE в Oracle 10g используют машинную арифметику и требуют меньше места для хранения, что делает их более эффективными, чем тип NUMBER

  • ONLY BINARY_FLOAT и BINARY_DOUBLE поддерживают значения NAN

- не точные расчеты

2 голосов
/ 11 мая 2012

Ответ Билла о Oracle FLOAT верен только в более поздней версии (скажем, 11i), в Oracle 8i документ гласит:

Вы можете указать числа с плавающей точкой в ​​форме, обсуждаемой в "NUMBER Datatype". Oracle также поддерживает тип данных ANSI FLOAT. Вы можете указать этот тип данных, используя одну из следующих синтаксических форм:

FLOAT определяет число с плавающей запятой с десятичной точностью 38, или двоичная точность 126. FLOAT (b) определяет число с плавающей точкой с двоичная точность б. Точность b может варьироваться от 1 до 126. К преобразовать двоичную в десятичную точность, умножить b на 0,30103. к преобразовать десятичную в двоичную точность, умножить десятичную Точность 3.32193. Максимум 126 цифр двоичной точности примерно эквивалентно 38 цифрам десятичной точности.

Звучит как четверная точность (двоичная точность 126). Если я не ошибаюсь, IEEE754 требует только b = 2, p = 24 для одинарной точности и p = 53 для двойной точности. Различия между 8i и 11i вызвали много путаницы, когда я изучал план конвертации между Oracle и PostgreSQL.

...