您可以对Postgres的NUMERIC计算强制采用任意精度吗?

时间:2019-03-07 21:41:12

标签: sql postgresql

比方说,我想在SQL中以任意十进制精度查看数字结果。考虑下面的SQL,该SQL产生黄金平均值(一个非常不合理的数字,该数字有很多小数位):

postgres=# SELECT (1 + SQRT(5)) / 2 AS golden_mean;
   golden_mean
------------------
 1.61803398874989
(1 row)

但是至少在psql中,此结果被截断为14个小数位。起初我认为这是因为sqrt函数中的默认强制转换为double precision

postgres=# SELECT pg_typeof((1 + SQRT(5)) / 2);
    pg_typeof
------------------
 double precision
(1 row)

但是,将输入(以及输出)强制转换为NUMERIC仍会显示截断(尽管这次是15 DP):

postgres=# SELECT (1 + SQRT(5::NUMERIC)) / 2 AS golden_mean;
    golden_mean
--------------------
 1.6180339887498950
(1 row)

这对我来说很奇怪,根据the specNUMERIC应该可以存储:

  

小数点前最多131072位数字;小数点后最多16383位数字

此外,

  

注:在类型声明中明确指定的最大允许精度为1000;没有指定精度的NUMERIC受表8-2中所述的限制。

但是,情况似乎并非如此,结果被截断了。我当然可以指定精度/小数位数,但这只能让我获得999个小数位:

postgres=# SELECT (1 + SQRT(5::NUMERIC(1000,999))) / 2 AS golden_mean;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                golden_mean                                                                                                                                                                                                                                                                                                                                                                                                                                        
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137484754088075386891752126633862223536931793180060766726354433389086595939582905638322661319928290267880675208766892501711696207032221043216269548626296313614438149758701220340805887954454749246185695364864449241044320771344947049565846788509874339442212544877066478091588460749988712400765217057517978834166256249407589069704000281210427621771117778053153171410117046665991466979873176135600670874807101317952368942752194843530567830022878569978297783478458782289110976250030269615617002504643382437764861028383126833037242926752631165339247316711121158818638513316203840052221657912866752946549068113171599343235973494985090409476213222981017261070596116456299098162905552085247903524060201727997471753427775927786256194320827505131218156285512224809394712341451702237358057727861600868838295230459264787801788992199027077690389532196819861514378031499741106926088674296226757560523172777520353613936
(1 row)

我认为这可能是因为实际上 存储了所需的精度,但是psql放弃了精度,但事实并非如此。如果尝试在计算后 进行强制转换,则只获得原始的15 DP舍入:

postgres=# SELECT ((1 + SQRT(5)) / 2)::NUMERIC(1000,999) AS golden_mean;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                golden_mean                                                                                                                                                                                                                                                                                                                                                                                                                                        
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1.618033988749890000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
(1 row)

postgres=#

那么,有什么方法可以指定此计算方式,以便我能够看到完整的表示形式到任意小数位,并且仅受实现限制(即16383 DP)的约束吗?或者,在另一种措辞中–我可以查询黄金中位数的第N位是什么(1000 < N < 16383在哪里)?还是这仅仅是Postgres sqrt函数的局限性(在这里(可能出于性能原因),他们已将默认返回类型指定为NUMERIC而不是NUMERIC(16,16)

1 个答案:

答案 0 :(得分:1)

您仅将 some 个值转换为所需的精度。如果希望整体计算保持该精度,则必须至少确保所有输入都具有该精度。

默认情况下,1不具有您描述的精度。因此,您需要将该值以及计算中包含的所有其他数字转换为具有所需精度的类型。

SELECT
    (1::NUMERIC(1000, 999) + SQRT(5::NUMERIC(1000, 999))) / 2::NUMERIC(1000, 999)
        AS golden_mean;