在.NET中使用令人难以置信的大数字

时间:2008-11-10 20:22:27

标签: c# .net biginteger largenumber

我正在努力解决projecteuler.net上的问题,但我遇到了一些问题。

第一个是在List<t>中存储大量元素的问题。在列表中存储大量数据时,我一直收到OutOfMemoryException。

现在我承认我可能没有以最好的方式做这些事情但是,有没有办法定义应用程序可以消耗多少内存?

当我满足100,000,000个元素时,它通常会崩溃:S

其次,一些问题需要增加大量数字。我使用ulong数据类型,我认为这个数字会变得非常大,但我仍然设法绕过最大的受支持的int并进入负数。

你有任何关于使用难以置信的大数字的提示吗?

10 个答案:

答案 0 :(得分:27)

您需要使用大量使用一些基本数学原理的类来拆分这些操作。 CodePoject上的implementation of a C# BigInteger library似乎是最有希望的。本文对大量数字的操作也有一些很好的解释。

另见: Big integers in C#

答案 1 :(得分:23)

答案 2 :(得分:11)

就Euler项目而言,如果你遇到OutOfMemory异常,你可能会咆哮错误的树。来自他们的网站:

  

每个问题都是根据“一分钟规则”设计的,这意味着虽然设计一个成功的算法可能需要几个小时来解决更难的问题,但是有效的实施将允许在适度的情况下获得解决方案不到一分钟就可以使用电脑。

答案 3 :(得分:4)

正如用户Jakers所说,如果你使用大数字,可能你做错了。

在我完成的ProjectEuler问题中,到目前为止还没有人需要大数学数学。 它更多的是找到适当的算法来避免大数字。

想要提示吗?发布在这里,我们可能会有一个有趣的Euler线程开始。

答案 4 :(得分:3)

我认为这是C#? F#内置了处理这两个问题的方法(BigInt类型和延迟序列)。

如果您愿意,可以使用C#中的两种F#技术。如果添加对核心F#程序集的引用,则BigInt类型可以从其他语言中合理使用。

懒惰序列基本上只是语法友好的枚举器。将100,000,000个元素放入列表中并不是一个好计划,因此您应该重新考虑解决方案以解决这个问题。如果您不需要保留信息,请将其扔掉!如果重新计算它比存储它便宜,扔掉它!

答案 5 :(得分:1)

查看此thread中的答案。您可能需要使用可用的第三方大整数库/类之一,或者等待包含本机BigInteger数据类型的C#4.0。

答案 6 :(得分:1)

至于定义应用程序将使用多少内存,您可以在使用MemoryFailPoint类执行操作之前检查可用内存。

这允许您在执行操作之前预先分配内存,因此您可以在运行之前检查操作是否会失败。

答案 7 :(得分:1)

您不需要使用BigInteger您可以使用字符串数组来执行此事件。

class Solution
{

    static void Main(String[] args)
    {
        int n = 5;
        string[] unsorted = new string[6] { "3141592653589793238","1", "3", "5737362592653589793238", "3", "5" };

        string[] result = SortStrings(n, unsorted);

        foreach (string s in result)
            Console.WriteLine(s);
        Console.ReadLine();
    }
    static string[] SortStrings(int size, string[] arr)
    {

        Array.Sort(arr, (left, right) =>
        {

            if (left.Length != right.Length)
                return left.Length - right.Length;
            return left.CompareTo(right);
        });

        return arr;
    }
}

答案 8 :(得分:0)

string Add(string s1, string s2)
{
        bool carry = false;
        string result = string.Empty;

        if (s1.Length < s2.Length)
            s1 = s1.PadLeft(s2.Length, '0');
        if(s2.Length < s1.Length)
            s2 = s2.PadLeft(s1.Length, '0');

        for(int i = s1.Length-1; i >= 0; i--)
        {
            var augend = Convert.ToInt64(s1.Substring(i,1));
            var addend = Convert.ToInt64(s2.Substring(i,1));
            var sum = augend + addend;
            sum += (carry ? 1 : 0);
            carry = false;
            if(sum > 9)
            {
                carry = true;
                sum -= 10;
            }
            result = sum.ToString() + result;
        }
        if(carry)
        {
            result = "1" + result;
        }

    return result;
}

答案 9 :(得分:0)

我不确定这是否是处理它的好方法,但是我在项目中使用了以下内容。

对于每个项目,我都有一个“ double theRelevantNumber”变量和一个“ int PowerOfTen”,在我的相关类中,我有一个“ int relatedDecimals”变量。

所以...当遇到大量数字时,将按以下方式处理它们:

首先将它们更改为x,yyy形式。因此,如果输入的数字为123456,789,而“ powerOfTen”为10,则它将像这样开始:

therelevantNumber = 123456,789 十次幂= 10 当时的数字是:123456,789 * 10 ^ 10

然后将其更改为: 1,23456789 * 10 ^ 15

然后将其四舍五入为相关的小数位数(例如5)至1,23456,然后与“ PowerOfTen = 15”一起保存

将数字相加或相减时,将忽略相关小数点后的任何数字。如果您选择的话:

1 * 10 ^ 15 + 1 * 10 ^ 10如果“ relevantDecimals”为5,它将更改为1,00001,但是如果“ relevantDecimals”为4,则将完全不更改。

此方法使您能够毫无问题地处理doubleLimit * 10 ^ intLimit上的数字,至少对于OOP而言,它并不难追踪。