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
になっていることが確認できた。