淺析number型別的值
number資料內部儲存時,以變長的陣列來存放,陣列裡的每個元素佔一個位元組,最多20個元素。內部程式碼為2。number資料的存放格式為:,sign bit/exponent,digit1,digit2,…,digit20
sign bit/exponent這部分叫做exponent byte。
exponent byte包括三部分:
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)。
sign bit/exponent這部分叫做exponent byte。
exponent byte包括三部分:
- sign bit:這表示高位bit,也就是128。並且我們有:
- 如果小於128,則數值為負數。
- 如果大於等於128,則數值為正數或0。
- offset,始終為65
- exponent:其範圍從-65到62。該部分的值是基於100而進行的科學計數法。
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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 淺析賦值、淺拷貝、深拷貝的區別賦值
- 淺析Kubernrtes服務型別(Service Types)型別
- Oracle基本資料型別儲存格式淺析——RAW型別Oracle資料型別
- Oracle的number資料型別Oracle資料型別
- JavaScript之number型別的數值轉換成某某進位制JavaScript型別
- JavaScript 隱性型別轉換步驟淺析JavaScript型別
- ORACLE NUMBER資料型別Oracle資料型別
- java多型性淺析Java多型
- SQL Server中datetimeset轉換datetime型別問題淺析SQLServer型別
- 值型別與引用型別的區別型別
- 超過 js 的 number 型別最大值(9007 1992 5474 0992)的解決辦法JS型別
- -XX:PretenureSizeThreshold的預設值和作用淺析
- jsp頁面number型別自動轉為String型別JS型別
- JS -- number資料型別詳解JS資料型別
- JS中其他資料型別轉為number資料型別的方法JS資料型別
- 值型別和引用型別型別
- 淺析MySQL InnoDB的隔離級別MySql
- 淺析多媒體互動展廳幾個常見型別型別
- js資料型別賦值,淺拷貝,深拷貝JS資料型別賦值
- JavaScript值型別和引用型別JavaScript型別
- c#:值型別&引用型別C#型別
- 淺談程式語言型別的強型別,弱型別,動態型別,靜態型別型別
- 淺析Java中的雜湊值HashCode的作用及用法Java
- 多型中的返回值型別多型型別
- 淺析mybatis中${}和#{}取值區別MyBatis
- MySQL bit型別增加索引後查詢結果不正確案例淺析MySql型別索引
- JavaScript - 基本型別與引用型別值JavaScript型別
- 從賦值看基本型別和引用型別的區別賦值型別
- 淺談JavaScript的型別轉換JavaScript型別
- [20191001]關於oracle number型別的一些疑惑.txtOracle型別
- TypeScript 數值型別TypeScript型別
- Python數值型別Python型別
- 10_深入解析Oracle number資料型別及os層number解析工具分享Oracle資料型別
- Go: 指標方法與值方法<->指標型別與值型別Go指標型別
- [20190930]oracle raw型別轉化number指令碼.txtOracle型別指令碼
- Python技術之Number資料型別介紹Python資料型別
- javascript原始值和引用值型別及區別JavaScript型別
- 自己挖的坑自己填--Mybatis mapper檔案if標籤中number型別及String型別的坑MyBatisAPP型別