C言語でべき乗を計算するには、標準ライブラリのmath.h
が提供するpow
関数を使います。
C言語にはべき乗演算子がないため、pow
の正しい使い方と注意点を知ることがとても重要です。
本記事では、基本的な使い方から型の扱い、よくある誤り、そして実行可能なサンプルまで丁寧に解説します。
powの基本
powとは?
pow
は、底(base)を指数(exponent)で累乗した結果を返す関数です。
形式はpow(base, exp)
で、戻り値はdouble
です。
たとえばpow(2.0, 3.0)
は8.0を返します。
C言語では^はべき乗ではなくビットXORなので、必ずpow
を使います。
#include <math.h> の書き方
pow
を使うには#include <math.h>
を記述します。
出力表示には#include <stdio.h>
も必要です。
// powの最小例: 2の10乗を表示
#include <stdio.h>
#include <math.h>
int main(void) {
double result = pow(2.0, 10.0); // 2^10
printf("2^10 = %.0f\n", result);
return 0;
}
2^10 = 1024
コンパイル方法
GCCやClangではリンク時に-lm
が必要です。
WindowsのMSVCでは不要です。
# GCC/Clang (Linux, macOSなど): -lmは末尾に付けるのが安全
gcc main.c -o pow_sample -lm
./pow_sample
# Clangの例
clang main.c -o pow_sample -lm
./pow_sample
# Windows (MSVC)
cl /W4 /EHsc main.c
.\main.exe
引数と戻り値
基本プロトタイプは次の通りです。
double pow(double x, double y);
float powf(float x, float y);
long double powl(long double x, long double y);
pow
はx
のy
乗を返します。
戻り値は浮動小数点であり、誤差やオーバーフロー、NaNやInfinityが起きる可能性があります。
負の底に小数指数などの定義域外ではNaNになります。
以下に簡単な対応表を示します。
関数 | 引数の型 | 戻り値の型 | 主な用途 |
---|---|---|---|
pow | double, double | double | 一般的な倍精度演算 |
powf | float, float | float | 単精度で統一したい場合 |
powl | long double, long double | long double | 高精度が必要な場合 |
基本の呼び出し(pow(base, exp))
最も基本的な使い方は、pow(底, 指数)
です。
指数に負数を渡せば逆数の計算になります。
#include <stdio.h>
#include <math.h>
int main(void) {
double a = pow(2.0, 5.0); // 2^5 = 32
double b = pow(2.0, -3.0); // 2^-3 = 1/8 = 0.125
double c = pow(9.0, 0.5); // 9^(1/2) = sqrt(9) = 3
printf("2^5 = %.0f\n", a);
printf("2^-3 = %.3f\n", b);
printf("9^0.5 = %.1f\n", c);
return 0;
}
2^5 = 32
2^-3 = 0.125
9^0.5 = 3.0
powの使い方と型の扱い
整数リテラルもdoubleに変換
pow
はdouble
を取るため、pow(2, 10)
のように整数リテラルを書いても、呼び出し時にdouble
へ自動変換されます。
可読性のため2.0
や10.0
のように小数点を付けることもあります。
#include <stdio.h>
#include <math.h>
int main(void) {
// いずれも内部的にはdouble演算です
double x = pow(2, 10); // intリテラル -> doubleへ変換
double y = pow(2.0, 10.0); // こちらは明示的にdouble
printf("pow(2, 10) = %.0f\n", x);
printf("pow(2.0, 10) = %.0f\n", y);
return 0;
}
pow(2, 10) = 1024
pow(2.0, 10) = 1024
結果をintにする
戻り値はdoubleなので、整数が欲しい場合は型変換が必要です。
ただし単純キャストは小数点以下を切り捨てます。
丸めたい場合はround
/lround
/llround
を使います。
また、結果が整数型の範囲に収まるか事前に確認してください。
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <limits.h>
int main(void) {
// 典型例: 2^10 は厳密に1024なので問題なし
double d1 = pow(2.0, 10.0);
int i1 = (int)d1; // 小数部分がなければそのまま
printf("2^10 -> (int)%d\n", i1);
// 注意例: 8^(1/3) は理論上2だが、powは1.999999...になる可能性
double d2 = pow(8.0, 1.0/3.0);
int i2_trunc = (int)d2; // 切り捨て -> 1 になるかもしれない
long long i2_round = llround(d2); // 最も近い整数へ丸め -> 2 になることを期待
printf("8^(1/3) = %.15f, (int) = %d, llround = %lld\n", d2, i2_trunc, i2_round);
// 安全のための範囲チェック: 丸める前に範囲を確認
double big = pow(10.0, 12.0); // 1e12 は long long に収まる
if (isfinite(big) && fabsl(big) <= (long double)LLONG_MAX) {
long long safely = llround(big);
printf("1e12 を llround -> %lld\n", safely);
} else {
printf("結果が整数型に収まりません\n");
}
return 0;
}
2^10 -> (int)1024
8^(1/3) = 1.999999999999999, (int) = 1, llround = 2
1e12 を llround -> 1000000000000
lround
やllround
は範囲外に丸めようとすると未定義動作になる可能性があります。
比較で範囲チェックをしてから使うと安全です。
大きな指数の限界
倍精度double
は約1e308までしか表現できません。
例えばpow(10.0, 400.0)
はオーバーフローで+Inf
になります。
逆に非常に小さい値はアンダーフローで0
になります。
#include <stdio.h>
#include <math.h>
int main(void) {
double of = pow(10.0, 400.0); // オーバーフロー -> +Inf
double uf = pow(10.0, -400.0); // アンダーフロー -> 0
double e2 = pow(2.0, 1024.0); // 2^1024 も通常は +Inf
printf("10^400 = %f, isinf = %d\n", of, isinf(of) != 0);
printf("10^-400 = %.1e\n", uf);
printf("2^1024 = %f, isinf = %d\n", e2, isinf(e2) != 0);
return 0;
}
10^400 = inf, isinf = 1
10^-400 = 0.0e+00
2^1024 = inf, isinf = 1
powf/powlの使い分け
型を統一すると精度と速度の両面で安定します。
float中心ならpowf
、long double中心ならpowl
を選び、混在しないようにします。
#include <stdio.h>
#include <math.h>
int main(void) {
float xf = 1.5f, yf = 3.0f;
float rf = powf(xf, yf); // 単精度
double xd = 1.5, yd = 3.0;
double rd = pow(xd, yd); // 倍精度
long double xl = 1.5L, yl = 3.0L;
long double rl = powl(xl, yl); // 拡張精度
printf("powf(1.5f, 3.0f) = %.6f\n", rf);
printf("pow(1.5, 3.0) = %.6f\n", rd);
printf("powl(1.5L, 3.0L) = %.6Lf\n", rl);
return 0;
}
powf(1.5f, 3.0f) = 3.375000
pow(1.5, 3.0) = 3.375000
powl(1.5L, 3.0L) = 3.375000
powの注意点とよくある誤り
^はべき乗ではない
^演算子はビットXORです。
べき乗で使うと間違った結果になります。
#include <stdio.h>
int main(void) {
int a = 2 ^ 3; // 2 XOR 3 = 1
printf("2 ^ 3 = %d (これはべき乗ではありません)\n", a);
return 0;
}
2 ^ 3 = 1 (これはべき乗ではありません)
負の底と小数の指数
負の底に非整数の指数は実数の範囲で定義できず、pow
はNaNになります。
実数の解が欲しい場合でもpow(-8.0, 1.0/3.0)
のような表現は移植性がありません。
立方根はcbrt
を使うと安全です。
#include <stdio.h>
#include <math.h>
int main(void) {
double r1 = pow(-8.0, 1.0/3.0); // 実装によってNaN
double r2 = cbrt(-8.0); // 立方根: -2 を返す
printf("pow(-8, 1/3) = %f, isnan = %d\n", r1, isnan(r1) != 0);
printf("cbrt(-8) = %f\n", r2);
return 0;
}
pow(-8, 1/3) = nan, isnan = 1
cbrt(-8) = -2.000000
整数の指数であれば負の底でも問題ありません。
例えばpow(-2.0, 3.0)
は-8を返します。
0の負の指数は不可
pow(0.0, 負の数)
は定義域外で、+Infになるのが一般的です。
除算による無限大のような扱いになります。
#include <stdio.h>
#include <math.h>
int main(void) {
double r = pow(0.0, -1.0); // 1 / 0.0 と同様の扱い
printf("0^-1 = %f, isinf = %d\n", r, isinf(r) != 0);
return 0;
}
0^-1 = inf, isinf = 1
丸め誤差で整数にならない
浮動小数点では「理論上は整数」でもぴったり表現できないことがあります。
pow(8.0, 1.0/3.0)
は2に近い値でも、(int)
で切り捨てると1になる場合があります。
整数にしたいなら丸め関数を使うか、整数べきは整数演算で計算するのが安全です。
#include <stdio.h>
#include <math.h>
int main(void) {
double v = pow(27.0, 1.0/3.0); // 3に近いが 2.999999... になる可能性
int bad = (int)v; // 切り捨て -> 2 になるかも
int good = (int)lround(v); // 丸め -> 3
printf("27^(1/3) = %.15f, (int) = %d, lround = %d\n", v, bad, good);
return 0;
}
27^(1/3) = 3.000000000000000, (int) = 3, lround = 3
実行環境によっては上の例で誤差が現れず、偶然きれいな3.0になることもあります。
誤差が出る可能性を常に考えることが大切です。
powサンプル集
2の10乗(pow(2, 10))
最も基本的な整数べきの例です。
#include <stdio.h>
#include <math.h>
int main(void) {
printf("2^10 = %.0f\n", pow(2.0, 10.0));
return 0;
}
2^10 = 1024
小数のべき乗(pow(1.5, 3))
小数の底と整数指数の組み合わせです。
#include <stdio.h>
#include <math.h>
int main(void) {
double ans = pow(1.5, 3.0); // 1.5^3 = 3.375
printf("1.5^3 = %.3f\n", ans);
return 0;
}
1.5^3 = 3.375
結果をintにキャスト
整数値が期待できる場合でも、丸めと範囲に注意します。
#include <stdio.h>
#include <math.h>
#include <limits.h>
int main(void) {
double val = pow(5.0, 3.0); // 125
int a = (int)val; // 小数なし -> そのまま125
int b = (int)lround(val); // 丸めても125
printf("5^3 = %f, (int) = %d, lround = %d\n", val, a, b);
// 範囲に注意 (例: 2^40 はintに収まらない)
double big = pow(2.0, 40.0); // 約1兆
printf("2^40 = %.0f -> intにキャストするとオーバーフローの危険\n", big);
return 0;
}
5^3 = 125.000000, (int) = 125, lround = 125
2^40 = 1099511627776 -> intにキャストするとオーバーフローの危険
関数内でpowを使う
たとえば複利計算など、関数内でpow
を用いると見通しが良くなります。
#include <stdio.h>
#include <math.h>
// 複利計算: 元本P, 年利r, 年数n -> P * (1 + r)^n
double compound(double principal, double rate, int years) {
return principal * pow(1.0 + rate, (double)years);
}
int main(void) {
double p = 100000.0; // 元本
double r = 0.03; // 年利3%
int n = 5; // 5年
double future = compound(p, r, n);
printf("元本%.0f円が年利%.1f%%で%d年後: %.2f円\n", p, r*100, n, future);
return 0;
}
元本100000円が年利3.0%で5年後: 115927.41円
まとめ
C言語でべき乗はpow
を使って計算します。
ヘッダはmath.h
で、GCCやClangではリンク時に-lm
が必要です。
戻り値は浮動小数点であり、丸め誤差、オーバーフロー/アンダーフロー、NaNの可能性を常に考慮します。
負の底に小数指数は避け、必要ならcbrt
やsqrt
などの専用関数を使いましょう。
整数が欲しい場合は、単純キャストではなく丸め関数と範囲チェックを組み合わせると安全です。
最後に、^はべき乗ではない点を忘れず、powf
やpowl
も含めて型を統一して使うことで、予期せぬ不具合を避けられます。