Skip to content

Latest commit

 

History

History
1110 lines (681 loc) · 36 KB

08.NumericOperations.md

File metadata and controls

1110 lines (681 loc) · 36 KB

Chapter 8. 数字操作

本章介绍了 Chez Scheme 对数字对象上的标准操作集的扩展。参见"The Scheme Programming Language, 第 4 版", 第 6 章,或 R6RS 中对数字对象上标准操作的介绍。

Chez Scheme 支持全部 Scheme 数字类型,包括精确和不精确整数,有理数,实数,及复数。并使用了一系列表示形式支持这些数据类型:

Fixnums 在 fixnum 范围内表示精确整数(参见 most-negative-fixnummost-positive-fixnum )。字符串,向量或 fxvector 的长度均被限定为 fixnum.

Bignums 表示 fixnum 范围外的任意精度的精确整数。

Ratnums 表示任意精度的精确有理数。每个有理数包含一个精确整数分子(fixnum 或 bignum)和一个精确整数分母。分数总是被约分为最简形式,分母从不为 1,而分子永不会为 0.

Flonums 表示不精确的实数。Flonums 是 IEEE 64 位浮点数。(由于 flonums 不能表示无理数,所有不精确的实数实际只是指有理数,虽然它们可能近似于无理数的数值)。

Exact complexnums 表示精确的复数。每个复数包含一个精确有理数(fixnum, bignum, 或 ratnum)的实部,和一个精确有理数的虚部。

Inexact complexnums 表示不精确的复数。每个不精确的复数包含一个浮点数实部和一个浮点数虚部。

大多数数字只能以一种方式表示;不过,实数有时会表示为虚部为 0 的不精确复数。

Chez Scheme 对数字对象的语法进行了扩展,包括 2 至 36 的任意基数,非十进制的浮点数,科学表示法,以及 IEEE 无穷数和 NAN(NAN 是 "not-a-number" 的缩写)的打印形式。

任意基数由前缀 #nr 指定, n 的范围是 2 至 36. 大于 9 的数字用字母 az 指定(大写小写均可)。例如, ~#2r101 ~ 是 510, 而 ~#36rZ ~ 是 3510.

对于较大的基数,对于特定字母的解读会出现歧义,例如, e , 作为数字还是作为指数指示符;在这类情况下,字母被当作一个数字。例如,在 #x3.2e5 中, e 被解读为一个数字,而不作为指数标记。而在 3.2e5 中, e 则被当作指数标记。

IEEE 无穷数被打印为+inf.0 和-inf.0, 而 IEEE NANs 被打印为 +nan.0 或-nan.0. (+nan.0 被用作所有 NANs 的输出)

(/ 1.0 0.0) => +inf.0
(/ 1.0 -0.0) => -inf.0
(/ 0.0 0.0) => +nan.0
(/ +inf.0 -inf.0) => +nan.0

本章第 1 节介绍了特定类型的数字类型谓词。8.2 至 8.4 节介绍了应用于 fixnums, flonums, 和不精确的复数(flonums 和/或不精确的 complexnums)上的快速的,类型专用的数字操作。专用于 fixnum 的版本,应只用于程序员确定操作数和结果都会是 fixnum 时,即,整数在范围 (most-negative-fixnum)(most-positive-fixnum) 之间时(两端均包含)。专用于 flonum 的版本,应只用于输入和输出确定为 flonum 时。flonum/complexnum 混合版本,应只用于输入确定为 flonum 或不精确的 complexnum 时。8.5 节介绍了支持把精确整数作为比特集合或序列的,任意精度和专用于 fixnum 的操作。8.6 节介绍了随机数生成,8.7 节介绍了其余各种数字操作。

Section 8.1. 数字类型谓词

R6RS 区分了两种特殊的数字对象:fixnum 和 flonum. Chez Scheme 进一步区分了 bignum(fixnum 范围之外的精确整数)和 ratnum(精确整数的比值)。它同时也提供了一个识别 cflonum 的谓词,其为 flonum 或不精确的复数。

procedure: (bignum? obj)

返回: 如果 obj 是 bignum,则为 #t, 否则为 #f.

libraries: (chezscheme)

(bignum? 0) => #f
(bignum? (most-positive-fixnum)) => #f
(bignum? (most-negative-fixnum)) => #f
(bignum? (* (most-positive-fixnum) 2)) => #t
(bignum? 3/4) => #f
(bignum? 'a) => #f

procedure: (ratnum? obj)

返回: 如果 obj 是 ratnum,则为 #t, 否则为 #f.

libraries: (chezscheme)

(ratnum? 0) => #f
(ratnum? (* (most-positive-fixnum) 2)) => #f
(ratnum? 3/4) => #t
(ratnum? -10/2) => #f
(ratnum? -11/2) => #t
(ratnum? 'a) => #f

procedure: (cflonum? obj)

返回: 如果 obj 是不精确的 complexnum 或 flonum,则为 #t, 否则为 #f.

libraries: (chezscheme)

(cflonum? 0) => #f
(cflonum? 0.0) => #t
(cflonum? 3+4i) => #f
(cflonum? 3.0+4i) => #t
(cflonum? +i) => #f
(cflonum? +1.0i) => #t

Section 8.2. Fixnum 操作

专用于 fixnum 的过程,通过会检查它们的输入和输出(需要时),但编译器在优化级别 3 下生成的代码,大多数情况下不执行这些检查。

procedure: (most-positive-fixnum)

returns: 系统支持的最大正 fixnum

procedure: (most-negative-fixnum)

returns: 系统支持的最大负 fixnum

libraries: (chezscheme)

这些过程和 R6RS 中的 greatest-fixnumleast-fixnum 过程一样。

procedure: (fx= fixnum1 fixnum2 …)

procedure: (fx< fixnum1 fixnum2 …)

procedure: (fx> fixnum1 fixnum2 …)

procedure: (fx<= fixnum1 fixnum2 …)

procedure: (fx>= fixnum1 fixnum2 …)

返回: 如果关系成立,则为 #t, 否则为 #f.

libraries: (chezscheme)

谓词 fx=在其实参相等时返回#t。谓词 fx<在其实参单调递增时返回#t,即,每个实参都大于它前一个实参,而 fx>在其实参单调递减时返回#t。谓词 fx<=在其实参单调非递减时返回#t,即,每个实参不小于它前一个实参,而 fx>=在其实参单调非递增时返回#t。只传入一个实参时,这些谓词均返回#t。

这些过程与 R6RS 中的过程 fx=?, fx<?, fx>?, fx<=?, 和 fx>=?类似,除了 R6RS 中的过程需要 2 个或更多参数,以及它们的名称中都有 "?" 后缀以外。

(fx= 0) => #t
(fx= 0 0) => #t
(fx< (most-negative-fixnum) 0 (most-positive-fixnum)) => #t
(let ([x 3]) (fx<= 0 x 9)) => #t
(fx<= 0 3 3) => #t
(fx>= 0 0 (most-negative-fixnum)) => #t

procedure: (fxnonpositive? fixnum)

返回: 如果 fixnum 不大于 0,则为 #t, 否则为 #f.

procedure: (fxnonnegative? fixnum)

返回: 如果 fixnum 不小于 0,则为 #t, 否则为 #f.

libraries: (chezscheme)

fxnonpositive?等价于(lambda (x) (fx<= x 0)), 而 fxnonnegative?等价于(lambda (x) (fx>= x 0)).

(fxnonpositive? 128) => #f
(fxnonpositive? 0) => #t
(fxnonpositive? -1) => #t

(fxnonnegative? -65) => #f
(fxnonnegative? 0) => #t
(fxnonnegative? 1) => #t

procedure: (fx+ fixnum …)

returns: 实参 fixnum …之和

libraries: (chezscheme)

When called with no arguments, fx+ returns 0. 不带参数调用时,fx+返回 0.

(fx+) => 0
(fx+ 1 2) => 3
(fx+ 3 4 5) => 12
(apply fx+ '(1 2 3 4 5)) => 15

procedure: (fx- fixnum1 fixnum2 …)

returns: 一个 fixnum

libraries: (chezscheme)

调用时若只传入一个实参,fx-返回 fixnum1 的负值。即,(fx- fixnum1)相当于(fx- 0 fixnum1).

调用时若传入 2 个以上的实参,fx-返回从 fixnum1 中减去数字 fixnum2 …之和的结果。

(fx- 3) => -3
(fx- 4 3) => 1
(fx- 4 3 2 1) => -2

procedure: (fx* fixnum …)

returns: 参数 fixnum …的乘积

libraries: (chezscheme)

不带参数调用时,fx*返回 1.

(fx*) => 1
(fx* 1 2) => 2
(fx* 3 -4 5) => -60
(apply fx* '(1 -2 3 -4 5)) => 120

procedure: (fx/ fixnum1 fixnum2 …)

returns: 参见后面的解释

libraries: (chezscheme)

调用时若只传入一个实参,fx/返回 fixnum1 的倒数。即,(fx/ fixnum1)相当于(fx/ 1 fixnum1).

调用时若传入 2 个以上的实参,fx/ 返回 fixnum1 除以其余实参 fixnum2 …的乘积的结果。

(fx/ 1) => 1
(fx/ -17) => 0
(fx/ 8 -2) => -4
(fx/ -9 2) => -4
(fx/ 60 5 3 2) => 2

procedure: (fx1+ fixnum)

procedure: (fx1- fixnum)

returns: fixnum 加 1 或 fixnum 减 1

libraries: (chezscheme)

(define fxplus
  (lambda (x y)
    (if (fxzero? x)
        y
        (fxplus (fx1- x) (fx1+ y)))))

(fxplus 7 8) => 15

fx1+ 和 fx1- 可依如下定义:

(define fx1+ (lambda (x) (fx+ x 1)))
(define fx1- (lambda (x) (fx- x 1)))

procedure: (fxquotient fixnum1 fixnum2 …)

returns: 参见后面的解释

libraries: (chezscheme)

fxquotient 和 fx/一样。参见上面关于 fx/的介绍。

procedure: (fxremainder fixnum1 fixnum2)

returns: fixnum1 除以 fixnum2 的 fixnum 余数

libraries: (chezscheme)

fxremainder 结果的符号与 fixnum1 相同。

(fxremainder 16 4) => 0
(fxremainder 5 2) => 1
(fxremainder -45 7) => -3
(fxremainder 10 -3) => 1
(fxremainder -17 -9) => -8

procedure: (fxmodulo fixnum1 fixnum2)

returns: fixnum1 和 fixnum2 的 fixnum 模数

libraries: (chezscheme)

fxmodulo 结果的符号与 fixnum2 相同。

(fxmodulo 16 4) => 0
(fxmodulo 5 2) => 1
(fxmodulo -45 7) => 4
(fxmodulo 10 -3) => -2
(fxmodulo -17 -9) => -8

procedure: (fxabs fixnum)

returns: fixnum 的绝对值

libraries: (chezscheme)

(fxabs 1) => 1
(fxabs -1) => 1
(fxabs 0) => 0

Section 8.3. Flonum 操作

不精确的实数通常以 flonum 表示。flonum 是一个单一的 64 位双精度浮点数。本节介绍针对 flonum 的操作,其中大多数接受 flonum 类型的实参,并返回 flonum 类型的值。大多数情况下,这些操作是内联编码或是在不进行实参类型检查的优化级别 3 下编码为机器语言子程序;全面的类型检查是在更低的优化级别下执行的。专用于 flonum 的过程名称带有前缀"fl",以区分于它们的通用版本。

不精确的实数也可以用虚部为 0 的不精确 complexnums 表示,这种表示形式不可用于 flonum 专用操作符的输入。然而,这些数字只会在显式调用 fl-make-rectangular, make-rectangular, 或 make-polar 时,或通过极坐标或直角坐标形式的数字输入,由涉及虚部非 0 的复数操作中生成。

procedure: (flonum->fixnum flonum)

returns: flonum 的 fixnum 表示形式(被截短的)

libraries: (chezscheme)

flonum 被截短后的值必须落在 fixnum 范围内。flonum->fixnum 是一个精确值的限定版本,会把任何数字表示转化为它的精确等价版本。

(flonum->fixnum 0.0) => 0
(flonum->fixnum 3.9) => 3
(flonum->fixnum -2.2) => -2

procedure: (fl= flonum1 flonum2 …)

procedure: (fl< flonum1 flonum2 …)

procedure: (fl> flonum1 flonum2 …)

procedure: (fl<= flonum1 flonum2 …)

procedure: (fl>= flonum1 flonum2 …)

返回: 如果关系成立,则为 #t, 否则为 #f.

libraries: (chezscheme)

谓词 fl=在其实参相等时返回#t。谓词 fl<在其实参单调递增时返回#t,即,每个实参都大于它前一个实参,而 fl>在其实参单调递减时返回#t。谓词 fl<=在其实参单调非递减时返回#t,即,每个实参不小于它前一个实参,而 fl>=在其实参单调非递增时返回#t。只传入一个实参时,这些谓词均返回#t。

IEEE NANs 不具有可比较性,即,涉及 NANs 的比较总是返回#f.

这些过程与 R6RS 中的过程 fl=?, fl<?, fl>?, fl<=?, 和 fl>=?类似,除了 R6RS 中的过程需要 2 个或更多参数,以及它们的名称中都有 "?" 后缀以外。

(fl= 0.0) => #t
(fl= 0.0 0.0) => #t
(fl< -1.0 0.0 1.0) => #t
(fl> -1.0 0.0 1.0) => #f
(fl<= 0.0 3.0 3.0) => #t
(fl>= 4.0 3.0 3.0) => #t
(fl< 7.0 +inf.0) => #t
(fl= +nan.0 0.0) => #f
(fl= +nan.0 +nan.0) => #f
(fl< +nan.0 +nan.0) => #f
(fl> +nan.0 +nan.0) => #f

procedure: (flnonpositive? fl)

返回: 如果 fl 不大于 0,则为 #t, 否则为 #f.

procedure: (flnonnegative? fl)

返回: 如果 fl 不小于 0,则为 #t, 否则为 #f.

libraries: (chezscheme)

flnonpositive?等价于(lambda (x) (fl<= x 0.0)), 而 flnonnegative?等价于(lambda (x) (fl>= x 0.0)).

虽然 flonum 的表示形式区分-0.0 和+0.0,但都判定为非负且非正。

(flnonpositive? 128.0) => #f
(flnonpositive? 0.0) => #t
(flnonpositive? -0.0) => #t
(flnonpositive? -1.0) => #t

(flnonnegative? -65.0) => #f
(flnonnegative? 0.0) => #t
(flnonnegative? -0.0) => #t
(flnonnegative? 1.0) => #t

(flnonnegative? +nan.0) => #f
(flnonpositive? +nan.0) => #f

(flnonnegative? +inf.0) => #t
(flnonnegative? -inf.0) => #f

procedure: (decode-float x)

returns: 参见下文

libraries: (chezscheme)

x 必须是 flonum. decode-float 返回一个包含 3 个整数元素的向量,m, e, 和 s, 满足 x = sm2e. 它主要是用于打印浮点数。

(decode-float 1.0) => #(4503599627370496 -52 1)
(decode-float -1.0) => #(4503599627370496 -52 -1)

(define slow-identity
  (lambda (x)
    (inexact
     (let ([v (decode-float x)])
       (let ([m (vector-ref v 0)]
             [e (vector-ref v 1)]
             [s (vector-ref v 2)])
         (* s m (expt 2 e)))))))

(slow-identity 1.0) => 1.0
(slow-identity -1e20) => -1e20

procedure: (fllp flonum)

returns: 参见下文

libraries: (chezscheme)

fllp 返回一个 12 位整数,由指数加上一个 flonum(ieee 64 位浮点数)的最高表示位组成。它可以用于快速计算这个数的对数的近似值。

(fllp 0.0) => 0
(fllp 1.0) => 2046
(fllp -1.0) => 2046

(fllp 1.5) => 2047

(fllp +inf.0) => 4094
(fllp -inf.0) => 4094

(fllp #b1.0e-1111111111) => 1
(fllp #b1.0e-10000000000) => 0

Section 8.4. 不精确复数的操作

本节介绍的过程提供了创建和操作不精确复数的机制。虚部非 0 的不精确复数表示为不精确的 complexnums. 不精确的 complexnum 包含 2 个 64 位双精度浮点数。虚部为 0 的不精确复数(即, 不精确实数)可以表示为不精确 complexnums 或 flonums. 本节介绍的操作接受任何不精确 complexnum 和 flonum(合称为"cflonums")实参的组合。

大多数情况下,这些操作在优化级别 3 执行最少化的类型检查;在更低的优化级别才会执行全面的类型检查。不精确复数过程的名称以前缀 "cfl" 开始,以区分于它们对应的通用版本。

procedure: (fl-make-rectangular flonum1 flonum2)

returns: 一个不精确 complexnum

libraries: (chezscheme)

通过 fl-make-rectangular 生成的不精确 complexnum,实部等于 flonum1, 而虚部等于 flonum2.

(fl-make-rectangular 2.0 -3.0) => 2.0-3.0i
(fl-make-rectangular 2.0 0.0) => 2.0+0.0i
(fl-make-rectangular 2.0 -0.0) => 2.0-0.0i

procedure: (cfl-real-part cflonum)

returns: cflonum 的实部

procedure: (cfl-imag-part cflonum)

returns: cflonum 的虚部

libraries: (chezscheme)

(cfl-real-part 2.0-3.0i) => 2.0
(cfl-imag-part 2.0-3.0i) => -3.0
(cfl-imag-part 2.0-0.0i) => -0.0
(cfl-imag-part 2.0-inf.0i) => -inf.0

procedure: (cfl= cflonum …)

返回: 如果实参相等,则为 #t, 否则为 #f.

libraries: (chezscheme)

(cfl= 7.0+0.0i 7.0) => #t
(cfl= 1.0+2.0i 1.0+2.0i) => #t
(cfl= 1.0+2.0i 1.0-2.0i) => #f

procedure: (cfl+ cflonum …)

procedure: (cfl* cflonum …)

procedure: (cfl- cflonum1 cflonum2 …)

procedure: (cfl/ cflonum1 cflonum2 …)

returns: 一个 cflonum

libraries: (chezscheme)

这些过程计算不精确复数数值的和,差,积或商,不论这些数值是以 flonums 表示,或以不精确 complexnums 表示。例如,如果 cfl+收到 2 个 flonum 实参 a 和 b,它返回它们的和 a + b; 在这种情况下,它和 fl+ 的行为一样。若 2 个实参为不精确 complexnum a + bi 和 c + di, 它返回和 (a + c) + (b + d)i. 若 1 个实参为 flonum a,而另一个为不精确 complexnum c + di, cfl+ 返回 (a + c) + di.

当传入 0 个实参,cfl+ 返回 0.0,而 cfl* 返回 1.0. 当传入 1 个实参,cfl- 返回实参的加法逆元,而 cfl/ 返回实参的乘法逆元。当传入 3 个或更多实参,cfl- 返回其第一个实参与其余实参之和的差,而 cfl/ 返回其第一个实参与其余实参之积的商。

(cfl+) => 0.0
(cfl*) => 1.0
(cfl- 5.0+1.0i) => -5.0-1.0i
(cfl/ 2.0+2.0i) => 0.25-0.25i

(cfl+ 1.0+2.2i -3.7+5.3i) => -2.7+7.5i
(cfl+ 1.0 -5.3) => -4.3
(cfl+ 1.0 2.0 -5.3i) => 3.0-5.3i
(cfl- 1.0+2.5i -3.7) => 4.7+2.5i
(cfl* 1.0+2.0i 3.0+4.0i) => -5.0+10.0i
(cfl/ -5.0+10.0i 1.0+2.0i 2.0) => 1.5+2.0i

procedure: (cfl-conjugate cflonum)

returns: cflonum 的共轭复数

libraries: (chezscheme)

当传入一个不精确的复数实参 a + bi 时,过程 cfl-conjugate 返回它的共轭复数 a + (-b)i.

参见 conjugate, 其为这个操作符的通用版本,对于一个复数的任何有效表现形式,返回其共轭复数。

(cfl-conjugate 3.0) => 3.0
(cfl-conjugate 3.0+4.0i) => 3.0-4.0i
(cfl-conjugate 1e-20-2e-30i) => 1e-20+2e-30i

procedure: (cfl-magnitude-squared cflonum)

returns: cflonum 的模的平方

libraries: (chezscheme)

当传入 1 个不精确的复数实参 a + bi, 过程 cfl-magnitude-squared 返回一个表示此实参的模的平方的 flonum, 即,a2 + b2.

参见 magnitude-squared, 其为此操作符的通用版本,对于 1 个复数的任何有效表示形式,返回它的模的平方。这两个操作都类似于过程 magnitude, 其返回它的复数实参的模,sqrt(a2 + b2).

(cfl-magnitude-squared 3.0) => 9.0
(cfl-magnitude-squared 3.0-4.0i) => 25.0

Section 8.5. 位和逻辑操作符

Chez Scheme 提供了一系列的逻辑操作符,以支持把精确整数 (fixnums 和 bignums) 作为位集合或位序列来处理。这些操作符包括 logand(逐位的逻辑与),logior(逐位的逻辑或),logxor(逐位的逻辑异或),lognot(逐位的逻辑非),logtest(测试多位),logbit?(测试单个位),logbit0(重置单个位),logbit1(设置单个位),以及 ash(算术移位)。这些操作符均把它的实参作为补码整数处理,不论这些实参的底层表示形式是什么。这种处理方法可被利用于表示无穷集合:a negative number represents an infinite number of one bits beyond the leftmost zero, and a nonnegative number represents an infinite number of zero bits beyond the leftmost one bit.

也提供了 fixnum 相应版本的逻辑操作符,比如 fxlogand, fxlogior, fxlogxor, fxlognot, fxlogtest, fxlogbit?, fxlogbit0, 以及 fxlogbit1. 还有三个用于移位的 fixnum 操作符: fxsll(逻辑左移位),fxsrl(逻辑右移位),fxsra(算术右移位)。逻辑和算术移位只在右移位上有差别。逻辑右移位在最左端填充 0,而算术右移位则复制符号位。

对任意精度的整数,逻辑移位没有意义,因为这些数没有必须移位的“最左端”。

procedure: (logand int …)

returns: 实参 int …的逻辑与

libraries: (chezscheme)

实参必须是精确的整数(fixnums 或 bignums),而且被作为补码整数处理,无论其底层的表示形式是什么。不传入实参时,logand 返回-1,即,所有位都设为 1.

(logand) => -1
(logand 15) => 15
(logand -1 -1) => -1
(logand -1 0) => 0
(logand 5 3) => 1
(logand #x173C8D95 7) => 5
(logand #x173C8D95 -8) => #x173C8D90
(logand #b1100 #b1111 #b1101) => #b1100

procedure: (logior int …)

procedure: (logor int …)

returns: 实参 int …的逻辑或

libraries: (chezscheme)

实参必须是精确的整数(fixnums 或 bignums),而且被作为补码整数处理,无论其底层的表示形式是什么。不传入实参时,logior 返回 0,即,所有位都被重置。

(logior) => 0
(logior 15) => 15
(logior -1 -1) => -1
(logior -1 0) => -1
(logior 5 3) => 7
(logior #b111000 #b101010) => #b111010
(logior #b1000 #b0100 #b0010) => #b1110
(apply logior '(1 2 4 8 16)) => 31

procedure: (logxor int …)

returns: 实参 int …的逻辑异或

libraries: (chezscheme)

实参必须是精确的整数(fixnums 或 bignums),而且被作为补码整数处理,无论其底层的表示形式是什么。不传入实参时,logxor 返回 0,即,所有位都被重置。

(logxor) => 0
(logxor 15) => 15
(logxor -1 -1) => 0
(logxor -1 0) => -1
(logxor 5 3) => 6
(logxor #b111000 #b101010) => #b010010
(logxor #b1100 #b0100 #b0110) => #b1110

procedure: (lognot int)

returns: int 的逻辑非

libraries: (chezscheme)

实参必须是精确的整数(fixnums 或 bignums),而且被作为补码整数处理,无论其底层的表示形式是什么。

(lognot -1) => 0
(lognot 0) => -1
(lognot 7) => -8
(lognot -8) => 7

procedure: (logbit? index int)

返回: 如果指定位被设置为 1,则为 #t, 否则为 #f.

libraries: (chezscheme)

实参必须是精确的整数(fixnums 或 bignums),而且被作为补码整数处理,无论其底层的表示形式是什么。

如果在 int 的索引 index 处的位被设为 1,logbit? 返回#t, 否则返回#f. 索引基于 0,从最低位向最高位数。索引没有上限;对于非负的 int,在最高的设置位以上的位均被当作 0,而对负值,在最高的重置位以上的位都被当作 1.

logbit? 等价于

(lambda (k n) (not (zero? (logand n (ash 1 k)))))

但更加高效。

(logbit? 0 #b1110) => #f
(logbit? 1 #b1110) => #t
(logbit? 2 #b1110) => #t
(logbit? 3 #b1110) => #t
(logbit? 4 #b1110) => #f
(logbit? 100 #b1110) => #f

(logbit? 0 -6) => #f  ; the two's complement of -6 is 1...1010
(logbit? 1 -6) => #t
(logbit? 2 -6) => #f
(logbit? 3 -6) => #t
(logbit? 100 -6) => #t

(logbit? (random 1000000) 0) => #f
(logbit? (random 1000000) -1) => #t

(logbit? 20000 (ash 1 20000)) => #t

procedure: (logtest int1 int2)

返回: 如果任何共同位被设为 1,则为 #t, 否则为 #f.

libraries: (chezscheme)

实参必须是精确的整数(fixnums 或 bignums),而且被作为补码整数处理,无论其底层的表示形式是什么。

如果有任何位在两个实参中都被设为 1,则 logtest 返回#t. 如果两个实参中没有任何共同位被设为 1,则返回#f.

logtest 等价于

(lambda (n1 n2) (not (zero? (logand n1 n2))))

但更加高效。

(logtest #b10001 #b1110) => #f
(logtest #b10101 #b1110) => #t
(logtest #b111000 #b110111) => #t

(logtest #b101 -6) => #f  ; the two's complement of -6 is 1...1010
(logtest #b1000 -6) => #t
(logtest 100 -6) => #t

(logtest (+ (random 1000000) 1) 0) => #f
(logtest (+ (random 1000000) 1) -1) => #t

(logtest (ash #b101 20000) (ash #b111 20000)) => #t

procedure: (logbit0 index int)

returns: 把 int 在索引 index 处的位清 0 后的结果

libraries: (chezscheme)

index 必须是一个非负的精确整数。int 必须是一个精确整数(fixnum 或 bignum),且被作为补码整数处理,无论它底层的表示形式是什么。

索引基于 0,从低位到高位计数。和 logbit?一样,索引没有上限。

logbit0 等价于

(lambda (i n) (logand (lognot (ash 1 i)) n))

但更加高效。

(logbit0 3 #b10101010) => #b10100010
(logbit0 4 #b10101010) => #b10101010
(logbit0 0 -1) => -2

procedure: (logbit1 index int)

returns: 把 int 在索引 index 处的位设为 1 后的结果

libraries: (chezscheme)

index 必须是一个非负的精确整数。int 必须是一个精确整数(fixnum 或 bignum),且被作为补码整数处理,无论它底层的表示形式是什么。

索引基于 0,从低位到高位计数。和 logbit?一样,索引没有上限。

logbit1 等价于

(lambda (i n) (logor (ash 1 i) n))

但更加高效。

(logbit1 3 #b10101010) => #b10101010
(logbit1 4 #b10101010) => #b10111010
(logbit1 4 0) => #b10000
(logbit1 0 -2) => -1

procedure: (ash int count)

returns: int 算术左移 count 位的结果

libraries: (chezscheme)

两个实参都必须是精确整数。第一个实参被作为补码整数处理,无论其底层的表示形式是什么。如果 count 是负数,则 int 右移 -count 位。

(ash 8 0) => 8
(ash 8 2) => 32
(ash 8 -2) => 2
(ash -1 2) => -4
(ash -1 -2) => -1

procedure: (fxlogand fixnum …)

returns: 实参 fixnum …的逻辑与

libraries: (chezscheme)

实参均被作为补码整数处理,无论其底层的表示形式是什么。不传入实参时,fxlogand 返回 -1, 即,所有位都设为 1.

(fxlogand) => -1
(fxlogand 15) => 15
(fxlogand -1 -1) => -1
(fxlogand -1 0) => 0
(fxlogand 5 3) => 1
(fxlogand #b111000 #b101010) => #b101000
(fxlogand #b1100 #b1111 #b1101) => #b1100

procedure: (fxlogior fixnum …)

procedure: (fxlogor fixnum …)

returns: 实参 fixnum …的逻辑或

libraries: (chezscheme)

实参均被作为补码整数处理,无论其底层的表示形式是什么。不传入实参时,fxlogior 返回 0, 即,所有位都被重置。

(fxlogior) => 0
(fxlogior 15) => 15
(fxlogior -1 -1) => -1
(fxlogior -1 0) => -1
(fxlogior #b111000 #b101010) => #b111010
(fxlogior #b1000 #b0100 #b0010) => #b1110
(apply fxlogior '(1 2 4 8 16)) => 31

procedure: (fxlogxor fixnum …)

returns: 实参 fixnum …的逻辑异或

libraries: (chezscheme)

The arguments are treated as two's complement integers, regardless of the underlying representation. With no arguments, fxlogxor returns 0, i.e., all bits reset. 实参均被作为补码整数处理,无论其底层的表示形式是什么。不传入实参时,fxlogxor 返回 0, 即,所有位都被重置。

(fxlogxor) => 0
(fxlogxor 15) => 15
(fxlogxor -1 -1) => 0
(fxlogxor -1 0) => -1
(fxlogxor 5 3) => 6
(fxlogxor #b111000 #b101010) => #b010010
(fxlogxor #b1100 #b0100 #b0110) => #b1110

procedure: (fxlognot fixnum)

returns: fixnum 的逻辑非

libraries: (chezscheme)

实参被作为补码整数处理,无论其底层的表示形式是什么。

(fxlognot -1) => 0
(fxlognot 0) => -1
(fxlognot 1) => -2
(fxlognot -2) => 1

procedure: (fxlogbit? index fixnum)

返回: 如果指定位是 1, 则为 #t, 否则为 #f.

libraries: (chezscheme)

index 必须是非负 fixnum. fixnum 被作为补码整数处理,无论其底层的表示形式是什么。

如果 fixnum 在索引 index 处的位被设为 1,则 fxlogbit? 返回 #t, 否则返回#f. 索引基于 0,从最低位向最高位计数。索引只受限 fixnum 的范围;对于非负的 int,在最高的设置位以上的位均被当作 0,而对负值,在最高的重置位以上的位都被当作 1.

(fxlogbit? 0 #b1110) => #f
(fxlogbit? 1 #b1110) => #t
(fxlogbit? 2 #b1110) => #t
(fxlogbit? 3 #b1110) => #t
(fxlogbit? 4 #b1110) => #f
(fxlogbit? 100 #b1110) => #f

(fxlogbit? 0 -6) => #f  ; the two's complement of -6 is 1...1010
(fxlogbit? 1 -6) => #t
(fxlogbit? 2 -6) => #f
(fxlogbit? 3 -6) => #t
(fxlogbit? 100 -6) => #t

(fxlogbit? (random 1000000) 0) => #f
(fxlogbit? (random 1000000) -1) => #t

procedure: (fxlogtest fixnum1 fixnum2)

返回: 如果任何共同位为 1,则为 #t, 否则为 #f.

libraries: (chezscheme)

实参均被作为补码整数处理,无论其底层的表示形式是什么。

如果有任何位在两个实参中均为 1,则 fxlogtest 返回 #t. 如果两个实参中没有任何共同位被设为 1,则返回 #f.

(fxlogtest #b10001 #b1110) => #f
(fxlogtest #b10101 #b1110) => #t
(fxlogtest #b111000 #b110111) => #t

(fxlogtest #b101 -6) => #f  ; the two's complement of -6 is 1...1010
(fxlogtest #b1000 -6) => #t
(fxlogtest 100 -6) => #t

(fxlogtest (+ (random 1000000) 1) 0) => #f
(fxlogtest (+ (random 1000000) 1) -1) => #t

procedure: (fxlogbit0 index fixnum)

returns: fixnum 在索引 index 处的位被清零后的结果

libraries: (chezscheme)

fixnum 被作为补码整数处理,无论其底层的表示形式是什么。index 必须非负,且小于一个 fixnum 中的位数(不包括符号位),即,小于 (integer-length (most-positive-fixnum)).索引基于 0,从最低位向最高位计数。

fxlogbit0 等价于

(lambda (i n) (fxlogand (fxlognot (fxsll 1 i)) n))

但更加高效。

(fxlogbit0 3 #b10101010) => #b10100010
(fxlogbit0 4 #b10101010) => #b10101010
(fxlogbit0 0 -1) => -2

procedure: (fxlogbit1 index fixnum)

returns: fixnum 在索引 index 处的位被设为 1 后的结果

libraries: (chezscheme)

fixnum 被作为补码整数处理,无论其底层的表示形式是什么。index 必须非负,且小于一个 fixnum 中的位数(不包括符号位),即,小于 (integer-length (most-positive-fixnum)).索引基于 0,从最低位向最高位计数。

fxlogbit1 等价于

(lambda (i n) (fxlogor (fxsll 1 i) n))

但更加高效。

(fxlogbit1 3 #b10101010) => #b10101010
(fxlogbit1 4 #b10101010) => #b10111010
(fxlogbit1 4 0) => #b10000
(fxlogbit1 0 -2) => -1

procedure: (fxsll fixnum count)

returns: fixnum 左移 count 位

libraries: (chezscheme)

fixnum 被作为补码整数处理,无论其底层的表示形式是什么。count 必须非负,且不大于一个 fixnum 中的位数,即,(+ (integer-length (most-positive-fixnum)) 1). 如果结果不能表示为 fixnum,则会抛出一个条件类型的 &implementation-restriction 异常。

(fxsll 1 2) => 4
(fxsll -1 2) => -4

procedure: (fxsrl fixnum count)

returns: fixnum 逻辑右移 count 位

libraries: (chezscheme)

fixnum 被作为补码整数处理,无论其底层的表示形式是什么。count 必须非负,且不大于一个 fixnum 中的位数,即,(+ (integer-length (most-positive-fixnum)) 1).

(fxsrl 4 2) => 1
(= (fxsrl -1 1) (most-positive-fixnum)) => #t

procedure: (fxsra fixnum count)

returns: fixnum 算术右移 count 位

libraries: (chezscheme)

fixnum 被作为补码整数处理,无论其底层的表示形式是什么。count 必须非负,且不大于一个 fixnum 中的位数,即,(+ (integer-length (most-positive-fixnum)) 1).

(fxsra 64 3) => 8
(fxsra -1 1) => -1
(fxsra -64 3) => -8

Section 8.6. 随机数生成

procedure: (random real)

returns: 小于 real 的一个非负伪随机数

libraries: (chezscheme)

real 必须是正整数,或正的不精确实数。

(random 1) => 0
(random 1029384535235) => 1029384535001, every now and then
(random 1.0) => 0.5, every now and then

thread parameter: random-seed

libraries: (chezscheme)

随机数生成器支持通过参数对象 random-seed 获取和修改当前的随机数种子。

不带实参调用时,random-seed 返回当前的随机数种子。当带 1 个实参调用时,实参必须是 1 至 232 -1 之间的非负精确整数,而 random-seed 把当前的随机数种子设为此实参的值。

(let ([s (random-seed)])
  (let ([r1 (random 1.0)])
    (random-seed s)
    (eqv? (random 1.0) r1))) => #t

Section 8.7. 其它各类数字操作

procedure: (= num1 num2 num3 …)

procedure: (< real1 real2 real3 …)

procedure: (> real1 real2 real3 …)

procedure: (<= real1 real2 real3 …)

procedure: (>= real1 real2 real3 …)

返回: 如果关系成立,则为 #t, 否则为 #f.

libraries: (chezscheme)

这些谓词和 R6RS 中的对应版本一样,只是它们被扩展为可接受 1 个以上参数,而非 2 个以上参数。当传入 1 个参数时,这些谓词均返回 #t.

(> 3/4) => #t
(< 3/4) => #t
(= 3/4) => #t

procedure: (1+ num)

procedure: (add1 num)

procedure: (1- num)

procedure: (-1+ num)

procedure: (sub1 num)

returns: num 加 1 或 num 减 1

libraries: (chezscheme)

1+ 和 add1 等价于 (lambda (x) (+ x 1)); 1-, -1+, 和 sub1 等价于 (lambda (x) (- x 1)).

(define plus
                                        ; x should be a nonnegative integer
  (lambda (x y)
    (if (zero? x)
        y
        (plus (1- x) (1+ y)))))

(plus 7 8) => 15

(define double
                                        ; x should be a nonnegative integer
  (lambda (x)
    (if (zero? x)
        0
        (add1 (add1 (double (sub1 x)))))))

(double 7) => 14

procedure: (expt-mod int1 int2 int3)

returns: int1 的 int2 次方,再对 int3 取模

libraries: (chezscheme)

int1, int2 和 int3 必须是非负整数。expt-mod 采用的计算方式使得中间结果永远不会比 int3 大太多。这意味着,当 int2 很大时,expt-mod 要比等价过程 (lambda (x y z) (modulo (expt x y) z)) 更加高效。

(expt-mod 2 4 3) => 1
(expt-mod 2 76543 76543) => 2

procedure: (isqrt n)

returns: n 的整数平方根

libraries: (chezscheme)

n 必须是非负整数。The integer square root of n is defined to be =>.TODO

(isqrt 0) => 0
(isqrt 16) => 4
(isqrt 16.0) => 4.0
(isqrt 20) => 4
(isqrt 20.0) => 4.0
(isqrt (* 2 (expt 10 20))) => 14142135623

procedure: (integer-length n)

returns: 参见下文

libraries: (chezscheme)

过程 integer-length 返回 n 的最小补码表示形式的位数长度,并假设负数前面有一个为 1 的符号位。对于 0,integer-length 返回 0.

(integer-length 0) => 0
(integer-length 1) => 1
(integer-length 2) => 2
(integer-length 3) => 2
(integer-length 4) => 3
(integer-length #b10000000) => 8
(integer-length #b11111111) => 8
(integer-length -1) => 0
(integer-length -2) => 1
(integer-length -3) => 2
(integer-length -4) => 2

procedure: (nonpositive? real)

返回: 如果 real 不大于 0,则为 #t, 否则为 #f.

libraries: (chezscheme)

nonpositive? 等价于 (lambda (x) (<= x 0)).

(nonpositive? 128) => #f
(nonpositive? 0.0) => #t
(nonpositive? 1.8e-15) => #f
(nonpositive? -2/3) => #t

procedure: (nonnegative? real)

返回: 如果 real 不小于 0,则为 #t, 否则为 #f.

libraries: (chezscheme)

nonnegative? 等价于 (lambda (x) (>= x 0)).

(nonnegative? -65) => #f
(nonnegative? 0) => #t
(nonnegative? -0.0121) => #f
(nonnegative? 15/16) => #t

procedure: (conjugate num)

returns: num 的共轭复数

libraries: (chezscheme)

当过程 conjugate 传入复数实参 a + bi 时,返回它的共轭复数 a + (-b)i.

(conjugate 3.0+4.0i) => 3.0-4.0i
(conjugate 1e-20-2e-30i) => 1e-20+2e-30i
(conjugate 3) => 3

procedure: (magnitude-squared num)

returns: num 的模的平方

libraries: (chezscheme)

对过程 magnitude-squared 传入复数实参 a + bi 时,返回它的模的平方,即,a2 + b2.

(magnitude-squared 3.0-4.0i) => 25.0
(magnitude-squared 3.0) => 9.0

procedure: (sinh num)

procedure: (cosh num)

procedure: (tanh num)

returns: num 的 hyperbolic sine, cosine, 或 tangent

libraries: (chezscheme)

(sinh 0.0) => 0.0
(cosh 0.0) => 1.0
(tanh -0.0) => -0.0

procedure: (asinh num)

procedure: (acosh num)

procedure: (atanh num)

returns: num 的 hyperbolic arc sine, arc cosine, 或 arc tangent

libraries: (chezscheme)

(acosh 0.0) => 0.0+1.5707963267948966i
(acosh 1.0) => 0.0
(atanh -1.0) => -inf.0

procedure: (string->number string)

procedure: (string->number string radix)

returns: string 所表示的数字,或 #f

libraries: (chezscheme)

这个过程和 R6RS 版本一样,除了基数可以是 2 至 36(两端包含)之间的任意精确整数。R6RS 版本要求基数属于集合 {2,8,10,16}.

(string->number "211012" 3) => 559
(string->number "tobeornottobe" 36) => 140613689159812836698

procedure: (number->string num)

procedure: (number->string num radix)

procedure: (number->string num radix precision)

returns: 作为字符串的一种 num 的外部表示形式 an external representation of num as a string

libraries: (chezscheme)

这个过程和 R6RS 版本一样,除了基数可以是 2 至 36(两端包含)之间的任意精确整数。R6RS 版本要求基数属于集合 {2,8,10,16}.

(number->string 10000 4) => "2130100"
(number->string 10000 27) => "DJA"

Chez Scheme Version 9 User's Guide Copyright © 2018 Cisco Systems, Inc. Licensed under the Apache License Version 2.0 (full copyright notice.). Revised January 2019 for Chez Scheme Version 9.5.1 about this book