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

日期: 2008-08-27 作者:杨廷琨 来源:TechTarget中国 英文

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


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


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


  其实在以前处理超大数值的时候,写过一个字符串相加的函数,不过当时这个函数只是处理正整数的相加,没有考虑小数的情况。


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








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 LTRIM(RTRIM(RTRIM( 
  86 F_ADD_STR 
  87 (F_ADD_STR(V_INTEGER_STR1, V_INTEGER_STR2), 1) 
  88 || ’.’ || SUBSTR(V_RESULT, 2), 
  89 ’0’), ’.’), ’0’); 
  90 ELSE 
  91 RETURN LTRIM(RTRIM(RTRIM( 
  92 F_ADD_STR(V_INTEGER_STR1, V_INTEGER_STR2) 
  93 || ’.’ || V_RESULT, 
  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 

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

相关推荐