計画と改善

エンジニアのブログ

16進数から10進数、2進数から10進数への変換プログラムを作った(C言語)

C言語本格入門にて16進数の最大値である0xffffffffは10進数で4,294,967,295との記載があったが、それを確かめるのにブラウザツールや電卓で計算しては学習にならないと思い、せっかくなので計算するプログラムを書いてみた。

16進数から10進数に変換

16進数から10進数への変換は仮数x基数^重み付けを使って計算する。今回の場合だとFは10進数の15なので(15 * 16 ^ 7 )+ (15 * 16 ^ 6) + (15 * 16 ^ 5) … (15 * 16 ^ 0)のように各桁に重みづけをしてその合計を算出し、10進数に変換する。完成したのは以下のプログラム(convert.c)

#include <stdio.h>
#include <math.h>

int
main(int argc, char *argv[])
{
        int sum = 0;
        printf("sum = %d\n", sum);
        for(int i = 0; i < 8; i++) {
                double pow_sum = pow(16 , i);
                printf("pow_sum = %lf\n", pow_sum);
                sum += 15 * pow_sum;
                printf("sum = sum + 15 * pow_sum;\n");
                printf("sum = %d\n", sum);
        }
        printf("%s\n", "-----------------------sum------------------");
        printf("%d\n", sum);

}

pow関数は累乗の計算ができる関数。第一引数にa、第二引数にbを入れるとaのb乗となる。

ビルドする用のMakefile

PROGRAM = convert
OBJS = convert.o
SRCS = $(OBJS:%.o=%.c)
CC = gcc
CFLAGS = -g -Wall
LDFLAGS =
LDLIBS = -lm

$(PROGRAM):$(OBJS)
        $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LDLIBS)

上記のプログラムをビルド

root@xxx:~/studyc/project# make
gcc -g -Wall   -c -o convert.o convert.c
gcc -g -Wall  -o convert convert.o -lm

実行

root@xxx:~/studyc/project# ./convert
sum = 0
pow_sum = 1.000000
sum = sum + 15 * pow_sum;
sum = 15
pow_sum = 16.000000
sum = sum + 15 * pow_sum;
sum = 255
pow_sum = 256.000000
sum = sum + 15 * pow_sum;
sum = 4095
pow_sum = 4096.000000
sum = sum + 15 * pow_sum;
sum = 65535
pow_sum = 65536.000000
sum = sum + 15 * pow_sum;
sum = 1048575
pow_sum = 1048576.000000
sum = sum + 15 * pow_sum;
sum = 16777215
pow_sum = 16777216.000000
sum = sum + 15 * pow_sum;
sum = 268435455
pow_sum = 268435456.000000
sum = sum + 15 * pow_sum;
sum = -2147483648 //オーバーフロー!!
------------------sum------------------
-2147483648

よく考えたらint型にこんなに大きな数字は入らないのだった。unsigned int型でも入るが、今回は試しにlong型を使うとする。(Debian GNU/Linux 11 (bullseye)環境)

#include <stdio.h>
#include <math.h>

int
main(int argc, char *argv[])
{
        long sum = 0;
        printf("sum = %ld\n", sum);
        for(int i = 0; i < 8; i++) {
                double pow_sum = pow(16 , i);
                printf("pow_sum = %lf\n", pow_sum);
                sum += 15 * pow_sum;
                printf("sum = sum + 15 * pow_sum;\n");
                printf("sum = %ld\n", sum);
        }
        printf("%s\n", "------------------sum------------------");
        printf("%ld\n", sum);
}

書き直してからビルド

root@xxx:~/studyc/project# make
gcc -g -Wall   -c -o convert.o convert.c
gcc -g -Wall  -o convert convert.o -lm

実行

root@xxx:~/studyc/project# ./convert
sum = 0
pow_sum = 1.000000
sum = sum + 15 * pow_sum;
sum = 15
pow_sum = 16.000000
sum = sum + 15 * pow_sum;
sum = 255
pow_sum = 256.000000
sum = sum + 15 * pow_sum;
sum = 4095
pow_sum = 4096.000000
sum = sum + 15 * pow_sum;
sum = 65535
pow_sum = 65536.000000
sum = sum + 15 * pow_sum;
sum = 1048575
pow_sum = 1048576.000000
sum = sum + 15 * pow_sum;
sum = 16777215
pow_sum = 16777216.000000
sum = sum + 15 * pow_sum;
sum = 268435455
pow_sum = 268435456.000000
sum = sum + 15 * pow_sum;
sum = 4294967295
------------------sum------------------
4294967295

ちゃんと4294967295になっていることが確認できた。

2進数から10進数に変換

2進数からの変換も先ほどと同様にこのプログラムで行える。long型でもできるが、今回は試しにunsinged int型を利用して変換を行うものとする。 16進数の0xffffffffは2進数に直すには1つのfが1111なのでそれを8つ並べた11111111111111111111111111111111となる。 そのため(1 * 2 ^ 31 )+ (1 * 2 ^ 6) + (1 * 2 ^ 5) … (1 * 2 ^ 0)を計算すれば良い。

#include <stdio.h>
#include <math.h>

int
main(int argc, char *argv[])
{
        unsigned int sum = 0;
        printf("sum = %u\n", sum);
        for(int i = 0; i < 32; i++) {
                double pow_sum = pow(2 , i);
                printf("pow_sum = %lf\n", pow_sum);
                sum += 1 * pow_sum;
                printf("sum = sum + 1 * pow_sum;\n");
                printf("sum = %u\n", sum);
        }
        printf("%s\n", "-----------------------sum------------------");
        printf("%u\n", sum);
}

ビルドを行う

root@xxx:~/studyc/project# make
gcc -g -Wall   -c -o convert.o convert.c
gcc -g -Wall  -o convert convert.o -lm

実行

root@xxx:~/studyc/project# ./convert
sum = 0
pow_sum = 1.000000
sum = sum + 1 * pow_sum;
sum = 1
pow_sum = 2.000000
sum = sum + 1 * pow_sum;
sum = 3
pow_sum = 4.000000
sum = sum + 1 * pow_sum;
sum = 7
pow_sum = 8.000000
sum = sum + 1 * pow_sum;
sum = 15
pow_sum = 16.000000
sum = sum + 1 * pow_sum;
sum = 31
pow_sum = 32.000000
sum = sum + 1 * pow_sum;
sum = 63
pow_sum = 64.000000
sum = sum + 1 * pow_sum;
sum = 127
pow_sum = 128.000000
sum = sum + 1 * pow_sum;
sum = 255
pow_sum = 256.000000
sum = sum + 1 * pow_sum;
sum = 511
pow_sum = 512.000000
sum = sum + 1 * pow_sum;
sum = 1023
pow_sum = 1024.000000
sum = sum + 1 * pow_sum;
sum = 2047
pow_sum = 2048.000000
sum = sum + 1 * pow_sum;
sum = 4095
pow_sum = 4096.000000
sum = sum + 1 * pow_sum;
sum = 8191
pow_sum = 8192.000000
sum = sum + 1 * pow_sum;
sum = 16383
pow_sum = 16384.000000
sum = sum + 1 * pow_sum;
sum = 32767
pow_sum = 32768.000000
sum = sum + 1 * pow_sum;
sum = 65535
pow_sum = 65536.000000
sum = sum + 1 * pow_sum;
sum = 131071
pow_sum = 131072.000000
sum = sum + 1 * pow_sum;
sum = 262143
pow_sum = 262144.000000
sum = sum + 1 * pow_sum;
sum = 524287
pow_sum = 524288.000000
sum = sum + 1 * pow_sum;
sum = 1048575
pow_sum = 1048576.000000
sum = sum + 1 * pow_sum;
sum = 2097151
pow_sum = 2097152.000000
sum = sum + 1 * pow_sum;
sum = 4194303
pow_sum = 4194304.000000
sum = sum + 1 * pow_sum;
sum = 8388607
pow_sum = 8388608.000000
sum = sum + 1 * pow_sum;
sum = 16777215
pow_sum = 16777216.000000
sum = sum + 1 * pow_sum;
sum = 33554431
pow_sum = 33554432.000000
sum = sum + 1 * pow_sum;
sum = 67108863
pow_sum = 67108864.000000
sum = sum + 1 * pow_sum;
sum = 134217727
pow_sum = 134217728.000000
sum = sum + 1 * pow_sum;
sum = 268435455
pow_sum = 268435456.000000
sum = sum + 1 * pow_sum;
sum = 536870911
pow_sum = 536870912.000000
sum = sum + 1 * pow_sum;
sum = 1073741823
pow_sum = 1073741824.000000
sum = sum + 1 * pow_sum;
sum = 2147483647
pow_sum = 2147483648.000000
sum = sum + 1 * pow_sum;
sum = 4294967295
-----------------------sum------------------
4294967295

こちらも4294967295になっていることが確認できた。