int main(void)
{
int a,x,yb;
printf("a=");
scanf("%i", &a);
printf("x=");
scanf("%i", &x);
printf("\r\ny=");
yb=a*(x*x-6);
printf("%i\n",yb);
}
если вводить большие числа (типа а=111111, х=111111) — считает неправильно
где копать?
Здравствуйте, emx, Вы писали:
emx>yb=a*(x*x-6); emx>если вводить большие числа (типа а=111111, х=111111) — считает неправильно
Прикинь порядок а*x*x с такими числами. Получится пятнадцатый порядок.
А самое большое число, которое влезает в 32х-битный int это 2147483647*, оно на 6 порядков меньше.
"Обычный" int (он же long) в MS VC 6.0 — 32х-битный.
Здравствуйте, emx, Вы писали:
emx>где копать?
Копать здесь
Однако программирование полно «подводных камней», о которых начинающий программист не подозревает. Одной из первых проблем, с которыми приходится столкнуться, является переполнение. Допустим, в нашей программе есть переменная a типа float, которая содержит величину, близкую к предельной, например, 1037. Что произойдет, если мы попытаемся выполнить такой оператор:
cout << a*1000 << endl;
Пока мы запускаем программу в интегрированной среде Borland C++ 3.1, операция не выполняется! Оператор выводит на экран значение 1е+37. Но стоит нам запустить программу независимо от среды, мы получаем сообщение:
Floating point error: Overflow. (Ошибка плавающей точки: Переполнение.)
Abnormal program termination (Ненормальное завершение программы)
Очевидно, результат просто не может поместиться в переменную типа float. Такие ситуации называются переполнением. Понятно, что аналогичная картина может возникнуть и при использовании других плавающих типов. Интегрированная среда просто отслеживает такую ситуацию и не дает программе совершить аварию. Рассмотрим аналогичную ситуацию с целыми числами. Заглянув в помощь системы Borland C++ 3.1, обнаруживаем, что целые числа типа int изменяются от -32768 до +32767. Посмотрим, что получится, если мы будем работать на границах диапазона.
Первый оператор выводит на экран отрицательное число -32768, а второй — положительное число 32767. Таким образом, мы наблюдаем, что при добавлении 1 к правой (положительной) границе диапазона получается отрицательное число — левая граница диапазона. При вычитании 1 из левой (отрицательной) границы диапазона получаем, соответственно, правую границу диапазона. От размера чисел эта ситуация не зависит — то же самое происходит и с числами типа long, и short.
Аналогичную картину наблюдаем и для беззнаковых чисел unsigned int, которые изменяются в диапазоне от 0 до 65535. Оператор
cout << 65535u+1 << endl;
выдает на экран ноль. Аналогично оператор
cout << 0u-1 << endl;
выводит число 65535. Самое неприятное, что не выводится никаких сообщений или предупреждений ни при трансляции, ни при выполнении программы.
С типом char — аналогичные проблемы, которые усугубляются «знаковостью- беззнаковостью», принятой по умолчанию. Диапазон «маленьких чисел» изменяется от -128 до 127. Однако ни системы фирмы Borland, ни Visual C++ 6 не «протестуют», если в программе встречается, например, такой оператор:
char ch = 255;
Вывод ch как целого числа показывает на экране -1. Справедливости ради надо сказать, что Visual C++ 6 выдает предупреждение
warning C4305: 'initializing' : truncation from 'const int' to 'char'
‘инициализация’: усечение 'const int' до 'char'
Иногда недоумение вызывают совершенно безобидные выражения. Например, переменная d в следующем операторе:
double d = 15/2;
будет равна 7, а не 7.5. А все дело в том, что выражение 15/2 — это деление целых чисел и выполняется с отсечением. И только после выполнения операции результат (целое число) преобразуется в дробное типа double. Чтобы таких ошибок не было, необходимо в выражениях задавать дробные константы:
double d = 15.0/2;
или
double d = 15/2.0;
Операция запятая тоже может спровоцировать ошибку, например
double d; d = 3,141592653;
Переменная d равно 3, а не «пи», как задумывал программист — вместо точки написана запятая.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, LaptevVV, Вы писали:
emx>>>где копать? LVV>>Копать здесь
К>Цитата из твоей книги?
К>
LVV>>Допустим, в нашей программе есть переменная a типа float, которая содержит величину, близкую к предельной, например, 1037.
К>кто бы мог подумать...
Не посмотрел. Кстати, как принято на RSDN верхний индекс обозначать? ИМХО подходит 10^37 К>
LVV>>double d; d = 3,141592653;
LVV>>Переменная d равно 3, а не «пи», как задумывал программист — вместо точки написана запятая.
К>Какой красивый баг! Супер супер супер . Не послать ли его в микрософт?
Тут где-то топик был — насыпать приколов по С++. Я с десяток отсыпал, но, как втидишь, в заначке еще остались.
Туда бы...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>>>double d; d = 3,141592653; LVV>Тут где-то топик был — насыпать приколов по С++. Я с десяток отсыпал, но, как втидишь, в заначке еще остались.
Из личного зверинца (самого покусали в детстве):
const pi = 3.141592653;
Взгляд не спотыкается совершенно! Искал ошибку долго...
При расчетах pi==3 (забыл double)
Здравствуйте, retalik, Вы писали:
R>Здравствуйте, LaptevVV, Вы писали:
LVV>>>>double d; d = 3,141592653; LVV>>Тут где-то топик был — насыпать приколов по С++. Я с десяток отсыпал, но, как втидишь, в заначке еще остались. R>Из личного зверинца (самого покусали в детстве): R>
R>const pi = 3.141592653;
R>
R>Взгляд не спотыкается совершенно! Искал ошибку долго... R>При расчетах pi==3 (забыл double)
Аналогично было как-то.
Хорошо, что сейчас по новому стандарту попасться на этом нельзя.
ёлки-палки, так что ж делать? на вопрос-то не ответили :(
и ещё:
float yc; // пробовал и double
yc=a/(x*x+6);
printf("%.4f\n",yc);
ввожу х=5 и а=5, ответ пишет 0,0000, в чём ж дело?
Здравствуйте, LaptevVV, Вы писали:
LVV>Здравствуйте, emx, Вы писали:
emx>>где копать? LVV>Копать здесь
LVV>
LVV>Операция запятая тоже может спровоцировать ошибку, например
LVV>double d; d = 3,141592653;
LVV>Переменная d равно 3, а не «пи», как задумывал программист — вместо точки написана запятая.
последний пример можно расширить и задавать на интервью:
чему будут равны a и b после следующих операций:
double a = 0, b = 0;
b = a = 3,1415926;
b = (a = 3,1415926);
Здравствуйте, emx, Вы писали:
emx>ёлки-палки, так что ж делать? на вопрос-то не ответили emx>и ещё: emx>float yc; // пробовал и double emx>yc=a/(x*x+6); emx>printf("%.4f\n",yc); emx>ввожу х=5 и а=5, ответ пишет 0,0000, в чём ж дело?
В арифметике, ёлки палки!!!
a — целое.
(x*x+6) — целое.
Сколько будет 5/31 ? Знаешь, сколько? НОЛЬ!!!
Потому что это целочисленное деление.
Хочешь получить вещественный результат — так и пиши соответственно