【问题标题】:How does one divide a big integer by another big integer?如何将一个大整数除以另一个大整数?
【发布时间】:2016-01-06 06:15:15
【问题描述】:

过去几天我一直在研究这个问题,但我无法找到答案。如果除数只有一个词,我想出了一种有效的算法。但是,如果除数是多个单词,那么我会得到一些奇怪的答案。我知道这个问题已经在这里被问过几次了,但是除了使用教科书的方法或者去买一本关于这个主题的书外,没有明确的答案。我已经能够让我的大整数库中的每个函数都可以工作,除了除法。似乎有些人认为大整数除法是一个 NP 难题,并且由于我遇到的麻烦,我倾向于同意。

数据存储在一个结构中,该结构包含指向 uint16_t 或 uint32_t 数组的指针,具体取决于是否支持 long long 数据类型。如果不支持 long long,则 uint16_t 用于从乘法和加法运算中捕获任何进位/溢出。我目前拥有的功能是加法、减法、乘法、2 的补码求反、比较和、或、异或、非、左移、右移、左旋转、右旋转、位反转(反射)、一些转换例程,一个随机数填充例程,以及其他一些实用例程。除除法外,所有这些都正常工作(我在计算器上检查了结果)。

typedef struct bn_data_t bn_t;
struct bn_data_t
  {
    uint32 sz1;         /* Bit Size */
    uint32 sz8;         /* Byte Size */
    uint32 szw;         /* Word Count */
    bnint *dat;         /* Data Array */
    uint32 flags;       /* Operational Flags */
  };

这与我问过的关于 inline assembler 的另一个问题有关,因为这就是它的用途。

到目前为止我发现了什么:

Algorithm for dividing very large numbers

What is the fastest algorithm for division of crazy large integers?

https://en.wikipedia.org/wiki/Division_algorithm

Newton-Raphson Division With Big Integers

还有一堆关于这个主题的学术论文。

到目前为止我所做的尝试:

我有一个基本的例程工作,但它将一个多字大整数除以一个字。我试图实现一个 Newton-Raphson 算法,但这不起作用,因为我得到了一些非常奇怪的结果。我从微积分中了解牛顿的方法,但这是整数数学而不是浮点数。我了解 Goldschmidt 除法算法背后的数学,但我不清楚如何用整数数学来实现它。其中一些算法的部分问题是它们需要以 2 为底的对数函数。我知道如何使用浮点数和泰勒级数实现对数函数,但在使用整数数学时不知道。

我曾尝试查看GMP 库,但除法算法的文档记录不是很好,这让我有点不知所措。似乎他们在不同的点使用了不同的算法,这增加了混乱。

对于学术论文,我大部分理解数学(我已经清除了基本微积分数学、多变量微积分和常微分方程),但我的数学和数学之间又一次脱节了使用整数数学的知识和实现。我已经看到建议的小学方法,据我所知,它类似于移位减法,但我也不太确定如何实现该方法。有任何想法吗?代码会很好。

编辑:

这是我个人的学习经历。我想了解它是如何完成的。

编辑:2016 年 6 月 4 日

我已经有一段时间没有做这个了,因为我还有其他的熨斗和其他项目要处理。现在我重新审视了这个项目,我终于使用两种不同的算法实现了大整数除法。基本的一种是here 概述的移位减法。使用 CPU 除数指令的高速算法只有在除数为一个字时才被调用。两种算法都已确认可以正常工作,因为它们产生的结果已通过online big number calculator 进行了检查。所以现在,所有基本的数学和逻辑功能都已经实现了。这些功能包括加法、减法、乘法、除法、模除法、模数和、或非、异或、取反、反转(反射)、左移、右移、左旋转和右旋转。我可能会在他们需要时添加其他功能。感谢所有回复的人。

【问题讨论】:

  • 这不是特定于语言的。基本上,您应该考虑一下您在学校是如何使用笔和纸学习除法的。
  • 认为大整数包含以 2**n 为底的数字,而不是以 2 或 10 为底的数字。这有时被称为“高基数”方法。在您的情况下,这些数字似乎存储在数组dat 中。如果您像在小学时所学的那样从手除法开始,那么您的工作将有一个合理的起点。一旦您有更多使用大整数的经验,您就可以进入更高级的方法。
  • 整数除法绝对不是 NP-anything。它可以在大致O(N*log(N)) 中被证明是正确的。它涉及使用 FFT 和牛顿法。为了以可证明正确的方式正确截断答案,还需要乘回 + 校正步骤。但这只会增加大 O 因素,并不会增加复杂性。
  • 如果您正在尝试长手方法:在开始之前将两个操作数左对齐,因此每个操作数的 ms 位都是 1
  • Mysticial 提到的技术是高级方法。人们不能期望 Wikipedia 文章成为此类方法的最终参考。一般来说,除法可以映射回乘法(这也意味着从 big-O 的角度来看,除法并不比乘法复杂),并且非常长整数的快速乘法方法可能涉及 FFT。

标签: c algorithm math biginteger division


【解决方案1】:

教科书除法(长除法)算法,常用于以 10 为底的操作数,也可用于任意大的操作数。我假设我们正在通过基数 B 中的数字数组来实现大数。

当我们为十进制操作数手动执行长除法时,我们通常依靠反复试验来找到每个商位 d。但是,当对基数 B 中的大操作数使用长除法时,可以用一种有效的方法(由于 D. A. Pope 和 M. L. Stein)来代替这种反复试验。

要猜测d,我们可以使用除数的第一个数字(e)和“当前余数”的前两个数字(yz)(由长除法的减法步骤产生)。假设d1d 的估计值,通过将数字yz 除以e 获得。可以证明,如果除数具有某些属性(总是可以实现的,请参阅下面的链接),d1d1-1d1-2 必须是所需的数字d。这三个候选者中的每一个都可以逐个检查d的所需属性。

因此,每个商数的查找变得有效,对于其余部分,我们可以遵循迭代的长除法过程。有关此算法和 C 实现的详细信息,请参阅以下文章(由我编写):

https://mathsanew.com/articles/implementing_large_integers_division.pdf

【讨论】:

    猜你喜欢
    • 2016-02-26
    • 2015-01-26
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 2022-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多