Nickolay.info. Алгоритмы. Некоторые математические расчёты на Паскале

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

Возведение в произвольную степень на Паскале

Требуется вычислить значение с = ab. В зависимости от значений основания a и показателя степени b, вычисление степени может быть реализовано по-разному.

Если a > 0, а b может принимать произвольные вещественные значения, используем известную формулу ab = exp (b * ln a):

c:=exp(b*ln(a));

Если b - целое число (вообще говоря, "не слишком большое" по модулю), а a - любое (не равное нулю при b < 0), возведение в степень может быть реализовано с помощью цикла:

var i:integer;
{...}
c:=1;
for i:=1 to abs(b) do c:=c*a; {перемножение одинаковых сомножителей b раз}
if b<0 then c:=1/c;           {учёт знака показателя}

Для целого b и не равного нулю a выгоднее считать с помощью экспоненты и логарифма, не забывая о том, что не существует логарифмов от отрицательных чисел:

c:=exp(b*ln(abs(a)));             {степень положительного основания}
if (odd(b)=true) and (a<0) then c:=-c; {если основание отрицательно, а показатель нечетный, то меняем знак}

Вычисление корня произвольной степени на Паскале

Стандартная функция sqrt умеет извлекать только квадратный корень.

Извлечь корень степени n (где n - натуральное) из числа a можно всегда, кроме случая, когда a < 0 и при этом n четно. Извлечь корень степени n из числа a означает возвести число a в степень 1/n. При этом знак корня совпадает со знаком a. Ниже приводится код функции, вычисляющей корень произвольной степени n от своего аргумента a:

function root(a:real;n:word):real;
 {Тип word здесь указывает, что n положительно}
var r: real;
begin
 r:=exp(ln(abs(a))/n);              {корень из модуля}
 if a<0 then root:=-r else root:=r  {учет знака}
end;

Вычисление логарифмов на Паскале

Стандартная функция ln вычисляет только натуральный логарифм. Для вычисления логарифмов по другим основаниям можно применить формулу log a b = ln b / ln a:

c:=ln(b)/ln(a);

В частности, для вычисления десятичного логарифма lg b можно записать:

c:=ln(b)/ln(10);

Вычисление обратных тригонометрических функций (арксинусов и арккосинусов) на Паскале

В Паскале имеется стандартная функция arctan для вычисления арктангенса.

Другие обратные тригонометрические функции могут быть выражены через неё с помощью формул тригонометрии.

Для вычисления y = arcsin x, где, конечно, |x| <= 1, можно применить один из следующих способов:

if x=1 then y:=pi/2 
else if x=-1 then y:=-pi/2 
else y:=arctan(x/sqrt(1-sqr(x)));

или

y:=2*arctan(x/(1+sqrt(1-sqr(x))));

на практике следует помнить о возможных погрешностях при сравнении вещественных чисел (глава учебника, п.7.2).

Для вычисления z = arccos x, где |x| <= 1, можно использовать тот факт, что сумма арксинуса и арккосинуса некоторого значения равна прямому углу:

if x=1 then z:=0 
else if x=-1 then z:=pi 
else z:=pi/2-arctan(x/sqrt(1-sqr(x)));

или

z:=pi/2-2*arctan(x/(1+sqrt(1-sqr(x))));

Вычисление полярных углов на Паскале

Полярным углом точки с координатами (x,y), отличной от начала координат, называют угол между положительным направлением оси Ox и направлением из начала координат на данную точку. При этом угол отсчитывается против часовой стрелки. Строго говоря, полярный угол не всегда равен arctg (y/x), это верно лишь при x > 0. Кроме того, при делении большого значения y на малое x возможно переполнение. Показанная ниже функция вычисляет полярный угол fi, лежащий в промежутке от -pi до +pi, для любой точки с координатами (x,y), не совпадающей с началом координат:

function fi(x:real; y:real):real;
var f:real;
begin
 if abs(x)>abs(y) then begin
  f:=arctan(y/x);
  if x>0 then fi:=f 
  else if y>=0 then fi:=f+pi 
  else fi:=f-pi 
 end 
 else begin
  f:=arctan(x/y);
  if y>0 then fi:=pi/2-f 
  else fi:=-pi/2-f
 end
end;

Проблема с приведением типов на Паскале

Начинающие "паскалисты" нередко не понимают строгой типизированности этого языка, из-за чего находят в нём несуществующие "баги". Вот простейший пример.

var a,b:integer;
    r:longint;
begin
 a:=1000;
 b:=200;
 r:=a*b;
 writeln (r);
end.

Эта программа выдаст отнюдь не 200000, как может показаться. Ответ будет равен 3392 (результат переполнения). Никакого бага нет. Тип выражения в Паскале определяется только типом входящих в него переменных, но не типом переменной, куда записывается результат. То есть, мы вычислили с переполнением произведение двух переменных типа Integer, а потом "испорченный" результат переписали в переменную типа Longint. ничего не изменит и

r:=Longint(a*b);

Здесь тоже сначала вычислен результат с переполнением, затем преобразован к типу Longint. А вот

r:=Longint(a)*b;

рулит, получите свои 200000 :) Указанная ошибка часто встречается в программах начинающих. Чтобы её не повторять, помните - выражение в Паскале должно быть приведено к нужному типу в процессе его вычисления, а не после его окончания или при присваивании.

Рейтинг@Mail.ru

вверх гостевая; E-mail