由于Oracle的数值类型的最大精度只有38位,因此对于高精度的数值计算就需要使用其他的方法来实现。
这篇文章利用字符串来保存高精度数值,并实现了两个字符串中数值的运算。
这篇描述两个表示整数的字符串相减。
利用字符串实现高精度数值运算(一):http://yangtingkun.itpub.net/post/468/469206
利用字符串实现高精度数值运算(二):http://yangtingkun.itpub.net/post/468/469241
上一篇给出了字符串相乘的算法,这一篇继续探讨减法的实现。由于前两篇文章实际上都使用了以前实现的整数部分的代码,而这一篇则没有相应的代码可以重用。
因此模仿前面的实现,将这个复杂的问题拆分成两个相对简单一些的问题,首先实现整数部分的减法,然后再扩展到小数部分。
SQL> CREATE OR REPLACE FUNCTION F_ADD_STR(P_ADD1 IN VARCHAR2, P_ADD2 IN VARCHAR2) RETURN VARCHAR2 AS
2 V_LENGTH1 NUMBER DEFAULT LENGTH(P_ADD1);
3 V_LENGTH2 NUMBER DEFAULT LENGTH(P_ADD2);
4 BEGIN
5 IF V_LENGTH1 > 37 THEN
6 RETURN
7 F_ADD_STR
8 (
9 SUBSTR(P_ADD1, 1, V_LENGTH1 - 37),
10 NVL
11 (
12 SUBSTR
13 (
14 F_ADD_STR(SUBSTR(P_ADD1, V_LENGTH1 - 36), P_ADD2),
15 1,
16 LENGTH(F_ADD_STR(SUBSTR(P_ADD1, V_LENGTH1 - 36), P_ADD2)) - 37
17 ),
18 '0'
19 )
20 ) || SUBSTR(F_ADD_STR(SUBSTR(P_ADD1, V_LENGTH1 - 36), P_ADD2), - 37);
21 ELSIF V_LENGTH2 > 37 THEN
22 RETURN
23 F_ADD_STR
24 (
25 NVL
26 (
27 SUBSTR
28 (
29 F_ADD_STR(P_ADD1, SUBSTR(P_ADD2, V_LENGTH2 - 36)),
30 1,
31 LENGTH(F_ADD_STR(P_ADD1, SUBSTR(P_ADD2, V_LENGTH2 - 36))) - 37
32 ),
33 '0'
34 ),
35 SUBSTR(P_ADD2, 1, V_LENGTH2 - 37)
36 )
37 || SUBSTR(F_ADD_STR(P_ADD1, SUBSTR(P_ADD2, V_LENGTH2 - 36)), - 37);
38 ELSE
39 RETURN
40 LTRIM
41 (
42 TO_CHAR
43 (
44 TO_NUMBER(P_ADD1) + TO_NUMBER(P_ADD2),
45 RPAD
46 (
47 '0',
48 GREATEST(V_LENGTH1, V_LENGTH2, LENGTH(TO_NUMBER(P_ADD1) + TO_NUMBER(P_ADD2))),
49 '9'
50 )
51 )
52 );
53 END IF;
54 END;
55 /
函数已创建。
先建立F_STR_ADD函数,这个函数需要被F_SUB_STR调用,将其作为F_SUB_STR的内部函数没有必要,而且会明显增加代码的长度。
SQL> CREATE OR REPLACE FUNCTION F_SUB_STR(P_SUB1 IN VARCHAR2, P_SUB2 IN VARCHAR2) RETURN VARCHAR2 AS
2 V_LENGTH1 NUMBER DEFAULT LENGTH(P_SUB1);
3 V_LENGTH2 NUMBER DEFAULT LENGTH(P_SUB2);
4 V_RES1 VARCHAR2(32767);
5 V_RES2 VARCHAR2(32767);
6 BEGIN
7 IF SUBSTR(P_SUB1, 1, 1) = '-' THEN
8 IF SUBSTR(P_SUB2, 1, 1) = '-' THEN
9 RETURN F_SUB_STR(SUBSTR(P_SUB2, 2), SUBSTR(P_SUB1, 2));
10 ELSE
11 RETURN '-' || F_ADD_STR(SUBSTR(P_SUB1, 2), P_SUB2);
12 END IF;
13 ELSE
14 IF SUBSTR(P_SUB2, 1, 1) = '-' THEN
15 RETURN F_ADD_STR(SUBSTR(P_SUB1, 2), P_SUB2);
16 END IF;
17 END IF;
18 IF V_LENGTH1 > 37 AND V_LENGTH2 > 37 THEN
19 V_RES1 := F_SUB_STR(SUBSTR(P_SUB1, 1, V_LENGTH1 - 37), SUBSTR(P_SUB2, 1, V_LENGTH2 - 37));
20 V_RES2 := F_SUB_STR(SUBSTR(P_SUB1, V_LENGTH1 - 36), SUBSTR(P_SUB2, V_LENGTH2 - 36));
21 IF SUBSTR(V_RES1, 1, 1) = '-' THEN
22 IF SUBSTR(V_RES2, 1, 1) = '-' OR LTRIM(V_RES2, '0') IS NULL THEN
23 RETURN V_RES1 || SUBSTR(V_RES2, 2);
24 ELSE
25 RETURN '-' || F_SUB_STR(SUBSTR(V_RES1, 2), '1')
26 || F_ADD_STR(F_SUB_STR(LPAD('9', 37, '9'), V_RES2), LPAD('1', 37, '0'));
27 END IF;
28 ELSIF LTRIM(V_RES1, '0') IS NULL THEN
29 RETURN V_RES2;
30 ELSE
31 IF SUBSTR(V_RES2, 1, 1) = '-' THEN
32 RETURN F_SUB_STR(V_RES1, 1)
33 || F_ADD_STR(F_SUB_STR(LPAD('9', 37, '9'), SUBSTR(V_RES2, 2)), LPAD('1', 37, '0'));
34 ELSE
35 RETURN V_RES1 || V_RES2;
36 END IF;
37 END IF;
38 ELSIF V_LENGTH2 > 37 THEN
39 V_RES1 := F_SUB_STR('0', SUBSTR(P_SUB2, 1, V_LENGTH2 - 37));
40 V_RES2 := F_SUB_STR(P_SUB1, SUBSTR(P_SUB2, V_LENGTH2 - 36));
41 IF SUBSTR(V_RES1, 1, 1) = '-' THEN
42 IF SUBSTR(V_RES2, 1, 1) = '-' OR LTRIM(V_RES2, '0') IS NULL THEN
43 RETURN V_RES1 || SUBSTR(V_RES2, 2);
44 ELSE
45 RETURN '-' || F_SUB_STR(SUBSTR(V_RES1, 2), '1')
46 || F_ADD_STR(F_SUB_STR(LPAD('9', 37, '9'), V_RES2), LPAD('1', 37, '0'));
47 END IF;
48 ELSIF LTRIM(V_RES1, '0') IS NULL THEN
49 RETURN V_RES2;
50 ELSE
51 IF SUBSTR(V_RES2, 1, 1) = '-' THEN
52 RETURN F_SUB_STR(V_RES1, 1)
53 || F_ADD_STR(F_SUB_STR(LPAD('9', 37, '9'), SUBSTR(V_RES2, 2)), LPAD('1', 37, '0'));
54 ELSE
55 RETURN V_RES1 || V_RES2;
56 END IF;
57 END IF;
58 ELSIF V_LENGTH1 > 37 THEN
59 V_RES1 := SUBSTR(P_SUB1, 1, V_LENGTH1 - 37);
60 V_RES2 := F_SUB_STR(SUBSTR(P_SUB1, V_LENGTH1 - 36), P_SUB2);
61 IF SUBSTR(V_RES1, 1, 1) = '-' THEN
62 IF SUBSTR(V_RES2, 1, 1) = '-' OR LTRIM(V_RES2, '0') IS NULL THEN
63 RETURN V_RES1 || SUBSTR(V_RES2, 2);
64 ELSE
65 RETURN '-' || F_SUB_STR(SUBSTR(V_RES1, 2), '1')
66 || F_ADD_STR(F_SUB_STR(LPAD('9', 37, '9'), V_RES2), LPAD('1', 37, '0'));
67 END IF;
68 ELSIF LTRIM(V_RES1, '0') IS NULL THEN
69 RETURN V_RES2;
70 ELSE
71 IF SUBSTR(V_RES2, 1, 1) = '-' THEN
72 RETURN F_SUB_STR(V_RES1, 1)
73 || F_ADD_STR(F_SUB_STR(LPAD('9', 37, '9'), SUBSTR(V_RES2, 2)), LPAD('1', 37, '0'));
74 ELSE
75 RETURN V_RES1 || V_RES2;
76 END IF;
77 END IF;
78 ELSE
79 RETURN SUBSTR(SIGN(TO_NUMBER(P_SUB1) - TO_NUMBER(P_SUB2)), -2, 1)
80 || LPAD(ABS(TO_NUMBER(P_SUB1) - TO_NUMBER(P_SUB2)), GREATEST(V_LENGTH1, V_LENGTH2), '0');
81 END IF;
82 END;
83 /
函数已创建。
下面验证一下:
SQL> SELECT F_SUB_STR('123451234512345', '5432154321') FROM DUAL;
F_SUB_STR('123451234512345','5432154321')
--------------------------------------------------------------------------------
123445802358024
SQL> SELECT F_SUB_STR('5432154321', '123451234512345') FROM DUAL;
F_SUB_STR('5432154321','123451234512345')
--------------------------------------------------------------------------------
-123445802358024
SQL> SELECT F_SUB_STR('55555555555555555555555555555555555555', '2222222222222') FROM DUAL;
F_SUB_STR('55555555555555555555555555555555555555','2222222222222')
--------------------------------------------------------------------------------
55555555555555555555555553333333333333
SQL> SELECT F_SUB_STR('55555555555555555555555555555555555555',
2 '2222222222222222222222222222222222222222222222222') FROM DUAL;
F_SUB_STR('55555555555555555555555555555555555555','2222222222222222222222222222
--------------------------------------------------------------------------------
-2222222222166666666666666666666666666666666666667
SQL> SELECT F_SUB_STR('55555555555555555555555555555555555555',
2 '66666666666666666666666666666666666666') FROM DUAL;
F_SUB_STR('55555555555555555555555555555555555555','6666666666666666666666666666
--------------------------------------------------------------------------------
-11111111111111111111111111111111111111
SQL> SELECT F_SUB_STR('555555555555555555555555555555555555555',
2 '66666666666666666666666666666666666666') FROM DUAL;
F_SUB_STR('555555555555555555555555555555555555555','666666666666666666666666666
--------------------------------------------------------------------------------
488888888888888888888888888888888888889
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-434627/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/4227/viewspace-434627/