Oracle 是大海,这里是它的一滴水! http://songhefei.itpub.net

number 小议 (转)

上一篇 / 下一篇  2008-06-25 12:06:12 / 个人分类:Oracle internal

number数据内部存储时,以变长的数组来存放,数组里的每个元素占一个字节,最多20个元素。内部代码为2。number数据的存放格式为:<[length]>,sign bit/exponent,digit1,digit2,…,digit20
:e8_1Ad5OJ"lU/a0sign bit/exponent这部分叫做exponent byte。
P}4FbP-_0
V*iY/Zs$u@Q0exponent byte包括三部分:ITPUB个人空间6M6]^2t9h+T/E
  • sign bit:这表示高位bit,也就是128。并且我们有:
  1. 如果小于128,则数值为负数。
  2. 如果大于等于128,则数值为正数或0。
  • offset,始终为65
  • exponent:其范围从-65到62。该部分的值是基于100而进行的科学计数法。
为0时比较特殊,就只有sign bit而没有offset和exponent,也就是128。比如:
v7x Fk/bs/y0SQL> select dump(0) from dual;ITPUB个人空间Ai|j%M

(V ^+YN"]};t0DUMP(0)
4@ h(n-l&{6u$d v0----------------
ym6^.p#?S0Typ=2 Len=1: 128ITPUB个人空间 v6A }-I&yCG
ITPUB个人空间(IM_&N&Sv B5C
来看一个非0的值:ITPUB个人空间&M*y E'E,]"E @Yn
SQL> select dump(25,16) from dual;ITPUB个人空间.ey!| `0|6_

_5`6[*P Pu%?0DUMP(25,16)ITPUB个人空间4y uk7{yTk2@z
------------------
B3kV0Wv,m3a}0Typ=2 Len=2: c1,1a
M m"@9Ot-|:y0ITPUB个人空间 Hw9s+J+u"x?
则exponent byte为c1,也就是
j[2T4R6a%g!p0SQL> select to_number('c1','xx'),to_number('1a','xx') from dual;ITPUB个人空间*ESo0U N.d

9w&m(SV+h-x wZ0TO_NUMBER('C1','XX') TO_NUMBER('1A','XX')
:x g yB!P4e0-------------------- --------------------ITPUB个人空间 Z(X$jkL9L6V]#?s;w
                 193                   26ITPUB个人空间%u8W q5@ Bh4b|

qD@pJj*r/f0而193=128+65+0,也就是sign bit为128,offset为65,exponent为0。ITPUB个人空间w!jaP*T X%ex:yD
同时,oracle存储时,用1表示0,2表示1,依此类推。也就是说用显示的值减1就是实际的值。如下所示:ITPUB个人空间7Q/_8[#GkK
SQL> select dump(1,16) from dual;ITPUB个人空间.Q(wj!yd5E naW
ITPUB个人空间t4n$n&o1H^[
DUMP(1,16)ITPUB个人空间-Z'FZ&P8}C&MX
-----------------
[ S|2Hx+}X8K@!d0Typ=2 Len=2: c1,2
oJJyLH`0
2`/}&g(u#r3\v2Co0因此,0xc11a就是:(26-1)*power(100,0)=25
R,F0t2}!mgx X0ITPUB个人空间 {V M^g~8^p
再来看另一个例子:ITPUB个人空间,Cl4@MUb:hi
SQL> select dump(1234,16) from dual;ITPUB个人空间L/{a`y)zz
ITPUB个人空间UaL9L [XM;W*E0W
DUMP(1234,16)
Dz&xm9OZV6IV0--------------------ITPUB个人空间 f-y i.h&j2k0}
Typ=2 Len=3: c2,d,23ITPUB个人空间9LP'}Oe;] B'Q1t}
ITPUB个人空间3{e+[;^4f R
这里c2表示194,也就是194=128+65+1。
:mD,ykT-l)i0
c5F"kBWp0SQL> select to_number('c2','xx'),to_number('d','xx'),to_number('23','xx') from dual;ITPUB个人空间 V,r-m1Wg9L
ITPUB个人空间_ \+DcSb
TO_NUMBER('C2','XX') TO_NUMBER('D','XX') TO_NUMBER('23','XX')
`0{[,scmu*Z6~0-------------------- ------------------- --------------------
8~P d1P(|!o0                 194                  13                   35
({T N|`8[/aG4U0
`$X0\4P F2D"r+Q0因此该数值为:(13-1)*power(100,1)+(35-1)*power(100,0)=1200+34=1234ITPUB个人空间|-H`)X(d:hF3Mi~ y

6M(JE/n\.}0如果数值为负数,则它的exponent byte的算法是一样的,只不过顺序是反过来的,从255开始计算。比如:
_ X g0jF ~'g0SQL> select dump(-25,16) from dual;
$c"U@0x.MyYG0ITPUB个人空间$y%{{8x:D?%`{
DUMP(-25,16)ITPUB个人空间h4D v S{#X U#S
---------------------
8Nw3E_N*U'?j|0Typ=2 Len=3: 3e,4c,66ITPUB个人空间6xgyaqU
ITPUB个人空间l%R fv UI F _7Q*gN
SQL> select to_number('3e','xx'),to_number('4c','xx') from dual;ITPUB个人空间/OPV-hgoR
ITPUB个人空间*D|FSsa+s.A
TO_NUMBER('3E','XX') TO_NUMBER('4C','XX')
t`/a q[5W%_!~0C0-------------------- --------------------ITPUB个人空间?M;NuyQ7C#t_d
                  62                   76ITPUB个人空间&r-m.^@L2H
负数的最后一位始终都是66,也就是说最后一位如果为66,则说明它是负数。
&VR m `y"q~gE0这时的exponent byte为:255-62=193=128+65+0
*a4yj\rX0同时,oracle在存放number型数据时,以100为基数,同时正数和负数互为相反数,也就是正数+负数=100。因此我们就有:(100-76-1)*power(100,0)=25ITPUB个人空间?Z ck\}3Uz
加上符号位,则数值为-25
3J2iF4g&o*k0
XS;_I,o4^ b k6t0我们在来看一个例子:
0[)WJu3uC'J e T0SQL> select dump(-1234,16) from dual;
o0ez/Smz%a0
pA%V;[|P/TR0DUMP(-1234,16)
A5@&{]%A)}0------------------------
8EP1R4Za bd!x0Typ=2 Len=4: 3d,59,43,66ITPUB个人空间qm }F%]-P
ITPUB个人空间[ r2y[4Md C
SQL> select to_number('3d','xx'),to_number('59','xx'),to_number('43','xx') from dual;ITPUB个人空间`kTrIZ\F U~b

` |9@,bi5o?0TO_NUMBER('3D','XX') TO_NUMBER('59','XX') TO_NUMBER('43','XX')ITPUB个人空间 yc [.HI"K&X?cjL
-------------------- -------------------- --------------------
p!yy efhl0                  61                   89                   67
-lU#C(r3L uqO0ITPUB个人空间{ fR.Fq/}e;L(] Q/h,J
于是exponent byte为:255-61=194=128+65+1
y!XJE`+V0(100-89-1)*power(100,1)+(100-67-1)*power(100,0)=1200+24=1234ITPUB个人空间M+V X P1p
加上符号位,则数值为-1234ITPUB个人空间*p%C/U S0N[$X1o}

"pMfI2JE*f V5u Ln2o0因此很明显,如果第一个字节大于等于128,则说明该数值为正数,并且exponent为:exponent = first byte - 128 - 65 = first byte - 193
C6`*c"Ezy~)G)vy0如果第一个字节小于128,则说明该数值为负数,并且exponent为:
/@]H@nv-\0exponent = (255 - first byte) - 128 - 65 = 62 - first byte
]*n){Vpe-Vr0
1jrO{@0对于小数来说:ITPUB个人空间:\_'D#k!m
SQL> select dump(1234567.89,16) from dual;ITPUB个人空间b[w9P%E/ul
ITPUB个人空间V$i E`%cDd8B+E
DUMP(1234567.89,16)
,p9]*Jd-y/W0-----------------------------
#ZC"w GEe3B0Typ=2 Len=6: c4,2,18,2e,44,5a
W&Xvz}U%W| w9m0
;lwb _7R0exponent为:0xc4,也就是196,也就是196-193=3ITPUB个人空间8ot.qIQV5qik
digits分别为:ITPUB个人空间 }o1y*f-AE
0x2=2-1=1=1*power(100,3)=1000000
{h%[1cB#Q4a$p5{00x18=24-1=23*power(100,2)=230000ITPUB个人空间Tfn{%w!`"yVf
0x2e=46-1=45*power(100,1)=4500ITPUB个人空间9r&A-d(k;yfD
0x44=68-1=67*power(100,0)=67ITPUB个人空间-S SL-g%U0cD
0x5a=90-1=89*power(100,-1)=0.89ITPUB个人空间 VyE A O&P
把它们都加起来,也就是1234567.89
:X*T^;?6uc[0ITPUB个人空间 vk"v$I-bB0^
再来看一个例子:ITPUB个人空间y$U8qM2@ `||L_
SQL> select dump(123456789.9876,16) from dual;ITPUB个人空间#s*y `!E|U?
ITPUB个人空间1X'R0O ` CP
DUMP(123456789.9876,16)ITPUB个人空间_ p7KT r]
-----------------------------------
8\"];fA }0Typ=2 Len=8: c5,2,18,2e,44,5a,63,4d
/A"Ir.an7HOAh0
?(iM.Vm*p0exponent为:0xc5,也就是197,也就是197-193=4ITPUB个人空间[)]kL3Y1r
digits分别为:
SBe)ncy00x2=2-1=1=1*power(100,4)=100000000
f.AB2a7P/fe:i3B00x18=24-1=23*power(100,3)=23000000
c6Xqz;h^v#Q8neO00x2e=46-1=45*power(100,2)=450000
Q#Y~9r.A#~V Y/^ q+O00x44=68-1=67*power(100,1)=6700ITPUB个人空间YGk;o \X+jm
0x5a=90-1=89*power(100,0)=89
.T9U4kE0Yxh'V00x63=99-1=98*power(100,-1)=.098
J.CB4d#}0W6{i00x4d=77-1=76*power(100,-2)=0.0076
\1mtCXK)VoW9H0把它们都加起来,就是123456789.9876ITPUB个人空间KYwQ Pwe

3p)s okB$r4P)Eo#L0而对于负数来说,比如:ITPUB个人空间:zf%@e1wI
SQL> select dump(-123456.789,16) from dual;ITPUB个人空间K0YJLuw:~J[

KwZ9S$n y0DUMP(-123456.789,16)
{2og0j/x9a J2D0--------------------------------ITPUB个人空间P5i#]iQW
Typ=2 Len=7: 3c,59,43,2d,17,b,66ITPUB个人空间P5y*`8{q0~z-t d

8_!ggs:}0Exponent => 0x3c= 62(dec) - 60 = 2
FL}U Q2X/N @F5}0Digits分别为:ITPUB个人空间2[ Zw9P1l/vG$a
0x59 = 89(dec): 101 - 89 = 12 > 12 * 100^2 = 120000
t g^bgI g2^00x43 = 67(dec): 101 - 67 = 34 > 34 * 100^1 = 3400ITPUB个人空间&ULh9r*XBW
0x2d = 45(dec): 101 - 45 = 56 > 56 * 100^0 = 56ITPUB个人空间S4s'e{^9K`~
0x17 = 23(dec): 101 - 23 = 78 > 78 * 100^-1 = .78ITPUB个人空间.|,^XYL&T+b G
0xb = 11(dec): 101 - 11 = 90 > 90 * 100^-2 = .009ITPUB个人空间GQ9dF"Kd[u O
sum = 123456.789 (-)ITPUB个人空间$b8F+cf;?m
忽略最后一位的符号位:0x66 = 102(dec)
/e I@i#O6]#OA0
V-Drj2o%X2m|V)t0oracle数值使用100作为基准,因此,每个digit都表示一个0到99的数值。总共最多使用20个digit来表示一个数值。ITPUB个人空间%d+u$c Q?wcR
在比较数值大小时,oracle从左边开始比较每个digit,直到最后一个digit。比如,对于4和3来说:4表示为<193,5>。3表示为<193,4>,5大于4,因此,4>3。
g[y3\*k%~2y#G0而对于-4和-3来说,存放-4时为:<62,97>,存放-3时为:<62,98>。因此在比较-4和-3谁大时,可以看到98>97,因此-3>-4。
.pUAk%gR"V0基于这样的比较方法,所以oracle会在数值最后存放102,也就是0x66,来表示它们都是负数。可以考虑下面的情况:-100 <61,100,102>和-115 <61, 100, 86, 102>。如果没有最后一位的102,则它们在比较大小时就要发生错误了。
M9g8H5q6f,y0ITPUB个人空间a5j? Y4Kh
因为digit基于100而来,一个字节可以表示的最大的数值为99。而exponent的范围从-65到62。因此,oracle能够保留的正数的最小值为:1 x 100^(-65) = 1 x 10^(-130)ITPUB个人空间*`~M(l o`1R[,} y
而最大值为:99 x 100^(62) + 99 x 100^(61) + 99 x 100^(60) + ... + 99 x 100^(0),大约为1 x 10^(126)。

TAG:

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar