求算阶乘PL/SQL/JAVA方法

本文介绍了当Oracle的NUMBER类型无法处理阶乘计算时,通过创建C和Java外部过程以及使用PL/SQL字符串操作来解决大数值计算。展示了如何创建C函数、Java外部过程以及PL/SQL自定义对象来实现阶乘计算,确保结果的精度和正确性。此外,还提供了一种利用循环和对象功能优化的解决方案,以提高计算效率和可读性。
摘要由CSDN通过智能技术生成

 

SQL> CREATE OR REPLACE FUNCTION F_SUM_MULTI(P_IN IN NUMBER) RETURN NUMBER AS
2 V_RESULT_MULTI NUMBER DEFAULT 1;
3 V_RESULT NUMBER DEFAULT 0;
4 BEGIN
5 FOR I IN 1..P_IN LOOP
6 V_RESULT_MULTI := V_RESULT_MULTI * I;
7 V_RESULT := V_RESULT + V_RESULT_MULTI;
8 END LOOP;
9 RETURN V_RESULT;
10 END;
11 /

函数已创建。

SQL> SELECT F_SUM_MULTI(5) FROM DUAL;

F_SUM_MULTI(5)
--------------
153

代码很简单,功能也已经实现了。但是,问题并不想我想的这么简单。

SQL> SELECT F_SUM_MULTI(100) FROM DUAL;

F_SUM_MULTI(100)
----------------
~

奇怪,输出结果为什么会是~呢?莫非是超过了NUMBER能表示的最大的范围?

SQL> SELECT F_SUM_MULTI(83) FROM DUAL;

F_SUM_MULTI(83)
---------------
3.994E+124

SQL> SELECT F_SUM_MULTI(84) FROM DUAL;

F_SUM_MULTI(84)
---------------
~

果然是超过了NUMBER能表示的最大的范围。NUMBER类型能表达的最大值是9.9999999999999999999999999999999999*10E125。以前还从没有碰到过超出Oracle最大处理范围的情况,也一直没有想到过会碰到超出最大精度。看来阶乘不愧是结果增长最迅速的操作。

由于超过了Oracle能处理的最大值,Oracle已经很难处理这个问题了。莫非已经没有办法来处理这个问题了?

 

 

上文以及提到,由于计算的数值的大小以及超过了Oracle所能表示的最大范围,因此,Oracle中已经无法进行计算了。

首先考虑的是能否通过外部过程来实现。利用CJAVA程序来计算,并将最终结果通过字符串的方式返回给Oracle

这篇文章给出通过外部C过程的方式来实现。本例是模仿TomEXPERT ONE ON ONE ORACLEC外部过程例子进行编写的。OCI程序的连接、初始化,以及数据传递部分和Tom的例子很相似,只是在需要的地方进行了一些小的修改。

整个程序代码如下,multi_sum.c

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>

#include <oci.h>

#define INI_FILE_NAME "/tmp/multi_sum.ini"

typedef struct ociStruct
{
OCIExtProcContext * ctx;
OCIEnv * envhp;
OCISvcCtx * svchp;
OCIError * errhp;

ub1 debugf_flag;
char debugf_path[255];
char debugf_filename[50];
} ocihStruct;

void _debugf(ocihStruct * ocih, char * fmt, ...)
{
va_list ap;
OCIFileObject * fp;
time_t theTime=time(NULL);
char msg[8192];
ub4 bytes;

if (OCIFileOpen(ocih->envhp, ocih->errhp, &fp, ocih->debugf_filename, ocih->debugf_path,
OCI_FILE_WRITE_ONLY, OCI_FILE_APPEND|OCI_FILE_CREATE, OCI_FILE_TEXT) != OCI_SUCCESS)
return;
strftime(msg, sizeof(msg), "%Y%m%d%H%M%S GMT", gmtime(&theTime));
OCIFileWrite(ocih->envhp, ocih->errhp, fp, msg, strlen(msg), &bytes);

va_start(ap, fmt);
vsprintf(msg, fmt, ap);
va_end(ap);
strcat(msg, "n");

OCIFileWrite(ocih->envhp, ocih->errhp, fp, msg, strlen(msg), &bytes);
OCIFileClose(ocih->envhp, ocih->errhp, fp);
}

void _debugf(ocihStruct * ocih, char * fmt, ...);

#define debugf if((ocih!=NULL) && (ocih->debugf_flag)) _debugf

static int raise_application_error(ocihStruct * ocih, int errCode, char * errMsg, ...)
{
char msg[8192];
va_list ap;

va_start(ap, errMsg);
vsprintf(msg, errMsg, ap);
va_end(ap);

debugf(ocih, "raise application error(%d, %s)", errCode, msg);
if(OCIExtProcRaiseExcpWithMsg(ocih->ctx, errCode, msg, 0) == OCIEXTPROC_ERROR)
{
debugf(ocih, "Unable to raise exception");
}
return -1;
}

static char * lastOciError(ocihStruct * ocih)
{
sb4 errcode;
char * errbuf=(ch

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值