由于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中国
作者
相关推荐
-
Collaborate 18大会:了解甲骨文云数据库和应用的进展
在Collaborate 18大会即将举行时,我们会发现,甲骨文用户社区的技术变化会略高于平常水平。 由独立甲 […]
-
甲骨文自治数据库亮相 带来云计算新希望
早前甲骨文还不在云计算公司之列,而现在该公司正在迅速弥补其失去的时间。甲骨文的云计算核心是甲骨文自治数据库(O […]
-
2017年12月数据库流行度排行榜 定格岁末排名瞬间
数据库知识网站DB-engines最近更新的2017年12月份数据库流行度排名情况是否能提供更多的看点呢?TechTarget数据库网站将与您分享12月份的榜单排名情况,让我们拭目以待。
-
2017年11月数据库流行度排行榜 半数以上数据库积分减少
数据库知识网站DB-engines更新了2016年11月份的数据库流行度排行榜。TechTarget数据库网站将与您一同关注11月份的榜单排名情况。