Emacs Lisp 的 object 数字

integer type

在大多数机器上,表示的范围是 -134217728 到 134217727 之间的数,也就是 28 比特。也有的机器上可能表示更大的范围。值得注意的是, Emacs Lisp 不检查溢出。也就是说,有可能 (1+ 134217727) 的结果就 是 -134217728 。

integer 的 read syntax 和我们平时使用整数的习惯很类似,用 十进制表示。

     -1               ; The integer -1.
     1                ; The integer 1.
     1.               ; Also the integer 1.
     +1               ; Also the integer 1.
     268435457        ; Also the integer 1 on a 28-bit implementation.
     0                ; The integer 0.
     -0               ; The integer 0.

也可以用其他进制表示一个整数

     #b1000          ; 二进制,表示 8 ,
     #o10            ; 八进制,也是 8 , 注意是字母 o ,不是数字 0 。
     #x10            ; 十六进制,表示 16,

Emacs Lisp 采用补码表示一个数。如果是 28 比特的话,那么 5 的二进制表示是

    0000  0000 0000  0000 0000  0000 0101
    1111  1111 1111  1111 1111  1111 1011

float type

浮点数表示小数。精度和范围和实现的计算机相关。

浮点数的 read syntax 也和我们平时的使用习惯一致,例如 `1500.0', `15e2', `15.0e2', `1.5e3', 和 `.15e4' 都表示1500.0 这样一个浮点数。

关于 number 类型的函数

floatp 用于判断一个 object 是否是一个浮点数。

   (floatp 1)    ; => nil
   (floatp 0.0)  ; => t
   (floatp 0)    ; => nil
   (floatp 1.0)  ; => t

integerp 用于判断一个 object 是否是一个 integer 。

   (integerp 1)     ; => t
   (integerp 0.0)   ; => nil
   (integerp 0)     ; => t
   (integerp 1.0)   ; => nil

注意到一个很重要的区别, 1 是一个 integer , 1.0 是一个float ,他们拥有不一样的 type 。是两个不同的 object 。可以从 read syntax 中很容易区分出来两种不同的 number 。

numberp 用于判断一个 object 是否是一个 number 。 number 类型是 integer 和 float 的并集。

   (numberp 1)     ; => t
   (numberp 1.0)   ; => t
wholenump 用于判断一个 object 是否是一个非负整数。
   (wholenump 1.0)  ; => nil
   (wholenump -1 )  ; => nil
   (wholenump 1)    ; => t
   (wholenump 0)    ; => t
zerop 用于判断一个 object 是否是零 。
  (zerop 0.0)  ; t
  (zerop 0)    ; t

四则运算

加减法

加减法的函数可以接受任何 number 的类型的object 最为参数。

  (+ 1 1)              ; => 2
  (+ 1 1 1.0 3.0)      ; => 6.0
  (- 1 2 3)            ; => -4 , 也就是 1 - 2 -3
  (integerp  (+ 1. 1)) ; =>t
  (integerp (+ 1.0 1)) ; =>nil
  (floatp (+ 1.0 1))   ; =>t

如果所有参数都是 integer 的 object ,那么函数返回一个 integer 。 如果参数中有一个的 float 的 object ,那么返回一 个 float object 。

加减法还可以接受一个参数,或者没有参数也可以。

  (+ 100)   ; => 100
  (- 100)   ; => 100
  (+ )      ; => 0
  (- )      ; => 0

这个特点在是很用的。例如,我们有一个 list ,其中的元素都是 number 。那么我们很容易对其求和。

  (setq a-number-list '( 1 2 3 4 5 6 7 8 9 10))
  (apply '+ a-number-list) ; => 55

如果 a-number-list 中只有一个元素或者没有任何元素,我们 一样可以得到一个合理的结果。

乘除法

如果乘除法中存在一个 float 的参数,那么就执行 float 的 乘除 法。

float 的除法和 integer 的除法是有区别的。 float 的除法和我 们平常使用的算术很类似。 但是 integer 的除法只返回商,而不 管余数。 如果想得到余数必须使用取模的函数。

和加减法类似,一样可以做连乘或者连除。取模的函数是只能接受 两个参数。

   (* 2.0 4 )    ; => 8.0 , 一个 float
   (* 2 4)       ; => 8   ,  一个 integer
   (* 2.0 4.0 5) ; => 40.0 ,一个 float
   (/ 10.0 4)    ; => 2.5 , 一个 float
   (/ 12.0 4)    ; => 3.0 , 一个 float
   (/ 24 4 3)    ; => 2  , 一个 integer
   (/ 13 4)      ; => 3 , 商是 3 ,  一个 integer
   (% 13 4)      ; => 1 , 余数是 1 .

乘法可以接受一个参数,或者一个参数都没有也行。除法必须要有 两个或者两个以上的参数。

  (* )          ; 返回 1
  (* 100)       ; 返回 100

和其他语言不同对于一些,Emacs Lisp 中的加减乘除也是一个函 数,而不是一个操作符。这样就不存在操作符优先级的问题。

number 的比较

通常我们使用 `' 函数来判断两个 number 是否相等。也可以用 >, <= , > , < , 来判断两个 number 的大小关系。

可以用 max 和 min 函数得到最大值或者最小值。

  ( > 100 200)   ;  => nil
  ( < 100 200)   ;  => t
  (max 100)      ;  => 100
  (min 100)      ;  => 100
  (max 1 2 3 4)  ;  => 4
  (min 1 2 3 4)  ;  => 1

转换函数

float 函数把一个 number 转换成为一个 number , truncate 把 一个 number 转换成为一个 integer 。

   (float 1)      ; => 1.0
   (float 1.0)    ; => 1.0
   (truncate 1.2) ; => 1
   (truncate 1.7) ; => 1
   (truncate -1.2); => -1
   (truncate -1.7); => -1

floor 函数和 ceiling 函数对应数学中的上取整函数和下取整函 数。round 函数表示四舍五入。

  (floor 1.2)
      => 1
  (floor 1.7)
      => 1
  (floor -1.2)
      => -2
  (floor -1.7)
      => -2
  (ceiling 1.2)
       => 2
  (ceiling 1.7)
       => 2
  (ceiling -1.2)
       => -1
  (ceiling -1.7)
       => -1
  (round 1.2)
       => 1
  (round 1.7)
       => 2
  (round -1.2)
       => -1
  (round -1.7)
       => -2
与他们对应的函数还有 ffloor , fceiling , ftruncate, fround ,区别是他们返回的是一个 float ,而不是一个 integer 。

二进制位操作函数

lsh, ash 函数用来完成位移动。 例如

   (lsh 4 3) ; => 32

表示把 4 左移 3 位, 如果第二个参数是负数表示右移。

lsh 和 ash 基本上功能一样,但是如果右移一个负数的时候,两 个就有区别了, lsh 是在高位补零, ash 在高位补一,用 ash 右移一个负数,结果一定是负数,而 lsh 就一定得到一个正书。

logand , logior , logxor 分别是逻辑与函数,逻辑或函数和逻 辑异或函数。lognot 逻辑取反函数。

random 函数可以返回一个伪随机数,一个 integer 。

其他数学函数

abs , sin, cos, tan, asin, acos, exp, log, log10, expt, sqrt 。

高级话题

eq, equal, = 之间的区别和联系。

  (eq (* (/ 1 3.0) 3) 1.0) ;;返回 nil
  (equal 1.0 1)  ;; 返回  nil
  (= 1.0 1)   ;;返回 t

看起来很复杂,其实使用起来很容易, 如果比较数字的时候,就用 = , 如果比较两个对象是 否是同一个时用 eq , 其他时候用 equal .

quick sort

(setq a
      (mapcar (lambda (x)
                (random))
              (make-list 10 0)))

(defun get-greater-less-list (x a-list)
  (if (not a-list)
      (cons nil nil)
    (let* ((a-tail (cdr a-list))
           (a-head (car a-list))
           (a-b    (get-greater-less-list x a-tail))
           (greater-list (car a-b))
           (less-list (cdr a-b)))
      (if (< x a-head)
          (cons
           (cons a-head greater-list)
           less-list)
        (cons
         greater-list
         (cons a-head less-list))))))

(get-greater-less-list 0 a)
(quick-sort a)
(defun quick-sort ( a-list)
  (if (not a-list)
      nil
    (let* ((a-head (car a-list))
           (a-tail (cdr a-list))
           (a-b (get-greater-less-list a-head a-tail)))
      (append
       (quick-sort (car a-b))
       (cons
        a-head
        (quick-sort (cdr a-b)))))))