C言語で小数点以下を落とすには、標準ライブラリのtrunc関数が最もシンプルです。
端数を切り捨てて整数方向へ丸めるのではなく、0に近づく方向に小数部分を捨てるのが特徴です。
本記事では、基本の使い方から小数第1位や第2位で切り捨てるテクニック、整数への変換時の注意点まで、初心者の方にもわかりやすく解説します。
trunc関数とは
小数点以下を切り捨てる
truncは、小数点以下を単純に捨てて整数部分だけを残す関数です。
丸めではないため、0.9も0.1も結果は同じ整数部分になります。
戻り値は浮動小数点のまま(整数型にはなりません)という点が重要です。
代表的な例
- 9 → 3.0
- 1 → 3.0
- 0 → 3.0
同じ「端数を落とす」系の関数と混同しがちですが、ceilは切り上げ、floorは切り下げであり、truncは0に向かって切り捨てます。
結果の「型」について
truncは整数ではなく、浮動小数点型(doubleなど)を返します。
そのため、表示時に%fで出力すると小数部(ゼロ)も表示されます。
整数として扱いたい場合は、必要に応じて整数型へキャストします。
負の数は0に近づける
truncは、負の数でも常に0に近づくように小数部を捨てます。
これが、常に小さい方向に丸めるfloorとの大きな違いです。
下の表は違いのイメージです。
| 入力 x | trunc(x) | floor(x) |
|---|---|---|
| 3.9 | 3.0 | 3.0 |
| -3.1 | -3.0 | -4.0 |
| -3.9 | -3.0 | -4.0 |
負の数で「どちらにずれるか」を意識して関数を選ぶことが大切です。
補足(符号付きゼロ)
実装によってはtrunc(-0.5)の結果が-0.0になることがあります。
ふつうの計算では問題になりませんが、符号付きゼロを表示したりビット表現を比較したりする高度な場面では知っておくと安心です。
truncの基本的な使い方
math.hをインクルード
利用には#include <math.h>が必要です。
さらに入出力のために#include <stdio.h>も使います。
#include <stdio.h>
#include <math.h>
宣言 double trunc
truncはC99以降で標準化されており、型ごとに3種類あります。
// math.h より(プロトタイプ宣言)
double trunc(double x);
float truncf(float x);
long double truncl(long double x);
引数と戻り値の型が一致している点がポイントです。
truncfとtrunclの使い分け
- 変数の型が
floatならtruncf - 変数の型が
doubleならtrunc - 変数の型が
long doubleならtruncl
関数は変数の精度に合わせて選ぶのが原則です。
型が合わない場合でも実引数が自動的に昇格(または降格)されて動作はしますが、無駄な型変換を避け、意図した精度を保つために、適切な関数を選ぶことをおすすめします。
なお、一部の環境ではlong doubleがdoubleと同じ精度の場合があります。
コンパイルは-lmを付ける
多くのUnix系環境(GNU/Linux、macOSの一部環境)では、数学ライブラリへのリンクに-lmが必要です。
GCCやClangの例
gcc -std=c11 trunc_basic.c -lm
# または
clang -std=c11 trunc_basic.c -lm
MSVC(Visual Studio)の例
WindowsのMSVCでは通常-lmは不要です。
プロジェクトにmath.hをインクルードしてビルドしてください。
truncの使い方例 小数点以下を落とす
正の数 3.9→3.0
3.9の小数部分を落として3.0にします。
戻り値はdoubleです。
// pos_trunc.c
#include <stdio.h>
#include <math.h>
int main(void) {
double x = 3.9;
double y = trunc(x); // 小数点以下を切り捨て(0に近づける)
printf("x=%.1f -> trunc(x)=%.1f\n", x, y); // 小数1桁で表示
return 0;
}
x=3.9 -> trunc(x)=3.0
truncは丸めではないので、3.9でも3.0になります。
3.0は実数表現のため%fで表示すると小数部が付きます。
負の数 -3.9→-3.0
負の数でも、0に近づく方向に小数部を捨てます。
// neg_trunc.c
#include <stdio.h>
#include <math.h>
int main(void) {
double x = -3.9;
double y = trunc(x); // -3.9 -> -3.0
double f = floor(x); // 比較用: floorは常に小さい方へ(-4.0)
printf("x=%.1f -> trunc(x)=%.1f, floor(x)=%.1f\n", x, y, f);
return 0;
}
x=-3.9 -> trunc(x)=-3.0, floor(x)=-4.0
truncは「0方向」、floorは「負方向」という違いを覚えると、負の値で迷いません。
小数第1位で切り捨てる方法
小数第1位で切り捨てるには、10倍してtruncしてから10で割るという手順を使います。
// trunc_to_1_decimal.c
#include <stdio.h>
#include <math.h>
int main(void) {
double a = 12.39;
double b = -12.39;
// 小数第1位で切り捨てる(= 小数第2位以降を落とす)
double a_tr = trunc(a * 10.0) / 10.0; // 12.39 -> 12.3
double b_tr = trunc(b * 10.0) / 10.0; // -12.39 -> -12.3
printf("a=%.2f -> %.1f\n", a, a_tr);
printf("b=%.2f -> %.1f\n", b, b_tr);
return 0;
}
a=12.39 -> 12.3
b=-12.39 -> -12.3
精度に関する注意
2進小数では10進小数が厳密に表せないため、表示の末尾が期待と微妙にズレることがあります。
表示には%.1fなどのフォーマット指定を使って、見た目の桁数を合わせるのが実務では有効です。
小数第2位で切り捨てる方法
考え方は同じで、100倍してtruncしてから100で割ります。
// trunc_to_2_decimals.c
#include <stdio.h>
#include <math.h>
int main(void) {
double a = 12.349; // 例: 12.349 -> 12.34
double b = -12.349; // 例: -12.349 -> -12.34
double a_tr = trunc(a * 100.0) / 100.0;
double b_tr = trunc(b * 100.0) / 100.0;
printf("a=%.3f -> %.2f\n", a, a_tr);
printf("b=%.3f -> %.2f\n", b, b_tr);
return 0;
}
a=12.349 -> 12.34
b=-12.349 -> -12.34
関数化すると便利
任意の桁で切り捨てる小関数にすると再利用しやすくなります。
// trunc_to_n_decimals.c
#include <stdio.h>
#include <math.h>
// xを小数点以下n桁で切り捨て(例: n=1で小数第1位を残す)
double trunc_n(double x, int n) {
// pow(10.0, n)でスケーリングし、truncで切り捨て、元に戻す
double s = pow(10.0, n);
return trunc(x * s) / s;
}
int main(void) {
double x1 = 123.4567;
double x2 = -123.4567;
printf("n=1: %.4f -> %.1f\n", x1, trunc_n(x1, 1));
printf("n=2: %.4f -> %.2f\n", x1, trunc_n(x1, 2));
printf("n=3: %.4f -> %.3f\n", x1, trunc_n(x1, 3));
printf("n=1: %.4f -> %.1f\n", x2, trunc_n(x2, 1));
printf("n=2: %.4f -> %.2f\n", x2, trunc_n(x2, 2));
printf("n=3: %.4f -> %.3f\n", x2, trunc_n(x2, 3));
return 0;
}
n=1: 123.4567 -> 123.4
n=2: 123.4567 -> 123.45
n=3: 123.4567 -> 123.456
n=1: -123.4567 -> -123.4
n=2: -123.4567 -> -123.45
n=3: -123.4567 -> -123.456
整数に変換するときの注意
intへキャストとの違い
(int)x は「0に向かって丸める」という点でtruncと同じ結果になりますが、戻り値の型と安全性が異なります。
trunc(x)は浮動小数点のまま(例:double)を返す(int)xは整数に変換する- 整数型に収まらない大きさのxを(int)にすると未定義動作(C規格)
比較コードを見てみます。
// trunc_vs_cast.c
#include <stdio.h>
#include <math.h>
#include <limits.h>
int main(void) {
double x1 = -3.9;
double t1 = trunc(x1); // -3.0
int i1 = (int)x1; // -3 (0方向に切り捨て)
printf("x1=%.1f -> trunc=%.1f, (int)=%d\n", x1, t1, i1);
// 安全にintへ入れるには、範囲チェックしてからキャスト
double x2 = 1e12; // intに収まらない例
double t2 = trunc(x2);
if (t2 >= INT_MIN && t2 <= INT_MAX) {
int i2 = (int)t2;
printf("x2=%.0f -> 安全に(int)=%d\n", x2, i2);
} else {
printf("x2=%.0f -> intに収まりません(範囲外)\n", x2);
}
return 0;
}
x1=-3.9 -> trunc=-3.0, (int)=-3
x2=1000000000000 -> intに収まりません(範囲外)
まとめると
- 「落とすだけ」ならtruncでOK
- 「整数として格納したい」なら、trunc後に範囲チェックしてからキャスト
大きな値はオーバーフローに注意
浮動小数点から整数へのキャストは、値が対象の整数型に収まらないと未定義動作です。
必ずINT_MINやINT_MAXなどと比較して範囲を確認してからキャストしてください。
// safe_cast.c
#include <stdio.h>
#include <math.h>
#include <limits.h>
int main(void) {
double x = -2147483648.9; // INT_MINより小さい可能性のある値
double tx = trunc(x);
if (tx >= INT_MIN && tx <= INT_MAX) {
int ix = (int)tx;
printf("安全にキャストできました: %d\n", ix);
} else {
printf("範囲外のためキャスト不可: tx=%.0f\n", tx);
}
return 0;
}
範囲外のためキャスト不可: tx=-2147483649
精度の壁にも注意
doubleは約15〜17桁程度の有効桁数しか持ちません。
2の53乗を超える整数は1刻みで表現できないため、その領域では小数部が最初から失われていることがあります。
truncは動作しますが、入力の表現精度自体が有限である点は理解しておくと良いでしょう。
printfの書式 %fと%d
表示には%f(浮動小数点)と%d(int)を使い分けます。
// printf_format.c
#include <stdio.h>
#include <math.h>
int main(void) {
double x = 3.9;
double y = trunc(x); // 3.0
// 浮動小数点として出力
printf("浮動小数点: %.1f\n", y); // 小数1桁表示(3.0)
// 整数として扱いたいならキャストしてから
printf("整数として: %d\n", (int)y); // 3
// フォーマット指定のミス例(やってはいけない)
// printf("%d\n", y); // 型不一致 -> 未定義動作になり得る
return 0;
}
浮動小数点: 3.0
整数として: 3
よくあるミス
- %dでdoubleを出力しない(未定義動作になり得ます)
- 必要な桁数をフォーマットで明示(例:
%.1f,%.2f)
まとめ
truncは「小数部分を0に向かって切り捨てる」関数で、負の数でも常に0方向へ寄せます。
基本は#include <math.h>を行い、環境によっては-lmを付けてビルドします。
floatにはtruncf、doubleにはtrunc、long doubleにはtrunclを使い分けましょう。
小数第1位や第2位で切り捨てたい場合は、10や100でスケールしてtruncし、元に戻すのが定石です。
整数として扱う必要があるときは、範囲チェックをしてからキャストすることで、未定義動作を避けられます。
表示は%fと%dを正しく使い分け、フォーマット指定で見た目の桁数を整えると実務で扱いやすくなります。
