K&R 演習2-1 解答 (プログラミング言語C 第2版)

スポンサーリンク

鍛錬 300

K&R 演習2-1 解答 (プログラミング言語C 第2版)

char,short,int,long 変数の signed および unsigned の両方の型について,それらの範囲を決めるプログラムを,標準ヘッダからの適当な値を印字することと,直接計算することとの双方で書け。計算しようとすると困難であるが,各種の浮動小数点型の範囲を決定せよ。

B.W.カーニハン D.M.リッチー 石田晴久 訳 『プログラミング言語C 第2版 ANSI 規格準拠』, (共立出版, 2017), pp.45.

 
スポンサーリンク

PC環境

私のPC環境は、以下に示す通りです。

関連記事:Linux,Ubuntuのバージョンとアーキテクチャを確認する

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.1 LTS
Release:	18.04
Codename:	bionic
***@ubuntu:~/***/test/c$ arch
x86_64

gcc環境

私のgcc環境は、以下に示す通りです。

関連記事:Linux,gccのバージョンと、ターゲットプロセッサを確認する

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ gcc -dumpversion
7
***@ubuntu:~/***/test/c$ gcc -dumpmachine
x86_64-linux-gnu

標準ヘッダ

以下は、私の環境での、標準ヘッダ内容の一部を抜粋しています。

limits.h

signed char

/* Minimum and maximum values a `signed char' can hold.  */
#  define SCHAR_MIN	(-128)
#  define SCHAR_MAX	127

unsigned char

/* Maximum value an `unsigned char' can hold.  (Minimum is 0.)  */
#  define UCHAR_MAX	255

signed short

/* Minimum and maximum values a `signed short int' can hold.  */
#  define SHRT_MIN	(-32768)
#  define SHRT_MAX	32767

unsigned short

/* Maximum value an `unsigned short int' can hold.  (Minimum is 0.)  */
#  define USHRT_MAX	65535

signed int

/* Minimum and maximum values a `signed int' can hold.  */
#  define INT_MIN	(-INT_MAX - 1)
#  define INT_MAX	2147483647

unsigned int

/* Maximum value an `unsigned int' can hold.  (Minimum is 0.)  */
#  define UINT_MAX	4294967295U

signed long

/* Minimum and maximum values a `signed long int' can hold.  */
#  if __WORDSIZE == 64
#   define LONG_MAX	9223372036854775807L
#  else
#   define LONG_MAX	2147483647L
#  endif
#  define LONG_MIN	(-LONG_MAX - 1L)

unsigned long

/* Maximum value an `unsigned long int' can hold.  (Minimum is 0.)  */
#  if __WORDSIZE == 64
#   define ULONG_MAX	18446744073709551615UL
#  else
#   define ULONG_MAX	4294967295UL
#  endif

float.h

関連記事:C言語,float.h が配置されている場所を確認する

float

#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F
#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F
#define __FLT_MIN_EXP__ (-125)
#define __FLT_MAX_EXP__ 128

double

#define __DBL_MIN__ ((double)2.22507385850720138309023271733240406e-308L)
#define __DBL_MAX__ ((double)1.79769313486231570814527423731704357e+308L)
#define __DBL_MIN_EXP__ (-1021)
#define __DBL_MAX_EXP__ 1024

プログラム

以下は、各型の範囲を、標準ヘッダからの引用及び計算により印字するプログラム、kr_2_1.c です。

#include <stdio.h>
#include <limits.h>
#include <float.h>

void PrintChar(void);
void PrintShort(void);
void PrintInt(void);
void PrintLong(void);
void PrintFloat(void);
void PrintDouble(void);

int main(void)
{
	// char の範囲を印字
	printf("----------------------------------------\n");
	PrintChar();
	
	// short の範囲を印字
	printf("----------------------------------------\n");
	PrintShort();
	
	// int の範囲を印字
	printf("----------------------------------------\n");
	PrintInt();
	
	// long の範囲を印字
	printf("----------------------------------------\n");
	PrintLong();
	
	// float (浮動小数点)の範囲を印字
	printf("----------------------------------------\n");
	PrintFloat();
	
	// double (浮動小数点)の範囲を印字
	printf("----------------------------------------\n");
	PrintDouble();
	
	return 0;
}

// =====================================
// @brief  charについての範囲を印字する
// @param  無し
// @return 無し
// @note   無し
// =====================================
void PrintChar(void)
{
	signed char sc;
	unsigned char uc;
	int num_min;
	int num_max;
	int i;
	
	// 標準ヘッダから印字(signed char)
	printf("標準ヘッダから印字(signed char)\n");
	printf("signed char min = %d\n", SCHAR_MIN);
	printf("signed char max = %d\n", SCHAR_MAX);
	printf("\n");
	
	// 標準ヘッダから印字(unsigned char)
	uc = 0;
	printf("標準ヘッダから印字(unsigned char)\n");
	printf("unsigned char min = %d\n", uc);
	printf("unsigned char max = %d\n", UCHAR_MAX);
	printf("\n");
	
	// 計算して印字(signed char)
	sc = 0;
	num_min = 0;
	num_max = 0;
	for (i = 0; i < UCHAR_MAX; ++i) {
		++sc;
		if (sc < num_min)
			num_min = sc;
		if (sc > num_max)
			num_max = sc;
	}
	printf("計算して印字(signed char)\n");
	printf("signed char min (calc) = %d\n", num_min);
	printf("signed char max (calc) = %d\n", num_max);
	printf("\n");
	
	// 計算して印字(unsigned char)
	uc = 0;
	num_min = 0;
	num_max = 0;
	for (i = 0; i < UCHAR_MAX; ++i) {
		++uc;
		if (uc > num_max)
			num_max = uc;
	}
	printf("計算して印字(unsigned char)\n");
	printf("unsigned char min (calc) = %d\n", num_min);
	printf("unsigned char max (calc) = %d\n", num_max);
	printf("\n");
}

// ======================================
// @brief  shortについての範囲を印字する
// @param  無し
// @return 無し
// @note   無し
// ======================================
void PrintShort(void)
{
	signed short ss;
	unsigned short us;
	int num_min;
	int num_max;
	int i;
	
	// 標準ヘッダから印字(signed short)
	printf("標準ヘッダから印字(signed short)\n");
	printf("signed short min = %d\n", SHRT_MIN);
	printf("signed short max = %d\n", SHRT_MAX);
	printf("\n");
	
	// 標準ヘッダから印字(unsigned short)
	us = 0;
	printf("標準ヘッダから印字(unsigned short)\n");
	printf("unsigned short min = %u\n", us);
	printf("unsigned short max = %u\n", USHRT_MAX);
	printf("\n");
	
	// 計算して印字(signed short)
	ss = 0;
	num_min = 0;
	num_max = 0;
	for (i = 0; i < USHRT_MAX; ++i) {
		++ss;
		if (ss < num_min)
			num_min = ss;
		if (ss > num_max)
			num_max = ss;
	}
	printf("計算して印字(signed short)\n");
	printf("signed short min (calc) = %d\n", num_min);
	printf("signed short max (calc) = %d\n", num_max);
	printf("\n");
	
	// 計算して印字(unsigned short)
	us = 0;
	num_min = 0;
	num_max = 0;
	for (i = 0; i < USHRT_MAX; ++i) {
		++us;
		if (us > num_max)
			num_max = us;
	}
	printf("計算して印字(unsigned short)\n");
	printf("unsigned short min (calc) = %u\n", num_min);
	printf("unsigned short max (calc) = %u\n", num_max);
	printf("\n");
}

// ====================================
// @brief  intについての範囲を印字する
// @param  無し
// @return 無し
// @note   無し
// ====================================
void PrintInt(void)
{
	unsigned int ui;
	signed int si_min;
	signed int si_max;
	unsigned int ui_min;
	unsigned int ui_max;
	
	// 標準ヘッダから印字(signed int)
	printf("標準ヘッダから印字(signed int)\n");
	printf("signed int min = %d\n", INT_MIN);
	printf("signed int max = %d\n", INT_MAX);
	printf("\n");
	
	// 標準ヘッダから印字(unsigned int)
	ui = 0;
	printf("標準ヘッダから印字(unsigned int)\n");
	printf("unsigned int min = %u\n", ui);
	printf("unsigned int max = %u\n", UINT_MAX);
	printf("\n");
	
	// 計算して印字(signed int)
	si_min = INT_MAX;
	++si_min;
	si_max = INT_MIN;
	--si_max;
	printf("計算して印字(signed int)\n");
	printf("signed int min (calc) = %d\n", si_min);
	printf("signed int max (calc) = %d\n", si_max);
	printf("\n");
	
	// 計算して印字(unsigned int)
	ui_min = 0;
	ui_max = 0;
	--ui_max;
	printf("計算して印字(unsigned int)\n");
	printf("unsigned int min (calc) = %u\n", ui_min);
	printf("unsigned int max (calc) = %u\n", ui_max);
	printf("\n");
}

// =====================================
// @brief  longについての範囲を印字する
// @param  無し
// @return 無し
// @note   無し
// =====================================
void PrintLong(void)
{
	unsigned long ul;
	signed long sl_min;
	signed long sl_max;
	unsigned long ul_min;
	unsigned long ul_max;
	
	// 標準ヘッダから印字(signed long)
	printf("標準ヘッダから印字(signed long)\n");
	printf("signed long min = %ld\n", LONG_MIN);
	printf("signed long max = %ld\n", LONG_MAX);
	printf("\n");
	
	// 標準ヘッダから印字(unsigned long)
	ul = 0;
	printf("標準ヘッダから印字(unsigned long)\n");
	printf("unsigned long min = %lu\n", ul);
	printf("unsigned long max = %lu\n", ULONG_MAX);
	printf("\n");
	
	// 計算して印字(signed long)
	sl_min = LONG_MAX;
	++sl_min;
	sl_max = LONG_MIN;
	--sl_max;
	printf("計算して印字(signed long)\n");
	printf("signed long min (calc) = %ld\n", sl_min);
	printf("signed long max (calc) = %ld\n", sl_max);
	printf("\n");
	
	// 計算して印字(unsigned long)
	ul_min = 0;
	ul_max = 0;
	--ul_max;
	printf("計算して印字(unsigned long)\n");
	printf("unsigned long min (calc) = %lu\n", ul_min);
	printf("unsigned long max (calc) = %lu\n", ul_max);
	printf("\n");
}

// ======================================
// @brief  floatについての範囲を印字する
// @param  無し
// @return 無し
// @note   無し
// ======================================
void PrintFloat(void)
{
	float f_min;
	float f_max;
	float result;
	float exp;
	float i;
	
	// 標準ヘッダから印字(float)
	printf("標準ヘッダから印字(float)\n");
	printf("float min = %e\n", __FLT_MIN__);
	printf("float max = %e\n", __FLT_MAX__);
	printf("\n");
	
	// 標準ヘッダから印字(float(exp))
	printf("標準ヘッダから印字(float(exp))\n");
	printf("float min (exp) = %d\n", __FLT_MIN_EXP__);
	printf("float max (exp) = %d\n", __FLT_MAX_EXP__);
	printf("\n");
	
	// 計算して印字(float min)
	f_min = 2.0;
	exp = -126.0;
	i = exp;
	result = 1.0;
	while (i != 0) {
		result = result / f_min;
		++i;
	}
	printf("計算して印字(float)\n");
	printf("float min (calc) = %e\n", 1.0 * result);
	
	// 計算して印字(float max)
	f_max = 2.0;
	exp = 127.0;
	i = exp;
	result = 1.0;
	while (i != 0) {
		result = result * f_max;
		--i;
	}
	printf("float max (calc) = %e\n", 2.0 * result);
	printf("\n");
}

// =======================================
// @brief  doubleについての範囲を印字する
// @param  無し
// @return 無し
// @note   無し
// =======================================
void PrintDouble(void)
{
	double d_min;
	double d_max;
	long double result;
	double exp;
	double i;
	
	// 標準ヘッダから印字(double)
	printf("標準ヘッダから印字(double)\n");
	printf("double min = %e\n", __DBL_MIN__);
	printf("double max = %e\n", __DBL_MAX__);
	printf("\n");
	
	// 標準ヘッダから印字(double(exp))
	printf("標準ヘッダから印字(double(exp))\n");
	printf("double min (exp) = %d\n", __DBL_MIN_EXP__);
	printf("double max (exp) = %d\n", __DBL_MAX_EXP__);
	printf("\n");
	
	// 計算して印字(double min)
	d_min = 2.0;
	exp = -1022.0;
	i = exp;
	result = 1.0;
	while (i != 0) {
		result = result / d_min;
		++i;
	}
	printf("計算して印字(double)\n");
	printf("double min (calc) = %Le\n", 1.0 * result);
	
	// 計算して印字(double max)
	d_max = 2.0;
	exp = 1023.0;
	i = exp;
	result = 1.0;
	while (i != 0) {
		result = result * d_max;
		--i;
	}
	printf("double max (calc) = %Le\n", 2.0 * result);
	printf("\n");
}

実行結果

以下は、プログラム kr_2_1.c を実行して、各型の範囲を印字しています。

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ gcc -Wall -Wextra kr_2_1.c -o kr_2_1
***@ubuntu:~/***/test/c$ ./kr_2_1
----------------------------------------
標準ヘッダから印字(signed char)
signed char min = -128
signed char max = 127

標準ヘッダから印字(unsigned char)
unsigned char min = 0
unsigned char max = 255

計算して印字(signed char)
signed char min (calc) = -128
signed char max (calc) = 127

計算して印字(unsigned char)
unsigned char min (calc) = 0
unsigned char max (calc) = 255

----------------------------------------
標準ヘッダから印字(signed short)
signed short min = -32768
signed short max = 32767

標準ヘッダから印字(unsigned short)
unsigned short min = 0
unsigned short max = 65535

計算して印字(signed short)
signed short min (calc) = -32768
signed short max (calc) = 32767

計算して印字(unsigned short)
unsigned short min (calc) = 0
unsigned short max (calc) = 65535

----------------------------------------
標準ヘッダから印字(signed int)
signed int min = -2147483648
signed int max = 2147483647

標準ヘッダから印字(unsigned int)
unsigned int min = 0
unsigned int max = 4294967295

計算して印字(signed int)
signed int min (calc) = -2147483648
signed int max (calc) = 2147483647

計算して印字(unsigned int)
unsigned int min (calc) = 0
unsigned int max (calc) = 4294967295

----------------------------------------
標準ヘッダから印字(signed long)
signed long min = -9223372036854775808
signed long max = 9223372036854775807

標準ヘッダから印字(unsigned long)
unsigned long min = 0
unsigned long max = 18446744073709551615

計算して印字(signed long)
signed long min (calc) = -9223372036854775808
signed long max (calc) = 9223372036854775807

計算して印字(unsigned long)
unsigned long min (calc) = 0
unsigned long max (calc) = 18446744073709551615

----------------------------------------
標準ヘッダから印字(float)
float min = 1.175494e-38
float max = 3.402823e+38

標準ヘッダから印字(float(exp))
float min (exp) = -125
float max (exp) = 128

計算して印字(float)
float min (calc) = 1.175494e-38
float max (calc) = 3.402824e+38

----------------------------------------
標準ヘッダから印字(double)
double min = 2.225074e-308
double max = 1.797693e+308

標準ヘッダから印字(double(exp))
double min (exp) = -1021
double max (exp) = 1024

計算して印字(double)
double min (calc) = 2.225074e-308
double max (calc) = 1.797693e+308