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