Você está na página 1de 5

Atividade 1 - MS211 - Turma I

Gabriel Jeronimo da Silva - RA: 247112


George Henrique de Lima Sá - RA: 231529
Otávio Casagrande Ferrari - RA: 252899

14 de março de 2023

1. Introdução
Nessa atividade tivemos o objetivo de elaborar, implementar e validar um procedimento com-
putacional para resolver a equação do segundo grau:

ax2 + bx + c = 0 (1.1)

2. Desenvolvimento
A princı́pio, escolhemos a linguagem Python para o desenvolvimento do programa. Por motivos
computacionais que serão explicados adiante, as entradas do programa, ou seja, os coeficientes a,
b e c, são da forma (a, b, c), em que cada coeficiente deve estar escrito na forma inteira/decimal,
em notação cientı́fica na forma “m ∗ 10ˆn”, com n inteiro1 , ou possivelmente como uma soma
“x ∗ 10ˆm + y ∗ 10ˆn”, com m e n inteiros, (o motivo de haver a possibilidade de escrever como
uma soma será explicado adiante)2 . Para melhor compreensão das entradas, veja alguns exemplos
no Apêndice A.
1 # Entrada dos coeficientes :
2 m = input ()
3 lista = m . split ( ’ , ’)
4 lista [0] = lista [0]. removeprefix ( ’( ’)
5 lista [2] = lista [2]. removesuffix ( ’) ’)
6
7 dict = { ’a ’ :[] , ’b ’ :[] , ’c ’ :[]}
8
9 for i in range (3) :
10 if ’+ ’ in lista [ i ]:
11 y , dy = lista [ i ]. split ( " + " )
12 if ’ *10^ ’ in y :
13 y , exp_y = y . split ( " *10^ " )
14 y = float ( y ) *10** int ( exp_y )
15 else :
16 y = float ( y )
17 if ’ *10^ ’ in dy :
1
Se o expoente for negativo, não utilize parênteses. Por exemplo, 10−5 escreve-se 1 ∗ 10ˆ − 5.
2
As entradas não serão aceitas se houver uma subtração, como 35 − 10. Para tal, escreva 35 + −10. Além disso,
convenciona-se que o segundo termo da soma é menor em magnitude que o primeiro.

1
18 dy , exp_dy = dy . split ( " *10^ " )
19 dy = float ( dy ) *10** int ( exp_dy )
20 else :
21 dy = float ( dy )
22 dict [ list ( dict ) [ i ]]. append ( y )
23 dict [ list ( dict ) [ i ]]. append ( dy )
24 elif ’ *10^ ’ in lista [ i ]:
25 y , exp_y = lista [ i ]. split ( " *10^ " )
26 y = float ( y ) *10** int ( exp_y )
27 dict [ list ( dict ) [ i ]]. append ( y )
28 dict [ list ( dict ) [ i ]]. append (0)
29 else :
30 y = float ( lista [ i ])
31 dict [ list ( dict ) [ i ]]. append ( y )
32 dict [ list ( dict ) [ i ]]. append (0)
33
34 a = dict [ ’a ’ ][0]+ dict [ ’a ’ ][1]
35 b = dict [ ’b ’ ][0]+ dict [ ’b ’ ][1]
36 c = dict [ ’c ’ ][0]+ dict [ ’c ’ ][1]
37 if a == dict [ ’a ’ ][0]:
38 da = dict [ ’a ’ ][1]
39 else :
40 da = 0
41 if b == dict [ ’b ’ ][0]:
42 db = dict [ ’b ’ ][1]
43 else :
44 db = 0
45 if c == dict [ ’c ’ ][0]:
46 dc = dict [ ’c ’ ][1]
47 else :
48 dc = 0
49
50 # ##### ###### ######
51
52 # Definindo funcao sinal :
53 def sinal ( x ) :
54 if x <0:
55 return -1
56 elif x >0:
57 return +1
58 else :
59 return 0
60
61 # ##### ###### ######
62

63 # Solucao da equacao :
64 if a == b == c == 0:
65 print ( ’( reta real ) ’)
66 elif a == b == 0:
67 print ( ’( equacao inconsistente ) ’)
68 elif a !=0:
69 if c == 0:
70 x = -b / a
71 print (0 , ’e ’ , x )
72 else :
73 if b **2 -4* a *c -4* a * dc -4* da * c +2* b * db >=0: # ( Delta >= 0)

Página 2
74 x_1 = -( b + sinal ( b ) *( b **2 -4* a *c -4* a * dc -4* da * c +2* b * db ) **(1/2) ) /(2* a )
75 x_2 = c /( a * x_1 )
76 print ( x_1 , ’e ’ , x_2 )
77 else : # ( Sol . complexas )
78 pt_real = -b /(2* a )
79 pt_imag = ( - b **2+4* a * c +4* a * dc +4* da *c -2* b * db ) **(1/2) /(2* a )
80 print ( pt_real , ’+ ’ , pt_imag , ’i ’ , ’ e ’ , pt_real , ’ - ’ , pt_imag , ’i ’ ,
sep = ’ ’)
81 else : # a =0 ( Eq . linear )
82 x = -c / b
83 print (x , ’( equacao linear ) ’)

O código utilizado se encontra acima, e ele foi dividido em 3 partes, como podemos ver, re-
presentadas pelos comentários #Entrada dos Coeficientes, #Definindo função sinal e #Solução
da equação. As informações de entrada foram manipuladas levando em consideração a entrada
no formato (a, b, c) descrito anteriormente. Para isso, utilizamos comandos para que pudéssemos
retirar os parênteses e vı́rgulas para conseguir armazenar os números dos coeficientes a, b e c.
Além disso, utilizamos listas e dicionários convenientes para armazenar os valores desejados da
maneira correta, armazenando-se tanto o valor do coeficiente, quanto um valor de correção que
será explicado adiante. É válido ressaltar que o programa compilado pela máquina é executado
com o uso da aritmética do ponto flutuante, com números binários, enquanto que as entradas e
saı́das são dadas por números na base 10.
Sendo assim, com as entradas prontas para calcular as raı́zes da equação (1.1), separamos a
solução de acordo com a nulidade de certos coeficientes. Para a = b = c = 0 temos que a solução é
toda a reta real, para a = b = 0 temos uma equação inconsistente, para somente a = 0 temos uma
equação linear, e para a ̸= 0, temos a resolução por Bhaskara, separada em dois casos: soluções
reais e soluções complexas, de acordo com o sinal de ∆.
Um dos métodos utilizados para diminuir erros no cálculo das raı́zes reais através de Bhaskara
foi o método de encontrar a raiz de maior valor absoluto por Bhaskara e a segunda raiz com base
no fato do produto das duas raı́zes ser igual a c/a (se a ̸= 0). Sabemos que a maior raiz é dada
por:
√ 
b + sinal(b) · b2 − 4ac
x1 = − (2.1)
2a
Logo, para utilizar essa equação, foi definida uma função sinal no código. Com o valor da raiz
de maior valor absoluto, encontramos a outra raiz por:
c
x2 = (2.2)
ax1
No caso das raı́zes complexas, separamos o cálculo da solução no cálculo da parte real e no
cálculo da parte imaginária, lembrando que as duas raı́zes complexas são conjugadas.
√ Na parte real,
fizemos simplesmente −b/(2a), enquanto que na parte complexa calculamos −∆/(2a). Assim,
os resultados das duas raı́zes complexas são expressados como (pt.real) ± (pt.complexa)i.
Nesse ponto, temos que tomar cuidado com o valor do ∆, pois pode adotar valores positivos
e negativos, tornando as raı́zes reais ou imaginárias. Logo, cuidados foram tomados para evitar
erros nos cálculos das raı́zes por conta da perda de precisão no valor de ∆.
Para evitar erros na determinação do sinal de ∆ devido à aproximações que levam ∆ a ter
um valor muito próximo de 0, foi implementado o sistema de entradas dos coeficientes como uma
soma. Assim, se tornou possı́vel armazenar separadamente números como 1010 + 10−10 de forma

Página 3
a mudar a ordem das operações realizadas para evitar arredondamentos indesejados, uma vez que
tal soma é instantaneamente aproximada para 1010 .
O sistema funciona da seguinte maneira: para cada coeficiente o sistema armazenará o valor
do coeficiente (a, b, c) e um valor “de correção” (que no código são chamados de da, db, dc). O
valor do coeficiente será simplesmente o valor calculado para a entrada, logo se a entrada for, por
exemplo, 5 × 104 + 2 × 10−7 , então o coeficiente será calculado como sendo o resultado da soma
dos termos acima. O valor de correção de um certo coeficiente será igual ao segundo termo da
soma3 se o sistema retornar True para a igualdade entre o primeiro termo da soma e a soma em
si. Se o sistema retornar False, o valor de correção será definido como 0. Ainda, caso a entrada
não envolva uma soma, o valor de correção será 0. Ou seja, o sistema retorna um valor de correção
diferente de 0 somente se o valor da soma for arredondado como sendo o valor do termo de maior
magnitude.
Por exemplo, se a entrada de um coeficiente for 5 × 104 + 2 × 10−7 , o valor do coeficiente
será armazenado como o resultado da operação (i.e., 50000.0000002 - o sistema não arredonda
neste caso). Como 50000.0000002 ̸= 50000, então o valor de correção será 0. Outro exemplo:
se a entrada de um coeficiente for 1010 + 10−10 (como é o caso dos testes 3 e 4), o valor do
coeficiente será o resultado da soma, que é arredondado pelo sistema para 1010 devido ao excesso
de algarismos significativos necessários para armazenar o valor exato. Como o sistema computará
1010 + 10−10 = 1010 , então o valor de correção será igual a 10−10 .
Por fim, para o cálculo de ∆ com as correções dos coeficientes (desprezando termos de segunda
ordem nas correções), temos:

∆ = (b + db)2 − 4(a + da)(c + dc) ≈ (b2 − 4ac) − 4a(dc) − 4(da)c + 2b(db) (2.3)

Logo, a rotina desenvolvida utiliza a seguinte expressão para delta:

∆ = (b2 − 4ac) − 4a(dc) − 4(da)c + 2b(db) (2.4)

em que a ordem de realização das operações foi pensada para que primeiramente seja calculada a
subtração entre os números de grande magnitude, a fim de possivelmente se cancelarem, e após
isso somar com os termos de pequena magnitude.
Com esse algoritmo, conseguimos superar os principais problemas de cancelamento e de
propagação de erro no cálculo das raı́zes de uma equação do segundo grau.

3. Resultados
Sendo assim, abaixo encontram-se duas tabelas a respeito dos resultados esperados e obtidos,
respectivamente, para os testes:
3
Lembre-se que, pela convenção adotada, se a entrada de um coeficiente for uma soma, então o segundo termo
da soma precisa ser o menor.

Página 4
teste coeficientes (a, b, c) soluções exatas
1 (1, − (5 × 106 + 2 × 10−7 ), 1) 5 × 106 e 2 × 10−7
2 (10−6 , 2 × 103 , 10−3 ) −2 × 109 e − 5 × 10−7
3 (1, − 2 × 105 , 1010 + 10−10 ) 100000 + 0.00001i e 100000 − 0.00001i
4 (1, − 2 × 10−5 , 1010 + 10−10 ) 0.00001 + 100000i e 0.00001 − 100000i
5 (103 , 0, 10−3 ) 0.001i e − 0.001i
6 (0, 2, 1) −1/2 (equação linear)
7 (0, 0, 1) ∄ (equação inconsistente)
8 (0, 0, 0) R (reta real)

Tabela 1: Soluções exatas apresentadas na atividade 01.4

teste coeficientes (a, b, c) resultados obtidos


1 (1, − (5 × 106 + 2 × 10−7 ), 1) 5000000.0 e 2 × 10−7
2 (10−6 , 2 × 103 , 10−3 ) −1999999999.9999995 e − 5.000000000000001 × 10−7
3 (1, − 2 × 105 , 1010 + 10−10 ) 100000.0 + 10−5 i e 100000.0 − 10−5 i
4 (1, − 2 × 10−5 , 1010 + 10−10 ) 10−5 + 100000.0i e 10−5 − 100000.0i
5 (103 , 0, 10−3 ) 0.0 + 0.001i e 0.0 − 0.001i
6 (0, 2, 1) −0.5 (equação linear)
7 (0, 0, 1) (equação inconsistente)
8 (0, 0, 0) (reta real)

Tabela 2: Resultados obtidos com o procedimento computacional.

Comparando as soluções exatas com os resultados obtidos, vemos que em 7 dos 8 testes o
resultado obtido foi a solução exata. Apenas no teste 2 que a solução obtida diferiu da exata.
Entretanto, o erro obtido nessas raı́zes foram de aproximadamente 2.4 · 10−14 % e 2.1 · 10−14 %,
mostrando que os resultados estão extremamente precisos.

A. Exemplos de entradas
Lembre-se: parênteses somente no inı́cio e no fim; espaços somente após a vı́rgula.

• (1, −2*10ˆ−5, 1*10ˆ10+1*10ˆ−10)

• (0, 2, 1)

• (1, −5*10ˆ6+−2*10ˆ−7, 1)

• (0.36284*10ˆ2, 57279.48+0.00000001, 20)

• (1*10ˆ3, 0, 1*10ˆ-3)

Observação: 10n deve ser escrito como 1 ∗ 10ˆn.

4
Obs: no arquivo do Classroom, a parte real das soluções do teste 3 parecem estar faltando um 0 (lá está 104
ao invés de 105 ) e a parte imaginária do teste 4 também parecem estar faltando um 0 (lá está 104 ao invés de 105 ).

Página 5

Você também pode gostar