PostgreSQL 浮点精度调整(extra_float_digits)

1 minute read

背景

之前写过一篇文章介绍PostgreSQL浮点类型存储值和表述值不一致带来的问题。

请参考:

《don’t mistake the float/double’s display & real value》

浮点精度,在大多数平台中,float4精确到6位数字,float8精确到15位数字。

On most platforms, the real type has a range of at least 1E-37 to 1E+37 with a precision of at least 6 decimal digits. The double precision type typically has a range of around 1E-307 to 1E+308 with a precision of at least 15 digits.

使用extra_float_digits 参数最多可以增加3位精度。

语法方面,PostgreSQL兼容IEEE的用法。支持在float()中输入bit位。

代码如下,1到24个比特位表示float4,25到53个比特位表示float8:

src/backend/parser/gram.y

opt_float:      '(' Iconst ')'  
                                {  
                                        /*  
                                         * Check FLOAT() precision limits assuming IEEE floating  
                                         * types - thomas 1997-09-18  
                                         */  
                                        if ($2 < 1)  
                                                ereport(ERROR,  
                                                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),  
                                                                 errmsg("precision for type float must be at least 1 bit"),  
                                                                 parser_errposition(@2)));  
                                        else if ($2 <= 24)  
                                                $$ = SystemTypeName("float4");  
                                        else if ($2 <= 53)  
                                                $$ = SystemTypeName("float8");  
                                        else  
                                                ereport(ERROR,  
                                                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),  
                                                                 errmsg("precision for type float must be less than 54 bits"),  
                                                                 parser_errposition(@2)));  
                                }  
                        | /*EMPTY*/  
                                {  
                                        $$ = SystemTypeName("float8");  
                                }  
                ;  

例子:

postgres=# select 123333333333333::float(1);  
   float4      
-------------  
 1.23333e+14  
(1 row)  

增加3个数字精度

postgres=# set  extra_float_digits=3;  
SET  
postgres=# select 123333333333333::float(1);  
     float4       
----------------  
 1.23333333e+14  
(1 row)  

1到24表示float4即real

postgres=# select pg_typeof(123333333333333::float(1));  
 pg_typeof   
-----------  
 real  
(1 row)  
postgres=# select pg_typeof(123333333333333::float(24));  
 pg_typeof   
-----------  
 real  
(1 row)  

25到53表示float8

postgres=# select pg_typeof(123333333333333::float(25));  
    pg_typeof       
------------------  
 double precision  
(1 row)  
postgres=# select pg_typeof(123333333333333::float(53));  
    pg_typeof       
------------------  
 double precision  
(1 row)  

必须注意float()括号中的值不代表小数点后几位,而是代表用来存储浮点数的比特位数。而且在PostgreSQL中这个值并没有意义,只是用来区分它是float4还是float8而已。

postgres=# set  extra_float_digits=0;  
SET  
postgres=# select 1.23333333333333::float(1);  
 float4    
---------  
 1.23333  
(1 row)  
postgres=# select 1.23333333333333::float(24);  
 float4    
---------  
 1.23333  
(1 row)  

Oracle的浮点类型有两种,一种是numeric的别名,一种是IEEE的浮点

2  
FLOAT [(p)]  
A subtype of the NUMBER datatype having precision p.   
A FLOAT value is represented internally as NUMBER.   
The precision p can range from 1 to 126 binary digits.   
A FLOAT value requires from 1 to 22 bytes.  
  
21  
BINARY_FLOAT  
32-bit floating point number. This datatype requires 5 bytes, including the length byte.  
  
22  
BINARY_DOUBLE  
64-bit floating point number. This datatype requires 9 bytes, including the length byte.  

http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements001.htm#i54330

http://www.cnblogs.com/BradMiller/archive/2010/11/25/1887945.html

PostgreSQL通过设置extra_float_digits可以来调配精度,从而达到和Oracle一致的目的。

参考

1. http://www.postgresql.org/docs/9.4/static/datatype-numeric.html#DATATYPE-FLOAT

2. src/backend/utils/adt/float.c

3. man float.h

4. http://www.cnblogs.com/BradMiller/archive/2010/11/25/1887945.html

5. http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements001.htm#i54330

Flag Counter

digoal’s 大量PostgreSQL文章入口