Выбор чисел с плавающей запятой в десятичной форме

У меня есть небольшое число в таблице PostgreSQL:

test=# CREATE TABLE test (r real);
CREATE TABLE
test=# INSERT INTO test VALUES (0.00000000000000000000000000000000000000000009);
INSERT 0 1

Когда я запускаю следующий запрос, он возвращает число как 8.96831e-44:

test=# SELECT * FROM test;
      r      
-------------
 8.96831e-44
(1 row)

Как я могу показать значение в psql в десятичной форме (0.00000000000000000000000000000000000000000009) вместо экспоненциального представления? Я бы тоже был счастлив с 0.0000000000000000000000000000000000000000000896831. К сожалению, я не могу изменить таблицу, и меня не волнует потеря точности.

(Я играл с to_char некоторое время без успеха .)


person palacsint    schedule 18.09.2013    source источник
comment
А, увидел, что это настоящее. Это представление с плавающей запятой... Вы никогда не вернете значение: Что должен знать каждый программист об арифметике с плавающей запятой   -  person ppeterka    schedule 18.09.2013
comment
@ppeterka66: это real (postgresql.org/docs/9.1/static/ числовой тип данных.html)   -  person palacsint    schedule 18.09.2013
comment
Обновил мой ответ: кажется, это известная проблема, и я не чувствую себя хорошо...   -  person ppeterka    schedule 18.09.2013


Ответы (1)


Real в Postgres — это тип данных с плавающей запятой, хранящийся в 4 байтах, который составляет 32 бита.

Ваша ценность,

0.00000000000000000000000000000000000000000009

Не может быть точно представлено в 32-битном числе с плавающей запятой IEEE754. Вы можете проверить точные значения в этом калькуляторе.

Вы можете попытаться использовать двойную точность (64 бита) для хранения, согласно калькулятору, это кажется точным представлением. НЕ ВЕРНО Патрисия показала, что это был просто калькулятор, который округлял значение, хотя явно просил этого не делать... Двойное значение означало бы немного большую точность, но все же не точное значение, поскольку это число не может быть представлено с использованием конечного числа двоичных цифр. (Спасибо, Патрисия, урок усвоен (снова): не верьте тому, что вы видите на Intertubez)

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

Однако ваше значение для хранения, по-видимому, имеет масштаб больше, чем позволяет postgres (который, кажется, равен 30) для точных десятичных представлений. Если вы не хотите выполнять вычисления, просто сохраните их (признаю, что это не очень распространенная ситуация), вы можете попробовать сохранить их в виде строк... (но это некрасиво...)

ИЗМЕНИТЬ

Эта проблема с to_char кажется известной ошибкой...

Цитировать:

Моя немедленная реакция на это заключается в том, что значения float8 не имеют 57-значной точности. Если вы ожидаете, что эта строка формата сделает что-то полезное, вы должны применить ее к числовому столбцу, а не к столбцу с двойной точностью.

Вполне возможно, что мы можем что-то изменить, чтобы этот конкретный случай работал так, как вы ожидаете, но всегда будут похожие случаи, которые не могут работать, потому что точности просто нет.

При беглом взгляде на код причина, по которой вы просто получаете «0». заключается в том, что он округляется после 15 цифр, чтобы гарантировать, что он не печатает мусор. Может быть, это было бы немного разумнее для случаев, когда значение намного меньше 1, но это не будет простым изменением.

(отсюда)

Тем не менее, я считаю, что это не оправдано. ИМХО, двойное число (точнее, 64-битная плавающая точка IEEE754) всегда будет иметь ~15 значащих десятичных цифр, если значение соответствует типу...

Рекомендуемое чтение:

person ppeterka    schedule 18.09.2013
comment
0,00000000000000000000000000000000000000000000009 не имеет точного представления в виде двоичного расширения конечной длины и, следовательно, не может быть точно представлен двойным числом. The closest double is 8.999999999999999701371399759001187751098450398312665851146155700922553097223778373253413973215499304719454149066593107164635512162931263446807861328125E-44. Это может показаться точным из-за округления. - person Patricia Shanahan; 18.09.2013
comment
@PatriciaShanahan, вы правы ... Черт возьми, мой надежный калькулятор IEEE754 округляет значение, даже если я отключил его округление ... Я ненавижу такие моменты ... - person ppeterka; 18.09.2013
comment
Уловка, которую я использую для получения точных значений удвоения, заключается в написании программы на Java, которая создает BigDecimal со значением удвоения и печатает его. Преобразование double в BigDecimal является точным, и toString BigDecimal производит все цифры, которые у него есть. - person Patricia Shanahan; 18.09.2013
comment
@PatriciaShanahan Печально то, что я знаю это - недавно я был довольно глубоко вовлечен в тонкости того, как это работает и как работает Double.toString, и все же с желтым предупреждением в моей голове о конечности двоичного файла представление, я решил поверить в то, что я видел, и написать что-то совершенно не так... - person ppeterka; 18.09.2013