2017-04-15 58 views
1

你好,程序员比我好。这不是一个大问题,但我对这个功能很好奇,更重要的是它有时会给出结果。所以我为包含负指数的家庭作业定义了递归功能函数。对于正值和0,它工作正常,但是当我输入一些负值时,答案真的很奇怪。下面是函数:递归功能函数给出奇怪的答案

public static double Power(int base, int exp){ 
    if (exp == 0) 
     return 1.0; 
    else if(exp >=1) 
     return base * Power(base, exp - 1); 
    else 
     return (1.0/base) * Power(base, exp + 1);    
} 

因此,对于呼叫电源(5,-1)函数返回0.2,像它应该。但是对于Power(5,-2)这个函数,函数返回值为0.04000000000000001,而不是0.04。 再一次,这不是一个很大的交易,因为它是作业而不是“现实生活”,但只是好奇为什么发生这种情况。我认为这与计算机内存或双重值的存储方式有关,但真的不知道。谢谢大家!

PS,这是用Java编码使用Netbeans如果有所作为。

+0

汤姆斯科特做了一个伟大的视频解释这个https://www.youtube.com/watch?v=PZRI1IfStY0 – SpiderPig

+0

http://stackoverflow.com/questions/8511312/java-double-variables-have-strange-values –

+0

重新开放以指出减少此特定程序的舍入误差的策略。 –

回答

0

仔细组织您的算术可以减少浮点舍入误差。一般来说,您希望最小化舍入操作的次数以及对舍入结果进行的计算次数。

我做了小改动,以你的函数:

public static double Power(int base, int exp) { 
    if (exp == 0) 
     return 1.0; 
    else if (exp >= 1) 
     return base * Power(base, exp - 1); 
    else 
     return (1.0/Power(base, -exp)); 
    } 

为您的测试情况下,Power(5, -2),这样做只有一个圆形的计算,在该递归的顶分工。它最接近1/25.0的两倍,打印为0.04。

0

这是1990年的事情

这将可能是一个被忽略的或有争议的答案,但我觉得它需要说。

其他人已将注意力集中在“浮点”计算(例如涉及一个或多个“双打”数字的计算)上的消息近似为数学。

我对这个答案的关注点在于,即使在普通Java代码中使用这种方式,并且在大多数编程语言中的普通代码中,数字如0.1的计算不必是近似值。


几种语言治疗号码,如0.1为有理数,两个整数之间的比率(分子分母上,在这种情况下1超过10或十分之一),就像他们在学校的数学。只包含整数和有理数的计算是100%准确的(忽略整数溢出和/或OOM)。

不幸的是,如果分母变得太大,理性计算会变得很慢。


有些语言采取妥协的立场。他们把一些理性看作是理性的(所以100%的准确性),只有100%的准确性才会放弃,当理性的计算在病态上是缓慢的时候,转换为漂浮。

例如,这里是一个相对较新的和前瞻性的编程语言的一些代码:

sub Power(\base, \exp) { 
    given exp { 
     when 0  { 1.0        } 
     when * >= 1 { base  * Power(base, exp - 1) } 
     default  { 1.0/base * Power(base, exp + 1) } 
    } 
} 

这在重复这个其他语言代码。

现在使用这个函数来获得结果的指数的列表:

for 1000,20,2,1,0,-1,-2,-20,-1000 -> \exp { say Power 5, exp } 

Running this code in glot.io显示:

9332636185032188789900895447238171696170914463717080246217143397959 
6691097577563445444032709788110235959498993032424262421548752135403 
2394841520817203930756234410666138325150273995075985901831511100490 
7962651131182405125147959337908051782711254151038106983788544264811 
1946981422866095922201766291044279845616944888714746652800632836845 
2647429261829862165202793195289493607117850663668741065439805530718 
1363205998448260419541012132296298695021945146099042146086683612447 
9295203482686461765792691604742006593638904173789582211836507804555 
6628444273925387517127854796781556346403714877681766899855392069265 
4394240087119736747017498626266907472967625358039293762338339810469 
27874558605253696441650390625 
95367431640625 
25 
5 
1 
0.2 
0.04 
0.000000000000010 
0 

上述结果是100%准确 - 直到最后的指数,-1000。我们可以看到在语言上的准确率100%放弃,如果我们检查结果的类型(使用WHAT):

for 1000,20,2,1,0,-1,-2,-20,-1000 -> \exp { say WHAT Power 5, exp } 

显示:

(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Num) 

转换Rat秒(默认理性型)成FatRat S(任意精度理性型)避免不准确甚至经病理大分母:

sub Power(\base, \exp) { 
    given exp { 
     when 0  { 1.0.FatRat        } 
     when * >= 1 { base   * Power(base, exp - 1) } 
     default  { 1.0.FatRat/base * Power(base, exp + 1) } 
    } 
} 

这产生同样显示为我们的原代码,除了它出来作为最后的计算:

0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 

我不知道这是正确的,但是,AIUI,它应该是。