Програми друку граничних констант. Введених засобів препроцесора і мови цілком достатньо для програми, що виводить на друк (на екран дісплея) значення констант, що визначають в конкретній системі (для конкретного компілятора) межі зміни даних різних типів. Кажучи про іменовані константи, треба відзначити, що серед стандартних заголовочних файлів компілятора завжди є файли 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.