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

由于Oracle的数值类型的最大精度只有38位,因此对于高精度的数值计算就需要使用其他的方法来实现。

这篇文章利用字符串来保存高精度数值,并实现了两个字符串中数值的运算。

这篇描述两个字符串相加。

 

 

其实在以前处理超大数值的时候,写过一个字符串相加的函数,不过当时这个函数只是处理正整数的相加,没有考虑小数的情况。详细描述可以参考:http://yangtingkun.itpub.net/post/468/241044

当前面临的问题则主要是小数精度的问题。不过这并不影响对原有代码的重用,只需要在原有的代码外面嵌套一层,分别对整数部分和小数部分进行运算,并最终将结果合并起来即可。

SQL> CREATE OR REPLACE FUNCTION F_STR_ADD (P_STR1 IN VARCHAR2, P_STR2 IN VARCHAR2) RETURN VARCHAR2 AS
  2   V_INTEGER_STR1 VARCHAR2(32767) := NVL(
  3    SUBSTR(P_STR1, 1,
  4     CASE INSTR(P_STR1, '.') WHEN 0 THEN LENGTH(P_STR1) ELSE INSTR(P_STR1, '.') - 1 END
  5    ), 0);
  6   V_INTEGER_STR2 VARCHAR2(32767) := NVL(
  7    SUBSTR(P_STR2, 1,
  8     CASE INSTR(P_STR2, '.') WHEN 0 THEN LENGTH(P_STR2) ELSE INSTR(P_STR2, '.') - 1 END
  9    ), 0);
 10   V_OTHER_STR1 VARCHAR2(32767) := CASE INSTR(P_STR1, '.')
 11    WHEN 0 THEN NULL ELSE SUBSTR(P_STR1, INSTR(P_STR1, '.') + 1) END;
 12   V_OTHER_STR2 VARCHAR2(32767) := CASE INSTR(P_STR2, '.')
 13    WHEN 0 THEN NULL ELSE SUBSTR(P_STR2, INSTR(P_STR2, '.') + 1) END;
 14   V_LENGTH_OTHER_1 NUMBER := NVL(LENGTH(V_OTHER_STR1), 0);
 15   V_LENGTH_OTHER_2 NUMBER := NVL(LENGTH(V_OTHER_STR2), 0);
 16   V_RESULT VARCHAR2(32767);
 17 
 18   FUNCTION F_ADD_STR(P_ADD1 IN VARCHAR2, P_ADD2 IN VARCHAR2) RETURN VARCHAR2 AS
 19    V_LENGTH1 NUMBER DEFAULT LENGTH(P_ADD1);
 20    V_LENGTH2 NUMBER DEFAULT LENGTH(P_ADD2);
 21   BEGIN
 22    IF V_LENGTH1 > 37 THEN
 23     RETURN
 24      F_ADD_STR
 25      (
 26       SUBSTR(P_ADD1, 1, V_LENGTH1 - 37),
 27       NVL
 28       (
 29        SUBSTR
 30        (
 31         F_ADD_STR(SUBSTR(P_ADD1, V_LENGTH1 - 36), P_ADD2),
 32         1,
 33         LENGTH(F_ADD_STR(SUBSTR(P_ADD1, V_LENGTH1 - 36), P_ADD2)) - 37
 34        ),
 35        '0'
 36       )
 37      ) || SUBSTR(F_ADD_STR(SUBSTR(P_ADD1, V_LENGTH1 - 36), P_ADD2), - 37);
 38    ELSIF V_LENGTH2 > 37 THEN
 39     RETURN
 40      F_ADD_STR
 41      (
 42       NVL
 43       (
 44        SUBSTR
 45        (
 46         F_ADD_STR(P_ADD1, SUBSTR(P_ADD2, V_LENGTH2 - 36)),
 47         1,
 48         LENGTH(F_ADD_STR(P_ADD1, SUBSTR(P_ADD2, V_LENGTH2 - 36))) - 37
 49        ),
 50        '0'
 51       ),
 52       SUBSTR(P_ADD2, 1, V_LENGTH2 - 37)
 53      )
 54      || SUBSTR(F_ADD_STR(P_ADD1, SUBSTR(P_ADD2, V_LENGTH2 - 36)), - 37);
 55    ELSE
 56     RETURN
 57      LTRIM
 58      (
 59       TO_CHAR
 60       (
 61        TO_NUMBER(P_ADD1) + TO_NUMBER(P_ADD2),
 62        RPAD
 63        (
 64         '0',
 65         GREATEST(V_LENGTH1, V_LENGTH2, LENGTH(TO_NUMBER(P_ADD1) + TO_NUMBER(P_ADD2))),
 66         '9'
 67        )
 68       )
 69      );
 70    END IF;
 71   END;
 72 
 73  BEGIN
 74   IF V_LENGTH_OTHER_1 >= V_LENGTH_OTHER_2 THEN
 75    V_RESULT := F_ADD_STR
 76     (V_OTHER_STR1,
 77     V_OTHER_STR2 || LPAD('0', V_LENGTH_OTHER_1 - V_LENGTH_OTHER_2, '0'));
 78   ELSE
 79    V_RESULT := F_ADD_STR
 80     (V_OTHER_STR1 || LPAD('0', V_LENGTH_OTHER_2 - V_LENGTH_OTHER_1, '0'),
 81     V_OTHER_STR2);
 82   END IF;
 83  
 84   IF LENGTH(V_RESULT) > GREATEST(V_LENGTH_OTHER_1, V_LENGTH_OTHER_2) THEN
 85    RETURN NVL(LTRIM(RTRIM(
 86      F_ADD_STR
 87       (F_ADD_STR(V_INTEGER_STR1, V_INTEGER_STR2), 1)
 88       || '.' || RTRIM(SUBSTR(V_RESULT, 2), '0'), 
 89      '.'), '0'), '0');
 90   ELSE
 91    RETURN NVL(LTRIM(RTRIM(
 92     F_ADD_STR(V_INTEGER_STR1, V_INTEGER_STR2)
 93      || '.' || RTRIM(V_RESULT, '0'),
 94     '.'), '0'), '0');
 95   END IF;
 96  END;
 97  /

函数已创建。

代码比较长,这里就不过多的描述实现了,下面简单看一下利用这个函数进行计算:

SQL> SELECT F_STR_ADD('12345.6789', '98.7654321') FROM DUAL;

F_STR_ADD('12345.6789','98.7654321')
------------------------------------------------------------------------------------------
12444.4443321

SQL> SELECT F_STR_ADD('5555', '12939') FROM DUAL;

F_STR_ADD('5555','12939')
------------------------------------------------------------------------------------------
18494

SQL> SELECT F_STR_ADD('0.234', '74') FROM DUAL;

F_STR_ADD('0.234','74')
------------------------------------------------------------------------------------------
74.234

SQL> SELECT F_STR_ADD('0.00001111111111111111111111111111111111111', '.234111111111111') FROM DUAL;

F_STR_ADD('0.00001111111111111111111111111111111111111','.234111111111111')
---------------------------------------------------------------------------------------
.23412222222222211111111111111111111111111

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/4227/viewspace-432940/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/4227/viewspace-432940/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值