浅析number类型的值

number数据内部存储时,以变长的数组来存放,数组里的每个元素占一个字节,最多20个元素。内部代码为2。number数据的存放格式为:,sign bit/exponent,digit1,digit2,…,digit20
sign bit/exponent这部分叫做exponent byte。

exponent byte包括三部分:
  • sign bit:这表示高位bit,也就是128。并且我们有:
  1. 如果小于128,则数值为负数。
  2. 如果大于等于128,则数值为正数或0。
  • offset,始终为65
  • exponent:其范围从-65到62。该部分的值是基于100而进行的科学计数法。
为0时比较特殊,就只有sign bit而没有offset和exponent,也就是128。比如:
SQL> select dump(0) from dual;

DUMP(0)
----------------
Typ=2 Len=1: 128

来看一个非0的值:
SQL> select dump(25,16) from dual;

DUMP(25,16)
------------------
Typ=2 Len=2: c1,1a

则exponent byte为c1,也就是
SQL> select to_number('c1','xx'),to_number('1a','xx') from dual;

TO_NUMBER('C1','XX') TO_NUMBER('1A','XX')
-------------------- --------------------
                 193                   26

而193=128+65+0,也就是sign bit为128,offset为65,exponent为0。
同时,oracle存储时,用1表示0,2表示1,依此类推。也就是说用显示的值减1就是实际的值。如下所示:
SQL> select dump(1,16) from dual;

DUMP(1,16)
-----------------
Typ=2 Len=2: c1,2

因此,0xc11a就是:(26-1)*power(100,0)=25

再来看另一个例子:
SQL> select dump(1234,16) from dual;

DUMP(1234,16)
--------------------
Typ=2 Len=3: c2,d,23

这里c2表示194,也就是194=128+65+1。

SQL> select to_number('c2','xx'),to_number('d','xx'),to_number('23','xx') from dual;

TO_NUMBER('C2','XX') TO_NUMBER('D','XX') TO_NUMBER('23','XX')
-------------------- ------------------- --------------------
                 194                  13                   35

因此该数值为:(13-1)*power(100,1)+(35-1)*power(100,0)=1200+34=1234

如果数值为负数,则它的exponent byte的算法是一样的,只不过顺序是反过来的,从255开始计算。比如:
SQL> select dump(-25,16) from dual;

DUMP(-25,16)
---------------------
Typ=2 Len=3: 3e,4c,66

SQL> select to_number('3e','xx'),to_number('4c','xx') from dual;

TO_NUMBER('3E','XX') TO_NUMBER('4C','XX')
-------------------- --------------------
                  62                   76
负数的最后一位始终都是66,也就是说最后一位如果为66,则说明它是负数。
这时的exponent byte为:255-62=193=128+65+0
同时,oracle在存放number型数据时,以100为基数,同时正数和负数互为相反数,也就是正数+负数=100。因此我们就有:(100-76-1)*power(100,0)=25
加上符号位,则数值为-25

我们在来看一个例子:
SQL> select dump(-1234,16) from dual;

DUMP(-1234,16)
------------------------
Typ=2 Len=4: 3d,59,43,66

SQL> select to_number('3d','xx'),to_number('59','xx'),to_number('43','xx') from dual;

TO_NUMBER('3D','XX') TO_NUMBER('59','XX') TO_NUMBER('43','XX')
-------------------- -------------------- --------------------
                  61                   89                   67

于是exponent byte为:255-61=194=128+65+1
(100-89-1)*power(100,1)+(100-67-1)*power(100,0)=1200+24=1234
加上符号位,则数值为-1234

因此很明显,如果第一个字节大于等于128,则说明该数值为正数,并且exponent为:exponent = first byte - 128 - 65 = first byte - 193
如果第一个字节小于128,则说明该数值为负数,并且exponent为:
exponent = (255 - first byte) - 128 - 65 = 62 - first byte

对于小数来说:
SQL> select dump(1234567.89,16) from dual;

DUMP(1234567.89,16)
-----------------------------
Typ=2 Len=6: c4,2,18,2e,44,5a

exponent为:0xc4,也就是196,也就是196-193=3
digits分别为:
0x2=2-1=1=1*power(100,3)=1000000
0x18=24-1=23*power(100,2)=230000
0x2e=46-1=45*power(100,1)=4500
0x44=68-1=67*power(100,0)=67
0x5a=90-1=89*power(100,-1)=0.89
把它们都加起来,也就是1234567.89

再来看一个例子:
SQL> select dump(123456789.9876,16) from dual;

DUMP(123456789.9876,16)
-----------------------------------
Typ=2 Len=8: c5,2,18,2e,44,5a,63,4d

exponent为:0xc5,也就是197,也就是197-193=4
digits分别为:
0x2=2-1=1=1*power(100,4)=100000000
0x18=24-1=23*power(100,3)=23000000
0x2e=46-1=45*power(100,2)=450000
0x44=68-1=67*power(100,1)=6700
0x5a=90-1=89*power(100,0)=89
0x63=99-1=98*power(100,-1)=.098
0x4d=77-1=76*power(100,-2)=0.0076
把它们都加起来,就是123456789.9876

而对于负数来说,比如:
SQL> select dump(-123456.789,16) from dual;

DUMP(-123456.789,16)
--------------------------------
Typ=2 Len=7: 3c,59,43,2d,17,b,66

Exponent => 0x3c= 62(dec) - 60 = 2
Digits分别为:
0x59 = 89(dec): 101 - 89 = 12 > 12 * 100^2 = 120000
0x43 = 67(dec): 101 - 67 = 34 > 34 * 100^1 = 3400
0x2d = 45(dec): 101 - 45 = 56 > 56 * 100^0 = 56
0x17 = 23(dec): 101 - 23 = 78 > 78 * 100^-1 = .78
0xb = 11(dec): 101 - 11 = 90 > 90 * 100^-2 = .009
sum = 123456.789 (-)
忽略最后一位的符号位:0x66 = 102(dec)

oracle数值使用100作为基准,因此,每个digit都表示一个0到99的数值。总共最多使用20个digit来表示一个数值。
在比较数值大小时,oracle从左边开始比较每个digit,直到最后一个digit。比如,对于4和3来说:4表示为<193,5>。3表示为<193,4>,5大于4,因此,4>3。
而对于-4和-3来说,存放-4时为:<62,97>,存放-3时为:<62,98>。因此在比较-4和-3谁大时,可以看到98>97,因此-3>-4。
基于这样的比较方法,所以oracle会在数值最后存放102,也就是0x66,来表示它们都是负数。可以考虑下面的情况:-100 <61,100,102>和-115 <61, 100, 86, 102>。如果没有最后一位的102,则它们在比较大小时就要发生错误了。

因为digit基于100而来,一个字节可以表示的最大的数值为99。而exponent的范围从-65到62。因此,oracle能够保留的正数的最小值为:1 x 100^(-65) = 1 x 10^(-130)
而最大值为:99 x 100^(62) + 99 x 100^(61) + 99 x 100^(60) + ... + 99 x 100^(0),大约为1 x 10^(126)。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/9842/viewspace-353137/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/9842/viewspace-353137/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值