ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 利用字符串实现高精度数值运算(二)

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

原创 Linux操作系统 作者:yangtingkun 时间:2008-08-22 21:11:23 0 删除 编辑

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

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

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

利用字符串实现高精度数值运算(一):http://yangtingkun.itpub.net/post/468/469206

 

 

上一篇给出了字符串表示的数值相加的函数,这一篇继续描述字符串表示数值相乘的算法。

采用代码重用的方法,利用以前处理整数乘法的基础,加上小数部分的处理。整数部分算法描述可以参考:http://yangtingkun.itpub.net/post/468/241044

由于包含了小数部分,一个乘法变成4个乘法的相加,因此还要利用前面一篇文章的字符串相加的函数:

SQL> CREATE OR REPLACE FUNCTION F_STR_MULTI(P_STR1 IN VARCHAR2, P_STR2 IN VARCHAR2) RETURN VARCHAR2 AS
  2 
  3  V_INTEGER_STR1 VARCHAR2(32767) := NVL(
  4    SUBSTR(P_STR1, 1,
  5     CASE INSTR(P_STR1, '.') WHEN 0 THEN LENGTH(P_STR1) ELSE INSTR(P_STR1, '.') - 1 END
  6    ), 0);
  7   V_INTEGER_STR2 VARCHAR2(32767) := NVL(
  8    SUBSTR(P_STR2, 1,
  9     CASE INSTR(P_STR2, '.') WHEN 0 THEN LENGTH(P_STR2) ELSE INSTR(P_STR2, '.') - 1 END
 10    ), 0);
 11   V_OTHER_STR1 VARCHAR2(32767) := CASE INSTR(P_STR1, '.')
 12    WHEN 0 THEN NULL ELSE SUBSTR(P_STR1, INSTR(P_STR1, '.') + 1) END;
 13   V_OTHER_STR2 VARCHAR2(32767) := CASE INSTR(P_STR2, '.')
 14    WHEN 0 THEN NULL ELSE SUBSTR(P_STR2, INSTR(P_STR2, '.') + 1) END;
 15   V_LENGTH_OTHER_1 NUMBER := NVL(LENGTH(V_OTHER_STR1), 0);
 16   V_LENGTH_OTHER_2 NUMBER := NVL(LENGTH(V_OTHER_STR2), 0);
 17   V_RESULT1 VARCHAR2(32767);
 18   V_RESULT2 VARCHAR2(32767);
 19 
 20   FUNCTION F_MULTI_STR(P_MUL1 IN VARCHAR2, P_MUL2 IN VARCHAR2) RETURN VARCHAR2 AS
 21    V_LENGTH1 NUMBER DEFAULT LENGTH(P_MUL1);
 22    V_LENGTH2 NUMBER DEFAULT LENGTH(P_MUL2);
 23   BEGIN
 24    IF V_LENGTH1 > 19 THEN
 25     RETURN F_STR_ADD(F_MULTI_STR(SUBSTR(P_MUL1, 1, V_LENGTH1 - 19), P_MUL2) || LPAD('0', 19, '0'),
 26     F_MULTI_STR(SUBSTR(P_MUL1, V_LENGTH1 - 18), P_MUL2));
 27    ELSIF V_LENGTH2 > 19 THEN
 28     RETURN F_STR_ADD(F_MULTI_STR(P_MUL1, SUBSTR(P_MUL2, 1, V_LENGTH2 - 19)) || LPAD('0', 19, '0'),
 29     F_MULTI_STR(P_MUL1, SUBSTR(P_MUL2, V_LENGTH2 - 18)));
 30    ELSE
 31     RETURN TO_NUMBER(P_MUL1) * TO_NUMBER(P_MUL2);
 32    END IF;
 33   END;
 34  
 35  BEGIN
 36   V_RESULT1 := F_MULTI_STR(V_INTEGER_STR1, V_OTHER_STR2);
 37   V_RESULT2 := F_MULTI_STR(V_INTEGER_STR2, V_OTHER_STR1);
 38   V_RESULT1 := SUBSTR(V_RESULT1, 1, LENGTH(V_RESULT1) - V_LENGTH_OTHER_2)
 39    || '.'
 40    || SUBSTR(V_RESULT1, - V_LENGTH_OTHER_2);
 41   V_RESULT2 := SUBSTR(V_RESULT2, 1, LENGTH(V_RESULT2) - V_LENGTH_OTHER_1)
 42    || '.'
 43    || SUBSTR(V_RESULT2, - V_LENGTH_OTHER_1);
 44   RETURN F_STR_ADD
 45    (
 46     F_STR_ADD
 47      (
 48       F_MULTI_STR(V_INTEGER_STR1, V_INTEGER_STR2)
 49        || '.'
 50        || LPAD(
 51         F_MULTI_STR(V_OTHER_STR1, V_OTHER_STR2),
 52         V_LENGTH_OTHER_1 + V_LENGTH_OTHER_2,
 53         '0'),
 54       V_RESULT1
 55      ),
 56     V_RESULT2
 57    );
 58  END;
 59  /

函数已创建。

下面简单测试一下函数的功能:

SQL> SELECT F_STR_MULTI('12345678900987654321', '555') FROM DUAL;

F_STR_MULTI('12345678900987654321','555')
------------------------------------------------------------------------
6851851790048148148155

SQL> SELECT F_STR_MULTI('1.2345678900987654321', '555') FROM DUAL;

F_STR_MULTI('1.2345678900987654321','555')
------------------------------------------------------------------------
685.1851790048148148155

SQL> SELECT F_STR_MULTI('0.12345678900987654321', '0.00555') FROM DUAL;

F_STR_MULTI('0.12345678900987654321','0.00555')
------------------------------------------------------------------------
.0006851851790048148148155

SQL> SELECT F_STR_MULTI('6.125', '4.8') FROM DUAL;

F_STR_MULTI('6.125','4.8')
------------------------------------------------------------------------
29.4

SQL> SELECT 12345678900987654321*555 FROM DUAL;

12345678900987654321*555
------------------------
              6.8519E+21

 

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

请登录后发表评论 登录
全部评论
暂无介绍

注册时间:2007-12-29

  • 博文量
    1964
  • 访问量
    11076556