不使用BigInt计算

时间:2014-11-15 01:12:44

标签: algorithm data-structures biginteger

有没有办法在不使用BigInt的情况下打印n ^ 1000的值?一直在思考使用某种转换逻辑的方法,但还没有能够提出一些好的东西。

2 个答案:

答案 0 :(得分:1)

你当然可以这样做,我推荐它作为练习。除此之外,没有什么理由以现有BigInteger实现的语言实现它。

如果您正在寻找练习,那么使用支持BigIntegers开箱即用的语言进行练习真的很有帮助。这样你就可以逐步用自己的操作取代BigInteger操作,直到没有什么可以替换。

BigInteger库通常使用相同基元类型的数组(如byte或int)表示大于最大基元的值。这里是我编写的一些Python,用于模拟无符号字节(UByte)和无符号字节列表(BigUInt)。任何具有多个UBytes的BigUInt都将索引0视为最重要的字节,使其成为一个大端表示。反之亦然。

class UByte:
    def __init__(self, n=0):
        n = int(n)
        if (n < 0) or (n >= 255):
            raise ValueError("Expecting integer in range [0,255).")
        self.__n = n

    def value(self):
        return self.__n

class BigUInt:
    def __init__(self, b=[]):
        self.__b = b

    def value(self):
        # treating index 0 as most-significant byte (big endian)                                                                                
        byte_count = len(self.__b)
        if byte_count == 0:
            return 0

        result = 0
        for i in range(byte_count):
            place_value = 8 * (byte_count - i - 1)
            byte_value = self.__b[i].value() << place_value
            result += byte_value
        return result

    def __str__(self):
        # base 10 representation                                                                                                                
        return "%s" % self.value()

上面的代码并没有完全符合您的要求。 BigUInt#value的几个部分依赖于Python的内置BigIntegers,例如,即使byte_value非常大,左移到计算place_value也不会溢出。在较低级别的机器代码中,每个值都有固定的位数,左移不小心会导致信息丢失。同样,更新+=的{​​{1}}操作最终会因为低级代码中的相同原因而溢出,但Python会为您处理。

请注意,result是通过调用__str__来实现的。绕过Python神奇的一种方法是重新实现value(),这样就不会调用__str__。弄清楚如何将二进制数转换为基数为10的数字。完成后,您只需拨打value()

即可value() __str__实施return int(self.__str__())

以下是上述代码的一些示例测试。在您重新编写代码时,它们可能有助于进行健全性检查。

ten_as_byte = UByte(10)
ten_as_big_uint = BigUInt([UByte(10)])
print "ten as byte ?= ten as ubyte: %s" % (ten_as_byte.value() == ten_as_big_uint.value())

three_hundred = 300
three_hundred_as_big_uint = BigUInt([UByte(0x01), UByte(0x2c)])
print "three hundred ?= three hundred as big uint: %s" % (three_hundred == three_hundred_as_big_uint.value())

two_to_1000th_power = 2**1000
two_to_1000th_power_as_big_uint = BigUInt([UByte(0x01)] + [UByte() for x in range(125)])
print "2^1000 ?= 2^1000 as big uint: %s" % (two_to_1000th_power == two_to_1000th_power_as_big_uint.value())

编辑:有关所需内容的更好的低级别说明,请参阅From NAND to Tetris课程的第2章。该章中的项目是实现一个16位ALU(算术逻辑单元)。如果然后扩展ALU以输出溢出位,则可以将任意数量的这些ALU链接在一起,以处理基于任意大输入数的基本计算。

答案 1 :(得分:0)

将一个小数字 - 一个适合普通整数变量 - 提升到一个高功率是最容易实现的大整数运算之一,它经常被用作让人们发现一些大整数数学实现原则的任务

一个很好的讨论 - 包括C中的许多不同的例子 - 在代码审查的主题Sum of digits in a^b中。 My contribution there显示了如何通过重复平方来进行快速取幂,使用std::vector<uint32_t>作为一种假冒&#39;大整数。但是在这个主题中甚至有更简单的解决方案,只需选择。

测试C / C ++大整数代码而不必寻找大型整数库的简单方法是在Visual C ++(Express)中将代码编译为托管C ++,这样您就可以访问.NET BigInteger类:

#using "System.Numerics.dll"
using System::Numerics::BigInteger;

BigInteger n = BigInteger::Parse("123456789");

System::Console::WriteLine(n.Pow(1000));