C#十进制精度在幂和斐波那契中的改进
我试图用负数和大数来解斐波那契序列,并提出了以下代码和算法。我确信算法是可行的,但我面临的问题是,对于非常大的数字,结果的精度是不正确的。代码如下:C#十进制精度在幂和斐波那契中的改进,c#,precision,fibonacci,C#,Precision,Fibonacci,我试图用负数和大数来解斐波那契序列,并提出了以下代码和算法。我确信算法是可行的,但我面临的问题是,对于非常大的数字,结果的精度是不正确的。代码如下: public class Fibonacci { public static BigInteger fib(int n) { decimal p = (decimal) (1 + Math.Sqrt(5)) / 2; decimal q = (decimal)
public class Fibonacci
{
public static BigInteger fib(int n)
{
decimal p = (decimal) (1 + Math.Sqrt(5)) / 2;
decimal q = (decimal) (1 - Math.Sqrt(5)) / 2;
decimal r = (decimal) Math.Sqrt(5);
Console.WriteLine("n: {0} p: {1}, q: {2}, t: {3}",
n,
p,
q,
(Pow(p, n) - Pow(q, n)) / r);
return (BigInteger) (Decimal.Round((Pow(p, n) - Pow(q, n)) / r));
}
public static decimal Pow(decimal x, int y)
{
if(y < 0)
return 1 / Pow(x, -1 * y);
else if(y == 0)
return 1;
else if(y % 2 == 0)
{
decimal z = Pow(x, y / 2);
return z * z;
}
else if(y % 2 == 1)
return Pow(x, y - 1) * x;
else
return 1;
}
公共类Fibonacci
{
公共静态大整数fib(int n)
{
十进制p=(十进制)(1+数学Sqrt(5))/2;
十进制q=(十进制)(1-数学Sqrt(5))/2;
十进制r=(十进制)数学Sqrt(5);
WriteLine(“n:{0}p:{1},q:{2},t:{3}”,
N
P
Q
(Pow(p,n)-Pow(q,n))/r;
返回(BigInteger)(十进制整数((Pow(p,n)-Pow(q,n))/r));
}
公共静态十进制功率(十进制x,整数y)
{
if(y<0)
返回1/Pow(x,-1*y);
如果(y==0),则为else
返回1;
如果(y%2==0),则为else
{
十进制z=功率(x,y/2);
返回z*z;
}
如果(y%2==1),则为else
返回功率(x,y-1)*x;
其他的
返回1;
}
如果我们取一个像-96这样的大数字来得到斐波那契函数,我得到的结果是-516807085733203484173,但实数是-5168070854858323072。我检查了舍入是否正确,但我的结果似乎在某个地方失去了精度,无法正确保存它的值。我认为使用小数可以解决这个问题ision问题(以前使用双倍),但这不起作用
在我的代码中,哪里错误地丢失了精度,或者我的代码中有另一个问题被误诊了?试试这个
public static BigInteger Fibonacci(int n)
{
BigInteger a = 0;
BigInteger b = 1;
for (int i = 31; i >= 0; i--)
{
BigInteger d = a * (b * 2 - a);
BigInteger e = a * a + b * b;
a = d;
b = e;
if ((((uint)n >> i) & 1) != 0)
{
BigInteger c = a + b;
a = b;
b = c;
}
}
return a;
}
祝你好运!试试这个
public static BigInteger Fibonacci(int n)
{
BigInteger a = 0;
BigInteger b = 1;
for (int i = 31; i >= 0; i--)
{
BigInteger d = a * (b * 2 - a);
BigInteger e = a * a + b * b;
a = d;
b = e;
if ((((uint)n >> i) & 1) != 0)
{
BigInteger c = a + b;
a = b;
b = c;
}
}
return a;
}
祝你好运!正如你所写的,
十进制
大约有28位小数精度。但是,Math.Sqrt(5)
,作为双精度
,却没有
使用更精确的平方根5可以使该算法在更长的时间内保持精确,当然它最终还是会受到精度的限制,就在稍后
public static BigInteger fib(int n)
{
decimal sqrt5 = 2.236067977499789696409173668731276235440618359611525724270m;
decimal p = (1 + sqrt5) / 2;
decimal q = (1 - sqrt5) / 2;
decimal r = sqrt5;
return (BigInteger) (Decimal.Round((Pow(p, n) - Pow(q, n)) / r));
}
这样一来,
fib(96)=5168070854858323072是正确的。但是,它在128处再次出错。正如您所写,decimal
大约有28位小数精度。但是,Math.Sqrt(5)
作为双精度
,却没有
使用更精确的平方根5可以使该算法在更长的时间内保持精确,当然它最终还是会受到精度的限制,就在稍后
public static BigInteger fib(int n)
{
decimal sqrt5 = 2.236067977499789696409173668731276235440618359611525724270m;
decimal p = (1 + sqrt5) / 2;
decimal q = (1 - sqrt5) / 2;
decimal r = sqrt5;
return (BigInteger) (Decimal.Round((Pow(p, n) - Pow(q, n)) / r));
}
这样fib(96)=5168070854858323072
这是正确的。但是,它在128处再次出错。将十进制更改为大整数不会神奇地提高十进制的分辨率。@AndrewMorton我理解这一点,但根据文档,十进制类型应具有28到29位精度。输出需要大整数这就是为什么我要进行十进制.四舍五入。但是,该值的精度几乎在10到15位之间,因此有些地方不准确。您是否检查过中间值的精度,例如Pow(p,n)
?@AndrewMorton正在检查。我可以验证算法无法处理超过第68个值的fibonacci数。将十进制更改为BigInteger不会神奇地提高十进制的分辨率。@AndrewMorton我理解,但根据文档,十进制类型的精度应为28到29位。BigIn输出需要teger,这就是为什么我要进行decimal.round。但是,该值在几乎10到15位的范围内失去精度,所以有些地方不对劲。您是否检查了中间值的准确性,例如Pow(p,n)
?@AndrewMorton正在检查。我可以验证该算法无法处理超过第68个值的斐波那契数。是的,这是求解斐波那契序列的一种非常标准的方法。但是,这不够快,需要不到几秒钟的时间,而不是几分钟的时间。而且,这个答案也没有回答我关于精度的问题。@RossGustafson我认为你应该检查这种方法的性能,它不应该花费几分钟。这不是简单的“添加最后两个值”方法。这种方法只有32次迭代。我尝试过斐波那契(96)结果:结果:5168070854858323072,经过时间:00:00:00.0020192。您期望的精度值是多少?这会中断负斐波那契数。我一开始误解了您的解决方案。我知道它在做什么。有趣的解决方案。是的,这是解决斐波那契序列的一种非常标准的方法。但是,这不够快,需要更少的工作几秒钟,而不是几分钟。而且,这个答案并没有回答我关于精度的问题。@RossGustafson我认为你应该回顾一下这种方法的性能,它不应该花费几分钟。这不是简单的“添加最后两个值”方法。这种方法只有32次迭代。我尝试过斐波那契(96)结果:结果:516807085548583323072,经过时间:00:00:00.0020192。您期望的精度值是多少?这会打断负斐波那契数。我一开始误读了您的解决方案。我看到了它在做什么。有趣的解决方案。这让我基本上达到了目的。这解决了正斐波那契数的问题,但负斐波那契数在之后仍然关闭大约10位。我想知道这是否与我的Pow方法如何处理负数以及它如何处理大数的求逆有关。@RossGustafson可以在fib
本身中处理,以避免一开始就采用负幂,尽管我不确定目前我需要处理负幂的问题是什么计算fibonacci数,处理完美整数精度,n值高达200000。我认为我的算法将无法工作,因为浮点精度。@RossGustafson fibonacci(200000)有