このページの解説は C99 をベースとしています。
以下は目次です。
ある整数の桁数を求めたいとします。整数は 10進数で考えます。
たとえば、以下のような結果を期待します。
実装の方法はいくつかありますが、正の数と負の数とでコードの切り分けが必要になるものがほとんどです。そこで、次のように、引数を unsigned にして正の数でしか渡せない仕様にしておきます。
/*
10進整数の桁数を求める
引数
n: 対象の整数
戻り値
n の桁数。0 は 1桁とみなす。
*/
unsigned int get_digit(unsigned int n);
これで、実装では正の数だけに集中できます。負の数の桁数を求めたいときは、呼び出し側が絶対値を渡すようにします(絶対値については「逆引き 絶対値を求める」を参照)。
int n = -123;
= get_digit(abs(n)); digit
シンプルな手法は、0 になるまで 10 で割り続け、割った回数をカウントする方法です。
#include <stdio.h>
#include <stdlib.h>
/*
10進整数の桁数を求める
引数
n: 対象の整数
戻り値
n の桁数。0 は 1桁とみなす。
*/
unsigned int get_digit(unsigned int n)
{
unsigned int digit = 1;
while (n /= 10) {
++digit;
};
return digit;
}
int main(void)
{
("%u\n", get_digit(1));
printf("%u\n", get_digit(123));
printf("%u\n", get_digit(abs(-1)));
printf("%u\n", get_digit(abs(-123)));
printf("%u\n", get_digit(0));
printf}
実行結果:
1
3
1
3
1
桁数を求めるための標準ライブラリ関数はありませんが、log10関数がこの目的に利用できます。log10関数は、math.h で以下のように宣言されています。
double log10(double x);
log10関数は、引数x の常用対数を返します。つまり、「x は 10 を何乗したものであるか」を求められます。引数x が 0 のときは 0 が返されます。
ただし、この関数は、整数の世界に留まるものではなく、引数も戻り値も浮動小数点数です。たとえば、次の3つに対して、
("%lf\n", log10(100));
printf("%lf\n", log10(300));
printf("%lf\n", log10(500)); printf
結果は次のようになります。
2.000000
2.477121
2.698970
小数点以下にも値がありますし、引数の値によって異なっていることもわかります。今欲しいのは、桁数として使える整数部分の値ですから、小数点以下は捨ててしまっていいです。
ただ、引数はすべて 3桁であるのに対して、結果の整数部分はどれも 2 になっており、目的の値よりも 1 小さいようです。なので、これらの結果を整数型に直し、さらに +1 してあつかう必要があります。
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
/*
10進整数の桁数を求める
引数
n: 対象の整数
戻り値
n の桁数。0 は 1桁とみなす。
*/
unsigned int get_digit(unsigned int n)
{
return (unsigned int)log10(n) + 1;
}
int main(void)
{
("%u\n", get_digit(1));
printf("%u\n", get_digit(123));
printf("%u\n", get_digit(abs(-1)));
printf("%u\n", get_digit(abs(-123)));
printf("%u\n", get_digit(0));
printf}
実行結果:
1
3
1
3
1
この方法は、管理者の環境で試すと(Windows10、VisualStudio 2017)、方法① よりも2倍ほど遅くなりました。
直観的ではですし、欠点が目立つ方法ですが、標準ライブラリ関数の sprintf関数を使う手法もあります。
sprintf関数は、printf関数と同様のルールで文字列をつくります。違うのは、出力先が標準出力ではなく、文字の配列であることです。
printf関数も sprintf関数も、出力できた文字数を返すという仕様です。そこで、桁数を知りたい整数を、“%u” の変換指定を使って sprintf関数を使って文字列に変換し、そのときに返される戻り値をみれば、それが元の整数の桁数になっています。
この方法は、sprintf関数が文字列を書き込むための配列を用意しなければならない欠点があります。可能性があるもっとも大きい桁数に応じて、十分な大きさの配列を用意しておかなければなりません。
#include <stdio.h>
#include <stdlib.h>
/*
10進整数の桁数を求める
引数
n: 対象の整数
戻り値
n の桁数。0 は 1桁とみなす。
*/
unsigned int get_digit(unsigned int n)
{
char s[32];
return sprintf(s, "%u", n);
}
int main(void)
{
("%u\n", get_digit(1));
printf("%u\n", get_digit(123));
printf("%u\n", get_digit(abs(-1)));
printf("%u\n", get_digit(abs(-123)));
printf("%u\n", get_digit(0));
printf}
実行結果:
1
3
1
3
1
この方法は、管理者の環境で試すと(Windows10、VisualStudio 2017)、方法① よりも10倍ほど遅くなりました。
return 0;
を削除(C言語編全体でのコードの統一)
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |