UP | HOME

数字

Table of Contents

现在就先从简单的数据类型:数字开始吧。emacs 的数字分为整数和浮点数

和 C 比没有双精度数 double

整数

1, 1.,+1, -1, 536870913, 0, -0 这些都是整数。整数的范围是和机器是有关的,一般来最小范围是在 -268435456 to 268435455(29位,-2**28 ~ 2**28-1)

可以从 most-positive-fixnum 和 most-negative-fixnum 两个变量得到整数的范围

可以用多种进制来输入一个整数。比如:

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

最神奇的是可以用 2 到 36 之间任意一个数作为基数,比如:

#24r1k ;; => 44 二十四进制
之所以最大是 36,是因为只有 0-9 和 a-z 36 个字符来表示数字

但是基本上不会有人会用到 elisp 的这个特性

浮点数

1500.0, 15e2, 15.0e2, 1.5e3, 和 .15e4 都可以用来表示一个浮点数 1500.

遵循 IEEE 标准,elisp 也有一个特殊类型的值称为 NaN (not-a-number)

可以用 (/ 0.0 0.0) 产生这个数

测试

整数类型测试函数是 integerp,浮点数类型测试函数是 floatp。数字类型测试用 numberp。可以分别运行这几个例子来试验一下:

(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 来实现了

/= 符号被用来作为不等于的测试了 

转换

整数向浮点数转换是通过 float 函数进行的。而浮点数转换成整数有这样几个函数:

  • truncate 转换成靠近 0 的整数
  • floor 转换成最接近的不比本身大的整数
  • ceiling 转换成最接近的不比本身小的整数
  • round 四舍五入后的整数,换句话说和它的差绝对值最小的整数

    可以用 1.2, 1.7, -1.2, -1.7 对这四个函数操作一遍就知道区别了
    
    浮点数的范围是无穷大的,而整数是有范围的,如果用前面的函数转换 1e20 成一个整数会出现什么情况呢?
    

运算

四则运算没有什么好说的,就是 + - * /。值得注意的是

和 C 语言类似,如果参数都是整数,作除法时要记住 (/ 5 6) 是会等于 0 的

如果参数中有浮点数,整数会自动转换成浮点数进行运算,所以 (/ 5 6.0) 的值才会是 5/6

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

(setq foo 10)                           ; => 10
(setq foo (1+ foo))                     ; => 11
(setq foo (1- foo))                     ; => 10
可能有人看过有 incf 和 decf 两个实现 ++ 和 -- 操作,这两个宏是可以用的

这两个宏是 Common Lisp 里的,emacs 有模拟的 Common Lisp 的库 cl。但是 RMS 认为最好不要使用这个库

可以在的 elisp 包中使用这两个宏,只要在文件头写上:

(eval-when-compile
  (require 'cl))
由于 incf 和 decf 是两个宏,所以这样写不会在运行里导入 cl 库
  • 取数的绝对值: abs
  • 取整的函数: 一个是符号 %,一个是函数 mod

    这两个函数有什么差别呢?
    
    一是 % 的第个参数必须是整数,而 mod 的第一个参数可以是整数也可以是浮点数
    
    二是即使对相同的参数,两个函数也不一定有相同的返回值
    
    • 三角运算有函数: sin, cos, tan, asin, acos, atan
    • 开方函数: sqrt
    • 指数函数:exp 是以 e 为底的指数运算,expt 可以指定底数的指数运算
    • 对数函数:log 默认底数是 e
      • 也可以指定底数。log10 就是以10为底数
      • logb 是以 2 为底数运算,但是返回的是一个整数。这个函数是用来计算数的位
    • 随机函数:random 可以产生随机数
    当然还包含位运算
    

Next:字符串

Top:数据类型