给定一个 n 位整数和一个 m 位整数。如何使用列表、数组或任何其他 lisp 特定数据类型在 LISP 中将它们相乘?
例如;
a(1)a(2)...a(n)
b(1)b(2)...b(m)
结果为;
r(1)r(2)...r(m+n)
给定一个 n 位整数和一个 m 位整数。如何使用列表、数组或任何其他 lisp 特定数据类型在 LISP 中将它们相乘?
例如;
a(1)a(2)...a(n)
b(1)b(2)...b(m)
结果为;
r(1)r(2)...r(m+n)
Common Lisp 已经有原生的bignums。你为什么不使用它们?
您基本上不必特别声明任何东西,它们“神奇地”发生:
% sbcl
This is SBCL 1.0.56.0.debian, an implementation of ANSI Common Lisp.
* (defun fact (n) (if (< n 1) 1 (* n (fact (- n 1)))))
FACT
* (fact 50)
30414093201713378043612608166064768844377641568960512000000000000
因此,使用 Common Lisp,您基本上不必费心......
而高效的bignum算法是一个非常困难的问题;高效算法比简单算法具有更好的复杂性;您可以找到解释它们的困难书籍(基础数学非常困难)。另请参阅此答案。
如果你想做一个有竞争力的 bignum 实现,准备好几年努力工作,把它做成博士论文。
一个简单的算法就是模仿你在手动计算乘法时所做的事情:
123 x
456 =
---
738
615
492
-----
56088
第一步是实现乘以单个“数字”(例如123 x 6 = 738
)。
之后,移位当然是微不足道的(只需滑动列表中的元素),因此可以使用加法功能完成乘法运算。
请注意,这不是计算两个大数的乘积的最快方法(例如,参见Karatsuba 算法)。
PS:思考如何手动计算两个大数的乘积也解释了一些“惊人”的结果,例如 111111111*111111111 = 12345678987654321
111111111 x
111111111 =
---------
111111111
111111111
111111111
111111111
111111111
111111111
111111111
111111111
111111111
-----------------
12345678987654321
(* 1234567890123456789123456789 1234567890123456789123456789)
大整数是 Common Lisp 原生的。