今回は double
型や float
型などの実数型(より正確には浮動小数点数型)の変数から “小数点以下の値” のみを取得する方法について解説します。
Contents
小数点以下の値のみを取得する方法
ではさっそく、実数から “小数点以下の値のみ” を取得する方法を解説していきます。
実数とその実数の整数部の差を求める
まずは関数を利用せずに、自力で小数点以下の値のみを取得する方法について説明していきたいと思います。
実数は、その実数の “整数部と小数部の和” で表すことが可能です。
ですので、実数と “その実数の整数部” の差を求めてやれば、小数部のみ、つまり実数の小数点以下の値のみを取得することができます。
では実数の整数部はどうやって求めれば良いのかというと、C言語では下記の2つの方法で取得することが可能です(関数を使えばもっと方法はありますが…)。
- 実数 or 実数型の変数を整数型にキャストする
- 実数 or 実数型の変数を整数型の変数に代入する
実数 or 実数型の変数を整数型にキャストする
前者の方法により、実数の小数点以下の値のみを取得するプログラムのソースコード例は下記のようになります。
#include <stdio.h>
int main(void) {
float num; /* 実数 */
float decimal; /* 小数点以下の値 */
/* 元々の実数の値を設定 */
num = 3.6;
/* 小数点以下の値を取得する */
decimal = num - (int)num;
printf("%f\n", decimal);
return 0;
}
(int)num
の部分がキャストを行なっている部分です。キャストというのは、ある型の変数や値を “他の型の変数や値に変換する” ことを言います。
実数型の変数を整数型(上記では int
型)にキャストすることで小数点以下の値が捨てられ、整数部のみを取得することが可能です。
ですので、下記の処理により、実数 num
から “num
の整数部” を引いて求めた “num
の小数点以下の値” が decimal
に格納されることになります。
decimal = num - (int)num;
実数 or 実数型の変数を整数型の変数に代入する
後者の方法により、実数の小数点以下の値のみを取得するプログラムのソースコード例は下記のようになります。
#include <stdio.h>
int main(void) {
float num; /* 実数 */
int integer; /* 整数部 */
float decimal; /* 小数点以下の値 */
/* 元々の実数の値を設定 */
num = 3.6;
/* 整数部を取得 */
integer = num;
/* 小数点以下の値を取得する */
decimal = num - integer;
printf("%f\n", decimal);
return 0;
}
別の方法として記述しましたが、実質的には前者の方法と同じ考えにより小数点以下の値を取得しています。
integer = num
では、整数型(int
型)の変数に実数型(float
型)の変数の値を代入することになります。
このように、異なる型の変数への代入が行われる時、右辺の値は左辺の変数の型に変換された後に代入が行われます。つまりキャスト(型の変換)が自動的に行われます。
ですので、前者の方法の解説で述べたように、上記の代入時には num
の小数点以下の値が捨てられて整数部に変換されたのちに、その整数部が integer
に格納されることになります。
したがって、下記を計算することにより num
の小数点以下の値が decimal
に格納されることになります。
decimal = num - integer;
スポンサーリンク
modf
・modff
関数を利用する
また、C言語には modf
や modff
という標準関数が用意されているので、これを利用することで実数から小数点以下の値のみを取得することも可能です。
#include <math.h>
double modf(double num, *double integer_ptr)
float modff(float num, *float integer_ptr)
modf
・modff
は、実数を整数部と小数部(小数点以下の値)に分離する関数です。この2つの関数の違いは型のみ(double
or float
)です。
第1引数 num
には、小数点以下の値を取得したい実数の値 or その値を格納した実数型の変数を指定します。
第2引数 integer_ptr
には、num
の整数部を格納する先のアドレスを指定します。
以上を指定した上で modf
・modff
を実行すると、戻り値として num
の小数点以下の値を取得することができます。
modff
関数の利用により、実数の小数点以下の値のみを取得するプログラムのソースコード例は下記のようになります。
#include <stdio.h>
#include <math.h>
int main(void) {
float num; /* 実数 */
float integer; /* 整数部 */
float decimal; /* 小数点以下の値 */
/* 元々の実数の値を設定 */
num = 3.6;
/* 小数点以下の値を取得 */
decimal = modff(num, &integer);
printf("%f\n", decimal);
return 0;
}
小数点以下の値を取得するための方法の解説は以上になります。
注意点
ここまで解説した方法で小数点以下の値を取得することは可能なのですが、いくつか注意点もありますので、その注意点について解説しておきたいと思います。
キャスト・代入時に桁あふれが発生する可能性あり
実数とその実数の整数部の差を求めるで紹介した方法で小数点以下の値を取得する場合、キャスト・代入時に桁あふれ(オーバーフロー)が発生する可能性があるので注意してください。
例えば下記では、キャスト時に桁あふれが発生するので小数点以下の値をうまく計算することができません。
#include <stdio.h>
int main(void) {
double num; /* 実数 */
double decimal; /* 小数点以下の値 */
/* 元々の実数の値を設定 */
num = 2147483648.5;
/* 小数点以下の値を取得する */
decimal = num - (int)num;
printf("%f\n", decimal);
return 0;
}
printf
で表示した結果は、おそらく下記のようになると思います。明らかにおかしな結果ですね…。
4294967296.500000
このような結果になるのは、num
の整数部が、キャスト先の型である int
型の最大値を超えているからです(int
型のサイズを4バイトとして説明しています)。
int
型の最大値は 2147483647
ですので、その値を超える値が int
型にキャストされた場合は桁あふれが発生します。2147483648
が int
型にキャストされた場合は -2147483648
になりますので、decimal
を求める処理では下記の計算が実行されることになります。
decimal = 2147483648.5 - (-2147483648)
この結果、上記のようなおかしな結果が得られることになります。前述のように、代入を行う際にもキャストが自動的に行われますので、この場合も同様におかしな結果が得られることになります。
もちろんキャスト先の型を long long
型など大きな値を扱えるものにすれば、ある程度上記のような現象は発生しにくくなります。
ですが、float
や double
型などで扱える最大値はとてつもなく大きいので、どれだけ大きな値を扱える整数型にキャストするようにしても、全てのケースで正常に演算が行えるようにするのは難しいです。
ですので、実数とその実数の整数部の差を求めるで紹介した方法は手軽ではありますが、小数点以下の取得先となる実数が極端に大きくなる可能性があるのであれば、自力で求めるのではなく modf
や modff
を利用した方が良いです。
スポンサーリンク
負の値をどう扱うかは要検討
負の実数の小数点以下の値をどう扱うのかは、作成したいプログラムに応じて検討必要だと思います。
ここまで解説した手法で小数点以下の値を求めた場合、元々の “実数が負の値” の場合、小数点以下の値も負の値になります。
作成したいプログラムにおいて、求めたい小数点以下の値が “負の値” でも良いのであればこれで良いのですが、小数点以下の値を “正の値” に統一したい場合などは、ここまで紹介したソースコードを変更する必要があります。
例えば下記は、元々の実数 num
が負の値の場合に、求めた小数点以下の値に -
を掛けることで正の値で小数点以下の値を取得するようにしたものになります。
#include <stdio.h>
int main(void) {
float num; /* 実数 */
float decimal; /* 小数点以下の値 */
/* 元々の実数の値を設定 */
num = -3.6;
/* 小数点以下の値を取得 */
if (num >= 0) {
/* numが正の値の場合 */
decimal = num - (int)num;
} else {
/* numが負の値の場合 */
decimal = -(num - (int)num);
}
printf("%f\n", decimal);
return 0;
}
あなたが作成するプログラムにおいて、負の値に対する小数点以下の値の符号が “負 or 正” のどちらの方が良いのかを検討し、必要に応じて上記のように処理を変更するようにしてください。
浮動小数点数なので誤差が発生する可能性あり
ここまで簡単に説明するために、”実数” という言葉を使用させていただきましたが、C言語で扱う実数は実際には “浮動小数点数” です。
浮動小数点数は “2の冪乗の和” しか表現できないため、“2の冪乗の和” で表現できない実数を扱おうとすると誤差が発生するので注意してください(冪乗といっても冪数は整数のみ)。
例えば実数 or 実数型の変数を整数型にキャストするで紹介したソースコードで、num
の値を 99999.333
に変更して実行すると、(私の環境では)最後に表示される小数点以下の値は下記のようになります。
0.335938
ただし、この誤差は num
に値を代入するときに発生するものであり、小数点以下の値を求める際に発生する誤差ではありません。実際に num
の値を表示してみると、num
の値自体に誤差が発生していることが確認できます。
99999.335398
なので、num
の値自体に誤差はあるものの、num
の小数点以下の値は今回紹介した方法で誤差なく計算できると思います。これは、浮動小数点数においては、整数部の値の絶対値が小さいほど小数部の誤差が小さくなるためです(小数点数以下のみの値は整数部の値は 0
なので、元々の実数よりも整数部の値は小さい)。
また、float
型よりも double
型の方が誤差が小さくなるので、誤差が気になる場合は double
を用いた方が良いです。
まとめ
このページではC言語で実数(浮動小数点数)の小数点以下の値を取得する方法について解説しました!
小数点以下の値を求める方法としては大きく下記の2つが挙げられます。
- 実数とその実数の整数部の差を求める
modf
・modff
関数を利用する
前者の方法はお手軽に実行できるというメリットがありますが、扱う実数が大きいと上手く小数点以下の値の値が取得できないというデメリットがあります。
大きな値の実数から小数点以下の値を取得したような場合は、modf
や modff
を利用するのが良いと思います!
オススメの参考書(PR)
C言語学習中だけど分からないことが多くて挫折しそう...という方には、下記の「スッキリわかるC言語入門」がオススメです!
まず学習を進める上で、参考書は2冊持っておくことをオススメします。この理由は下記の2つです。
- 参考書によって、解説の仕方は異なる
- 読み手によって、理解しやすい解説の仕方は異なる
ある人の説明聞いても理解できなかったけど、他の人からちょっと違った観点での説明を聞いて「あー、そういうことね!」って簡単に理解できた経験をお持ちの方も多いのではないでしょうか?
それと同じで、1冊の参考書を読んで理解できない事も、他の参考書とは異なる内容の解説を読むことで理解できる可能性があります。
なので、参考書は2冊持っておいた方が学習時に挫折しにくいというのが私の考えです。
特に上記の「スッキリわかるC言語入門」は、他の参考書とは違った切り口での解説が豊富で、他の参考書で理解できなかった内容に対して違った観点での解説を読むことができ、オススメです。題名の通り「なぜそうなるのか?」がスッキリ理解できるような解説内容にもなっており、C言語入門書としてもかなり分かりやすい参考書だと思います。
もちろんネット等でも色んな観点からの解説を読むことが出来ますので、分からない点は別の人・別の参考書の解説を読んで解決していきましょう!もちろん私のサイトも参考にしていただけると嬉しいです!
入門用のオススメ参考書は下記ページでも紹介していますので、こちらも是非参考にしていただければと思います。
https://daeudaeu.com/c_reference_book/