PostgreSQL реальный тип теряет целочисленную точность при печати с помощью PHP sprintf

Я скопировал этот стол из википедии в базу данных PostgreSQL. Колонка Cultivated land (km2) стал столбцом типа real, Затем я использую команду PHP

echo rtrim(rtrim(sprintf('%.10F',$v),'0'),'.');

отображать цифры ($v) в таблице (как целые, так и с плавающей точкой), но некоторые значения теряют точность. Например, значение из США, 1669302, становится 1669300, что странно, так как Я ожидал 10 десятичных цифр точности. Я думал, что потерял точность при сохранении в real столбец, но преобразование столбца в double precision делает разницу (02) появляется снова, так что это было где-то там.

Я не думаю, что мне нужна двойная точность, так как я могу правильно отобразить реальное значение? Имейте в виду, что некоторые столбцы имеют десятичные разряды, а другие bigintи они также должны отображаться правильно.

0

Решение

Кажется, проблема возникает из-за того, как PHP возвращает результаты. Значения не возвращаются как соответствующий тип данных, а скорее отформатирован как строка с использованием стандартного форматирования PostgreSQL. Это форматирование, отличается для real а также double precision Таким образом, при преобразовании типов столбцов таблицы вы видите разные результаты. Причина, по которой вы видите этот конкретный результат, заключается в том, что PostgreSQL гарантирует 6 десятичных знаков для real типы и 15 знаков после запятой для double precision.

настройка extra_float_digits

Руководство состояния

Обратите внимание extra_float_digits Параметр setting определяет количество дополнительных значащих цифр, включаемых при преобразовании значения с плавающей запятой в текст для вывода. Со значением по умолчанию 0выходные данные одинаковы для всех платформ, поддерживаемых PostgreSQL. Увеличение его приведет к выводу, который более точно представляет сохраненное значение, но может быть непереносимым.

Поэтому простым решением вашей проблемы является увеличение extra_float_digits перед выдачей SELECT-query:

pg_query($connection, "set extra_float_digits = 3");

Кроме того, вы также можете указать это изменение при подключении к вашей базе данных, добавив options на ваш строка подключения следующее:

$connection = pg_connect("host=localhost port=5432 dbname=test user=php password=pass connect_timeout=5 options='-c extra_float_digits=3'");

Другим вариантом будет установить этот флаг в postgresql.conf файл конфигурации сервера PostgreSQL, если у вас есть доступ к серверу и вы хотите изменить эту опцию глобально.

Приведение ценностей

Другое решение — PostgreSQL возвращает другую строку в бэкэнд PHP. Это может быть достигнуто путем приведения ваших столбцов к типам с различным форматированием по умолчанию, что позволяет избежать обрезания некоторых цифр. В вашем случае вы могли бы либо бросить на integer или же double precisionвместо использования

select cultivated_land from table

вы могли бы использовать

select cultivated_land::integer from table

или же

select cultivated_land::double precision from table

Изменение типов данных

Глядя на указанные вами данные, я заметил, что все числовые значения, кроме тех столбцов, в которых указаны проценты, содержат целые числа, следовательно, использование integer Тип данных больше подходит в этом случае. Он может соответствовать всем целочисленным значениям этой таблицы (максимально 149 000 000, поэтому bigint не требуется), требует тот же размер хранилища, что и real (4 байта) и подразумевает форматирование целых чисел по умолчанию, которое вы ищете.

Обновление: справочная информация об интерфейсе PostgreSQL-PHP и представлении с плавающей запятой

Как упоминалось выше, интерфейс PostgreSQL-PHP работает так, что все значения, отправляемые из PostgreSQL в PHP, форматируются в виде строки в зависимости от типа. Ни один из pg_fetch_* ни функции pg_copy_to обеспечит необработанные значения и все эти функции конвертируют значения в строки одинаково. Насколько мне известно, текущий интерфейс PHP не даст вам ничего, кроме строки (что, на мой взгляд, не лучший дизайн интерфейса).

Причина 18.22 возвращается как 18.2199993 можно найти в том, как PostgreSQL конвертирует float4 в строки. Вы можете проверьте код о том, как PostgreSQL внутренне использует float4out и найдите соответствующую строку, которая выполняет преобразование строки:

snprintf(ascii, MAXFLOATWIDTH + 1, "%.*g", ndig, num);

num это float4-номер для печати в виде строки. Обратите внимание, однако, что C будет продвигать float-вариант к double-переменную при звонке snprintf, Это преобразование в двойную точность приводит к значению 18.219999313354492 вот почему вы в конечном итоге видите 18.2199993 (Вы можете проверить это Вот а также найдете некоторые подробности о представлении чисел с плавающей точкой на этом сайте).

Вывод сообщение, что все ваши float4 значения будут преобразованы с помощью этой функции, и единственный параметр, на который вы можете повлиять, это ndig варьируя extra_float_digitsОднако ни одно значение для этой переменной не удовлетворит все ваши потребности в представлении значений так, как вы хотите. Так что, пока вы продолжаете использовать float4 в качестве типа данных и использовать текущий PHP-интерфейс для получения данных вы столкнетесь с этими проблемами.

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

3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector