この記事では、Rustのデータ型(浮動小数点)について、初心者の方にも分かりやすく解説を進めていきます!
プログラミングをしていると、どうしても小数点以下の数値を扱いたい場面って出てきますよね。例えば、計算結果が「3.14」になったり、物の割合を「0.75」みたいに表現したり。Rustでは、そういった小数点を扱うために「浮動小数点型」というものが用意されています。
でも、「f32とf64って何が違うの?」「どうやって書くの?」「計算するときに変な誤差が出たりしない?」なんて、疑問に思うこともあるかもしれません。
この記事を読めば、そんなモヤモヤもスッキリ解消するはずです。
この記事で学べること
- 浮動小数点数ってそもそも何なのか、サクッと理解
- Rustの浮動小数点型、f32とf64の違いと選び方
- コードでの具体的な書き方(変数の作り方)
- 計算など、実際のプログラムでの使い方サンプル
- これだけは知っておきたい!浮動小数点数を扱う時の注意点
Rustの浮動小数点型(f32, f64)とは? 基本を理解しよう
まずは基本から!Rustで小数点を扱うためのデータ型、それが浮動小数点型です。Rustには主に2種類の浮動小数点型があります。それは f32
と f64
です。
これらの型を使うことで、プログラムの中で温度(例 25.5度)、確率(例 0.5)、座標(例 x=10.5, y=3.8)といった、整数では表現しきれない細かな数値を扱えるようになります。
料理で言えば、きっちり計量するための計量スプーンみたいなもの、とイメージすると分かりやすいかもしれませんね。
そもそも浮動小数点数とは?(前提知識)
ちょっとだけコンピュータ内部の話に触れてみましょう。
浮動小数点数は、コンピュータが限られたメモリの中で、すごく大きな数からすごく小さな小数まで、幅広い範囲の数値を効率よく表現するための工夫です。
「浮動」という名前の通り、小数点の位置を固定せず、動かすことで柔軟に数値を表現します。(科学の授業で習った「$1.23 \times 10^5$」みたいな書き方、あれに近いイメージです)
完璧に正確というわけではないのですが(後で詳しく触れます)、ほとんどのケースで十分な精度で小数を扱える便利な仕組みなんですよ。
Rustの浮動小数点型 - f32とf64の概要
Rustにはf32
とf64
の2つの浮動小数点型がある、とお話ししました。この2つの主な違いは、扱える数値の「範囲」と「精度」、そして使用する「メモリサイズ」です。
f32
(単精度) 32ビットのメモリを使います。f64
に比べてメモリ使用量は少ないですが、表現できる数値の範囲や精度は少し劣ります。f64
(倍精度) 64ビットのメモリを使います。f32
の約2倍のメモリを使いますが、より広い範囲の数値を、より高い精度で表現できます。Rustでは、特に指定しない限り、小数は基本的にこのf64
型として扱われます。迷ったら、まずはf64
を使うのが一般的です。
ゲームのグラフィック処理など、大量の計算を高速に行いたい特定の場面ではf32
が選ばれることもありますが、多くのアプリケーションではf64
の精度があれば十分でしょう。
Rustのデータ型 - 浮動小数点数の書き方(宣言と初期化)
それでは、実際にRustのコードで浮動小数点型の変数をどうやって作るのか見ていきましょう。
変数を作るには let
というキーワードを使います。値をセットすることを「初期化」と呼びます。
Rustは賢いので、書かれた数値を見て「あ、これは小数点があるから浮動小数点数だな」と判断してくれることがあります(型推論)。
でも、自分で「これはf32型だよ!」「こっちはf64型ね!」と明示的に教えてあげる書き方もあります。
f32型の書き方
f32
型の変数を作りたい場合は、変数名の後に : f32
と書くか、数値の後に f32
と付け加えます。どちらの方法でもOKです。
書き方1 型注釈を使う
fn main() { let pi_f32: f32 = 3.14; // 変数名の後に : f32 と書く println!("f32の値(型注釈): {}", pi_f32); }
書き方2 サフィックスを使う
fn main() { let e_f32 = 2.718f32; // 数値の後に f32 と書く println!("f32の値(サフィックス): {}", e_f32); }
こんな感じで、明示的にf32型であることを示すことができます。
f64型の書き方 (デフォルト)
f64
型はRustのデフォルトなので、実はもっと簡単に書けます。普通に小数点を書けば、Rustが「これはf64
だな」と解釈してくれます。もちろん、f32
と同じように明示的に指定することも可能です。
書き方1 型推論に任せる (デフォルト)
fn main() { let gravity = 9.8; // 普通に小数を書くと f64 になる println!("f64の値(型推論): {}", gravity); }
書き方2 明示的に指定する
fn main() { let precise_pi: f64 = 3.1415926535; // : f64 で明示 let light_speed = 299792458.0f64; // f64 サフィックスで明示 (整数っぽいけど .0 をつけるかサフィックスで示す) println!("f64の値(明示): {}", precise_pi); println!("f64の値(サフィックス): {}", light_speed); }
特に理由がなければ、単に小数を書くだけでf64になる、と覚えておくと楽ちんですね。
Rustでの浮動小数点型の使い方
変数の作り方がわかったところで、次は実際にプログラムでどう使うのかを見ていきましょう!ここでは、一番よく使うであろう「計算」と、異なるデータ型の間で値を変換する「型変換(キャスト)」を取り上げます。
サンプルコードと、そのコードを実行したらどういう結果が出るのか(実行結果)も一緒に載せていくので、ぜひお手元の環境で試してみてくださいね。
基本的な算術演算(四則演算)
浮動小数点数も、整数と同じように足し算、引き算、掛け算、割り算ができます。記号も同じ +
, -
, *
, /
を使います。割り算の余りを求める %
も使えますよ。
fn main() { let a: f64 = 10.5; let b: f64 = 2.0; let sum = a + b; // 足し算 let difference = a - b; // 引き算 let product = a * b; // 掛け算 let quotient = a / b; // 割り算 let remainder = a % b; // 剰余 (余り) println!("a = {}", a); println!("b = {}", b); println!("足し算 (a + b) = {}", sum); println!("引き算 (a - b) = {}", difference); println!("掛け算 (a * b) = {}", product); println!("割り算 (a / b) = {}", quotient); println!("剰余 (a % b) = {}", remainder); }
実行結果
a = 10.5 b = 2.0 足し算 (a + b) = 12.5 引き算 (a - b) = 8.5 掛け算 (a * b) = 21.0 割り算 (a / b) = 5.25 剰余 (a % b) = 0.5
このように、算術演算子が直感的に使えるので、計算も簡単に行えますね。
型変換の方法(キャスト)
プログラムを書いていると、「整数を小数として扱いたい」とか、「f32型の値をf64型として計算したい」といった場面が出てきます。
そんな時に使うのが「型変換(キャスト)」です。Rustでは as
というキーワードを使って型変換を行います。
整数から浮動小数点型へ
fn main() { let integer_val = 100; // これは整数 (i32) // as を使って f64 に変換! let float_val: f64 = integer_val as f64; println!("元の整数: {}", integer_val); println!("f64に変換後: {}", float_val); // 100.0 と表示される }
f32からf64へ
fn main() { let num_f32: f32 = 1.23456789; // as を使って f64 に変換 let num_f64: f64 = num_f32 as f64; println!("元のf32: {}", num_f32); println!("f64に変換後: {}", num_f64); }
注意点として、f64
からf32
のように、より精度の低い型へ変換すると、情報が失われる(値が変わってしまう)可能性があることは覚えておきましょう。
キャストは便利な機能ですが、どんな変換が行われるのか意識しながら使うことが大事です。
Rustの浮動小数点数を扱う上での注意点
さて、ここまで浮動小数点型の基本的な使い方を見てきましたが、実はちょっとだけ注意が必要な点があります。特に「精度」の問題と「比較」の仕方です。
これを知らないと思わぬバグの原因になることもあるので、しっかり押さえておきましょう!
浮動小数点数特有の「精度」の問題
コンピュータは、実はほとんどの小数を完全に正確に表現できるわけではありません。
これは、コンピュータ内部では数を0と1の組み合わせ(二進数)で扱っているため、十進数できりの良い小数(例えば0.1)が、二進数だと無限に続く小数になってしまうことがあるからです。
その結果、計算するとわずかな「誤差」が生じることがあります。有名な例を見てみましょう。
fn main() { let result = 0.1 + 0.2; println!("0.1 + 0.2 = {}", result); // 期待するのは 0.3 だけど…? }
実行結果 (環境による可能性があります)
0.1 + 0.2 = 0.30000000000000004
あれ? 0.3 ぴったりじゃない! と驚くかもしれません。これが浮動小数点数の「丸め誤差」と呼ばれるものです。
多くの場合、この程度の誤差は問題になりませんが、金融計算など、非常に高い精度が求められる場面では注意が必要です。
浮動小数点数同士の比較方法
上で見た「精度」の問題があるため、浮動小数点数同士を ==
で直接比較するのは危険な場合があります。
fn main() { let a = 0.1 + 0.2; let b = 0.3; // 直接比較すると... if a == b { println!("a と b は等しい"); // これは表示されないかもしれない! } else { println!("a と b は等しくない"); // こっちが表示されるかも } }
では、どうすればいいのでしょうか?
よく使われるのは、2つの数値の差の絶対値が、非常に小さい特定の数値(許容誤差、イプシロン(epsilon)と呼ばれることもあります)よりも小さいかどうかで判断する方法です。
推奨される比較方法
fn main() { let a: f64 = 0.1 + 0.2; let b: f64 = 0.3; let difference = (a - b).abs(); // 差が十分に小さいかチェック (std::f64::EPSILON は f64 で表現できる最小の正の値) // もっと大きな許容誤差が必要な場合もある (例: 1e-9 など) if difference < std::f64::EPSILON { println!("a と b は実質的に等しい (EPSILON比較)"); } else { println!("a と b は等しくない (EPSILON比較)"); } // より実用的な許容誤差を使う例 let tolerance: f64 = 1e-9; if (a - b).abs() < tolerance { println!("a と b は実質的に等しい (tolerance比較)"); } else { println!("a と b は等しくない (tolerance比較)"); } }
このように、わずかな誤差を許容する形で比較を行うのが、浮動小数点数を安全に扱うコツです。
std::f64::EPSILON
は非常に小さい値なので、目的に応じて `1e-6` や `1e-9` のような、もう少し大きい許容誤差を使うのが一般的です。
【まとめ】Rustの浮動小数点型を使いこなすために
お疲れ様でした!今回はRustの浮動小数点型 f32
と f64
について、基本的なところから実践的な使い方、そして注意点までを見てきました。
最後に、今回のポイントをまとめておきましょう。
- Rustで小数点を扱うには
f32
(単精度) とf64
(倍精度) を使う。 - 特に指定しなければ
f64
が使われる (デフォルト)。 - 変数宣言は
let
を使い、型注釈 (: f64
) やサフィックス (f64
) で型を明示できる。 - 基本的な四則演算 (
+
,-
,*
,/
,%
) が可能。 - 型変換には
as
キーワードを使う (キャスト)。 - 浮動小数点数には「精度」の問題があり、計算結果に誤差が生じることがある。
==
での直接比較は避け、差の絶対値が許容誤差内かで比較するのが安全。
浮動小数点数は、最初は少し戸惑う部分もあるかもしれませんが、今回の内容をしっかり押さえておけば、自信を持って扱えるようになるはずです!
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。