Програми друку граничних констант.
Введених засобів препроцесора і мови цілком достатньо для програми, що виводить на друк (на екран дісплея) значення констант, що визначають в конкретній системі (для конкретного компілятора) межі зміни даних різних типів. Кажучи про іменовані константи, треба відзначити, що серед стандартних заголовочних файлів компілятора завжди є файли limits.h і float.h, що включають препроцесорне визначення граничних констант. Наступна програма друкує деякі із значень граничних констант для цілих типів, визначених конкретною реалізацією компілятора з мови Сі.
#include <stdio.h>
#include <limits.h> /* Визначення граничних цілочисельних констант*/
void main( )
{
printf("\nCHAR_BIT=%d", CHAR_BIT);
printf("\nSCHAR_MIN=%d\t\tSCHAR_MAX=%d",SCHAR_MIN,SCHAR_MAX);
printf("\nUCHAR_MAX=%d", UCHAR_MAX);
printf("\nINT_MIN=%d\t\tINT_MAX=%d", INT_MIN,INT_MAX) ;
printf("\nLONG_MIN=%ld\tLONG_MAX=%ld", LONG_MIN, LONG_MAX);
}
Результат виконання програми з компілятором Turbo С:
CHAR_BIT=8
SCHAR_MIN=-128 SCHAR_MAX=127
UCHAR_MAX=255
INT_MIN=-32768 INT_MAX=32767
LONG_MIN=-2147483648 LONG_MAX=2147483647
У викликах функції printf() потрібно звернути увагу на специфікації перетворення. Всі константи цілочисельні, тому використовується специфікатор 'd'. Для величин типу long потрібно модифікатор 'l', тобто константи LONG_MIN і LONG_MAX виводяться з використанням специфікацій перетворення %ld. У всіх специфікаціях перетворення відсутнє зведення про довжину зображення значень, що виводяться. Кількість позицій в зображеннях констант залежить від їх значень. Управляючі послідовності '\n' і '\t' забезпечують при виводі відповідно переходи на нові рядки і табуляцію.
Для виводу дійсних значень з мантисою і порядком в рядку формату функції printf( ) потрібно використати специфікацію %е. Наступна програма виводить на екран значення деяких з граничних дійсних констант:
#include <stdio.h>
#include <float.h> /* Визначення граничних дійсних констант*/
void main( )
{
printf("\nFLT_EPSILON=%e", FLT_EPSILON);
printf<"\nDBL_EPSILON=%e", DBL_EPSILON);
printf("\nFLT_MIN=%e\tFLT_MAX=%e", FLT_MIN, FLT_MAX);
printf("\n \t \t \tDBL_MAX=%e", DBL_MAX);
printf("\nFLT_MANT_DIG=%d", FLT_MANT_DIG);
printf ("\nDBL_MANT_DIG=%d", DBL_MANT__DIG) ;
}
Результати виконання програми з компілятором Turbo C:
FLT_EPSILON=1.192093е-07
DBL_EPSILON=2.22044бе-16
FLT_MIN=1.1754 94e-38 FLT_MAX=3.402823е+38
DBL_MAX=1.797693е+308
FLT_MANT_DIG=24
DBL_MANT_DIG=53
Надруковані константи FLT_EPSILON і DBL_EPSILON - максимальні значення типів float і double, сума кожного з яких із значенням 1.0 не відрізняється від 1.0. Граничні константи FLT_EPSILON і DBL_EPSILON називають "машинними нулями" щодо дійсного значення 1.0. FLT_MIN, FLT_MAX і DBL_MAX - граничні значення для дійсних даних. FLT_MANT_DIG, DBL_MANT_DIG - кількість двійкових цифр (бітів) в мантисах відповідно чисел типу float і double.
Застосування дійсних даних.
Навіть познайомившись з
На IBM PC:
для float - 4 байти;
для double - 8 байт;
для long double - 10 байт.
Звернувши увагу на значення граничних констант, відмічають, що максимальні значення, які можна представити дійсними числами, визначені константами: FLT_MAX приблизно рівно 1Е+37 (для float);DBL_MAX приблизно рівно 1Е+308 (для double).Кількість вірних десяткових цифр в мантисах: FLT_DIG рівно 6 (для float);DBL_DIG рівно 10 (для double). Мінімальні нормалізовані числа:
FLT_MIN приблизно рівно 1Е-37 (для float);
DBL_MIN приблизно рівно 1Е-308 (для double).
За замовчанням всі константи що не відносяться до цілих типів, приймають тип double.
Наступна програма ілюструє небезпеки, зв'язані із застосуванням даних типу float навіть
в нескладних арифметичних виразах:
#include <stdio.h>
void main( )
{
float а, b, з, t1, t2, t3;
a=95.0;
b=0.02;
t1= (a+b) * (a+b) ;
t2=-2.0*a*b-a*a;
t3=b*b;
c=(tl+t2)/t3;
printf("\nc=%f\n", з); }
Результат виконання програми: c=2.441406
Якщо в тій же програмі змінної а присвоїти значення 100.0, то результат ще гірше:
с=0.000000.
Таким чином, запрограмоване з використанням змінних типу float нескладний алгебраїчний вираз

ніяк не "хоче" обчислюватися і приймати своє явне теоретично одиничне значення.
Якщо замінити в програмі тільки один рядок, тобто так оголосити змінні:
double а, b, c, tl, t2, t3;
значення виразу обчислюється абсолютно точно: с=
1.000000
Наведений приклад і загальні положення обчислювальної математики примушує істотно обмежити застосування змінних типу float.
Тип float можна вибирати для представлення початкових даних або остаточних результатів в програмі. Проте застосування даних типу float в проміжних обчисленнях (особливо в ітераційних алгоритмах) слідує обмежити і завжди використати double або long double.
На жаль, ні double, ні long double не знімають повністю проблем кінцевої точності представлення дійсних чисел в пам'яті ЕОМ. Істотна відмінність в порядках значень операндів арифметичних виразів може привести до подібних некоректних результатів і при використанні типів double і long double.
Виділення лексем з тексту програми.
Перша задача яку вирішує компілятор - це лексичний аналіз тексту програми. В результаті лексичного аналізу з суцільного тексту виділяються лексичні одиниці (лексеми). Компілятор проглядає символи (літери) тексту програми зліва направо. При цьому його перша задача - виділити лексеми мови. За чергову лексичну одиницю приймається найбільша послідовність літер, яка утворює лексему. Таким чином, з послідовності int_line компілятор не стане виділяти як лексему службове слово int, а сприйме всю послідовність як введений користувачем ідентифікатор.
Відповідно до того ж принципу вираз d+++b трактується як d++ +b, а вираз b-->с еквівалентно (b--)>с. Наступна програма ілюструє сказане:
#include <stdio.h>
void main()
{
int n=10,m=2;
printf("\nn+++m=%d",n+++m);
printf("\nn=%d, m=%d",n,m);
printf("\nm—>n=%d",m—>n);
printf("\nn=%d, m=%d",n,m);
printf("\nn—>m=%d",n—>m);
printf("\nn=%d, m=%d",n,m); }
Результат виконання програми:
n+++m=12
n=11,m=2
m—>n=0
n=11, m=l
n-->m=l
n=10,m=l
Результати обчислення виразів n+++m, n-->m, m-->n повністю відповідають правилам інтерпретації виразів. Унарні операції ++ і -- мають ранг 2. Аддитивні операції + і - мають ранг 4. Операції відносин мають ранг 6.