Elisp 基本数据类型:数字

Table of Contents

内建的 emacs 数据类型(primitive types)包括整数、浮点数、cons、符号(symbol)、字符串、向量(vector)、散列表(hash-table)、subr(内建函数,比如 cons, if, and 之类)、byte-code function,和其它特殊类型,例如缓冲区(buffer)。

emacs 的数字分为整数和浮点数,整数的范围可以从 most-positive-fixnummost-negative-fixnum 这两个变量得到。

elisp 有一个特殊类型的值称为 NaN (not-a-number),可以用 (/ 0.0 0.0) 产生这个数。

数的运算

elisp 没有 ++-- 操作,类似的两个函数是 1+1- 。可以用 setq 赋值来代替 ++--

(setq foo 10)                           ; => 10
(setq foo (1+ foo))                     ; => 11
(setq foo (1- foo))                     ; => 10

测试函数

(integerp 1.)                           ; => t
(integerp 1.0)                          ; => nil
(floatp 1.)                             ; => nil
(floatp -0.0e+NaN)                      ; => t
(numberp 1)                             ; => t

还提供一些特殊测试,比如测试是否是零的 zerop ,还有非负整数测试的 wholenump

注:elisp 测试函数一般都是用 p 来结尾,p 是 predicate 的第一个字母。如果函数名是一个单词,通常只是在这个单词后加一个 p,如果是多个单词,一般是加 -p。

数的比较

常用的比较操作符号是我们在其它言中都很熟悉的,比如 <, >, >=, <=,不一样的是,由于赋值是使用 set 函数,所以 = 不再是一个赋值运算符了,而是测试数字相等符号。和其它语言类似,对于浮点数的相等测试都是不可靠的。比如:

(setq foo (- (+ 1.0 1.0e-3) 1.0))       ; => 0.0009999999999998899
(setq bar 1.0e-3)                       ; => 0.001
(= foo bar)                             ; => nil

所以一定要确定两个浮点数是否相同,是要在一定误差内进行比较。这里给出一个函数:

(defvar fuzz-factor 1.0e-6)
(defun approx-equal (x y)
  (or (and (= x 0) (= y 0))
      (< (/ (abs (- x y))
            (max (abs x) (abs y)))
         fuzz-factor)))
(approx-equal foo bar)                  ; => t

还有一个测试数字是否相等的函数 eql,这是函数不仅测试数字的值是否相等,还测试数字类型是否一致,比如:

(= 1.0 1)                               ; => t
(eql 1.0 1)                             ; => nil

elisp 没有 +=、/=、*=、-= 这样的命令式语言里常见符号,如果你想实现类似功能的语句,只能用赋值函数 setq 来实现了。 /= 符号被用来作为不等于的测试了。

多进制

#b101100 => 44      ; 二进制
#o54 => 44          ; 八进制
#x2c => 44          ; 十进制

elisp 可以用 2 到 36 之间任意一个数作为基数,比如:

#24r1k => 44        ; 二十四进制

之所以最大是 36,是因为只有 0-9 和 a-z 36 个字符来表示数字。不过这个特性使用场景较少。

1500.0, 15e2, 15.0e2, 1.5e3, 和 .15e4 都可以用来表示一个浮点数 1500,遵循 IEEE 标准。