我正在解决这个问题,他们要求第一个斐波纳契数为1000位的索引,我的第一个想法是类似于:
BigInteger x = 1; BigInteger y = 1; BigInteger tmp = 0; int currentIndex = 2; while (x.NoOfDigits < 1000) { tmp = x + y; y = x; x = tmp; currentIndex++; } return currentIndex;
但是,据我所知,没有方法可以计算BigInteger的位数.这是真的?绕过它的一种方法是使用BigInteger的.ToString().Length方法,但我被告知字符串处理很慢.
BigInteger也有一个.ToByteArray(),我想把BigInteger转换成一个字节数组并检查该数组的长度 - 但我不认为这唯一地决定了BigInteger中的位数.
为了它的价值,我实现了另一种解决方法,即手动将Fibonacci数存储在数组中,并在数组填满后立即停止,并将其与基于.ToString的方法进行比较,大约为2.5时间慢,但第一种方法需要0.1秒,这也似乎很长一段时间.
编辑:我已经在下面的答案中测试了这两个建议(一个是BigInteger.Log,一个是MaxLimitMethod).我得到以下运行时间:
原始方法:00:00:00.0961957
StringMethod:00:00:00.1535350
BigIntegerLogMethod:00:00:00.0387479
MaxLimitMethod:00:00:00.0019509
程序
using System; using System.Collections.Generic; using System.Numerics; using System.Diagnostics; class Program { static void Main(string[] args) { Stopwatch clock = new Stopwatch(); clock.Start(); int index1 = Algorithms.IndexOfNDigits(1000); clock.Stop(); var elapsedTime1 = clock.Elapsed; Console.WriteLine(index1); Console.WriteLine("Original method: {0}",elapsedTime1); Console.ReadKey(); clock.Reset(); clock.Start(); int index2 = Algorithms.StringMethod(1000); clock.Stop(); var elapsedTime2 = clock.Elapsed; Console.WriteLine(index2); Console.WriteLine("StringMethod: {0}", elapsedTime2); Console.ReadKey(); clock.Reset(); clock.Start(); int index3 = Algorithms.BigIntegerLogMethod(1000); clock.Stop(); var elapsedTime3 = clock.Elapsed; Console.WriteLine(index3); Console.WriteLine("BigIntegerLogMethod: {0}", elapsedTime3); Console.ReadKey(); clock.Reset(); clock.Start(); int index4 = Algorithms.MaxLimitMethod(1000); clock.Stop(); var elapsedTime4 = clock.Elapsed; Console.WriteLine(index4); Console.WriteLine("MaxLimitMethod: {0}", elapsedTime4); Console.ReadKey(); } } static class Algorithms { //Find the index of the first Fibonacci number of n digits public static int IndexOfNDigits(int n) { if (n == 1) return 1; int[] firstNumber = new int[n]; int[] secondNumber = new int[n]; firstNumber[0] = 1; secondNumber[0] = 1; int currentIndex = 2; while (firstNumber[n-1] == 0) { int carry = 0, singleSum = 0; int[] tmp = new int[n]; //Placeholder for the sum for (int i = 0; i= 10) carry = 1; else carry = 0; tmp[i] += singleSum % 10; if (tmp[i] >= 10) { tmp[i] = 0; carry = 1; } int countCarries = 0; while (carry == 1) { countCarries++; if (tmp[i + countCarries] == 9) { tmp[i + countCarries] = 0; tmp[i + countCarries + 1] += 1; carry = 1; } else { tmp[i + countCarries] += 1; carry = 0; } } } for (int i = 0; i < n; i++ ) { secondNumber[i] = firstNumber[i]; firstNumber[i] = tmp[i]; } currentIndex++; } return currentIndex; } public static int StringMethod(int n) { BigInteger x = 1; BigInteger y = 1; BigInteger tmp = 0; int currentIndex = 2; while (x.ToString().Length < n) { tmp = x + y; y = x; x = tmp; currentIndex++; } return currentIndex; } public static int BigIntegerLogMethod(int n) { BigInteger x = 1; BigInteger y = 1; BigInteger tmp = 0; int currentIndex = 2; while (Math.Floor(BigInteger.Log10(x) + 1) < n) { tmp = x + y; y = x; x = tmp; currentIndex++; } return currentIndex; } public static int MaxLimitMethod(int n) { BigInteger maxLimit = BigInteger.Pow(10, n - 1); BigInteger x = 1; BigInteger y = 1; BigInteger tmp = 0; int currentIndex = 2; while (x.CompareTo(maxLimit) < 0) { tmp = x + y; y = x; x = tmp; currentIndex++; } return currentIndex; } }
PHeiberg.. 8
假设x> 0
int digits = (int)Math.Floor(BigInteger.Log10(x) + 1);
会得到位数.
出于好奇,我测试了
int digits = x.ToString().Length;
做法.对于10万次迭代,它比Log10解决方案慢3倍.
假设x> 0
int digits = (int)Math.Floor(BigInteger.Log10(x) + 1);
会得到位数.
出于好奇,我测试了
int digits = x.ToString().Length;
做法.对于10万次迭代,它比Log10解决方案慢3倍.
扩展我的评论 - 而不是基于数字的测试,基于超过具有问题上限的常量进行测试:
public static int MaxLimitMethod(int n) { BigInteger maxLimit = BigInteger.Pow(10, n); BigInteger x = 1; BigInteger y = 1; BigInteger tmp = 0; int currentIndex = 2; while (x.CompareTo(maxLimit) < 0) { tmp = x + y; y = x; x = tmp; currentIndex++; } return currentIndex; }
这应该会导致显着的性能提升.