现在常在考试里用的 CASIO fx-991CN X 计算器所提供的计算功能,实际上可以实现很多常用编程算法。虽然由于计算器的局限性,对于非顺序结构的程序的实现较为复杂,但是在特定的场景中,计算器也有其方便之处。本篇杂记主要就是针对这一型号计算器在计算器上编程的一些技巧的研究。由于此型号计算器至多输入 199 个字符,故本文不具备实用性。
运算符与赋值# 常用运算符 +, -, *, /, ^ 有直接对应的符号,整除对应 ÷R 键。mod 取余可以通过 a m o d b = a − ( a ∣ b ) × b a \bmod b = a - \left(a \mid b\right) \times b a mod b = a − ( a ∣ b ) × b 来表示,即为 A − A ÷ R B × B A - A \mathbin{\div\!\text{R}} B \times B A − A ÷ R B × B 。同理,Int 取整可以写成 A ÷ R 1 A \mathbin{\div\!\text{R}} 1 A ÷ R 1 。
整除限制# 如果被除数和除数有小数位数大于三位的,或有负数,或有大于等于 10 10 10^{10} 1 0 10 的数,则不会输出取整后的结果。于是只能通过计算精度舍入来解决这一问题。
以下是改正后的取余代码:
x ÷ 10 12 + 1 → x : ( x − 1 ) × 10 12 → x : 10 − Rnd ( log ( x + 1 ) + 1 ) × 10 6 ÷ R 10 6 → y : x × 10 y ÷ R 10 y → y \begin{aligned}
&x \div 10^{12} + 1 \rightarrow x\colon \\
&(x - 1) \times 10^{12} \rightarrow x\colon \\
&10 - \text{Rnd}(\log(x + 1) + 1) \times 10^6 \mathbin{\div\!\text{R}} 10^6 \rightarrow y\colon \\
&x \times 10^y \mathbin{\div\!\text{R}} 10^y \rightarrow y
\end{aligned} x ÷ 1 0 12 + 1 → x : ( x − 1 ) × 1 0 12 → x : 10 − Rnd ( log ( x + 1 ) + 1 ) × 1 0 6 ÷ R 1 0 6 → y : x × 1 0 y ÷ R 1 0 y → y 变量赋值# 在计算器中,变量有 A, B, C, D, E, F, x, y, M,以下是对变量赋值的三种方法。
所有变量的赋值都可用 STO 键。
注意当输入 STO + 变量名 后,→ 变量 会被计算器放到全部语句的最后,同时计算结果。所以每当输入 STO + 变量名 后都要按一下 AC + 左键,以恢复原式。
变量 M 自带累加器功能,可利用 M+ 和 M- 来对 M 赋值。
利用 Pol 和 Rec 组合可实现对于 x、y 的组合赋值。CASIO 计算器提供了这两个用于极坐标和角坐标互转的函数,我们可以利用这一对函数来实现同时对 x、y 赋值,比如想将 2 赋值给 x、3 赋值给 y,可以写 Rec(Pol(2, 3), y),不过有一点需要注意,当且仅当要赋的两个值同时为 0 时会出现数学错误。
顺序与循环结构# 编程中实现一个功能往往需要多条语句分步执行。计算器提供了 : 冒号用来分割语句。在计算器中输入[1] [ALPHA] [∫□] [2],然后多次按等号,你会发现结果依次输出 1、2、1、2、… ,这就说明 1 和 2 这两条语句被依次且多次执行了。这也是无限循环在计算器里的基本框架。
问题 1:求极限# 当你输入一组赋值语句后,比如希望实现以下内容:
∀ a 0 , a 1 ∈ ( 0 , + ∞ ) , 求 lim i → + ∞ a i ( Ans = 4 ) \forall a_0,a_1 \in (0, +\infty), \text{求} \lim\limits_{i \to +\infty} a_i \quad (\text{Ans} = 4) ∀ a 0 , a 1 ∈ ( 0 , + ∞ ) , 求 i → + ∞ lim a i ( Ans = 4 )
a i = { a i − 1 + a i − 2 2 i 为大于1的偶数 a i − 1 − a i − 2 i 为大于1的奇数 a_i=\left\{ \begin{array}{}
\frac{a_{i-1} + a_{i-2}}{2} & i\text{为大于1的偶数} \\
\sqrt{a_{i-1}} - \sqrt{a_{i-2}} & i\text{为大于1的奇数} \\
\end{array} \right. a i = { 2 a i − 1 + a i − 2 a i − 1 − a i − 2 i 为大于 1 的偶数 i 为大于 1 的奇数 时遇到问题:
先赋初值 36 →A,24 →B 再写 ( A + B ) ÷ 2 → A : A + B → B (A + B) ÷ 2 \rightarrow A: \sqrt{A} + \sqrt{B} \rightarrow B ( A + B ) ÷ 2 → A : A + B → B 在输入 →A 时 A 已经被改变。此时我们可以在式子最前面加 1:,变成 1 : ( A + B ) ÷ 2 → A : A + B → B 1 : (A + B) \div 2 \rightarrow A : \sqrt{A} + \sqrt{B} \rightarrow B 1 : ( A + B ) ÷ 2 → A : A + B → B 即可解决这一问题。当然,在输完表达式后可将 1: 删去以减少按等号的次数。
问题 2:Fibonacci 数列# Fibonacci 数列 a i = a i − 1 + a i − 2 a_i = a_{i-1} + a_{i-2} a i = a i − 1 + a i − 2 如何实现。
1 → B , 1 → C 1 \rightarrow B,\;1 \rightarrow C\;\; 1 → B , 1 → C // 把 B、C 的初值设为1
d o B → A : C → B : A + B → C do\;B \rightarrow A : C \rightarrow B : A + B \rightarrow C\;\; d o B → A : C → B : A + B → C // C 即为数列的值
利用对于 x 0 = x 1 = 1 , i − 2 ∈ N x_0 = x_1 = 1,\;i - 2 \in N x 0 = x 1 = 1 , i − 2 ∈ N
有 x i = x i − 1 + x i − 2 = ∑ 1 i − 2 x n + 1 {x_i = x_i-1} + x_{i-2} = \sum_1^{i-2}x_n + 1 x i = x i − 1 + x i − 2 = ∑ 1 i − 2 x n + 1 可化为:
d o M + 1 − A n s M + do\;M + 1 - Ans\;\mathbin{\text{M}\!+}\;\; d o M + 1 − A n s M + // 记得初始化保证 M = Ans = 0
利用递推表达式的特殊性可化为:
Rec ( Pol ( 1 , 1 ) , y ) \text{Rec}(\text{Pol}(1, 1), y) Rec ( Pol ( 1 , 1 ) , y )
d o Rec ( Pol ( y , x + y ) , y ) do\;\text{Rec}(\text{Pol}(y, x + y), y) d o Rec ( Pol ( y , x + y ) , y )
条件分支# 既然计算器不能实现跳过语句,那又如何实现如 if (a >= 0) c = b; 这样的判断分支语句呢?很容易想到的方法是在满足 a ≥ 0 a \geq 0 a ≥ 0 时将 b 赋值给 c,否则就将 c 赋值给自身。如果事先已经判断了 a ≥ 0 a \geq 0 a ≥ 0 是否成立,成立就把 d 设为 1,否则就把 d 设为 0,那只需要写 d b + ( 1 − d ) c → c db + (1 - d)c \rightarrow c d b + ( 1 − d ) c → c 即可。可是如何实现判断 a ≥ 0 a \geq 0 a ≥ 0 呢?你可能会想到利用 ∣ a ∣ ÷ a → d \left|a\right| \div a \rightarrow d ∣ a ∣ ÷ a → d ,但是这个函数定义域不为 R。为了使其定义域为 R,我们便需要保证 a ≠ 0 a \neq 0 a = 0 ,一个很巧妙的方法是取整,像如下这样:
代码实现# ( − a − 1 + 1 + a ) × 10 90 + a → d : ( ( − d − 1 ) ÷ 10 12 + 1 − 1 ) × 10 12 → d : .5 − ( d + .5 ) ÷ ∣ d + .5 ∣ ÷ 2 → d : d b + ( 1 − d ) c → c \begin{aligned}
& (-a - 1 + 1 + a) \times 10^{90} + a \rightarrow d: \\
& ((-d - 1) \div 10^{12} + 1 - 1) \times 10^{12} \rightarrow d: \\
& .5 - (d + .5) \div \left|d + .5\right| \div 2 \rightarrow d: \\
& db + (1 - d)c \rightarrow c
\end{aligned} ( − a − 1 + 1 + a ) × 1 0 90 + a → d : (( − d − 1 ) ÷ 1 0 12 + 1 − 1 ) × 1 0 12 → d : .5 − ( d + .5 ) ÷ ∣ d + .5 ∣ ÷ 2 → d : d b + ( 1 − d ) c → c 就实现了 if (a >= 0) c = b; 的功能。
同理,如果要再加上个 else c = e; 只需要
把最后一句改成 d b + ( 1 − d ) e → c db + (1 - d)e \rightarrow c d b + ( 1 − d ) e → c 。如果条件
是 if (a == 0),利用 a = 0 ⇔ − ∣ a ∣ ≥ 0 a = 0 \Leftrightarrow -|a| \geq 0 a = 0 ⇔ − ∣ a ∣ ≥ 0 即可。
关于循环# 计算器里编程,就像在整个程序外有个默认的死循环,而你就是在这个死循环中写程序。如果你希望结束程序,你只能通过“错误”来终止循环。这不需要复杂的条件判断,只需要利用根号大于等于 0、真数大于 0、分母不等于 0 等的特点来产生错误,循环便终止了。然后在退出“数学错误”界面后按 SHIFT STO 即可查看最终结果。即使是顺序结构的程序,也最好要在末尾加上一句 : 0 ÷ 0 来结束程序。