Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЗФ_ОАиП / Лекции ГГУ Скорины - Программирование.doc
Скачиваний:
179
Добавлен:
21.03.2016
Размер:
2.27 Mб
Скачать

10.8. Стандартные математические функции

В любых арифметических выражениях можно использовать стандартные математические функции, которые можно применять к любым числовым операндам. При использовании этих функций в программу необходимо включить файл <math.h>. При этом будут определены, например, следующие функции:

sin(x) – синус (аргумент в радианах);

cos(x) – косинус (аргумент в радианах);

tan(x) – тангенс (аргумент в радианах);

exp(x) – экспонента ex;

log(x) – натуральный логарифм ln(x);

log10(x) – десятичный логарифм log10(x);

sqrt(x) – квадратный корень;

pow10(x) – возведение числа 10 в степень x, т.е. 10x;

pow(x,y) – возведение в степень xy;

fabs(x) – абсолютная величина для double;

abs(x) – абсолютная величина для int.

11. Вычисление выражений и побочные эффекты

11.1. Преобразования типов при вычислении выражений

При выполнении операций происходят неявные (автоматические) преобразования типов в следующих случаях:

  • при выполнении операций, если операнды разных типов;

  • при выполнении операций присваивания, если значение одного типа присваивается переменной другого типа;

  • при передаче аргументов функции.

При выполнении операций автоматическое преобразование типов выполняется, чтобы привести операнды выражений к общему типу так, чтобы не было потери точности. Затем осуществляется сама операция. В таком случае всегда происходит расширение коротких величин до размера больших величин (другими словами, операнды приводятся к «старшему» типу, т.е. более длинному типу). Типы по убыванию старшинства: long double, double, float, unsigned long, long, unsigned int, int, short, char.

Правила неявного преобразования типов в выражения:

1) char и short преобразуется в int, float – в double (в С все действия с вещественными числами производятся с двойной точностью);

2) если один из операндов double, то другие тоже преобразуются к double, и результат тоже double;

3) если один из операндов long, то другие тоже преобразуются к long, и результат тоже long;

4) если один из операндов unsigned, то другие тоже преобразуются к unsigned, и результат тоже unsigned;

5) если все операнды типа int, то результат будет тоже int.

В операциях присваивания тип значения, которое присваивается, преобразуется к типу переменной, получающей это значение. Допускается преобразования целых и плавающих типов, даже если такое преобразование ведет к потере информации. Т.е. в этом случае возможно преобразование старшего типа к младшему.

int x, y = 7;

float z = 5.7;

x = z; // x = 5

z = y; // z = 7.0

Преобразования при вызове функции: если задан прототип функции, и он включает объявление типов аргументов, то над аргументами в вызове функции выполняются обычные арифметические преобразования. Эти преобразования выполняются независимо для каждого аргумента. Например, тип параметра float, а задали при вызове функции в качестве параметра целое 7. Тогда перед выполнением функции целое число 7 преобразуется к вещественному числу 7.0.

Обратить внимание! Арифметические операции над операндами выполняются корректно при условии, что результат не выходит за пределы разрешенного диапазона. Преобразования, выполняемые при операциях, не обеспечивают обработку ситуаций переполнения. При этом сообщение об ошибке не выдается.

Например, если к максимальному int числу (2 байта) прибавить 1, то вместо положительного числа +32768 в компьютере окажется отрицательное число –32768. И никакого предупреждения о нарушении допустимого интервала система не выдаст. Считается, что программист сам должен позаботиться о соответствующих проверках.

int i=30000, j=30000, k; // max_int = 32767

long y =30000;

long x;

k = i + j; // k = -5536 => 60000 - 65536 (216)

x = i + j; // x = -5536

x = i + y; // x = 60000

x = (long)i + j; // x = 60000

Почему на работает эта программа (зацикливается)?

#include <stdio.h>

main(){

unsigned char i;

for(i=0;i<=255;i++)

printf("%d\n",i);

}

По замыслу эта программа должна вывести на экран все числа от нуля до 255 и затем прекратить работу. На самом же деле она будет работать вечно, выводя на экран все числа от 0 до 255 вновь и вновь. Весь фокус в том, что переменная i объявлена как unsigned char, а диапазон ее значений – от нуля до 255. Казалось бы, условие i<=255 показывает, что i меняется в допустимых пределах. Но давайте посмотрим, что будет с циклом, когда i достигнет 255. Условие i <= 255 в этом случае выполнится, printf() покажет число 255, а дальше i увеличится на единицу и снова будет проверено условие i < =255. Чему будет равно i в этот момент, мы уже знаем: 255+1 означает для переменной unsigned char ноль! Условие i <= 255 будет выполнено, и цикл будет прокручен снова 256 раз, затем i снова станет равна нулю и так до бесконечности.

Очень важно понимать, что компилятор не может и не хочет обнаруживать такие ошибки. Язык С не вмешивается в замысел программиста, считая, что тот хорошо знает, что делает. С создавался для программистов, которым не нужно мешать надоедливыми проверками и предупреждениями.

Любые операнды типа char и short преобразуются к типу int, а любые операнды unsigned char или unsigned short преобразуются к типу unsigned int.

unsigned char a=150, b=150, c; // max_uchar = 255

int d;

c = a + b; // c = 44, но потеря информации произойдет при приведении типов при присваивании, а не при сложении => 300 – 256 (28)

d = a + b; // d = 300

int i = 30000, j = 30000;

long y = 30000, x;

x = i + j + y; // x = 24464, т.к. при i+j уже информация потеряется

x = i + (j + y); // x = 90000

Про такие эффекты надо помнить. Но это не единственные подводные камни при вычислении выражений.