9.2 转换及取出 (Conversion and Extraction)
Lisp 提供四种不同类型的数字的转换及取出位数的函数。函数 float
将任何实数转换成浮点数:
> (mapcar #'float '(1 2/3 .5))
(1.0 0.6666667 0.5)
将数字转成整数未必需要转换,因为它可能牵涉到某些资讯的丧失。函数 truncate
返回任何实数的整数部分:
> (truncate 1.3)
1
0.29999995
第二个返回值 0.29999995
是传入的参数减去第一个返回值。(会有 0.00000005 的误差是因为浮点数的计算本身就不精确。)
函数 floor
与 ceiling
以及 round
也从它们的参数中导出整数。使用 floor
返回小于等于其参数的最大整数,而 ceiling
返回大于或等于其参数的最小整数,我们可以将 mirror?
(46 页,译注: 3.11 节)改成可以找出所有回文(palindromes)的版本:
(defun palindrome? (x)
(let ((mid (/ (length x) 2)))
(equal (subseq x 0 (floor mid))
(reverse (subseq x (ceiling mid))))))
和 truncate
一样, floor
与 ceiling
也返回传入参数与第一个返回值的差,作为第二个返回值。
> (floor 1.5)
1
0.5
实际上,我们可以把 truncate
想成是这样定义的:
(defun our-truncate (n)
(if (> n 0)
(floor n)
(ceiling n)))
函数 round
返回最接近其参数的整数。当参数与两个整数的距离相等时, Common Lisp 和很多程序语言一样,不会往上取(round up)整数。而是取最近的偶数:
> (mapcar #'round '(-2.5 -1.5 1.5 2.5))
(-2 -2 2 2)
在某些数值应用中这是好事,因为舍入误差(rounding error)通常会互相抵消。但要是用户期望你的程序将某些值取整数时,你必须自己提供这个功能。 [1] 与其他的函数一样, round
返回传入参数与第一个返回值的差,作为第二个返回值。
函数 mod
仅返回 floor
返回的第二个返回值;而 rem
返回 truncate
返回的第二个返回值。我们在 94 页(译注: 5.7 节)曾使用 mod
来决定一个数是否可被另一个整除,以及 127 页(译注: 7.4 节)用来找出环状缓冲区(ring buffer)中,元素实际的位置。
关于实数,函数 signum
返回 1
、 0
或 -1
,取决于它的参数是正数、零或负数。函数 abs
返回其参数的绝对值。因此 (* (abs x) (signum x))
等于 x
。
> (mapcar #'signum '(-2 -0.0 0.0 0 .5 3))
(-1 -0.0 0.0 0 1.0 1)
在某些应用里, -0.0
可能自成一格(in its own right),如上所示。实际上功能上几乎没有差别,因为数值 -0.0
与 0.0
有着一样的行为。
比值与复数概念上是两部分的结构。(译注:像 Cons 这样的两部分结构) 函数 numerator
与 denominator
返回比值或整数的分子与分母。(如果数字是整数,前者返回该数,而后者返回 1
。)函数 realpart
与 imgpart
返回任何数字的实数与虚数部分。(如果数字不是复数,前者返回该数字,后者返回 0
。)
函数 random
接受一个整数或浮点数。这样形式的表达式 (random n)
,会返回一个大于等于 0
并小于 n
的数字,并有着与 n
相同的类型。