Отправляет email-рассылки с помощью сервиса Sendsay

Всё о работе в Интернет

  Все выпуски  

Занятие 31.


Продолжаем заниматься алгоритмизацией и программированием математических задач, уважаемые подписчики.

По материалам предыдущих занятий мы уже видели, что во многих случаях решение какой-либо простой задачи может являться частью решения некоторой сложной задачи. Сегодня мы в этом убедимся окончательно.

ЗАДАЧИ, СВЯЗАННЫЕ С РЕШЕНИЕМ КВАДРАТНОГО УРАВНЕНИЯ

1. Решение задачи “Общий случай решения уравнения”.

Задача V.3.4. “Общий случай решения уравнения”. Построить подпрограмму для определения действительных корней уравнения a  x2 + b  x + c = 0 при условии, что заданные коэффициенты abc – произвольные числа.

Прежде всего отметим принципиальное отличие задачи решения уравнения a  x2 + b  x + c = 0 от задачи решения квадратного уравнения аналогичного вида. В первом случае предполагается, что коэффициенты abc – произвольные числа, во втором случае коэффициент a <> 0, иначе уравнение не было бы квадратным.

Из этого немедленно следует подход к решению поставленной задачи: если коэффициент a = 0, то решать следует линейное уравнение b  x + c = 0, в противном случае решать следует квадратное уравнение.

Для её решения в качестве вспомогательных будем использовать процедуры Lineal_Equation (см. материалы занятия 30) и Square_Equation (см. материалы занятия 24). Необходимо только согласовать их между собой по результатам. Имеется в виду, что возможные случаи результата решения данного уравнения должны быть объединением возможных случаев решения линейного и квадратного уравнений.

Вспомним, что варианты решения линейного уравнения обозначены тремя возможными значениями целочисленного флажка z: единственный корень z = 1, бесчисленное множество корней z = 2, корни отсутствуют z = 3. Вспомним также, что варианты решения квадратного уравнения обозначены двумя возможными значениями логического флажка z: действительные корни отсутствуют z = False и имеются в наличии два корня z = True.

Отметим, что ситуации отсутствия корней и отсутствия действительных корней – не одно и то же. Если мы говорим, что корни отсутствуют, то это значит, что их вовсе нет. Но если мы говорим, что отсутствуют действительные корни, то предполагаем при этом, что имеются какие-то иные. Действительно, известно, что квадратное уравнение в случае отсутствия действительных корней обязательно имеет комплексные.

Таким образом, множества вариантов решений линейного и квадратного уравнения не пересекаются. Именно поэтому значения логического флажка следует преобразовать в значения флажка целочисленного посредством расширения числа его значений: действительные корни отсутствуют z = 4 и имеются в наличии два действительных корня z = 5.

Обращаться к процедуре решения линейного уравнения следует в виде Lineal_Equation (b, c, x1, z). Объясняется это тем, что при a = 0 она должна решать линейное уравнение b  x + c = 0. Логика алгоритмизации подсказывает также то, что в случае единственного корня уравнения из двух переменных x1 и x2 значение должна получить именно переменная x1.

Решение рассмотренной задачи оформлено в виде процедуры Shared_Equation. Соответствующая программа имеет вид:

{$B+,D+,E+,I+,L+,N+,Q+,R+,X-}
Program V_03_04;
   Procedure Lineal_Equation ( a,b: Real; Var x: Real; Var z: Byte);
   Begin
      If a<>0 Then Begin x:=–b/a; z:=1 End
         Else If b=0 Then z:=2 Else z:=3
   End;
   Procedure Square_Equation ( a,b,c: Real; Var x1,x2: Real; Var z: Boolean);
      Var D: Real;
   Begin
      D := b*b - 4*a*c; D := Int(D*1E10)/1E10;
      z := D >= 0; If Not z Then Exit;
      x1 := ( -b + Sqrt(D) ) / (2*a); x2 := -b/a - x1
   End;
   Procedure Shared_Equation ( a,b,c: Real; Var x1,x2: Real; Var z: Byte);
      Var v: Boolean;
   Begin
      If a=0 Then Lineal_Equation(b,c,x1,z)
             Else Begin Square_Equation(a,b,c,x1,x2,v);
                        Case v Of
                           False: z:=4;
                           True:  z:=5
                        End;
                  End
   End;
   Var a,b,c,x1,x2: Real; z: Byte;
Begin
   Write('Введите коэффициенты уравнения a,b,c: ');
   ReadLn(a,b,c);
   Shared_Equation(a,b,c,x1,x2,z);
   Case z Of
      1: WriteLn('Один корень: x1=',x1:0:4);
      2: WriteLn('Бесчисленное множество корней');
      3: WriteLn('Корни отсутствуют');
      4: WriteLn('Отсутствуют действительные корни');
      5: WriteLn('Два корня: x1=',x1:0:4,',x2=',x2:0:4);
   End
End.

2. Решение задачи “Биквадратное уравнение”.

Задача V.3.5. “Биквадратное уравнение”. Построить программу решения биквадратного уравнения a  x4 + b  x2 + c = 0, для которого требуется найти действительные корни.

Биквадратными называют уравнения, содержащие исключительно чётные степени переменной x (x4, x2, x0). При этом наличие члена с x4 является обязательным, то есть a <> 0.

Известен следующий порядок решения биквадратного уравнения. Сначала решается соответствующее квадратное уравнение a  y2 + b  y + c = 0, образованное посредством замены x2 = y. Пусть результатами его решения будут корни y1 и y2, а также логическая переменная T. Эти результаты становятся предметом следующего анализа:

-       если квадратное уравнение не имеет действительных корней (логическая переменная T = False), то не имеет таковых и биквадратное уравнение;

-       если оба корня y1 и y2 квадратного уравнения отрицательны, то и в этом случае биквадратное уравнение действительных корней не имеет;

-       если из обоих корней квадратного уравнения неотрицателен только один, то биквадратное уравнение имеет два корня; при y1 ³ 0 и y2 < 0 корни вычисляются по формулам x1 = Sqrt (y1), x2 = x1; при y2 ³ 0 и y1 < 0 – по формулам x1 = Sqrt (y2), x2 = x1;

-       если оба корня квадратного уравнения неотрицательны, то биквадратное уравнение имеет четыре корня x1 = Sqrt (y1), x2 = x1, x3 = Sqrt (y2), x4 = x3.

Из вышеизложенного следует, что дополнительным результатом решения биквадратного уравнения должно быть сообщение о количестве его корней k. Отметим, что среди корней биквадратного уравнения могут быть равные (например, в случае y1 = y2 ³ 0). Однако, это никоим образом не влияет на общее их количество.

В операторе ветвления все пять вложенных ветвей схемы решения уравнения реализованы последовательным делением множества значений корней y1 и y2 на две части так, чтобы на каждом шаге первое из множеств дальнейшему делению уже не подлежало. Сначала отбрасываются все те случаи, когда биквадратное уравнение корней не имеет, а затем те, когда оно имеет только два корня. В конце концов остаётся множество значений корней y1 и y2, соответствующее четырём корням биквадратного уравнения.

Решение рассмотренной задачи оформлено в виде процедуры Biquadratic. Соответствующая программа имеет вид:

{$B+,D+,E+,I+,L+,N+,Q+,R+,X-}
Program V_03_05;
   Procedure Square_Equation ( a,b,c: Real; Var x1,x2: Real; Var z: Boolean);
      Var D: Real;
   Begin
      D := b*b - 4*a*c;
D := Int(D*1E10)/1E10;
      z := D >= 0; If Not z Then Exit;
      x1 := ( -b + Sqrt(D) ) / (2*a);
x2 := -b/a - x1
   End;
   Procedure Biquadratic(a,b,c: Real; Var x1,x2,x3,x4: Real; Var k: Byte);
      Var y1,y2: Real; T: Boolean;
   Begin
      Square_Equation(a,b,c,y1,y2,T);
      If Not T Then k:=0 Else

       
 If (y1<0) And (y2<0) Then k:=0 Else
           
If y2<0 Then Begin x1:=Sqrt(y1); x2:=-x1; k:=2 End Else
              
If y1<0 Then Begin x1:=Sqrt(y2); x2:=-x1; k:=2 End Else
                  
Begin x1:=Sqrt(y1); x2:=-x1; x3:=Sqrt(y2); x4:=-x3; k:=4 End
  
End;
   Var a,b,c,x1,x2,x3,x4: Real; z: Byte
;
Begin

  
Write('Введите коэффициенты уравнения a,b,c: ');
  
ReadLn(a,b,c
);
  
Biquadratic(a,b,c,x1,x2,x3,x4,z
);
   Case z Of
      0: WriteLn('
Действительные корни отсутствуют
');
      2: WriteLn('
Два корня
: x1=',x1:0:4,', x2=',x2:0:4);
     
4: WriteLn('Четыре корня: x1=',x1:0:4,',x2=',x2:0:4,',x3=',x3:0:4,',x4=',x4:0:4);

  
End
End.

Представляют интерес типичные ошибки при решении рассматриваемой задачи, которые достаточно часто встречаются в практике программирования.

1. Проверка не тех условий:

If Not T Then k:=0 Else
   If (y1<0) And (y2<0) Then k:=0 Else
      If y
1
>=0 Then Begin x1:=Sqrt(y1); x2:=-x1; k:=2 End Else
         If y2>=0 Then Begin x1:=Sqrt(y2); x2:=-x1; k:=2 End Else
            Begin x1:=Sqrt(y1); x2:=-x1; x3:=Sqrt(y2); x4:=-x3; k:=4 End

В таком операторе последняя ветвь не выполняется никогда.

2. Объединение ветвей:

If Not T Or (y1<0) And (y2<0) Then k:=0...

Ошибка состоит в том, что все переменные T, y1 и y2 проанализированы совместно. Однако, в случае, если T – ложно, то переменные y1 и y2 неопределены, следовательно, включать их в единое логическое выражение противопоказано.

3. Постепенное доопределение корней:

k := 0;
If y1>=0 Then Begin x1:=Sqrt(y1); x2:=-x1; k:=2 End;
If y2>=0 Then Begin x3:=Sqrt(y2); x4:=-x3; k:=k+2 End;

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

3. Преобразование типов.

Идентификаторы порядковых типов (стандартных и нестандартных) можно использовать как имена функций преобразования типов.

Указанный способ позволяет достаточно просто преобразовать тип данной величины к более мощному непосредственно в выражении. Это во многих случаях помогает при вычислениях. Например, легко убедиться, что при D: Integer = 200 выражение D*D вычислить невозможно. Причина в том, что правильный результат 40000 лежит за пределами возможностей типа Integer. Однако преобразование типа одного из операндов в более мощный, например, с помощью выражения Word(D)*D, решает возникшую проблему.

Функции преобразования позволяют сопоставлять одно другому значения различных порядковых типов. При этом, в обычных случаях, порядковые номера значения аргумента и значения функции совпадают. Например, Integer(G) = 78 при G = ’N’, Char(B) = ’Q’ при B = 81, Boolean(C) = True при C = 1, Char(F) = #0 при F = False и т. п.

Этот метод позволяет также преобразовывать величины к менее мощным типам. При этом, если данное значение величины выходит за пределы менее мощного типа, то используется принцип “кольца”. Например, известно, что значение 32767 является наибольшим допустимым для типа Integer, поэтому преобразование следующего за ним значения 32768 к типу Integer осуществляется по принципу “кольца”. Действительно, если значения из диапазона –32768..32767 рассматривать находящимися в кольце, то за значением 32767 следует значение –32768. Этим и объясняется результат  Integer(E) = –32768 при E = 32768. Сообщение об ошибке при этом не появляется независимо от настройки компилятора.

Отмеченными свойствами в отношении кольца значений того или иного типа обладают также и процедуры Inc и Dec. Например, при A: Byte = 200 обращение Inc(A, 70) даёт результат A = 14. Размер кольца значений при использовании этих процедур зависит от типа изменяемого аргумента.

Уважаемые подписчики! Вы уже, очевидно, обратили внимание на то, что при построении подпрограмм решения относительно сложных задач мы всегда стараемся использовать в качестве вспомогательных подпрограммы решения более простых задач. Не заставляет ли всё это задуматься над тем, что полезно было бы иметь некую библиотеку подпрограмм, из которой нужные вспомогательные подпрограммы можно было бы извлекать автоматически?

Уважаемые подписчики! При необходимости задать вопрос, проконсультироваться, уточнить или обсудить что-либо обращайтесь через Гостевую книгу моего персонального сайта http://a-morgun.narod.ru. При этом настоятельно рекомендую пользоваться браузером Internet Explorer.

С уважением, Александр.


В избранное