编程语言如何处理大数算术

Posted

技术标签:

【中文标题】编程语言如何处理大数算术【英文标题】:How do programming languages handle huge number arithmetic 【发布时间】:2010-11-29 03:40:48 【问题描述】:

对于使用 64 位处理器的计算机,它可以处理的最大数字是 264 = 18,446,744,073,709,551,616。编程语言(比如 Java 或 C、C++)如何处理高于此值的数字的算术运算。任何收银机都不能将其作为一个整体保存。这个问题是如何解决的?

【问题讨论】:

这是一个关于大整数的问题还是关于表示多大的浮点数的问题? 整数只是为了让这个概念像现在一样正确:) 我问了一个类似的问题,最终找到了我的方式; ***.com/questions/1218149/… 狩猎愉快! 【参考方案1】:

有很多专门的技术可以对大于寄存器大小的数字进行计算。其中一些在arbitrary precision arithmetic的这篇***文章中进行了概述@

C 和 C++ 等低级语言将大量计算留给您选择的库。一个值得注意的是GNU Multi-Precision library。 Python等高级语言将其集成到语言的核心中,因此普通数字和非常大的数字对程序员来说是相同的。

【讨论】:

【参考方案2】:

你假设错了。 在单个寄存器中可以处理的最大数字是 64 位数字。但是,使用一些智能编程技术,您可以将几十个这些 64 位数字连续组合在一起,以生成一个巨大的 6400 位数字,并使用它来进行更多计算。只是没有将数字放在一个寄存器中那么快。

即使是旧的 8 位和 16 位处理器也使用了这个技巧,他们只会让数字溢出到其他寄存器。它使数学变得更复杂,但并没有结束可能性。

但是,如此高精度的数学运算是极其不寻常的。即使你想计算美国的全部国债并将结果存储为津巴布韦元,我认为 64 位整数仍然足够大。不过,它绝对足够容纳我的储蓄账户的金额。

【讨论】:

not true.... 尤其是小数部分,他们不想快速四舍五入(例如使用普通浮点数时) @reinier,Donald Knuth 写了几本关于这个主题以及计算机和数学的好书和文章。我建议你开始阅读其中的一些。许多语言都有一个特殊的 BigNum 库,可以通过多种方式实现。 (见en.wikipedia.org/wiki/Bignum) 不稀奇..嗯怎么样..说我想要35!..很容易越界【参考方案3】:

处理真正大量数字的编程语言使用自定义数字原语,这些原语超出了为 32、64 或 128 位 CPU 优化的正常操作。这些数字在计算机安全和数学研究中特别有用。

GNU Multiple Precision Library 可能是这些方法中最完整的示例。

您可以使用数组来处理更大的数字。在您的网络浏览器中尝试一下。在 Web 浏览器的 javascript 控制台中键入以下代码:

JavaScript 失败的地方

console.log(9999999999999998 + 1)
// expected 9999999999999999
// actual  10000000000000000  oops!

JavaScript 不处理9999999999999998 以上的纯整数。但是编写自己的数字原语是为了使这个计算工作足够简单。这是使用a custom number adder class in JavaScript 的示例。

使用自定义数字类通过测试

// Require a custom number primative class
const Num = require('./bases')

// Create a massive number that JavaScript will not add to (correctly)
const num = new Num(9999999999999998, 10)

// Add to the massive number
num.add(1)

// The result is correct (where plain JavaScript Math would fail)
console.log(num.val)  // 9999999999999999

工作原理

您可以查看class Num ... 的代码以查看正在发生的事情的详细信息;但这里是使用逻辑的基本概述:

类:

Num 类包含单个 Digit 类的数组。 Digit 类包含单个数字的值,以及处理Carry flag 的逻辑

步骤:

    选择的数字变成字符串 每个数字都转换为Digit 类并作为数字数组存储在Num 类中 当Num 递增时,它会被传送到数组中的第一个Digit(最右边的数字) 如果Digit值加上Carry flag等于Base,则调用左边的下一个Digit递增,并将当前编号重置为0 ...一直重复到数组最左边的数字

从逻辑上讲,它与机器级别发生的事情非常相似,但在这里它是无限的。你可以read more about about how digits are carried here;这可以应用于任何基数。

【讨论】:

【参考方案4】:

Ada 实际上本机支持这一点,但仅限于它的无类型常量(“命名数字”)。对于实际变量,您需要找到一个任意长度的包。见Arbitrary length integer in Ada

【讨论】:

+1 很高兴在 SO 上见到你,T.E.D. 我只是注意到 Ada 支持它作为内置的,在其他地方阅读,但不知道它仅限于常量。这有点奇怪。你甚至可以取一个常量 bignum + 一个小的 int,并最终得到一个 bignum 结果吗?【参考方案5】:

差不多。在学校里,你记住了个位数的加法、乘法、减法和除法。然后,您学习了如何将多位数问题作为单位数问题的序列来处理。

如果您愿意,您可以将两个 20 位数字相乘,只需了解简单的算法和一位数的乘法表即可。

【讨论】:

这是真的,就目前而言。然而,它只完成了最基本的操作:加法、减法、乘法和除法只是开始。然后,要真正处理好任意数字,您必须担心平方根、精确跟踪等。这就是为什么我认为每种语言都应该提供一个好的、完整的实现作为标准。【参考方案6】:

一般来说,语言本身不处理高精度、高精度的大数运算。 更有可能是编写的,它使用替代的数值方法来执行所需的操作。

例如(我现在只是在编造这个),这样的库可能会模拟您可能用来手动执行大量算术的实际技术。此类库通常比使用内置算法慢得多,但有时需要额外的精度和准确度。

【讨论】:

好吧,不管怎样,当涉及到算术运算时,比如将两个大数相加,它们都必须在寄存器中,而寄存器的大小是不够的。这个问题是如何解决的? 您可以通过执行许多较小的算术运算来执行单个大型算术运算。我想我在第二段中说得很清楚...... 你不会一下子在一张纸上把 123098712380714091823 加到 120497235897345089273403 上吧?您一次执行许多较小的操作。【参考方案7】:

作为一个思想实验,想象存储为字符串的数字。具有对这些任意长的数字进行加法、乘法等功能。

实际上,这些数字可能以更节省空间的方式存储。

【讨论】:

【参考方案8】:

将一个机器大小的数字视为一个数字,并从小学开始应用多位乘法算法。这样您就不需要将整数保存在寄存器中,只需将数字保存在它们的处理上即可。

【讨论】:

【参考方案9】:

大多数语言将它们存储为整数数组。如果您添加/减去这些大数字中的两个,则库会分别添加/减去数组中的所有整数元素并处理进位/借位。 这就像学校里的手动加/减法,因为它在内部是这样工作的。

一些语言使用真正的文本字符串而不是整数数组,这样效率较低但更容易转换为文本表示形式。

【讨论】:

以上是关于编程语言如何处理大数算术的主要内容,如果未能解决你的问题,请参考以下文章

如何处理不同语言的 iOS 推送通知

如何处理以编程方式添加的按钮事件? C#

QTranslator 如何处理语言环境修饰符 PyQT?

Windows 如何处理无符号 64 位整数?

函数式编程中如何处理副作用?

函数式编程中如何处理副作用?