如何处理任意大整数

时间:2008-11-21 21:36:45

标签: c++ integer overflow long-integer integer-overflow

我正在编写一种编程语言,今天我得到了可以编译阶乘函数(递归)的点,但是由于整数的最大值,我可以获得的最大值是阶乘(12)。什么是处理任意最大大小的整数的技术。目前,该语言通过将代码转换为C ++来实现。

7 个答案:

答案 0 :(得分:18)

如果需要大于32位,可以考虑使用64位整数(long long),或使用或编写任意精度数学库,例如: GNU MP

答案 1 :(得分:5)

如果你想要推出自己的任意精度库,请参阅Knuth的精神数学算法,他的巨着的第2卷。

答案 2 :(得分:3)

如果您将其构建为一种语言(出于学习目的,我猜),我想我可能会写一个小BCD库。只需将BCD编号存储在字节数组中即可。

事实上,使用当今巨大的存储能力,您可能只使用一个字节数组,其中每个字节只保存一个数字(0-9)。然后编写自己的例程来添加,减去乘法并除以字节数组。

(Divide很难,但我打赌你可以在某处找到一些代码。)

我可以给你一些类似Java的伪代码但是现在不能从头开始做C ++:

class BigAssNumber {
    private byte[] value;

    // This constructor can handle numbers where overflows have occurred.
    public BigAssNumber(byte[] value) {
        this.value=normalize(value);
    }

    // Adds two numbers and returns the sum.  Originals not changed.
    public BigAssNumber add(BigAssNumber other) {
        // This needs to be a byte by byte copy in newly allocated space, not pointer copy!
        byte[] dest = value.length > other.length ? value : other.value;         

        // Just add each pair of numbers, like in a pencil and paper addition problem.
        for(int i=0; i<min(value.length, other.value.length); i++)
            dest[i]=value[i]+other.value[i];

        // constructor will fix overflows.
        return new BigAssNumber(dest);
    }

    // Fix things that might have overflowed  0,17,22 will turn into 1,9,2        
    private byte[] normalize(byte [] value) {
        if (most significant digit of value is not zero)
            extend the byte array by a few zero bytes in the front (MSB) position.

        // Simple cheap adjust.  Could lose inner loop easily if It mattered.
        for(int i=0;i<value.length;i++)
            while(value[i] > 9) {
                value[i] -=10;
                value[i+1] +=1;
            }
        }
    }
}

我使用的事实是,我们在一个字节中有很多额外空间来帮助以通用方式处理额外溢出。也可以用于减法,并帮助增加一些。

答案 3 :(得分:1)

在C ++中没有简单的方法。您必须使用GNU Multiprecision之类的外部库,或使用本机支持Python等任意大整数的其他语言。

答案 4 :(得分:0)

其他海报已经为图书馆提供了链接,这些图书馆将为您完成此任务,但您似乎正在尝试将其构建为您的语言。我的第一个想法是:你确定你需要这样做吗?大多数语言都会像其他人建议的那样使用附加库。

假设您正在编写编译器并且确实需要此功能,则可以在汇编中为任意大的值实现整数运算函数。

例如,一个简单(但非最佳)的实现将数字表示为二进制编码的十进制。如果你用铅笔和纸做数学运算,算术函数可以使用与你使用的算法相同的算法。

另外,请考虑为这些大整数使用专门的数据类型。这样“正常”整数可以使用标准的32位算法。

答案 5 :(得分:0)

我首选的方法是将我当前的int类型用于32位整数(或者可能将其更改为内部长或类似,只要它可以继续使用相同的算法),然后当它溢出,将其更改为存储为bignum,无论是我自己的创建,还是使用外部库。但是,我觉得我需要检查每个算术运算的溢出,算术运算大约是2倍的开销。我怎么能解决这个问题?

答案 6 :(得分:0)

如果我实现了我自己的语言并希望支持任意长度的数字,我将使用带有进位/借位概念的目标语言。但是由于没有HLL实现这一点而没有严重的性能影响(例如异常),我肯定会在汇编中实现它。它可能需要一条指令(如在x86中的JC中)来检查溢出并处理它(如在x86中的ADC中),这对于实现任意精度的语言来说是可接受的折衷。然后我将使用一些用汇编代替常规运算符的函数,如果你可以利用重载来获得更优雅的输出,甚至更好。但我不认为生成的C ++可以作为目标语言进行维护(或意味着维护)。

或者,只需使用一个比您需要更多铃声和口哨的图书馆,并将它用于您的所有数字。

作为一种混合方法,检测汇编中的溢出并在溢出时调用库函数,而不是滚动自己的迷你库。