Методичне об'єднання вчителів інформатики

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.



Мова програмування C++

Сообщений 1 страница 4 из 4

1

Приклад проблеми пов'язаної з перетіворенням типів.

Задача. Вводиться дійсне число - значення суми грошей (наприклад, 12.32). Вивести у форматі: G grn K kop (наприклад, 12 grn 32 kop).

Учень написав:

#include "stdafx.h"
#include <conio.h>
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
float m;

int grn, kop;

cin>>m;

grn=m;
kop=(m-grn)*100;
cout<<grn<<" grn "<<kop<< " kop";

getch();

return 0;
}

Комп'ютер видав: 12 grn 31 kop

Я розумію, що програма не найраціональніша і що при перетворенні типів можлива втрата точності, але така велика! Навіть якщо ввести 0.32, то отримаємо 0 grn 31 kop. Це ж друга значуща цифра! Учень робив у DevCpp, я перевірив у Visual C++ 2005 EE (звідти й наведений текст).

Може хтось пояснити механізм виникнення такої великої похибки?

2

При компілюванні компілятор видавав зауваження, що відбувається переведення, яке може призвести до втрати даних. Це переведення з дробової зміної  до цілої   без контролю.  Для такого контролю є команди, які вказують, яким чином це зробити.
Далі  знову переведення даних без контолю правильності і це знову помилка. Обчислював би  далі за формулою :m*100-grn*100 (хоча цей запис те ж не дуже коректний), тоді правильність гарантовано. Суть в тому, що С++ так як і С велику кількість контролю за переведеннями, переповненями надає програмісту, що в свою чергу робить програму швидкою та компактною, але і дає в програмах робити такі помилки. В Паскалі набагато більший контроль, але і швидкодія і компактність коду набагато гірша.

3

Дякую. Ідею я розумію. Думав, хтось може пояснити деталі: внутрішнє представлення типів і механізм виникнення саме такої помилки. Помилка виникає саме для 32-х копійок!

4

Там не тільки було для 32 копійок, у мене ще 1 тест точно давав таку неточність. А з 32 у мене виправлялось при переході на тип double.
В літературі зустрів застереження на те, що взагалі програма може видавати різні "коники", якщо використовувати переведення типу float до int чи щось подібне, а от навпаки все нормально. Тут можна було використати контрольоване переведення static_cast<int> і таким чином попередити помилку. В С++ навіть допустимі переведення типів, які на перший погляд взагалі між собою не сумісні :)