# 数値

数値には 2 つの系統があります。**有界整数** `Int<lo, hi>` は、物語が実行時に保持できる唯一の数値です。チューリング完全な種別では、**Rust の整数**と、整数でない正確な 2 つの型 `Decimal` と `Rat` も使えます。浮動小数点数はありません。浮動小数点数は `Eq` ではなく（`NaN != NaN`）、画面は等価性で比較する必要があるからです。浮動小数点数の代わりに `Decimal` を、正確な分数には `Rat` を使います。

| 型 | 値 | 実行時に保持できる種別 |
| -- | -- | ---------------------- |
| `Int<lo, hi>` | `lo` から `hi` までの整数（両端を含む） | すべての種別 |
| `u8` … `u128`、`i8` … `i128`、`usize`、`isize` | Rust と同じ | `fn`、`const fn` |
| `Decimal` | 正確な十進数 | `fn`、`const fn` |
| `Rat` | 正確な分数 | `fn`、`const fn` |

これらの型の定数式は、値がコンパイル時に計算されるので、`pushdown fn` の中にも書けます。たとえばレンダー関数の中の `fade(ms(500))` です。`pushdown fn` にできないのは、それらを実行時に保持することです。そうした型のローカル変数、パラメータ、戻り値、物語変数はエラーになります（[有限型](../concepts/kinds.md#finite-types)を参照）。

## `Int<lo, hi>` {#intlo-hi}

```kis
static mut AFFECTION_MIO: Int<0, 5> = 0;
```

`Int<lo, hi>` はプリミティブ型で、宣言した範囲（両端を含む）の整数です。

- `lo` と `hi` は `i64` に収まる[型レベル定数](./types.md#type-level-constants)で、`lo <= hi` でなければなりません（[`E2004`](../../diagnostics/types.md#e2004)）。
- 既定の範囲はありません。すべての `Int` 型は境界を明記します。
- アナライザは物語変数を範囲に必要なだけのビット数で表すので、0 から 5 のカウンタは 3 ビットです。収まる最小の範囲を使ってください。

パターンはリテラルと範囲で `Int` の値に一致し、しきい値はそのように書きます。

```kis
match AFFECTION_MIO {
    3..=5 => MioSmiles(),
    _ => MioShrugs(),
}
```

## 整数リテラル {#integer-literals}

接尾辞のない整数リテラルは「整数 `n`」という柔軟な型を持ちます。文脈が期待する整数型（`Int<lo, hi>` または Rust の整数）の範囲が `n` を含む限り、その型になります。含まなければ [`E2013`](../../diagnostics/types.md#e2013) です。何も型を決めない場合、リテラルは `Int<n, n>` になります。接尾辞は型を固定し、`5u8` は `u8` です。整数リテラルが `Decimal` や `Rat` になることはありません。`1` ではなく `1.0` と書きます。

```kis
let a: Int<0, 5> = 3;     // Int<0, 5>
let b: u32 = 3;           // u32
let c = 3u8;              // u8
let d: Int<0, 5> = 9;     // E2013: 9 does not fit
```

リテラルだけの演算はリテラルの範囲で計算されます。`2 * 3` は「整数 6」です。コンパイラは整数を 128 ビットで表すので、`i128::MAX` を超える `u128` の値はリテラルとして書けません。

## `Int` の算術 {#arithmetic-on-int}

*暫定。* 有界整数の算術は正確です。結果の型はとりうる結果すべての範囲なので、実行時にオーバーフローしません。

| 式（`a: Int<l1, h1>`、`b: Int<l2, h2>`） | 型 |
| ---------------------------------------- | -- |
| `a + b` | `Int<l1 + l2, h1 + h2>` |
| `a - b` | `Int<l1 - h2, h1 - l2>` |
| `a * b` | 4 つの角の積を含む最小の範囲 |
| `a / b` | 4 つの角の商を含む最小の範囲 |
| `a % b` | 被除数と、除数の絶対値の最大値から 1 を引いた値で抑えられる範囲 |
| `-a` | `Int<-h1, -l1>` |
| `a == b`、`a < b`、… | `bool` |

- 除算は 0 方向に切り捨て、`%` の符号は Rust と同じく被除数に従います。
- `/` と `%` の除数の範囲は 0 を含んではいけません（[`E2016`](../../diagnostics/types.md#e2016)）。`match` などで先に型を狭めてください。
- ビット演算子 `& | ^ << >>` と `!` は `Int` には定義されていません（[`E2015`](../../diagnostics/types.md#e2015)）。
- `Int` と Rust の整数は 1 つの演算や比較の中で混ぜられません（[`E2014`](../../diagnostics/types.md#e2014)）。先にどちらかを変換してください。
- 結果の範囲が 128 ビットに収まらなければ [`E2015`](../../diagnostics/types.md#e2015) です。

### 拡大と複合代入 {#widening-and-compound-assignment}

値は、自分の範囲を含む範囲の `Int` 型へ暗黙に変換されます。`Int<1, 6>` は `Int<0, 10>` に格納できます。より広い範囲の値を格納するには `.saturate()` で変換します（[変換](#conversions)を参照）。

**複合代入は飽和します。** `Int` の変数に対する `x += e`、`x -= e`、`x *= e`、`x /= e`、`x %= e` は、正確な結果を計算して `x` の境界に切り詰めます。`x += 1` は `x = (x + 1).saturate()` です。右辺は任意の `Int` でかまいません。飽和によってすべてのステップは全域的になります。これは定義された動作で、実行時エラーにはなりません。`/=` と `%=` の除数の範囲は 0 を含んではならず、ビット演算の複合代入は `Int` には定義されていません。

```kis
static mut AFFECTION_MIO: Int<0, 5> = 0;

pushdown fn praise() {
    AFFECTION_MIO += 1;     // stays 5 once it is 5
}
```

黙って飽和するカウンタは、範囲が狭すぎることを示していることがよくあります。

## 変換 {#conversions}

リテラルと、`Int` 型から別の `Int` 型への拡大を除き、整数型が暗黙に変換されることはありません。標準ライブラリのトレイト `Integer` は `Int<lo, hi>` とすべての Rust の整数が実装しており、2 つの明示的な変換を提供します。変換先の型は文脈から推論するか、ターボフィッシュ（`x.into::<u32>()`）で書きます。

| メソッド | 結果 |
| -------- | ---- |
| `x.into()` | 同じ値。変換元の型のすべての値が変換先の型に収まらなければコンパイルエラーです（[`E2018`](../../diagnostics/types.md#e2018)） |
| `x.saturate()` | 変換先の型の範囲に切り詰めた値 |

```kis
const fn label_width(chars: Int<0, 40>) -> u32 {
    let n: u32 = chars.into();      // every Int<0, 40> fits in u32
    n * 16
}

fn set_level(level: u32) {
    let level: Int<0, 100> = level.saturate();
    MUSIC.set(volume(level));
}
```

`as` によるキャストはありません（[`E2019`](../../diagnostics/types.md#e2019)）。整数と `Decimal` の間の変換はありません。`Rat::new` は 2 つの `i128` から `Rat` を作り、`Rat::to_decimal` は `Rat` を `Decimal` に変換します。

## Rust の整数 {#rust-integers}

チューリング完全な種別では Rust の整数型 `u8`、`u16`、`u32`、`u64`、`u128`、`i8`、`i16`、`i32`、`i64`、`i128`、`usize`、`isize` を使えます。`usize` と `isize` はどのプラットフォームでも 64 ビットです。

| 演算子 | 意味 |
| ------ | ---- |
| `+ - * / %` | 算術。両辺は同じ型です |
| `& \| ^` | ビット積、ビット和、ビット排他的論理和 |
| `<< >>` | シフト。シフト量の型は任意の整数型でかまいません |
| `-x` | 符号反転。符号付き型のみ（[`E2015`](../../diagnostics/types.md#e2015)） |
| `!x` | ビット否定 |
| `== != < <= > >=` | 比較 |

- 算術は検査されます。オーバーフロー、ゼロ除算、型の範囲外の結果はエラーです（[エラー](#errors-at-compile-time-and-at-runtime)を参照）。黙って折り返すことはありません。
- `/` は 0 方向に切り捨て、`%` の符号は被除数に従います。
- シフト量は型のビット幅より小さくなければなりません。`<<` はあふれたビットを捨て、`>>` は符号付き型では算術シフトです。
- 異なる 2 つの Rust の整数型は混ぜられません。`.into()` か `.saturate()` で変換します。

## `Decimal` {#decimal}

`Decimal` は正確な十進数で、不透明度、音量、レイアウト上の位置など、もともと十進で書く値に使います。`0.5` や `1.0` のように小数点を含むリテラルは `Decimal` です。浮動小数点数の代わりであり、`Eq` です。`0.1 + 0.2 == 0.3` は `true` です。

| 演算子 | 意味 |
| ------ | ---- |
| `+ - *` | 正確 |
| `/` | 正確に計算したうえで、小数点以下 7 桁までを 0 方向に切り捨てます。`1.0 / 3.0` は `0.3333333` です |
| `-x` | 符号反転 |
| `== != < <= > >=` | 比較 |

`Decimal` に `%` はありません。`Decimal` の仮数部は 128 ビットで、収まらない結果はオーバーフローエラーです。

## `Rat` {#rat}

`Rat` は正確な有理数で、既約の分子と正の分母（どちらも `i128`）からなります。`Rat` のリテラルはありません。値は `Rat::new(num, den)` と書き、分数は約分されます（`Rat::new(2, -4)` は `-1/2`）。`den == 0` はゼロ除算です。

演算子は `Decimal` と同じで、`/` は正確です。`Rat::to_decimal` は `Decimal` に変換します。整数部と小数点以下最大 7 桁を残し、0 方向に切り捨てます（`Rat::new(1, 3).to_decimal()` は `0.3333333`、`Rat::new(-2, 3).to_decimal()` は `-0.6666666`）。

```kis
const fn rats() -> Rat {
    let a = Rat::new(1, 3);
    a * a - a / Rat::new(2, 1)      // 1/9 - 1/6 = -1/18
}
```

## コンパイル時と実行時のエラー {#errors-at-compile-time-and-at-runtime}

| エラー | コンパイル時の評価中 | 実行時 |
| ------ | -------------------- | ------ |
| オーバーフロー、型の範囲外の結果、不正なシフト量 | [`E4001`](../../diagnostics/eval.md#e4001) | VM パニック |
| ゼロ除算、`Rat::new(_, 0)` | [`E4002`](../../diagnostics/eval.md#e4002) | VM パニック |

VM パニックは定義されたゲームの停止で、[ランタイム](../tools/runtime.md)が扱います。コンパイル時に評価されるコード（定数、レンダー関数、物語から呼ばれる `const fn`）では、これらのエラーは値を必要とした呼び出しの位置で診断として報告されるので、物語そのものがこの形で失敗することはありません。`Int<lo, hi>` の複合代入は飽和し、失敗しません。
