如何提高将BigInteger计数到2 ^ 256的速度

时间:2013-10-02 13:54:49

标签: c# biginteger largenumber

这个小型控制台应用程序会计算一个BigInteger并给我一个反馈,它指向它所指向的指数。

现在我对一些速度提升感到好奇。我该怎么办?

感谢您的推荐!

using System;
using System.Collections.Generic;
using System.Numerics;

namespace Counter
{
    internal class Program
    {
        private static readonly Dictionary<BigInteger, int> Dic = new Dictionary<BigInteger, int>();

        private static void Main(string[] args)
        {
            Console.WriteLine("Start with counting ... from 1 to 2^256.");
            Console.WriteLine();

            CreateDict();

            var bigInteger = new BigInteger();

            Console.WriteLine("D:HH:mm:ss,ms      - fac.  - Number");
            Console.WriteLine("---------------------------------------------------");

            var startTime = DateTime.UtcNow;
            while (true)
            {
                bigInteger++;
                if (Dic.ContainsKey(bigInteger))
                {
                    Console.WriteLine("{0:G} - 2^{1,3} = {2:#,0}", (DateTime.UtcNow - startTime), Dic[bigInteger], bigInteger);
                }
            }
        }

        private static void CreateDict()
        {
            for (int i = 1; i <= 256; i++)
            {
                Dic.Add(BigInteger.Pow(2, i), i);
            }
        }
    }
}

输出:http://pastebin.com/bMBntFsL

进度

使用BigInteger并不是那么好。

BigInteger 2 ^ 26 = 5s

Double 2 ^ 26 = 1,3s

从Dict切换到直接比较要快得多

            int i = 1;
            double pow = Math.Pow(2, i);
            while (true)
            {
                bigInteger++;
                if (bigInteger == pow)
                {
                    Console.WriteLine("{0:G} - 2^{1,3} = {2:#,0}", (DateTime.UtcNow - startTime), Dic[bigInteger], bigInteger);

                    i++;
                    pow = Math.Pow(2, i);
                }
            }

Dict 2 ^ 26 = 1,3s

&#34;&LT;&#34; 2 ^ 26 = 0,5s

1 个答案:

答案 0 :(得分:2)

如果确实想要在循环中计算最多2 ^ 256,请不要使用BigInteger

来自MSDN

  
    

.NET Framework中的其他数字类型也是不可变的。但是,由于BigInteger类型没有上限或下限,因此其值可能会变得非常大并且会对性能产生可测量的影响。

         

虽然此过程对调用方是透明的,但确实会导致性能损失。在某些情况下,特别是在非常大的BigInteger值的循环中执行重复操作时,性能损失可能显着

  

由于您所需的值很大但非常大,您可以改用doubledouble值可以达到1.7 × 10^308,因此您可以使用2 ^ 256(1.15 × 10^77)。这对应用程序的性能有很大帮助。


另一项改进是将TryGetValue用于您的词典,而不是ContainsKey,正如您在this answer中所看到的那样。

因为您同时执行ContainsKey(bigInteger)Dic[bigInteger],所以您要进行两次查找。

所以代码将成为:

while (true)
{
    bigValue++;

    int exponent;
    if (Dic.TryGetValue(bigValue, out exponent))
    {
        Console.WriteLine("{0:G} - 2^{1,3} = {2:#,0}", (DateTime.UtcNow - startTime), exponent, bigValue);
    }
}