用一种无法处理的语言处理大量数字?


15

我正在尝试思考如果语言构造无法处理大于某个特定值的数字时,我将如何对极大的数字进行计算(无穷大-整数不浮点数)。

我确定我不是第一个也不是最后一个问这个问题的人,但是我使用的搜索字词并未给我提供处理这些情况的算法。相反,大多数建议都会提供语言更改或变量更改,或谈论似乎与我的搜索无关的事情。所以我需要一些指导。

我会勾勒出这样的算法:

  1. 确定该语言的整数变量的最大长度。

  2. 如果数字大于变量最大长度的一半,则将其拆分为数组。(给一点游戏室)

  3. 数组顺序[0] =最右边的数字[n-max] =最左边的数字

    例如 编号:29392023 Array [0]:23,Array [1]:20,array [2]:39,array [3]:29

由于我将变量的长度的一半确定为标记的起点,因此我可以计算出它们的十分之一,十分之一,百分之一等。通过中途标记进行放置,这样,如果可变的最大长度为0到9999999999之间的10位数字,那么我知道减半到五位数给我一些游戏空间。

因此,如果我加或乘,我可以使用一个变量检查​​器函数,该函数可以看到array [0]的第六个数字(从右)与array [1]的第一个数字(从右)在同一位置。

除法和减法都有自己的问题,我还没有考虑过。

我想知道支持比程序更大数量的最佳实现。


1
首先想到的是Java的BigInteger:docs.oracle.com/javase/6/docs/api/java/math/BigInteger.html
Ivan,

这是这里任何人都可能知道并且能够提出特定建议的语言,还是晦涩难懂且专有的语言?
FrustratedWithFormsDesigner 2012年

我不知道我想要哪种语言。我最了解php,但是我不想用这种语言。Lisp颇具吸引力,因为据我所读,它的长度没有限制。但是,由于我个人想知道它是如何工作的缺点,如果我被困在一个岛上,我想有自由地在qbasic中进行操作。(这也很有趣,我一直在考虑计算大数,并且一些在线计算器对于这项任务来说太麻烦了。)
Mallow 2012年

Answers:


25

您正在寻找所用语言的任意精度算术(也称为“多精度”或“大数”)库。例如,如果您使用C语言,则可以使用GNU Bignum库-> http://gmplib.org/

如果您想了解它是如何工作的,还可以编写自己的big num库并使用它。处理此问题的最简单方法是使用数组,其中每个元素都是您正在使用的数字的数字。之后,您需要实现所有功能,以进行加,减,乘,除,乘幂运算等。


5
当然“数字”是相对的,许多bignum库都使用从256(无符号byte [])到2 ^ 64(无符号long [])的数字
棘轮怪胎

1
只要确保我理解,“数字”可以是基数为256的数字的数组?我想我可能会弄错了,在256基上进行数学运算比在88基上进行数学运算要容易,但仍然是一项艰巨的任务……(至少当我昨晚在一张纸上做哈哈)
Mallow

1
“基于256的数学比基于88的数学容易”。假。它们同样容易。
S.Lott 2012年

2
@ S.Lott:嗯...当您有按位运算可用时,以256为基础进行数学运算绝对比以88为基础容易
Jason S

1
建立自己的加/减/乘运算非常简单。但是,除法很困难,除非您以二进制形式实现它,否则它将成为有条件减法和移位的一种练习。
詹森·S

13

这是一个众所周知的问题:任意精度算术

当您使用的语言不能解决此问题时,请首先尝试找到可以解决此问题的第三方库。如果找不到或感到好奇,请尝试实施它;否则,请尝试执行它。维基百科文章对经典实现有很好的引用。


6

在处理大量数字时,最基本的设计决策之一可能是如何代表大量数字?

它是字符串,数组,列表还是自定义(本地)存储类。

做出决定后,可以将实际的数学运算分解成较小的部分,然后使用本地语言类型(例如int或integer)执行。

我在C#.Net中包含了一个非常基本的 ADDITION示例,该示例将生成的大数字存储为字符串。传入的“数字”也是字符串,因此一个人应该能够发送非常“大”的数字。请记住,为简单起见,该示例仅适用于整数。

即使使用字符串,字符数或数字中的“数字”也有限制,如下所示:

.NET字符串的最大可能长度是多少?

但是您可以添加一些非常大的数字,远远超出.Net的int32或int64本机类型。

无论如何,这是一个字符串存储实现。

/// <summary>
/// Adds two "integers".  The integers can be of any size string.
/// </summary>
/// <param name="BigInt1">The first integer</param>
/// <param name="BigInt2">The second integer</param>
/// <returns>A string that is the addition of the two integers passed.</returns>
/// <exception cref="Exception">Can throw an exception when parsing the individual parts     of the number.  Callers should handle. </exception>
public string AddBigInts(string BigInt1, string BigInt2)
{
    string result = string.Empty;

    //Make the strings the same length, pre-pad the shorter one with zeros
    int length = (BigInt1.Length > BigInt2.Length ? BigInt1.Length : BigInt2.Length);
    BigInt1 = BigInt1.PadLeft(length, '0');
    BigInt2 = BigInt2.PadLeft(length, '0');

    int remainder = 0;

    //Now add them up going from right to left
    for (int i = (BigInt1.Length - 1); i >= 0; i--)
    {
        //If we don't encounter a number, this will throw an exception as indicated.
        int int1 = int.Parse(BigInt1[i].ToString());
        int int2 = int.Parse(BigInt2[i].ToString());

        //Add
        int add = int1 + int2 + remainder;

        //Check to see if we need a remainder;
        if (add >= 10)
        {
            remainder = 1;
            add = add % 10;
        }
        else
        {
            remainder = 0;
        }

        //Add this to our "number"
        result = add.ToString() + result;
    }

    //Handle when we have a remainder left over at the end
    if (remainder == 1)
    {
        result = remainder + result;
    }

    return result;
}

我希望这会给您一些有关您自己的实现的想法。请注意,示例代码可能未经过优化或类似的处理。它旨在给出一些如何实现的想法。


凉!!谢谢,它有助于清除剩余的东西,我会把这些多余的部分弄复杂。
锦葵

-2

这对我来说工作更快:

static string Add(string a, string b)
        {
            string c = null;

            if (Compare(a, b) < 0)
            {
                c = a;
                a = b;
                b = c;
            }

            StringBuilder sb = new StringBuilder();

            b = b.PadLeft(a.Length, '0');

            int r = 0;

            for (int i = a.Length - 1; i >= 0; i--)
            {
                int part = a[i] + b[i] + r - 96;

                if (part <= 9)
                {
                    sb.Insert(0, part);

                    r = 0;
                }
                else
                {
                    sb.Insert(0, part - 10);

                    r = 1;
                }
            }

            if (r == 1)
            {
                sb.Insert(0, "1");
            }

            return sb.ToString();
        }

2
这个网站是关于概念性问题的,答案可能会解释这些问题。抛出代码转储而不是进行解释就像将代码从IDE复制到白板一样:它看起来很熟悉,甚至有时是可以理解的,但是感觉很奇怪……只是很奇怪。白板没有编译器
gna

该站点是交换站点,因此我们会尽力帮助彼此。也许我应该在StackOverflow中做这样的评论,但是我试图为我的方法提供帮助。如果有人仍然需要解释,他会要求。我在这里从头开始逐位执行标准的数学加法运算。
Andranik Sargsyan'5

同意。至少在转储代码之前先说明算法。
弗兰克·希勒曼

只是不加说明地转储代码就像鼓励复制粘贴。我不认为这在SoftwareEngineering中可能有用。也许在StackOverflow上可以,但是实际上这两个站点的用途完全不同。
拉夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.