2023年03月26日くいなちゃん


プログラミング言語Kuin」の実行環境がexe用の逆引き辞典1、数の扱い方についてです。

整数や小数を扱う

ビット演算を行う

文字を扱う

論理値を扱う

目次

1整数や小数を扱う

1.1整数や小数を扱う



Kuinで整数を扱うときにはint型を、小数を扱うときにはfloat型を使い、それぞれ四則演算などの基本的な演算が行えます(図1-1)。
  1. func main()
  2.   var a: int :: 7
  3.   var b: int :: 3
  4.   var c: int
  5.   do c :: a + b {c = 10}
  6.   do c :: a - b {c = 4}
  7.   do c :: a * b {c = 21}
  8.   do c :: a / b {c = 2}
  9.   do c :: a % b {c = 1}
  10.   do c :: a ^ b {c = 343}
  11.  
  12.   var x: float :: 7.0
  13.   var y: float :: 3.0
  14.   var z: float
  15.   do z :: x + y {z = 10.0}
  16.   do z :: x - y {z = 4.0}
  17.   do z :: x * y {z = 21.0}
  18.   do z :: x / y {z = 2.33333...}
  19.   do z :: x % y {z = 1.0}
  20.   do z :: x ^ y {z = 343.0}
  21. end func
図1-1: int型とfloat型
足し算は「+」、引き算は「-」、掛け算は「*」、割り算は「/」、割り算の余りは「%」、冪(累乗)は「^」の記号を使います。 足し算より掛け算の計算が先に行われ、また括弧で計算順序が変えられるなど、数学の式と同様に書けます。
int型の「/」の計算は、小数点以下が切り捨てられます。
ソースコード上に数を直接書くとき、「5」や「-3」のように書くとint型になり、「5.0」や「-3.0」のように「.」を付けて書くとfloat型になります。

1.2値を比較する



int型やfloat型の数に対し、値の大小を比較するには、比較演算子を使います(図1-2)。
  1. func main()
  2.   var n: int :: 3
  3.   var m: int :: 5
  4.   var b: bool
  5.   do b :: n < m {true}
  6.   do b :: n <= m {true}
  7.   do b :: n > m {false}
  8.   do b :: n >= m {false}
  9.   do b :: n = m {false}
  10.   do b :: n <> m {true}
  11. end func
図1-2: 比較演算子
比較演算子はそれぞれ数学の記号とほぼ一致しますが、「<=」は「」、「>=」は「」、「<>」は「」に相当します。
ただしfloat型は計算誤差が生じるため、数学的には一致しても「=」で比較するとfalseが返ることがあります。 そこで「lib@same」関数を使うと、計算誤差をある程度許容して比較することができます(図1-3)。
  1. func main()
  2.   var x: float :: lib@cos(lib@pi) {-1.0から若干の計算誤差がある}
  3.   var y: float :: -1.0
  4.   var b: bool
  5.   do b :: x = y {false}
  6.   do b :: lib@same(x, y) {true}
  7. end func
図1-3: lib@same関数

1.3型を変換する



int型とfloat型の変換は、キャスト演算子「$」を使います(図1-4)。
  1. func main()
  2.   var n: int :: -2
  3.  
  4.   var x: float
  5.   do x :: n $ float {x = -2.0}
  6.   var m: int
  7.   do m :: x $ int {m = -2}
  8. end func
図1-4: int型とfloat型の変換

1.4絶対値や符号を得る



int型やfloat型の数に対し、負の数を正にする絶対値は「.abs」メソッドを使い、符号が正なら1、負なら-1、ゼロなら0を得るには「.sign」メソッドを使います(図1-5)。
  1. func main()
  2.   var a: int :: -3
  3.   var b: int :: 5
  4.   var c: int :: 0
  5.   var d: int
  6.   do d :: a.abs() {3}
  7.   do d :: b.abs() {5}
  8.   do d :: c.abs() {0}
  9.   do d :: a.sign() {-1}
  10.   do d :: b.sign() {1}
  11.   do d :: c.sign() {0}
  12. end func
図1-5: 絶対値と符号

1.5値を上限や下限で打ち切る



int型やfloat型の数に対し、値を上限や下限で打ち切るには「lib@min」「lib@max」「lib@clamp」関数を使います。
「lib@min」はx以上の数をxにする関数で、「lib@max」はx以下の数をxにする関数で、「lib@clamp」はそれらを同時に行う関数です(図1-6)。
  1. func main()
  2.   var a: int :: 2
  3.   var b: int :: 5
  4.   var c: int :: 9
  5.   var d: int
  6.   do d :: lib@max(a, 4) {4}
  7.   do d :: lib@max(b, 4) {5}
  8.   do d :: lib@max(c, 4) {9}
  9.   do d :: lib@min(a, 7) {2}
  10.   do d :: lib@min(b, 7) {5}
  11.   do d :: lib@min(c, 7) {7}
  12.   do d :: lib@clamp(a, 4, 7) {4}
  13.   do d :: lib@clamp(b, 4, 7) {5}
  14.   do d :: lib@clamp(c, 4, 7) {7}
  15. end func
図1-6: 値のクランプ

1.6三角関数などの初等関数を使う



三角関数などの初等関数を使うには、「lib@」内の関数を使います(図1-7)。
  1. func main()
  2.   var x: float
  3.   do x :: lib@sin(lib@pi / 2.0) {sin(π / 2.0) = 1.0}
  4.   do x :: lib@ln(lib@e) {log_e(e) = 1.0}
  5.   do x :: lib@log(2.0, 8.0) {log_2.0(8.0) = 3.0}
  6.   do x :: lib@sqrt(9.0) {√(9.0) = 3.0}
  7. end func
図1-7: 初等関数

1.7乱数を生成する



乱数を生成するには、「lib@rnd」「lib@rndFloat」関数を使います(図1-8)。
  1. func main()
  2.   var n: int :: lib@rnd(3, 5) {3以上5以下の乱数}
  3.   var x: float :: lib@rndFloat(3.0, 5.0) {3.0以上5.0未満の小数の乱数}
  4. end func
図1-8: 乱数の生成
「lib@rnd」「lib@rndFloat」はプログラムを起動するたびに異なる乱数が返ります。 同じ乱数列を再現したい場合には「lib@Rnd」クラスを使います(図1-9)。
  1. func main()
  2.   var rnd: lib@Rnd :: lib@makeRnd(1234b32) {引数には乱数の種を指定}
  3.   var a: int :: rnd.rnd(1, 10) {a = 2}
  4.   var b: int :: rnd.rnd(1, 10) {b = 5}
  5.   var c: int :: rnd.rnd(1, 10) {c = 4}
  6.   var d: int :: rnd.rnd(1, 10) {d = 7}
  7.  
  8.   do rnd :: lib@makeRnd(1234b32)
  9.   do a :: rnd.rnd(1, 10) {a = 2}
  10.   do b :: rnd.rnd(1, 10) {b = 5}
  11.   do c :: rnd.rnd(1, 10) {c = 4}
  12.   do d :: rnd.rnd(1, 10) {d = 7}
  13. end func
図1-9: 再現性のある乱数の生成

1.8階乗や素因数分解などの数学計算を行う



階乗や素因数分解などの数学計算は「math@」内にある関数を使います(図1-10)。
  1. func main()
  2.   var x: float :: math@fact(6.0) {6.0! = 720.0}
  3.   var n: int :: math@lcm(12, 16) {12と16の最小公倍数 = 48}
  4.   var m: int :: math@gcd(12, 16) {12と16の最大公約数 = 4}
  5.   var b: bool :: math@prime(2147483647) {2147483647が素数かどうかを判定 = true}
  6.   var ps: []int :: math@primeFactors(44444) {44444の素因数分解 = [2, 2, 41, 271]}
  7. end func
図1-10: 数学計算

2ビット演算を行う

ビット単位で演算を行いたいときには、「bit8」「bit16」「bit32」「bit64」の型を使います(図2-1)。
  1. func main()
  2.   var a: bit8 :: 0x12b8 {a = 0x12}
  3.   var b: bit16 :: 0x1234b16 {b = 0x1234}
  4.   var c: bit32 :: 0x12345678b32 {c = 0x12345678}
  5.   var d: bit64 :: 0x123456789ABCDEF0b64 {d = 0x123456789ABCDEF0}
  6. end func
図2-1: ビット型
「bit8」「bit16」「bit32」「bit64」が扱えるサイズは、それぞれ8ビット、16ビット、32ビット、64ビットで、負の値は扱えません。
「bit8」「bit16」「bit32」「bit64」の数をソースコードに直接書く場合は、int型での数の表記の後にそれぞれ「b8」「b16」「b32」「b64」という接尾辞を付けて表します。
これらの型は、「and」「or」「not」「xor」などのビット演算が行えます(図2-2)。
  1. func main()
  2.   var a: bit16 :: 0xF333b16 {a = 0xF333}
  3.   var b: bit16 :: 0x1234b16 {b = 0x1234}
  4.   var c: bit16
  5.  
  6.   do c :: a.and(b) {c = 0x1230}
  7.   do c :: a.or(b) {c = 0xF337}
  8.   do c :: a.not() {c = 0x0CCC}
  9.   do c :: a.xor(b) {c = 0xE107}
  10.   do c :: a.shl(8) {c = 0x3300 (aを左に8ビット論理シフト)}
  11.   do c :: a.shr(8) {c = 0x00F3 (aを右に8ビット論理シフト)}
  12.   do c :: a.sar(8) {c = 0xFFF3 (aを右に8ビット算術シフト)}
  13.   do c :: a.endian() {c = 0x33F3 (エンディアンの変換)}
  14. end func
図2-2: ビット演算

3文字を扱う

3.1文字を扱う



Kuinで文字を扱うときにはchar型を使います。 ソースコード上に直接文字を書くときには「'」で囲んで文字を表します(図3-1)。
  1. func main()
  2.   var c1: char :: 'A'
  3.   var n: int :: c1 $ int {n = 65 (0x41)}
  4.   var c2: char :: n $ char {c2 = 'A'}
  5. end func
図3-1: 文字型
char型は内部では0x0000~0xFFFFの整数になっており、文字はUTF-16の文字コードで格納されます。 $演算子でint型と変換することで、直接文字コードで操作できます。

3.2改行文字などの特殊な文字を記述する



改行文字などの特殊な文字をソースコード上で表すには、「\」の文字と1文字の組み合わせで記述します。 例えば改行文字は「'\n'」と書きます(図3-2)。
  1. func main()
  2.   var c: char
  3.   do c :: '\n' {改行文字}
  4.   do c :: '\t' {タブ文字}
  5.   do c :: '\"' {ダブルクォーテーション文字}
  6.   do c :: '\'' {シングルクォーテーションの文字}
  7.   do c :: '\\' {「\」の文字}
  8.   do c :: '\u0041' {文字コードが0x0041の文字('A')}
  9. end func
図3-2: エスケープシーケンス

4論理値を扱う

4.1論理値を扱う



「...したとき」などの条件を表すときなど、論理値を扱いたい場合にはbool型を使います。 bool型には「真」を表す「true」と、「偽」を表す「false」の2種類の値のみを持ちます(図4-1)。
  1. func main()
  2.   var b: bool
  3.   var n: int
  4.  
  5.   do b :: true
  6.   if(b)
  7.     do n :: 1 {この処理は行われる}
  8.   end if
  9.  
  10.   do b :: false
  11.   if(b)
  12.     do n :: 2 {この処理は行われない}
  13.   end if
  14. end func
図4-1: 論理型
「...または...」に相当する論理和は「|」の記号を使い、「...かつ...」に相当する論理積は「&」の記号を使います。 また「条件式 ?(真のときの値, 偽のときの値)」と書くことで、論理値に応じた値を得ることもできます(図4-2)。
  1. func main()
  2.   var b1: bool :: true
  3.   var b2: bool :: false
  4.   var b3: bool
  5.   var n: int
  6.  
  7.   do b3 :: b1 | b2 {b3 = true}
  8.   do b3 :: b1 & b2 {b3 = false}
  9.   do n :: b1 ?(3, 5) {n = 3}
  10.   do n :: b2 ?(3, 5) {n = 5}
  11. end func
図4-2: 論理演算
「|」演算子と「&」演算子の演算結果は表4-1の通りです。
表4-1: 真理値表
aの値 bの値 「a | b」の値 「a & b」の値
false false false false
false true true false
true false true false
true true true true
1679820310jaf