Напишите программу, которая будет выдавать диапазоны значений типов char, short, int и long, описанных как signed и как unsigned, с помощью печати соответствующих значений из стандартных заголовочных файлов и путем прямого вычисления. Определите диапазоны чисел с плавающей точкой различных типов. Вычислить эти диапазоны сложнее.
INT_MAX – максимально возможное значение типа signed int
UINT_MAX – максимально возможное значение типа unsigned int
...
Как видно из примера наше большое число не уменьшилось на единицу. И я пока не знаю, чем объясняется такое поведение.
Write a program to determine the ranges of char, short, int, and long variables, both signed and unsigned, by printing appropriate values from standard headers and by direct computation. Harder if you compute them: determine the ranges of the various floating-point types.
Информация о свойствах основных арифметических типов, таких как размер, содержится в двух заголовочных файлах <limits.h> (объявляются макросы для целых типов) и <float.h> (объявляются макросы для типов с плавающей точкой). Фактические свойства типов зависят от реализации.
Информация о свойствах основных арифметических типов, таких как размер, содержится в двух заголовочных файлах <limits.h> (объявляются макросы для целых типов) и <float.h> (объявляются макросы для типов с плавающей точкой). Фактические свойства типов зависят от реализации.
Свойства целых типов:
CHAR_MIN – минимально возможное значение типа signed char
CHAR_MAX – максимально возможное значение типа signed char
UCHAR_MAX – максимально возможное значение типа unsigned char
SHRT_MIN – минимально возможное значение типа signed short
SHRT_MAX – максимально возможное значение типа signed short
USHRT_MAX – максимально возможное значение типа unsigned short
INT_MIN – минимально возможное значение типа signed intINT_MAX – максимально возможное значение типа signed int
UINT_MAX – максимально возможное значение типа unsigned int
LONG_MIN – минимально возможное значение типа signed long
LONG_MAX – максимально возможное значение типа signed long
ULONG_MAX – минимально возможное значение типа unsigned long
LONG_MAX – максимально возможное значение типа signed long
ULONG_MAX – минимально возможное значение типа unsigned long
Свойства типов с плавающей точкой:
FLT_MIN – минимально возможное значение типа float
FLT_MAX – максимально возможное значение типа float
DBL_MIN – минимально возможное значение типа double
DBL_MIN – минимально возможное значение типа double
DBL_MAX – максимально возможное значение типа double
LDBL_MIN – минимально возможное значение типа long double
LDBL_MAX – максимально возможное значение типа long doubleLDBL_MIN – минимально возможное значение типа long double
Для выполнения первой части упражнения достаточно вывести на экран значения, указанных выше свойств типов данных. Но на этапе компиляции программы я столкнулся со следующими предупреждениями:
ex_2_1.c: In function 'main':
ex_2_1.c:21: warning: format '%d' expects type 'int', but argument 2 has type 'long int'
ex_2_1.c:21: warning: format '%d' expects type 'int', but argument 3 has type 'long int'
ex_2_1.c:22: warning: format '%d' expects type 'int', but argument 2 has type 'long unsigned int'
...
21. printf("Переменные типа \'signed long int\' принимают значения в диапазоне от %d до %d\n", LONG_MIN, LONG_MAX);
22. printf("Переменные типа \'unsigned long int\' принимают значения в диапазоне от 0 до %d\n", ULONG_MAX);
...
Выходит, что спецификатор %d не подходит для выдачи аргументов в виде типов long int и long unsigned int. А спецификатор %f подходит только для типа float. Ниже я подготовил таблицу соответствия типов данных их спецификаторам:
signed char – %d
unsigned char – %d
signed short int – %d
unsigned short int – %d
signed int – %d
unsigned int – %u
signed long int – %ld
unsigned long int – %lu
float – %f
double – %lf
long double – %Lf
long long int – %lld
#include <stdio.h>
#include <limits.h>
#include <float.h>
#include <math.h>
int main()
{
int max_char; /* Максимальное значение для переменной типа char */
max_char = 0;
int max_short; /* Максимальное значение для переменной типа short int */
max_short = 0;
long long int max_int; /* чтобы поместилось максимальное значение типа (unsigned long int + 1) */
max_int = 0;
int i; /* максимальное значение переменной целочисленного типа */
int j; /* минимальное значение переменной целочисленного типа */
i = j = 0;
printf("1. Данные берем из заголовочного файла <limits.h>\n");
printf("Переменные типа \'signed char\' принимают значения в диапазоне от %d до %d\n", CHAR_MIN, CHAR_MAX);
printf("Переменные типа \'unsigned char\' принимают значения в диапазоне от 0 до %d\n", UCHAR_MAX);
printf("Переменные типа \'signed short int\' принимают значения в диапазоне от %d до %d\n", SHRT_MIN, SHRT_MAX);
printf("Переменные типа \'unsigned short int\' принимают значения в диапазоне от 0 до %d\n", USHRT_MAX);
printf("Переменные типа \'signed int\' принимают значения в диапазоне от %d до %d\n", INT_MIN, INT_MAX);
printf("Переменные типа \'unsigned int\' принимают значения в диапазоне от 0 до %u\n", UINT_MAX);
printf("Переменные типа \'signed long int\' принимают значения в диапазоне от %ld до %ld\n", LONG_MIN, LONG_MAX);
printf("Переменные типа \'unsigned long int\' принимают значения в диапазоне от 0 до %lu\n", ULONG_MAX);
printf("Переменные типа \'float\' принимают значения в диапазоне от %.0f до %f\n", FLT_MIN, FLT_MAX);
printf("Переменные типа \'double\' принимают значения в диапазоне от %.0lf до %lf\n", DBL_MIN, DBL_MAX);
printf("Переменные типа \'long double\' принимают значения в диапазоне от %.0Lf до %Lf\n", LDBL_MIN, LDBL_MAX);
printf("\n2. Получаем данные путем прямого вычисления\n");
/* Из файла limits.h получаем количество битов в char */
/* printf("Размер переменной типа \'char\' %d бит\n", CHAR_BIT); */
/* Для возведения в степень будем использовать функцию стандартной библиотеки pow()*/
max_char = pow(2, CHAR_BIT);
max_char = max_char - 1;
printf("Переменные типа \'unsigned char\' принимают значения в диапазоне от 0 до %d\n", max_char);
i = max_char / 2; /* дробная часть отсекается */
j = i - max_char;
printf("Переменные типа \'signed char\' принимают значения в диапазоне от %d до %d\n", j, i);
/* Согласно файлу limits.h тип short int имеет размер 16 бит */
/* printf("Размер переменной типа \'short int\' %d бит\n", 16); */
max_short = pow(2, 16);
max_short = max_short - 1;
printf("Переменные типа \'unsigned short int\' принимают значения в диапазоне от 0 до %d\n", max_short);
i = max_short / 2;
j = i - max_short;
printf("Переменные типа \'signed short int\' принимают значения в диапазоне от %d до %d\n", j, i);
/* Согласно файлу limits.h тип int имеет размер 32 бита */
/* printf("Размер переменной типа \'int\' %d бит\n", 32); */
max_int = pow(2, 32);
max_int = max_int - 1;
printf("Переменные типа \'unsigned int\' принимают значение от 0 до %lld\n", max_int);
i = max_int / 2;
j = i - max_int;
printf("Переменные типа \'signed int\' принимают значения в диапазоне от %d до %d\n", j, i);
return 0;
}
Примечание!
signed char – %d
unsigned char – %d
signed short int – %d
unsigned short int – %d
signed int – %d
unsigned int – %u
signed long int – %ld
unsigned long int – %lu
float – %f
double – %lf
long double – %Lf
long long int – %lld
#include <stdio.h>
#include <limits.h>
#include <float.h>
#include <math.h>
int main()
{
int max_char; /* Максимальное значение для переменной типа char */
max_char = 0;
int max_short; /* Максимальное значение для переменной типа short int */
max_short = 0;
long long int max_int; /* чтобы поместилось максимальное значение типа (unsigned long int + 1) */
max_int = 0;
int i; /* максимальное значение переменной целочисленного типа */
int j; /* минимальное значение переменной целочисленного типа */
i = j = 0;
printf("1. Данные берем из заголовочного файла <limits.h>\n");
printf("Переменные типа \'signed char\' принимают значения в диапазоне от %d до %d\n", CHAR_MIN, CHAR_MAX);
printf("Переменные типа \'unsigned char\' принимают значения в диапазоне от 0 до %d\n", UCHAR_MAX);
printf("Переменные типа \'signed short int\' принимают значения в диапазоне от %d до %d\n", SHRT_MIN, SHRT_MAX);
printf("Переменные типа \'unsigned short int\' принимают значения в диапазоне от 0 до %d\n", USHRT_MAX);
printf("Переменные типа \'signed int\' принимают значения в диапазоне от %d до %d\n", INT_MIN, INT_MAX);
printf("Переменные типа \'unsigned int\' принимают значения в диапазоне от 0 до %u\n", UINT_MAX);
printf("Переменные типа \'signed long int\' принимают значения в диапазоне от %ld до %ld\n", LONG_MIN, LONG_MAX);
printf("Переменные типа \'unsigned long int\' принимают значения в диапазоне от 0 до %lu\n", ULONG_MAX);
printf("Переменные типа \'float\' принимают значения в диапазоне от %.0f до %f\n", FLT_MIN, FLT_MAX);
printf("Переменные типа \'double\' принимают значения в диапазоне от %.0lf до %lf\n", DBL_MIN, DBL_MAX);
printf("Переменные типа \'long double\' принимают значения в диапазоне от %.0Lf до %Lf\n", LDBL_MIN, LDBL_MAX);
printf("\n2. Получаем данные путем прямого вычисления\n");
/* Из файла limits.h получаем количество битов в char */
/* printf("Размер переменной типа \'char\' %d бит\n", CHAR_BIT); */
/* Для возведения в степень будем использовать функцию стандартной библиотеки pow()*/
max_char = pow(2, CHAR_BIT);
max_char = max_char - 1;
printf("Переменные типа \'unsigned char\' принимают значения в диапазоне от 0 до %d\n", max_char);
i = max_char / 2; /* дробная часть отсекается */
j = i - max_char;
printf("Переменные типа \'signed char\' принимают значения в диапазоне от %d до %d\n", j, i);
/* Согласно файлу limits.h тип short int имеет размер 16 бит */
/* printf("Размер переменной типа \'short int\' %d бит\n", 16); */
max_short = pow(2, 16);
max_short = max_short - 1;
printf("Переменные типа \'unsigned short int\' принимают значения в диапазоне от 0 до %d\n", max_short);
i = max_short / 2;
j = i - max_short;
printf("Переменные типа \'signed short int\' принимают значения в диапазоне от %d до %d\n", j, i);
/* Согласно файлу limits.h тип int имеет размер 32 бита */
/* printf("Размер переменной типа \'int\' %d бит\n", 32); */
max_int = pow(2, 32);
max_int = max_int - 1;
printf("Переменные типа \'unsigned int\' принимают значение от 0 до %lld\n", max_int);
i = max_int / 2;
j = i - max_int;
printf("Переменные типа \'signed int\' принимают значения в диапазоне от %d до %d\n", j, i);
return 0;
}
Примечание!
1. Для работы функции pow() необходимо подключить заголовочный файл <math.h>.
2. Тип float не годится для работы с большими целыми числами. Для этих целей необходимо использовать тип long long int. Ниже, на примере, показано почему.
#include <math.h>
int main()
{
float x;
x = 0;
x = pow(2, 32); /* возводим 2 в 32 степень */
printf("pow(2, 32) = %.0f\n", x);
x = x - 1;
printf("pow(2, 32) - 1 = %.0f\n", x);
return 0;
}
pow(2, 32) - 1 = 4294967296
$ vim test.c#include <stdio.h>
#include <math.h>
int main()
{
float x;
x = 0;
x = pow(2, 32); /* возводим 2 в 32 степень */
printf("pow(2, 32) = %.0f\n", x);
x = x - 1;
printf("pow(2, 32) - 1 = %.0f\n", x);
return 0;
}
$ ./a.outpow(2, 32) = 4294967296
pow(2, 32) - 1 = 4294967296
Как видно из примера наше большое число не уменьшилось на единицу. И я пока не знаю, чем объясняется такое поведение.
Как видно из примера наше большое число не уменьшилось на единицу. И я пока не знаю, чем объясняется такое поведение.
ОтветитьУдалитьМожет быть уже знаете в чем дело? А то столкнулся с таким же нюансом
Проблема как раз в одинарной точности. Для типа float только 7 значущих цифр в десятичной системе мантиссы будут верными. В нашем случае 2 в 32 степени это 10 цифр. Если в приведённом примере вместо float указать double, то значение будет верным.
Удалитьпокороче:
ОтветитьУдалитьprintf("values from standard headers\n\n");
printf("signed char: %d %d\n", SCHAR_MIN, SCHAR_MAX);
printf("unsigned char: %d %d\n", 0, UCHAR_MAX);
printf("signed int: %d %d\n", INT_MIN, INT_MAX);
printf("unsigned int: %d %u\n", 0, UINT_MAX);
printf("signed short: %d %d\n", SHRT_MIN, SHRT_MAX);
printf("unsigned short: %d %d\n", 0, USHRT_MAX);
printf("signed long: %ld %ld\n", LONG_MIN, LONG_MAX);
printf("unsigned long: %d %lu\n\n", 0, ULONG_MAX);
printf("values by direct computation\n\n");
printf("signed char: -%g %g\n", pow(2, 8)/2, pow(2, 8)/2-1);
printf("unsigned char: %d %g\n", 0, pow(2, 8)-1);
printf("signed int: -%.lf %.lf\n", pow(2, 32)/2, pow(2, 32)/2-1);
printf("unsigned int: %d %.lf\n", 0, pow(2, 32)-1);
printf("signed short: -%.lf %.lf\n", pow(2, 16)/2, pow(2, 16)/2-1);
printf("unsigned short: %d %.lf\n", 0, pow(2, 16)-1);
printf("signed long: -%.lf %.lf\n", pow(2, 32)/2, pow(2, 32)/2-1);
printf("unsigned long: %d %.lf\n\n", 0, pow(2, 32)-1);
да и русский может не отображаться в компиляторах каких-либо
У float 128 бит тогда? А сколько у double и ldouble?
ОтветитьУдалить