Rust勉強中 - その6 -> 浮動小数点数

# 自己紹介
出田 守と申します。
しがないPythonプログラマです。
情報セキュリティに興味があり現在勉強中です。CTFやバグバウンティなどで腕を磨いています。主に低レイヤの技術が好きで、そっちばかり目が行きがちです。

Rustを勉強していくうえで、読んで学び、手を動かし、記録し、楽しく学んでいけたらと思います。

# 環境
新しい言語を学ぶということで、普段使わないWindowsとVimという新しい開発環境で行っています。
OS: Windows10 Home 64bit 1903
CPU: Intel Core i5-3470 @ 3.20GHz
Rust: 1.38.0
RAM: 8.00GB
Editor: Vim 8.1.1
Terminal: PowerShell

# 前回
前回は整数型について学びました。
[Rust勉強中 - その5](https://qiita.com/deta-mamoru/items/5f8399757c9c79997abf)

# 型
今回はRustの浮動小数点数を学びます。
## 浮動小数点数
Rustの浮動小数点数は[IEEE 754-2008](https://ja.wikipedia.org/wiki/IEEE_754)の単精度、倍精度の浮動小数点数、正と負の無限大、正と負の0、NaNなどをサポートしています。
### 単精度浮動小数点数
|型|範囲|
|---|---|
|f32|-3.4028235e38 ~ 3.4028235e38|

### 倍精度浮動小数点数
|型|範囲|
|---|---|
|f64|-1.7976931348623157e308 ~ 1.7976931348623157e308|

### 浮動小数点数リテラル
Rustでは整数リテラルと浮動小数点数リテラルは区別されます。なので、浮動小数リテラルを表現するには明示的に型を宣言するか、小数部または指数部を指定します。
型推論の際にf32型とf64型どちらも表現できる場合はf64型が選択されます。
整数リテラルと同じように、アンダーバーを含めることもできます。ただし、小数点直後のアンダーバーはエラーが出ました。

|浮動小数リテラル|補足|
|----------------|---|
|1f32|f32型を宣言|
|1_f32|整数部にアンダーバー|
|1f64|f64型を宣言|
|1.0f32|f32型を宣言|
|1_.0f32|f32型で整数部にアンダーバー|
|1.1|f64型で型推論|
|1_.1|f64型で整数部にアンダーバー|
|1.1_1|f64型で小数部にアンダーバー|
|1.|小数点を付けてf64型で型推論|
|1e2|指数部を付けてf64で型推論(=100)|
|1_e2|指数部前にアンダーバー|
|1e-2|指数部を付けてf64で型推論(=0.01)|
|1_e-2|指数部前にアンダーバー|

### 浮動小数点数のキャスト
浮動小数点数にも`as`演算子で型変換ができます。また、整数型と浮動小数点数との型変換もできます。

|変換|結果|補足|
|---|---|---|
|1.1f64        as f32|1.1f32|f64型からf32型へ変換|
|1.1f32        as f64|1.100000023841858f64|f32型からf64型へ変換|
|std::f64::MAX as f32|inff32|f64型最大値からf32型へ変換|
|std::f32::MAX as f64|3.4028234663852886e38f64|f32型最大値からf64型へ変換|
|1i32          as f32|1f32|i32型からf32型へ変換|
|-1i32         as f32|-1f32|負のi32型からf32型へ変換|
|1f32          as i32|1i32|f32型からi32型へ変換|
|-1f32         as i32|-1i32|負のf32型からi32型へ変換|
|std::i32::MAX as f32|2147483600f32|i32型最大値からf32型へ変換|
|std::i32::MIN as f32|-2147483600f32|i32型最小値からf32型へ変換|
|std::i64::MAX as f32|9223372000000000000f32|i64型最大値からf32型へ変換|
|std::i64::MIN as f32|-9223372000000000000f32|i64型最小値からf32型へ変換|
|std::i32::MAX as f64|2147483647f64|i32型最大値からf64型へ変換|
|std::i32::MIN as f64|-2147483648f64|i32型最小値からf64型へ変換|
|std::i64::MAX as f64|9223372036854776000f64|i64型最大値からf64型へ変換|
|std::i64::MIN as f64|-9223372036854776000f64|i64型最小値からf64型へ変換|
|std::f32::MAX as i32|2147483647i32|f32型最大値からi32型へ変換|
|std::f32::MIN as i32|-2147483648i32|f32型最小値からi32型へ変換|
|std::f64::MAX as i32|2147483647i32|f64型最大値からi32型へ変換|
|std::f64::MIN as i32|-2147483648i32|f64型最小値からi32型へ変換|
|std::f32::MAX as i64|9223372036854775807i64|f32型最大値からi64型へ変換|
|std::f32::MIN as i64|-9223372036854775808i64|f32型最小値からi64型へ変換|
|std::f64::MAX as i64|9223372036854775807i64|f64型最大値からi64型へ変換|
|std::f64::MIN as i64|-9223372036854775808i64|f64型最小値からi64型へ変換|

### 浮動小数点数のメソッド
整数型と同じく浮動小数点数にもメソッドがあります。一部を試してみます。

|式|結果|
|---|---|
|(-0.5f64).abs()|0.5|
|-0.5f64.abs()|-0.5|
|0.5f64.round()|1|
|0.4f64.round()|0|
|0.5f64.trunc()|0|
|std::f64::NAN.is_nan()|true|

浮動小数点数のメソッドもマイナスよりも優先して評価されるので注意が必要です。

浮動小数点数の調査用のプログラムは前回のソースに追記しました。

```Rust:main.rs
...

fn print_float_range() {
    println!("\n[print floating point range]");
    println!("f32:     {:e} ~ {:e}", std::f32::MIN, std::f32::MAX);
    println!("f64:     {:e} ~ {:e}", std::f64::MIN, std::f64::MAX);
    println!("f64_Inf: {}",          std::f64::INFINITY);
    println!("f64_Inf: {}",          std::f64::NEG_INFINITY);
    println!("f64_nan: {}",          std::f64::NAN);
}

fn print_float_literals() {
    println!("\n[print floating point literals]");
    println!("1f32:    \ttype={}, \tdigits={}", get_type(1f32),    1f32);
    println!("1_f32:   \ttype={}, \tdigits={}", get_type(1_f32),   1_f32);
    println!("1f64:    \ttype={}, \tdigits={}", get_type(1f64),    1f64);
    println!("1.0f32:  \ttype={}, \tdigits={}", get_type(1.0f32),  1.0f32);
    println!("1_.0f32: \ttype={}, \tdigits={}", get_type(1_.0f32), 1_.0f32);
    println!("1.1:     \ttype={}, \tdigits={}", get_type(1.1),     1.1);
    println!("1_.1:    \ttype={}, \tdigits={}", get_type(1_.1),    1_.1);
    println!("1.1_1:   \ttype={}, \tdigits={}", get_type(1.1_1),   1.1_1);
    println!("1.:      \ttype={}, \tdigits={}", get_type(1.),      1.);
    println!("1e2:     \ttype={}, \tdigits={}", get_type(1e2),     1e2);
    println!("1_e2:    \ttype={}, \tdigits={}", get_type(1_e2),    1_e2);
    println!("1e-2:    \ttype={}, \tdigits={}", get_type(1e-2),    1e-2);
    println!("1_e-2:   \ttype={}, \tdigits={}", get_type(1_e-2),   1_e-2);
}

fn print_float_cast() {
    println!("\n[print floating point cast]");
    println!("1.1f64        as f32 => {}{}",   1.1f64 as f32,        get_type(1.1f64 as f32));
    println!("1.1f32        as f64 => {}{}",   1.1f32 as f64,        get_type(1.1f32 as f64));
    println!("std::f64::MAX as f32 => {:e}{}", std::f64::MAX as f32, get_type(std::f64::MAX as f32));
    println!("std::f32::MAX as f64 => {:e}{}", std::f32::MAX as f64, get_type(std::f32::MAX as f64));
    println!("1i32          as f32 => {}{}",   1i32 as f32,          get_type(1i32 as f32));
    println!("-1i32         as f32 => {}{}",   -1i32 as f32,         get_type(-1i32 as f32));
    println!("1f32          as i32 => {}{}",   1f32 as i32,          get_type(1f32 as i32));
    println!("-1f32         as i32 => {}{}",   -1f32 as i32,         get_type(-1f32 as i32));
    println!("std::i32::MAX as f32 => {}{}",   std::i32::MAX as f32, get_type(std::i32::MAX as f32));
    println!("std::i32::MIN as f32 => {}{}",   std::i32::MIN as f32, get_type(std::i32::MIN as f32));
    println!("std::i64::MAX as f32 => {}{}",   std::i64::MAX as f32, get_type(std::i64::MAX as f32));
    println!("std::i64::MIN as f32 => {}{}",   std::i64::MIN as f32, get_type(std::i64::MIN as f32));
    println!("std::i32::MAX as f64 => {}{}",   std::i32::MAX as f64, get_type(std::i32::MAX as f64));
    println!("std::i32::MIN as f64 => {}{}",   std::i32::MIN as f64, get_type(std::i32::MIN as f64));
    println!("std::i64::MAX as f64 => {}{}",   std::i64::MAX as f64, get_type(std::i64::MAX as f64));
    println!("std::i64::MIN as f64 => {}{}",   std::i64::MIN as f64, get_type(std::i64::MIN as f64));
    println!("std::f32::MAX as i32 => {}{}",   std::f32::MAX as i32, get_type(std::f32::MAX as i32));
    println!("std::f32::MIN as i32 => {}{}",   std::f32::MIN as i32, get_type(std::f32::MIN as i32));
    println!("std::f64::MAX as i32 => {}{}",   std::f64::MAX as i32, get_type(std::f64::MAX as i32));
    println!("std::f64::MIN as i32 => {}{}",   std::f64::MIN as i32, get_type(std::f64::MIN as i32));
    println!("std::f32::MAX as i64 => {}{}",   std::f32::MAX as i64, get_type(std::f32::MAX as i64));
    println!("std::f32::MIN as i64 => {}{}",   std::f32::MIN as i64, get_type(std::f32::MIN as i64));
    println!("std::f64::MAX as i64 => {}{}",   std::f64::MAX as i64, get_type(std::f64::MAX as i64));
    println!("std::f64::MIN as i64 => {}{}",   std::f64::MIN as i64, get_type(std::f64::MIN as i64));
}

fn print_float_methods() {
    println!("\n[print floating point methods]");
    println!("(-0.5f64).abs()        = {}", (-0.5f64).abs());
    println!("-0.5f64.abs()          = {}", -0.5f64.abs());
    println!("0.5f64.round()         = {}", 0.5f64.round());
    println!("0.4f64.round()         = {}", 0.4f64.round());
    println!("0.5f64.trunc()         = {}", 0.5f64.trunc());
    println!("std::f64::NAN.is_nan() = {}", std::f32::NAN.is_nan());
}

fn main() {
    // println!(">> Integer type <<");
    // print_int_range();
    // print_int_literals();
    // print_byte_literals();
    // print_int_cast();
    // print_int_methods();
    println!(">> Floating point type <<");
    print_float_range();
    print_float_literals();
    print_float_cast();
    print_float_methods();
}
```
```
$ cargo run                                                                                 Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target\debug\types.exe`
>> Floating point type <<

[print floating point range]
f32:     -3.4028235e38 ~ 3.4028235e38
f64:     -1.7976931348623157e308 ~ 1.7976931348623157e308
f64_Inf: inf
f64_Inf: -inf
f64_nan: NaN

[print floating point literals]
1f32:           type=f32,       digits=1
1_f32:          type=f32,       digits=1
1f64:           type=f64,       digits=1
1.0f32:         type=f32,       digits=1
1_.0f32:        type=f32,       digits=1
1.1:            type=f64,       digits=1.1
1_.1:           type=f64,       digits=1.1
1.1_1:          type=f64,       digits=1.11
1.:             type=f64,       digits=1
1e2:            type=f64,       digits=100
1_e2:           type=f64,       digits=100
1e-2:           type=f64,       digits=0.01
1_e-2:          type=f64,       digits=0.01

[print floating point cast]
1.1f64        as f32 => 1.1f32
1.1f32        as f64 => 1.100000023841858f64
std::f64::MAX as f32 => inff32
std::f32::MAX as f64 => 3.4028234663852886e38f64
1i32          as f32 => 1f32
-1i32         as f32 => -1f32
1f32          as i32 => 1i32
-1f32         as i32 => -1i32
std::i32::MAX as f32 => 2147483600f32
std::i32::MIN as f32 => -2147483600f32
std::i64::MAX as f32 => 9223372000000000000f32
std::i64::MIN as f32 => -9223372000000000000f32
std::i32::MAX as f64 => 2147483647f64
std::i32::MIN as f64 => -2147483648f64
std::i64::MAX as f64 => 9223372036854776000f64
std::i64::MIN as f64 => -9223372036854776000f64
std::f32::MAX as i32 => 2147483647i32
std::f32::MIN as i32 => -2147483648i32
std::f64::MAX as i32 => 2147483647i32
std::f64::MIN as i32 => -2147483648i32
std::f32::MAX as i64 => 9223372036854775807i64
std::f32::MIN as i64 => -9223372036854775808i64
std::f64::MAX as i64 => 9223372036854775807i64
std::f64::MIN as i64 => -9223372036854775808i64

[print floating point methods]
(-0.5f64).abs()        = 0.5
-0.5f64.abs()          = -0.5
0.5f64.round()         = 1
0.4f64.round()         = 0
0.5f64.trunc()         = 0
std::f64::NAN.is_nan() = true
```

今回はここまで。