【C言語】値の特定の桁のみを取得する方法

値から特定の桁のみを取得する方法の解説ページアイキャッチ

このページでは、値から特定の桁のみを取得する方法について解説していきます。

この方法を知っておけば、例えば下記のように任意の値から特定の桁のみを取得することができるようになります。

  • 123456 から 13 桁目を取得:345
  • 123456 から 00 桁目を取得:6

最初は自然数に対して解説していきますが、後ほど小数点以下の桁を指定して取得する方法や、2進数や8進数で考えた場合の取得方法についても解説していきたいと思います!

自然数から特定の桁のみを取得する

では、特定の桁のみを取得する方法について解説していきます。

今後の説明が曖昧にならないように、まずは言葉の定義から整理していきたいと思います。

このページでは、1の位を 0 桁目として解説していきたいと思います。そして、この 0 桁目を基準として、そこから左側の桁ほど大きな桁、右側の桁ほど小さな桁として扱っていきたいと思います。

例えば10の位であれば 1 桁目、100の位であれば 2 桁目、小数第1位(10分の1の位)は -1 桁目、小数第2位(100分の1の位)は -2 桁目といった感じになります。

桁の表現の仕方の解説図

ですので、123.456 の値の -2 桁目から 1 桁目のみを取得した場合、結果は 2345 になることになります。

特定の桁の取得例

自然数から特定の桁のみを取得する方法

では、ここからは値から取得する桁を m 桁目 〜 n 桁目(m ≦ n)として解説していきたいと思います。

まずは自然数(0 を含めた自然数)から特定の桁のみを取得する方法を解説していきます。

自然数から m 桁目 〜 n 桁目を取得するためには下記の3つの処理を行えば良いです。

  1. 値を 10 の n + 1 乗で剰余算する
  2. 1. の結果を 10 の m 乗で除算する
  3. 2. の結果の小数点以下を切り捨てる

値を 10 の n + 1 乗で剰余算することで、その値の 0 桁目 〜 n 桁目のみを取得することができます。

剰余算により値の0からn桁目のみを取得する様子

さらにその結果に対して 10 の m 乗の値で除算すれば、除算前に比べて各桁が右側(小さい方)に m 桁分シフトすることになります。つまり、m 桁目 〜 n 桁目のみが整数部に残ることになります(0 桁目 〜 m - 1 桁目は小数部に移動する)。

除算により値のmからn桁目のみが整数部に残る様子

ですので、後はその結果の小数点以下を切り捨ててやれば、元々の値の m 桁目 〜 n 桁目のみを取得した結果を得ることができます。

小数点以下を捨てることにより値のmからn桁目のみを取得する様子

ここで説明した下記の3つを利用すれば、小数点以下の特定の桁の取得や、10進数以外の進数の値の特定の桁の取得も行うことができます。

  • 剰余算
  • 桁のシフト
  • 小数点以下の切り捨て

スポンサーリンク

自然数から特定の桁のみを取得する関数

上記のように処理を行なって自然数から特定の桁のみを取得する関数は、下記における getDigits のように記述することができます。

自然数の特定の桁のみ取得する
#include <stdio.h>
#include <math.h> /* pow */

/*****************************
 * valueのm桁目からn桁目を取得する
 * value:取得先となる自然数
 * m:取得を開始する桁
 * n:取得を終了する桁
 * 返却値:取得した桁(整数)
 * ****************************/
int getDigits(int value, int m, int n) {
    int mod_value;
    int result;

    /* n桁目以下の桁を取得 */
    mod_value = value % (int)pow(10, n + 1);

    /* m桁目以上の桁を取得 */
    result = mod_value / pow(10, m);

    return result;

}

int main(void) {
    int result;

    /* 123456の3桁目〜4桁目を取得する */
    result = getDigits(123456, 3, 4);

    printf("%d\n", result);

    return 0;
}

第1引数 value に桁の取得先となる自然数を指定し、さらに第2引数 m と第3引数 n で取得したい桁を指定して getDigits を実行すれば、valuem 桁目 〜 n 桁目のみの値を戻り値として取得することができます。

getDigits 関数で使用している pow は、第1引数の値を第2引数の値で冪乗する関数になります。pow を使用する際は math.h をインクルードする必要があります。

また、pow の返却値は double 型の浮動小数点数であることに注意してください。

剰余算を行う % 演算子では、左辺と右辺の値の両方が整数である必要があります。ですので、剰余算を行うときに下記のように記述してしまうと、右辺が浮動小数点数の値になるのでコンパイル時にエラーが発生します。

浮動小数点数との剰余算
mod_value = value % pow(10, n + 1);

このエラーが発生しないように、上記の getDigits では pow 関数の結果を int 型でキャストしてから剰余算を行うようにしています((int)pow(10, n+1) と記述すれば、pow 関数の結果が int 型として扱われる)。

また、前述で紹介した切り捨て処理を行なっている箇所がありませんが、C言語 では 整数 / 整数 の結果は自動的に小数点以下が切り捨てられた整数となりますので、mod_value / (int)pow(10, m) の処理で自動的に小数点以下が切り捨てられていることになります。

負の整数から特定の桁のみを取得する関数

もし負の整数も扱えるようにしたいのであれば、その負の整数の絶対値を求めてから特定の桁を取得するようにしていけば良いです。

絶対値を取得する方法については下記ページでまとめていますので詳しく知りたい方は下記ページ後を参照いただければと思います。

C言語で絶対値を求める方法の解説ページアイキャッチ【C言語】絶対値を求める方法(abs関数の利用・関数使わない・マクロなど)

要は、int 型の変数の絶対値は abs 関数により算出できますので、下記のように事前に abs 関数で絶対値を求めてから計算を行なっていくようにすれば良いです(abs 関数を使用するには stdlib.h をインクルードする必要があります)。

/*****************************
 * valueのm桁目からn桁目を取得する
 * value:取得先となる整数
 * m:取得を開始する桁
 * n:取得を終了する桁
 * 返却値:取得した桁(整数)
 * ****************************/
int getDigits(int value, int m, int n) {
    int mod_value;
    int result;

    /* 絶対値を求める */
    value = abs(value);

    /* n桁目以下の桁を取得 */
    mod_value = value % (int)pow(10, n);

    /* m桁目以上の桁を取得 */
    result = mod_value / pow(10, m - 1);

    return result;

}

小数点以下も含めて取得する

では、次は小数点以下も含めて特定の桁を取得する方法について解説していきます。

スポンサーリンク

小数点以下も含めて特定の桁のみを取得する方法

考え方は自然数の時と同様で、m 桁目 〜 n 桁目のみを取得したい場合、下記の3つの処理を行えば良いです。

  1. 値を 10 の n + 1 乗で剰余算する
  2. 1. の結果を 10 の m 乗で除算する
  3. 2. の結果の小数点以下を切り捨てる

ただし、今回は小数点以下の値も扱うため、桁の取得先となる値は浮動小数点数である必要があります(先程紹介した getDigits 関数の第1引数 valuedouble 型 or float 型となる)。

さらに、% 演算子では浮動小数点数に対する剰余演算を行うことはできません。これを行うとコンパイル時にエラーになります。

したがって、下記のように単に getDigits 関数の第1引数 valuedouble 型や float 型に変えるだけだとコンパイル時にエラーが出てしまいます(value に対して剰余演算子を使ってはダメ)。

コンパイルエラーが発生するgetDigits
int getDigits(double value, int m, int n) {
    int mod_value;
    int result;

    /* n桁目以下の桁を取得 */
    mod_value = value % (int)pow(10, n + 1);

    /* m桁目以上の桁を取得 */
    result = mod_value / pow(10, m);

    return result;

}

ですので、今回の場合、そのまま % 演算子を使うのは NG です。

C言語 においては、浮動小数点数に対して剰余算を行うための関数 fmod が存在するので、今回はこの関数を利用して剰余算を行なっていきたいと思います。

ただ、fmod 関数の場合、浮動小数点数の誤差によって思わぬ結果が算出されることがあるので注意が必要です(本当であれば整数化してから剰余演算子 % により剰余算を求める方が良い)。

この辺りの解説は下記ページで解説していますので、詳しく知りたい方は下記ページを参照していただければと思います。

浮動小数点数に対して剰余演算を行う方法の解説ページアイキャッチ【C言語】浮動小数点数に対して剰余演算を行う方法(fmodや自力で演算など)

剰余算をfmod 関数で行うようにすれば、あとは自然数の時と同様に下記を実行するだけで、小数点以下も含めた特定の桁の取得を行うことができるようになります。

  1. 値を 10 の n + 1 乗で剰余算する
  2. 1. の結果を 10 の m 乗で除算する
  3. 2. の結果の小数点以下を切り捨てる

小数点以下も含めて特定の桁のみを取得する関数

以上の解説を踏まえて特定の桁の取得を行う関数は、下記の getDigits 関数のように記述することができます。

小数点以下も含めて特定の桁のみ取得する
#include <stdio.h>
#include <math.h> /* pow */

/*****************************
 * valueのm桁目からn桁目を取得する
 * value:取得先となる浮動小数点数
 * m:取得を開始する桁
 * n:取得を終了する桁
 * 返却値:取得した桁(整数)
 *****************************/
int getDigits(double value, int m, int n) {
    double mod_value;
    int result;

    /* 事前に絶対値を求めておく */
    value = fabs(value);

    /* n桁目以下の桁を取得 */
    mod_value = fmod(value, pow(10, n + 1));

    /* m桁目以上の桁を取得 */
    result = mod_value / pow(10, m);

    return result;
}

int main(void) {

    int result;

    result = getDigits(54321.123, -2, 3);

    printf("%d\n", result);

    return 0;
}

getDigits 関数の第1引数 value には浮動小数点数を指定することが可能になっていますが、そのほかの関数の使用方法等は 自然数から特定の桁のみを取得する関数 と同じです。

また、上記の getDigits 関数では負の浮動小数点数も扱えるように、第1引数 valuefabs 関数により絶対値に変換してから、特定の桁の取得を行う処理を開始するようにしています。

他の進数で考えた場合の特定の桁のみを取得する

最後に、10進数の値を他の進数で考えた場合の特定の桁を取得する方法について解説していきます。

例えば10進数の 345 は2進数表記では下記のようになります。

101011001

この時の 3 桁目 〜 6 桁目を取得した場合の結果は下記のようになります(桁の数え方は 自然数から特定の桁のみを取得する の最初で説明した通りとします)。

1011

また、10進数の 54321 は16進数表記では下記のようになります。

D431

この時の 2 桁目 〜 3 桁目を取得した場合の結果は下記のようになります。

D4

スポンサーリンク

他の進数で考えた場合の特定の桁のみを取得する方法

なんだか難しそうですが、実は 自然数から特定の桁のみを取得する で紹介した自然数から特定の桁のみを取得する方法とほぼ同様の手順でこれらを実現することができます。

10進数の自然数から m 桁目 〜 n 桁目のみを取得したい場合は下記の3つの処理を行う必要がありました。

  1. 値を 10 の n + 1 乗で剰余算する
  2. 1. の結果を 10 の m 乗で除算する
  3. 2. の結果の小数点以下を切り捨てる

これに対し、10進数の自然数を他の進数(その進数を B 進数とします)で考えた時の m 桁目 〜 n 桁目のみを取得したい場合に行う処理は下記の通りになります。

  1. 値を B の n + 1 乗で剰余算する
  2. 1. の結果を B の m 乗で除算する
  3. 2. の結果の小数点以下を切り捨てる
  4. 3. の結果を B 進数表記にする

1. と 2. の処理に関しては、10進数から特定の桁のみを取得する場合に 10 の冪乗の値を用いて行なっていたところを  B の冪乗の値を用いるように変更すれば良いだけです。

さらに、3. の処理は10進数の自然数から特定の桁のみを取得する場合と全く同じになります。

これはつまり、値を B の n + 1 乗で剰余算を行うということは、B 進数表記した値の 0 桁目 〜 n 桁目のみを取得する処理と同等であり、さらに剰余算結果に対して B の m 乗で除算を行って小数点以下を切り捨てるということは、B 進数表記した値の m 桁目 〜 n 桁目のみを取得する処理と同等であると考えることができることを意味します。

345を2進数で考えた時の特定の桁を取得する流れの説明図

ただし、上記の処理で取得できる値は10進数の値になるので、最後に 4. で、それを B 進数表記に変換する必要があります。

この方法については下記ページで解説していますので、10進数の値を他の進数に変換する方法を詳しく知りたい方は下記ページを参照していただければと思います。

おそらく下記ページを読んでいただければ、B 進数に関しても剰余算と除算により特定の桁が取得できるメカリズムを理解していただけると思います(下記ページでは B 進数を N 進数と読んでいるので注意してください)。

10進数からN進数への変換方法の解説ページアイキャッチ【C言語】10進数をN進数に変換する

ここでは、上記ページの プログラムのソースコード で紹介している DectoN 関数を使用して、10進数の値を特定の進数表記に変換することとしたいと思います。

DectoN 関数を利用する場合、下記の配列や関数等も必要になるので、必要に応じてこれらも上記ページの プログラムのソースコード からコピペしてください。

  • 関数 reverse
  • 配列 coef

他の進数で考えた場合の特定の桁のみを取得する関数

ここまでの解説を踏まえて作成した、他の進数で考えた場合の特定の桁のみを取得する関数は下記の getDigits になります。

他の進数で考えた場合の特定の桁のみ取得する
#include <stdio.h>
#include <math.h> /* pow */
#include <stdlib.h> /* abs */

/* unsigned intのビット数 */
#define MAX_NUM_DIGITS 32

/* 係数を文字に変換するテーブル */
const char coef[36] = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
    'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
    'U', 'V', 'W', 'X', 'Y', 'Z'
};

/* num文字の文字列の並びを逆順にする */
void reverse(char ans[], int num) {
    int i;
    char tmp;

    for (i = 0; i < num / 2; i++) {
        tmp = ans[i];
        ans[i] = ans[num - 1 - i];
        ans[num - 1 - i] = tmp;
    }
}

/* 10進数decをn進数に変換して結果をansに格納する */
void DectoN(char ans[], unsigned int dec, unsigned int n) {

    unsigned int i;
    unsigned int digit_num;

    if (n > 36 || n < 2) {
        /* 対応しているのは2進数から36進数まで */
        return;
    }
    
    i = 0;
    while (dec > 0) {
        /* i桁目の係数を求める */
        digit_num = dec % n;

        /* 文字に変換 */
        ans[i] = coef[digit_num];
        
        /* n進数で1桁分桁下げ */
        dec = dec / n;

        /* 次に求める係数の桁 */
        i++;
    }

    /* 最後にヌル文字をつける */
    ans[i] = '\0';

    /* 文字列の並びを逆順にする */
    reverse(ans, i);

}

/*****************************
 * valueのm桁目からn桁目を取得する
 * ans:取得した桁を格納する配列
 * value:取得先となる整数
 * m:取得を開始する桁
 * n:取得を終了する桁
 * base:基数
 * ****************************/
void getDigits(char ans[], int value, int m, int n, unsigned int base) {
    int mod_value;
    unsigned int result;
    unsigned int unsigned_value;

    /* 負の値は正の値に変換 */
    unsigned_value = abs(value);

    /* n桁目以下の桁を取得 */
    mod_value = unsigned_value % (int)pow(base, n + 1);

    /* m桁目以上の桁を取得 */
    result = mod_value / pow(base, m);

    /* 取得した桁をbase進数に変換 */
    DectoN(ans, result, base);
}

int main(void) {

    int result;
    char ans[MAX_NUM_DIGITS + 1];

    getDigits(ans, 54321, 2, 3, 16);

    printf("%s\n", ans);

    return 0;
}

引数や返却値が 自然数から特定の桁のみを取得する関数 で紹介した getDigits 関数のものとは異なるので注意してください。

この getDigits 関数での変換結果は文字列になります。これは、10進数を超える進数の場合、文字を扱う必要があるためです。

そのため、その変換結果の文字列を格納するための配列を第一引数の ans で受け取るようにしています。

また引数 base により、どの進数に変換するのかを関数実行側から指定できるようにしています。

例えば引数 base16 であれば16進数に変換した結果が ans に格納されることになります。

関数内で行なっている処理は主に下記の4つになります(負の整数も扱えるように事前に abs 関数の実行も行っています)。

  1. 値を B の n + 1 乗で剰余算する
  2. 1. の結果を B の m 乗で除算する
  3. 2. の結果の小数点以下を切り捨てる
  4. 3. の結果を B 進数表記にする

4. に関しては前述の DectoN 関数を利用して行なっています。この関数の中で、第1引数 ans に 3. の結果を引数 base で指定された進数に変換した結果が格納されます。

DectoN 関数では、変換先の進数は2進数から36進数のみとなりますので、getDigits 関数に関しても base が 236 以外の場合は桁の取得が出来ないので注意してください。

また、DectoN 関数が使用している reversecoef に関しては、前述の通り下記ページの プログラムのソースコード で紹介しているものになります。

10進数からN進数への変換方法の解説ページアイキャッチ【C言語】10進数をN進数に変換する

まとめ

このページでは、値の特定の桁のみを取得する方法について解説しました!

特定の桁の取得先としては、主に「自然数のみ」「小数点以下も含めて」「10進数以外」のパターンについて解説しましたが、いずれにおいてもポイントになるのが除算と剰余算です。

基数(B 進数における B の値)の冪乗による除算を行うことで、値の各桁をシフトさせて不要な桁を整数部から追い出したり必要な桁を整数部に移動することができます。

除算の効果を示す図

今回は除算を中心に解説しましたが、乗算でも同様に桁のシフトを行うことが可能です。

また剰余算を行うことで 0 桁目から必要な桁のみを取得するようなことも可能です。逆に考えれば、剰余算では不要な桁を全て 0 にする処理とも捉えることができます。

剰余算の効果を示す図

例えば前述でも紹介した下記ページでの “10進数から N 進数への変換” も、結局は上記の考え方を応用したものになります。

10進数からN進数への変換方法の解説ページアイキャッチ【C言語】10進数をN進数に変換する

このあたりの除算(もしくは乗算)によるシフトや剰余算による不要な桁を 0 にするような使い方はいろんなところで活躍しますので、是非覚えておいてください!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です