原帖由 newkid 于 10-9-8 00:48 发表
0.1肯定无法分解,可是oracle不会那么像你想的那样表示,它只用了两个字节表示。咱们按最土的办法,存一个小数点和一个1不也就可以了吗。
你的例子太复杂了,弄个简单的抵消的例子?我觉得很困难,误差只能积累。
两个字节,一个字节是8位,两个字节就是16位,对不?
我那样表示应该没错的,还没超过16位呢
要不然,oracle是怎么表示的呢?
不过我顺道做了测试,发现从0.1~0.9,dump出来的结果很有意思:
SCOTT@lw.lw> select dump(rownum/10) from dual connect by rownum<10;
DUMP(ROWNUM/10)
--------------------------------------------------------------------------------
Typ=2 Len=2: 192,11
Typ=2 Len=2: 192,21
Typ=2 Len=2: 192,31
Typ=2 Len=2: 192,41
Typ=2 Len=2: 192,51
Typ=2 Len=2: 192,61
Typ=2 Len=2: 192,71
Typ=2 Len=2: 192,81
Typ=2 Len=2: 192,91
已选择9行。
如果除以100或1000,还能有进一步的发现,在此就不赘述了,至少我自己还没找出什么特别有价值的东西。
但貌似这些比较符合你说的“可是oracle不会那么像你想的那样表示”
————————————————————————————————————————————————————
我的例子里没有抵消的,或者说有抵消的但我没看出来
我尝试去找一下:
1、找出先除后乘后,存在计算误差的数
SCOTT@lw.lw> select rn, n, n1 from (select rownum rn, n, n/rownum*rownum
n1 from (select 1.39*10.5 n from dual) connect by rownum<40) where n1-n<>0;
RN N N1
---------- ---------- ----------
9 14.595 14.595
11 14.595 14.595
13 14.595 14.595
已用时间: 00: 00: 00.03
(在这里,先乘后除,试验了40万以内的正整数,没一个出现误差的)
2、构造序列,做笛卡尔积,找出误差被抵消的情况
SCOTT@lw.lw> with cand as ( select rn, n, n1 from (select rownum rn, n, n/
rownum*rownum n1 from (select 1.39*10.5 n from dual) connect by rownum<40) where
n1-n<>0),
2 t as (select rownum mp from dual connect by rownum<100)
3 select mp, rn, n, n1, n-n1, n-n1*mp/mp, n-n1/mp*mp from cand, t where n-n1*
mp/mp=0 or n-n1/mp*mp=0
4 /
MP RN N N1 N-N1 N-N1*MP/MP N-N1/MP*MP
---------- ---------- ---------- ---------- ---------- ---------- ----------
7 9 14.595 14.595 -3.000E-38 0 0
8 9 14.595 14.595 -3.000E-38 0 0
9 9 14.595 14.595 -3.000E-38 0 -3.000E-38
10 9 14.595 14.595 -3.000E-38 0 0
11 9 14.595 14.595 -3.000E-38 0 2.0000E-38
12 9 14.595 14.595 -3.000E-38 0 0
13 9 14.595 14.595 -3.000E-38 0 -3.000E-38
14 9 14.595 14.595 -3.000E-38 0 0
15 9 14.595 14.595 -3.000E-38 0 -3.000E-38
16 9 14.595 14.595 -3.000E-38 0 -3.000E-38
4 11 14.595 14.595 2.0000E-38 2.0000E-38 0
5 11 14.595 14.595 2.0000E-38 2.0000E-38 0
6 11 14.595 14.595 2.0000E-38 2.0000E-38 0
7 11 14.595 14.595 2.0000E-38 0 0
8 11 14.595 14.595 2.0000E-38 0 0
9 11 14.595 14.595 2.0000E-38 0 6.0000E-38
10 11 14.595 14.595 2.0000E-38 0 0
11 11 14.595 14.595 2.0000E-38 0 2.0000E-38
12 11 14.595 14.595 2.0000E-38 0 0
13 11 14.595 14.595 2.0000E-38 0 -3.000E-38
14 11 14.595 14.595 2.0000E-38 0 0
15 11 14.595 14.595 2.0000E-38 0 2.0000E-38
16 11 14.595 14.595 2.0000E-38 0 2.0000E-38
17 11 14.595 14.595 2.0000E-38 0 2.0000E-38
18 11 14.595 14.595 2.0000E-38 0 2.0000E-38
19 11 14.595 14.595 2.0000E-38 0 2.0000E-38
20 11 14.595 14.595 2.0000E-38 0 2.0000E-38
21 11 14.595 14.595 2.0000E-38 0 2.0000E-38
22 11 14.595 14.595 2.0000E-38 0 2.0000E-38
23 11 14.595 14.595 2.0000E-38 0 2.0000E-38
24 11 14.595 14.595 2.0000E-38 0 2.0000E-38
25 11 14.595 14.595 2.0000E-38 0 2.0000E-38
7 13 14.595 14.595 -3.000E-38 0 0
8 13 14.595 14.595 -3.000E-38 0 0
9 13 14.595 14.595 -3.000E-38 0 -3.000E-38
10 13 14.595 14.595 -3.000E-38 0 0
11 13 14.595 14.595 -3.000E-38 0 2.0000E-38
12 13 14.595 14.595 -3.000E-38 0 0
13 13 14.595 14.595 -3.000E-38 0 -3.000E-38
14 13 14.595 14.595 -3.000E-38 0 0
15 13 14.595 14.595 -3.000E-38 0 -3.000E-38
16 13 14.595 14.595 -3.000E-38 0 -3.000E-38
已选择42行。
3、验证一下:
选择上面标红的数据做验证,注意在下面的例子中,因为用到round函数,而小数点后第三位为5,所以一定要选取N-N1大于0的数据来做方能看出效果
SCOTT@lw.lw>select round(n,2) x, round(n/11*11,2) y, round(n/11*11/4*4,2)
z from (select 1.39*10.5 n from dual);
X Y Z
---------- ---------- ----------
14.6 14.59 14.6
误差抵消了????做个减法测试下:
SCOTT@lw.lw>select n-14.595 xx, n/11*11-14.595 yy,
n/11*11/4*4-14.595 zz from (select 1.39*10.5 n from dual);
XX YY ZZ
---------- ---------- ----------
0 -2.000E-38 0
果然如此,误差抵消了…………