PostgreSQL 浮点精度调整(extra_float_digits)
背景
之前写过一篇文章介绍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