Sql Oracle中的数字精度

Sql Oracle中的数字精度,sql,oracle,floating-point,precision,floating-accuracy,Sql,Oracle,Floating Point,Precision,Floating Accuracy,我有一个带有浮动列的表,如中所定义。 我插入了一个包含52个二进制数字的数字,不计算初始值1,这是隐式的,但我发现oracle只需要50个数字就可以正确存储它。怎么可能呢 create table numeric_types2( f1 float(60) ); insert into numeric_types2 SELECT BIN_TO_NUM( 1, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,

我有一个带有浮动列的表,如中所定义。 我插入了一个包含52个二进制数字的数字,不计算初始值1,这是隐式的,但我发现oracle只需要50个数字就可以正确存储它。怎么可能呢

create table numeric_types2(
    f1 float(60)
);
insert into numeric_types2 SELECT BIN_TO_NUM(
    1,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,1
                                      ) FROM DUAL;
然后:

select to_char(cast(f1 as float(49)), 'XXXXXXXXXXXXXXXXX'),
       to_char(cast(f1 as float(50)), 'XXXXXXXXXXXXXXXXX'),
       to_char(cast(f1 as float(51)), 'XXXXXXXXXXXXXXXXX')
from root.numeric_types2;
返回:

10000000000004,    10000000000001,    10000000000001

为什么呢?我缺少一些基本的浮点数学吗?

链接的文档页面显示

浮点值在内部表示为数字

可能是二进制数被舍入为十进制数吗

此外,转换为十进制后,十六进制数为:

10000000000001 -> 4503599627370497
10000000000004 -> 4503599627370500
所以在我看来,这个数字在内部被转换成十进制表示,四舍五入到14或15位十进制数字——497将四舍五入到500位

请注意,在拉丁语中,数字是以10为基数的digitus=finger。

浮点数据类型是NUMBER的子类型

所以这是一个隐藏的数字

要将二进制精度转换为十进制精度,请将n乘以0.30103

插入数字:

49 * 0.30103 = 14.75047
50 * 0.30103 = 15.05150
51 * 0.30103 = 15.65356
所以float50和float51对应数字16,而float49是数字15

您可以通过转储以下值来验证这一点:

create table numeric_types2 (
    f1 float(60), n1 number
);
insert into numeric_types2 
with rws as (
  select BIN_TO_NUM(
    1,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,1) n from dual
)
  select n, n from rws;

select dump ( f1 ), dump ( n1 ), 
       dump ( cast ( n1 as float(50) ) ) df50, 
       dump ( cast ( n1 as float(49) ) ) df49
from   numeric_types2;

DUMP(F1)                                 DUMP(N1)                                 DF50                                     DF49                                  
Typ=2 Len=9: 200,46,4,60,97,28,38,5,98   Typ=2 Len=9: 200,46,4,60,97,28,38,5,98   Typ=2 Len=9: 200,46,4,60,97,28,38,5,98   Typ=2 Len=8: 200,46,4,60,97,28,38,6    
注意

转储f1=转储n1=转储将n1转换为浮动50

仅将数字强制转换为float49会给出不同的值

最后请注意,这些文件还包含以下建议:

Oracle FLOAT可供您使用,但Oracle建议 您可以使用BINARY_FLOAT和BINARY_DOUBLE数据类型,因为它们 它们更加健壮


如前所述,这是因为在这种类型下有一个数字实现。正如您可以通过以下查询检查的那样,二进制精度完全被忽略:

二进制精度向上舍入为十进制精度N。 数字在数学上四舍五入到前N个有效位置,例如,对于N=2:101变为100,106变为110。 数字以数字格式存储,具有步骤2中的前N个有效数字,并按原始数字的比例缩放,例如,结果具有相同的长度,但有N个有效数字。 在这里

如您所见,对于精度1-3,您只能存储一个数字,对于4-6,您可以存储两个数字,等等。您还可以观察到,转储、列比例中的前两个字节每两个十进制数字改变一次比例


所以存储是:两个字节用于缩放,最多20个字节用于精度,其中每两个字节保存0到99之间的数字。但我不知道他们在哪里丢失了两位数,精度为38 19*2,应该是20。

谢谢!这里的上下文注释:这意味着,如果您使用的是cx_Oracle python驱动程序,那么FLOAT50是能够容纳53个二进制位的数字的最低精度,不计算第一个隐式1,当转换为python的float时,它将丢失,并截断为0x1.0000000000000 p+53
with a as (
  select level as l,
    cast(level as float(1)) as c,
    cast(level as float(2)) as c2,
    cast(level as float(3)) as c3,
    cast(level as float(4)) as c4,
    cast(level as float(6)) as c6,
    cast(level as float(7)) as c7
  from dual
  connect by level < 121
)
select a.*,
  dump(c, 16) as cd,
  dump(c4, 16) as c4d,
  dump(power(10, l), 16) as scale
from a