使用 Java 开发移动设备应用程序时可能需要用到特定 Java VM 所没有的数学方法本文将专门解决 Java ME 没有幂方法 Mathpow() 的问题我们将演示使用三种不同的方法开发同一个 ME 应用程序并从中选出最佳的编程解决方案
要讨论此问题我们先考察整数和分数幂参数将我们的分析限于正实数我们将演示求整数问题和小数问题的解集相对而言比较容易(而不考虑指数的符号)在大多数情况下我们将使用示例问题 n = /其中我们会求出 n 的良好估计或实际解如果初始指数事先不可用则此问题的其他解(包括牛顿法和割线法)不易编程虽然二分法是可行的解决方案但我们将关注传统上不为人所探究的三个方法第一个是简单的(不过有时效率低下)几何衰变算法而第二个方法将利用 Mathsqrt() 方法并保证在不超过 次迭代中收敛到一个近似解第三个方法将使用泰勒级数逼近法求对数并对泰勒级数进行欧拉转换
产生整数解的 ME Mathpow() 方法
传统上Java Mathpow() 方法包含两个参数这两个参数包括底数和指数我们假定(最初)这两个参数均为整数然后求出 ME 中与 Java 方法使用相同参数的 Mathpow() 方法的可编程解此处可编程解相当简单如示例 所示在本例中我们仅运行以指数值为指标的倍乘循环
示例
intpow(intxinty)/*wedefinethepowermethodwith
basexandpowery(iex^y)*/
{
intz=x;
for(inti=;i<y;i++)z*=x;
return
}
当然有人可能会发现需要求出非整数幂的值正实数的简单解(无需访问 Mathpow() 方法)可能涉及使用 Mathlog()例如请考虑 / 的情况利用 /*ln() = 中自然对数的结果要得到最终解需要利用指数 (特别指出 e = )在这种情况下可能不需要使用幂函数遗憾的是Java ME 也不支持 Mathlog() 方法没有 Mathpow() 或 Mathlog() 方法时我们会考虑使用朴素的强力试探性方法应用 Mathsqrt() 方法以及自然对数(和欧拉 e)的泰勒级数逼近来求得 Java ME 问题的解
使用几何衰变算法作为强力解的 ME Mathpow()
Java ME 的早期实现包括浮点主数据类型 float 和 double最近已添加了这些类型现在我们将 Mathpow() 声明中的整型参数替换为 double 数据类型
可能需要在 Java ME Mathpow() 幂方法中使用小数指数我们提供的生成 Mathpow() 的第一种方法是使用几何衰变算法的朴素的强力试探性方法简单而言衰变算法以一个大于已知解的值开始然后应用某个方法来衰变该值直到该值非常逼近该解(有关简单线性衰变算法的演示请参见示例 )在我们的例子中将进一步演示向上述解收敛的几何形式
示例
/*Thisexampleillustratesasimplisticdecayalgorithmthatwewillassume
convergestoourdesiredsolution(apositiveinteger)*/
intn;//assumethatnisthesolutiontothenumberwearetryingtofind
intvarX=;//assumethatweknowthesolutionislessthanorequalto
while(varX>)
{
varX=;//decrementby
if(varX==n)returnvarX;
}
在示例 中我们从 开始递减直到找到预期的数字假定预期数字是一个正整数这种类型的算法构成了强力试探性方法的基础
使用类似的方法我们可在遇到小数时应用此算法假定我们需要求出 n 的值其中 n = /要使用衰变算法我们必须首先找到一个合适的起点该点要等于或大于解本身这对于带有正指数的正实数很容易做到对于我们的示例要对此解进行编程对方法两边求立方得到 n= 当然此方程与 n= 等效之后我们的起始值将变为 我们知道 n 必须小于 (因为 n = )注意如果限于正实数则此推导方法同样适用于任何正指数值现在我们可能需要设计一个循环来产生 n 的充分接近预期数字的解我们再来看示例 它适合于所有正底数和正指数
示例
doublepow(doublexdoubley)//wedefineournewpowermethodforfractions
{
intden=;//specifyarbitrarydenominator
intnum=(int)(y*den);//findnumerator
ints=(num/den)+;
/***********************************************************************
**Variablesprovidesthepowerforwhichwemultiplythebasetofind
**ourstartingsearchvalueForexampleifweseekasolutionfor
**n=^(/)thenwewilluse^orasourstartingvalue(whichis
**generatedinournextsectionofcode)Why?Thesolutionforour
**problem(giventhatthebaseispositive)willalwaysbelessthanor
**equaltothebasetimesthenumeratorpower
************************************************************************/
/***********************************************************************
**Becausewesetthedenominatortoanarbitraryhighvalue
**wemustattempttoreducethefractionIntheexamplebelow
**wefindthehighestallowablefractionthatwecanusewithout
**exceedingthelimitationofourprimitivedatatypes
************************************************************************/
doublez=DoubleMAX_VALUE;
while(z>=DoubleMAX_VALUE)
{
den=;//decrementdenominator
num=(int)(y*den);//findnumerator
s=(num/den)+;//adjuststartingvalue
//findvalueofourbasenumbertothepowerofnumerator
z=x;
for(inti=;i<num;i++)z*=x;
}
/***********************************************************************
**Nowwearegoingtoimplementthedecayalgorithmtofind
**thevalueofn
************************************************************************/
/***********************************************************************
**WenowfindntothepowerofsWewillthendecrementn
**findingthevalueofntothepowerofthedenominatorThis
**valuevariableawillbecomparedtozIftheaisnearly
**equaltozthenwewillreturnnourdesiredresult
************************************************************************/
doublen=x;//Wedefinenasourreturnvalue(estimate)forx
//findntothepowerofs
for(inti=;i<s;i++)n*=x;
//Begindecayloop
while(n>)
{
doublea=n;//proxyforn
//findathevalueofntothepowerofdenominator
for(inti=;i<den;i++)a*=n;
//compareatozIsthevaluewithinthehundredthousandth?
//ifsoreturnn
doublecheck=az;
doublecheck=za;
if(check<||check>)returnn;
n*=;//Wearbitrarilyuseadecayof%periteration
}
//valuecouldnotbefoundreturn
return;
}
本示例演示了衰变算法的使用方法您会注意到n 的值(解的估计值)将按 % 强制递减您可能需要根据编程精度要求来改变此值也可能考虑包括编程逻辑该逻辑用于将前一迭代解与当前迭代进行比较然后如果有改善继续进行迭代但是如果解已回归则返回前一个值
这里讲述的解只处理正指数如果值为负会出现什么情况呢?下面我们将解决这种意外情况
处理负指数
要再增加一层复杂度假定正在向 Mathpow() 方法传递负指数在这种情况下指数为负一种简单的解决方案是将底数转换为小数使指数为正例如 可转换为 (/)我们以可编程的方式用底数 x 来除 用 来乘 y(参见示例 )
示例
if(y<)
{
x=(/x);//convertbasenumbertofraction
y*=;//makeexponentpositive
}
现在我们已经讨论了用于在 Java ME 中估计幂函数的强力几何衰变算法读者会注意到对于较大的底数和指数分子组合朴素的强力试探性方法有性能问题请考虑示例 /使用此算法的起始值将为 = 如果使用 % 的衰变则要求全部 次迭代都求该解这样几乎达不到最优谨记此事实并且不提供改善的试探性搜索算法我们转到二次逼近这会提供更多合理的迭代要求