Rod*_*igo 1 php postgresql precision
我已将此表从 Wikipedia复制到 PostgreSQL 数据库中。该列Cultivated land (km2)变为类型为 的列real。然后我使用PHP命令
echo rtrim(rtrim(sprintf('%.10F',$v),'0'),'.');
Run Code Online (Sandbox Code Playgroud)
$v在表格中显示数字 ( )(整数和浮点数),但某些值会失去精度。例如,来自美国的值 1669302 变成了 1669300,这很奇怪,因为我期望精度为 10 位十进制数字。我以为我在保存到real列中时失去了精度,但是将列转换为double precision使差异 (02) 再次出现,所以它在某处。
我认为我不需要双精度,那么如何正确显示真实值?请记住,有些列有小数位,而有些则是bigint,它们也应该正确显示。
问题似乎源于 PHP 返回结果的方式。这些值不会作为相应的数据类型返回,而是使用 PostgreSQL 默认格式设置为字符串。这种格式real与double precision类型不同,因此在转换表的列类型时会看到不同的结果。您看到此特定结果的原因是PostgreSQL 保证real类型保留 6 个小数位,而double precision.
extra_float_digits手册指出
注意:该
extra_float_digits设置控制将浮点值转换为文本以进行输出时包含的额外有效数字的数量。使用默认值0,PostgreSQL 支持的每个平台上的输出都是相同的。增加它会产生更准确地表示存储值的输出,但可能无法移植。
因此,您的问题的一个简单解决方案是extra_float_digits在发出SELECT-query之前增加:
pg_query($connection, "set extra_float_digits = 3");
Run Code Online (Sandbox Code Playgroud)
或者,您也可以在连接到数据库时通过添加options到连接字符串来指定此更改,如下所示:
$connection = pg_connect("host=localhost port=5432 dbname=test user=php password=pass connect_timeout=5 options='-c extra_float_digits=3'");
Run Code Online (Sandbox Code Playgroud)
如果您有权访问服务器并希望全局更改该选项,则另一种选择是在 PostgreSQL 服务器的配置文件中设置此标志postgresql.conf。
一个不同的解决方案是让 PostgreSQL 向 PHP 后端返回一个不同的字符串。这可以通过将您的列转换为具有不同默认格式的类型来实现,以避免切断某些数字。在您的情况下,您可以转换为integer或double precision,即代替使用
select cultivated_land from table
Run Code Online (Sandbox Code Playgroud)
你可以用
select cultivated_land::integer from table
Run Code Online (Sandbox Code Playgroud)
或者
select cultivated_land::double precision from table
Run Code Online (Sandbox Code Playgroud)
查看您指定的数据,我注意到除了指定百分比的列之外的所有数值都包含整数,因此integer在这种情况下使用数据类型更合适。它可以适合该表的所有整数值(最大值为 149,000,000,因此bigint不是必需的),需要与real(4 个字节)相同的存储大小并暗示您正在寻找的整数的默认格式。
如上所述,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);
Run Code Online (Sandbox Code Playgroud)
num是float4要作为字符串打印的-number。但是请注意,C 将在调用时将float-variable 提升为double-variablesnprintf。这种转换为双精度的结果18.219999313354492是您最终看到的值18.2199993(您可以在此处查看此内容,并且还将在此站点上找到有关浮点数表示的一些详细信息)。
外卖信息是,您的所有float4值都将使用此函数进行转换,您可以影响的唯一参数是ndig变量extra_float_digits,但是此变量的单个值无法满足您按照需要表示值的所有需求。因此,只要您继续使用float4作为您的数据类型并使用当前的 PHP 接口来获取数据,您就会遇到这些问题。
因此,我仍然建议为您的列选择不同的数据类型。如果您认为您需要十进制数,您可能需要研究decimal数据类型,您可以根据应用程序的要求指定精度和小数位数。如果您想坚持使用浮点数,我建议在向用户显示之前对 PHP 中的值进行四舍五入。
| 归档时间: |
|
| 查看次数: |
2105 次 |
| 最近记录: |