利用字符串实现高精度数值运算(三)

由于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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值