CB2325NumericaG5 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CB2325NumericaG5/__init__.py +0 -0
- CB2325NumericaG5/aproximacao.py +251 -0
- CB2325NumericaG5/erros.py +104 -0
- CB2325NumericaG5/graficos_aproximacao.py +60 -0
- CB2325NumericaG5/integracao.py +190 -0
- CB2325NumericaG5/interpolacao.py +410 -0
- CB2325NumericaG5/raizes.py +284 -0
- cb2325numericag5-0.0.1.dist-info/METADATA +20 -0
- cb2325numericag5-0.0.1.dist-info/RECORD +12 -0
- cb2325numericag5-0.0.1.dist-info/WHEEL +5 -0
- cb2325numericag5-0.0.1.dist-info/licenses/LICENSE +21 -0
- cb2325numericag5-0.0.1.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
from CB2325NumericaG5.graficos_aproximacao import grafico_ajuste_linear, grafico_ajuste_polinomial
|
|
2
|
+
|
|
3
|
+
def media(dado: list) -> float:
|
|
4
|
+
"""Esta função retorna a média dos elementos da lista dada.
|
|
5
|
+
|
|
6
|
+
Args:
|
|
7
|
+
dado (list): Números (inteiros ou float).
|
|
8
|
+
|
|
9
|
+
Raises:
|
|
10
|
+
ValueError: A lista está vazia.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
float: A média aritmética dos dados fornecidos.
|
|
14
|
+
"""
|
|
15
|
+
if len(dado) == 0:
|
|
16
|
+
raise ValueError("A lista está vazia.")
|
|
17
|
+
|
|
18
|
+
soma = sum(dado)
|
|
19
|
+
|
|
20
|
+
return float(soma/(len(dado))) #deixado float explícito aqui - não era necessário, mas fica mais claro
|
|
21
|
+
|
|
22
|
+
def coeficiente_determinacao(valores_y:list, valores_y_ajustados:list) -> float:
|
|
23
|
+
"""Calcula o coeficiente de determinação R² para avaliar a qualidade do ajuste.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
valores_y (list): Valores reais de y.
|
|
27
|
+
valores_y_ajustados (list): Valores ajustados de y pela regressão.
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
ValueError: As listas de valores_y e valores_y_ajustados devem ter o mesmo tamanho.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
float: O coeficiente de determinação R².
|
|
34
|
+
"""
|
|
35
|
+
if len(valores_y) != len(valores_y_ajustados):
|
|
36
|
+
raise ValueError("As listas de valores_y e valores_y_ajustados devem ter o mesmo tamanho.")
|
|
37
|
+
|
|
38
|
+
y_medio = media(valores_y)
|
|
39
|
+
soma_erros_quadrados = sum((y - valores_y_ajustados[i]) ** 2 for i, y in enumerate(valores_y))
|
|
40
|
+
soma_total_variacao = sum((y - y_medio) ** 2 for y in valores_y)
|
|
41
|
+
|
|
42
|
+
if soma_total_variacao == 0:
|
|
43
|
+
return 0.0
|
|
44
|
+
|
|
45
|
+
r_quadrado = 1 - (soma_erros_quadrados / soma_total_variacao)
|
|
46
|
+
|
|
47
|
+
return r_quadrado
|
|
48
|
+
|
|
49
|
+
def regressao_linear(valores_x:list, valores_y:list, mostrar_grafico: bool = True, coeficiente_determinacao_r: bool = True) -> tuple :
|
|
50
|
+
"""Calcula os coeficientes (angular,linear) da reta que melhor se ajusta aos dados.
|
|
51
|
+
Args:
|
|
52
|
+
valores_x (list): Coordenada x de cada ponto.
|
|
53
|
+
valores_y (list): Coordenada y de cada ponto.
|
|
54
|
+
mostrar_grafico (bool, optional): Indica se o gráfico de dispersão e a reta de ajuste
|
|
55
|
+
devem ser exibidos automaticamente. Por padrão, é True.
|
|
56
|
+
coeficiente_determinacao_r (bool, optional): Indica se o coeficiente de determinação R² deve ser calculado e exibido no terminal. Por padrão, é True.
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
ValueError: A quantidade de abcissas deve ser igual à de ordenadas.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
tuple: Coeficientes da reta de regressão linear. (Coeficiente angular,Coeficiente linear)
|
|
63
|
+
"""
|
|
64
|
+
if len(valores_x) != len(valores_y):
|
|
65
|
+
raise ValueError("A quantidade de abcissas deve ser igual à de ordenadas.")
|
|
66
|
+
|
|
67
|
+
den_beta_chapeu = -len(valores_x)*(media(valores_x)*media(valores_x))
|
|
68
|
+
num_beta_chapeu = -len(valores_x)*media(valores_x)*media(valores_y)
|
|
69
|
+
|
|
70
|
+
for k in range(len(valores_x)):
|
|
71
|
+
den_beta_chapeu += valores_x[k]*valores_x[k]
|
|
72
|
+
num_beta_chapeu += valores_x[k]*valores_y[k]
|
|
73
|
+
|
|
74
|
+
beta_chapeu = num_beta_chapeu/den_beta_chapeu
|
|
75
|
+
alpha_chapeu = media(valores_y) - beta_chapeu*media(valores_x)
|
|
76
|
+
r_quadrado = coeficiente_determinacao(valores_y,[beta_chapeu*x + alpha_chapeu for x in valores_x])
|
|
77
|
+
|
|
78
|
+
if mostrar_grafico == True:
|
|
79
|
+
grafico_ajuste_linear(valores_x,valores_y,beta_chapeu,alpha_chapeu,r_quadrado)
|
|
80
|
+
|
|
81
|
+
if coeficiente_determinacao_r == True:
|
|
82
|
+
print(f"Coeficiente de Determinação R²: {r_quadrado:.2f}")
|
|
83
|
+
|
|
84
|
+
return (beta_chapeu,alpha_chapeu)
|
|
85
|
+
|
|
86
|
+
def resolvedor_de_sistemas(MC:list, VI:list, tolerancia:float = 1e-11) -> list:
|
|
87
|
+
"""Resolve Sistemas Lineares. Medios e grandes é por Gauss-Jordan.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
MC (list): Os coeficientes das incognitas do sistema linear.
|
|
91
|
+
VI (list): Os coeficientes independentes das variáveis.
|
|
92
|
+
tolerancia (float, optional): Abaixo desse valor o número é considerado zero; isso para que não haja divisões por números muito pequenos. Defaults to 1e-11.
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
ValueError: Sistema impossível de ser resolvido, alguma linha deu apenas 0.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
list: Lista do valor de cada incognita, caso venha na ordem MC = [[a_x + a_y + a_z + ...], [b_x + b_y+...], ...], a resposta virá em [x,y,z,...].
|
|
99
|
+
"""
|
|
100
|
+
Matriz_Coeficientes = list(MC)
|
|
101
|
+
Vetor_Independentes = list(VI)
|
|
102
|
+
Matriz_Aumentada = [Matriz_Coeficientes[e] + [Vetor_Independentes[e]] for e in range(len(Vetor_Independentes))]
|
|
103
|
+
|
|
104
|
+
def prod_linha(linha:list, produtado:float, div=False) -> list[float]:
|
|
105
|
+
|
|
106
|
+
auxiliar = [r for r in linha]
|
|
107
|
+
|
|
108
|
+
if div == True:
|
|
109
|
+
for r in range(len(linha)):
|
|
110
|
+
auxiliar[r] /= produtado
|
|
111
|
+
|
|
112
|
+
else:
|
|
113
|
+
for r in range(len(linha)):
|
|
114
|
+
auxiliar[r] *= produtado
|
|
115
|
+
|
|
116
|
+
return auxiliar
|
|
117
|
+
|
|
118
|
+
def soma_linha_linha(linha:list, somado:list, sub:bool =False) -> list[float]:
|
|
119
|
+
auxiliar = [r for r in linha]
|
|
120
|
+
|
|
121
|
+
if sub == True:
|
|
122
|
+
for r in range(len(linha)):
|
|
123
|
+
auxiliar[r] -= somado[r]
|
|
124
|
+
|
|
125
|
+
else:
|
|
126
|
+
for r in range(len(linha)):
|
|
127
|
+
auxiliar[r] += somado[r]
|
|
128
|
+
|
|
129
|
+
return auxiliar
|
|
130
|
+
|
|
131
|
+
for kk in range(len(Vetor_Independentes)):
|
|
132
|
+
linhas_trocadas = False
|
|
133
|
+
if abs(Matriz_Aumentada[kk][kk]) <= tolerancia:
|
|
134
|
+
for j in range(kk+1, len(Vetor_Independentes)):
|
|
135
|
+
if abs(Matriz_Aumentada[j][kk]) > tolerancia:
|
|
136
|
+
Matriz_Aumentada[j], Matriz_Aumentada[kk] = Matriz_Aumentada[kk], Matriz_Aumentada[j]
|
|
137
|
+
linhas_trocadas = True
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
if linhas_trocadas == False:
|
|
141
|
+
raise ValueError ("Sistema sem solução única.")
|
|
142
|
+
|
|
143
|
+
e = Matriz_Aumentada[kk][kk]
|
|
144
|
+
transicao = list(Matriz_Aumentada[kk])
|
|
145
|
+
Matriz_Aumentada[kk] = prod_linha(transicao, e, True) #Divide aquela linha pelo elemento da diagonal.
|
|
146
|
+
|
|
147
|
+
for i in range(kk+1, len(Vetor_Independentes)): #Processo de triangulação
|
|
148
|
+
if abs(Matriz_Aumentada[i][kk]) <= tolerancia:
|
|
149
|
+
Matriz_Aumentada[i][kk] = 0
|
|
150
|
+
continue
|
|
151
|
+
variavel_de_suporte1 = Matriz_Aumentada[i][kk]
|
|
152
|
+
variavel_de_suporte2 = prod_linha(Matriz_Aumentada[kk], variavel_de_suporte1)
|
|
153
|
+
Matriz_Aumentada[i] = soma_linha_linha(Matriz_Aumentada[i], variavel_de_suporte2, True)
|
|
154
|
+
|
|
155
|
+
#A partir daqui já temos uma matriz triangular superior.
|
|
156
|
+
x = [0 for i in range(len(Vetor_Independentes))]
|
|
157
|
+
|
|
158
|
+
for i in reversed(range(len(Vetor_Independentes))):
|
|
159
|
+
soma = sum(Matriz_Aumentada[i][j] * x[j] for j in range(i + 1, len(Vetor_Independentes)))
|
|
160
|
+
x[i] = (Matriz_Aumentada[i][-1] - soma) / Matriz_Aumentada[i][i]
|
|
161
|
+
|
|
162
|
+
return x #retorna [x,y,z,...]
|
|
163
|
+
|
|
164
|
+
def aproximacao_polinomial(lista_de_coordenadas:list, grau_do_polinomio:int, mostrar_grafico: bool = True, coeficiente_determinacao_r: bool = True) -> list[float]:
|
|
165
|
+
"""Utiliza MMQ para fazer a regressão polinomial dos pontos dados. Tudo no plano. Retorna os coeficientes.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
lista_de_coordenadas (list): Uma lista dos pontos cuja função vai aproximar.
|
|
169
|
+
grau_do_polinomio (int): Qual tipo de polinômio a função retornará. 1 é linear, por exemplo.
|
|
170
|
+
mostrar_grafico (bool, optional): Indica se o gráfico de dispersão e a curva ajustada
|
|
171
|
+
devem ser exibidos automaticamente. Por padrão, é True.
|
|
172
|
+
coeficiente_determinacao_r (bool, optional): Indica se o coeficiente de determinação R² deve ser calculado e exibido no terminal. Por padrão, é True.
|
|
173
|
+
|
|
174
|
+
Raises:
|
|
175
|
+
KeyError: Caso haja menos dados do que o número do grau do polinômio requerido, existirão infinitas "soluções".
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
list: Lista dos coeficientes em ordem crescente de grau.
|
|
179
|
+
"""
|
|
180
|
+
quantidade_de_pontos = len(lista_de_coordenadas)
|
|
181
|
+
|
|
182
|
+
if quantidade_de_pontos < grau_do_polinomio+1: #Condição necessária para que um polinômio seja encontrado.
|
|
183
|
+
raise KeyError("A quantidade de dados deve ser maior ou igual ao grau do polinômio desejado.")
|
|
184
|
+
#(
|
|
185
|
+
valores_x = [e for e,ee in lista_de_coordenadas]
|
|
186
|
+
valores_y = [ee for e,ee in lista_de_coordenadas]
|
|
187
|
+
# )Isola cada conjunto de dados de cada coordenada num vetor.
|
|
188
|
+
|
|
189
|
+
matriz_valores_x = [[e**i for e in valores_x] for i in range(grau_do_polinomio+1)]
|
|
190
|
+
|
|
191
|
+
#Feita a matriz de cada xis nos devidos graus para que o polinômio seja encontrado.
|
|
192
|
+
def produto_de_linhas(linha1:list, linha2:list) -> float: #Retorna o elemento da matriz resultado, quando se trata do produto de matrizes.
|
|
193
|
+
"""Executa uma operação entre listas do mesmo tamanho.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
linha1 (list): Lista de floats.
|
|
197
|
+
linha2 (list): Lista de floats.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
int: O resultado do "produto interno" dos "vetores" fornecidos.
|
|
201
|
+
"""
|
|
202
|
+
contador = 0
|
|
203
|
+
if len(linha1) == len(linha2):
|
|
204
|
+
for i in range(len(linha1)):
|
|
205
|
+
contador += linha1[i]*linha2[i]
|
|
206
|
+
|
|
207
|
+
return contador
|
|
208
|
+
|
|
209
|
+
matriz_produto_valores_x = [[produto_de_linhas(matriz_valores_x[i],matriz_valores_x[ii]) for i in range(len(matriz_valores_x))] for ii in range(len(matriz_valores_x[0])+1 - len(valores_x)+grau_do_polinomio)] #Menos um ou menos 2? Talvez 1 - (quantidade de dados - grau do polinomio)
|
|
210
|
+
#A matriz que define o sistema de equações que deve ser resolvido. A outra é:
|
|
211
|
+
|
|
212
|
+
vetor_valores_y_do_sistema = [produto_de_linhas(valores_y,matriz_valores_x[i]) for i in range(len(matriz_valores_x))]
|
|
213
|
+
vetor_solucao = resolvedor_de_sistemas(matriz_produto_valores_x,vetor_valores_y_do_sistema)
|
|
214
|
+
valores_y_ajustados = [
|
|
215
|
+
sum(vetor_solucao[i]*(x**i) for i in range(len(vetor_solucao)))
|
|
216
|
+
for x in valores_x
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
r_quadrado = coeficiente_determinacao(valores_y,valores_y_ajustados)
|
|
220
|
+
|
|
221
|
+
if mostrar_grafico == True:
|
|
222
|
+
grafico_ajuste_polinomial(valores_x, valores_y, vetor_solucao, r_quadrado)
|
|
223
|
+
|
|
224
|
+
if coeficiente_determinacao_r == True:
|
|
225
|
+
print(f"Coeficiente de Determinação R²: {r_quadrado:.2f}")
|
|
226
|
+
|
|
227
|
+
return vetor_solucao
|
|
228
|
+
|
|
229
|
+
def txt_aproximacao_polinomial(lista_de_coordenadas:list, grau_do_polinomio:int) -> str:
|
|
230
|
+
"""Utiliza MMQ para fazer a regressão polinomial dos pontos dados. Tudo no plano. Retorna o polinômio.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
lista_de_coordenadas (list): Uma lista dos pontos cuja função vai aproximar.
|
|
234
|
+
grau_do_polinomio (int): Qual tipo de polinômio a função retornará. 1 é linear, por exemplo.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
str: O polinômio na sua forma por extenso.
|
|
238
|
+
"""
|
|
239
|
+
k = str()
|
|
240
|
+
a = aproximacao_polinomial(lista_de_coordenadas,grau_do_polinomio, False, False) #não mostrar o gráfico e o R² duas vezes
|
|
241
|
+
|
|
242
|
+
for i in range(len(a)):
|
|
243
|
+
if a[len(a)-1-i] > 0:
|
|
244
|
+
k+=f"({a[len(a)-1-i]:.3})x^{len(a)-i-1}"
|
|
245
|
+
elif a[len(a)-1-i] == 0:
|
|
246
|
+
continue
|
|
247
|
+
else:
|
|
248
|
+
k+=f" + ({a[len(a)-1-i]:.3})x^{len(a)-i-1} "
|
|
249
|
+
|
|
250
|
+
return k
|
|
251
|
+
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Módulo para cálculo de erros numéricos.
|
|
3
|
+
|
|
4
|
+
Esse módulo fornece funções para calcular o erro absoluto e o erro relativo entre um valor real e um valor aproximado.
|
|
5
|
+
"""
|
|
6
|
+
from typing import List
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def erro_absoluto(valor_real: float, valor_aprox: float, casas_decimais: int = 6) -> float:
|
|
10
|
+
"""
|
|
11
|
+
Retorna o erro absoluto entre o valor real de um número e seu valor aproximado,
|
|
12
|
+
de acordo com a quantidade desejada de casas decimais.
|
|
13
|
+
Calcula o erro absoluto entre dois valores de um mesmo número: seu valor real e seu valor
|
|
14
|
+
aproximado. O erro absoluto é calculado por meio do módulo da diferença entre o valor real e o
|
|
15
|
+
valor aproximado.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
valor_real (float): É o valor real (ou exato, caso seja) do número
|
|
19
|
+
valor_aprox (float): É o valor aproximado do número
|
|
20
|
+
casas_decimais (int, optional): Número de casas decimais do resultado. Por padrão, é 6.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
float: Resultado do cálculo do erro absoluto
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
TypeError: se o `valor_real` e o `valor_aprox` não forem float ou int
|
|
27
|
+
ValueError: se `casas_decimais` não for um inteiro não negativo
|
|
28
|
+
"""
|
|
29
|
+
if not isinstance(valor_aprox, (int, float)) or not isinstance(valor_real, (int, float)):
|
|
30
|
+
raise TypeError("O valor real e o valor aproximado devem ser números reais.")
|
|
31
|
+
if not isinstance(casas_decimais, int) or casas_decimais<0:
|
|
32
|
+
raise ValueError("O número de casas decimais deve ser um inteiro não-negativo.")
|
|
33
|
+
erro = abs(valor_real - valor_aprox)
|
|
34
|
+
return round(erro, casas_decimais)
|
|
35
|
+
|
|
36
|
+
def erro_relativo(valor_real: float, valor_aprox: float, casas_decimais: int = 6) -> float:
|
|
37
|
+
"""
|
|
38
|
+
Retorna o erro relativo entre o valor real de um número e seu valor aproximado, de acordo
|
|
39
|
+
com a quantidade desejada de casas decimais.
|
|
40
|
+
O erro relativo é o erro absoluto dividido pelo valor absoluto do valor real.
|
|
41
|
+
Fórmula: E_r=|(valor_real-valor_aprox)/valor_real|
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
valor_real (float): O valor exato ou de referência. Deve ser diferente de zero.
|
|
45
|
+
valor_aprox (float): O valor obtido por medição ou aproximação.
|
|
46
|
+
casas_decimais (int, optional): Número de casas decimais do resultado. Por padrão, é 6.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
float: O erro relativo calculado, arredondado para o número de casas decimais
|
|
50
|
+
especificado em `casas_decimais`.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
ValueError: Se o `valor_real` for zero, o que causaria divisão por zero.
|
|
54
|
+
TypeError: se o `valor_real` e o `valor_aprox` não forem float ou int
|
|
55
|
+
ValueError: se `casas_decimais` não for um inteiro não negativo
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
if valor_real==0:
|
|
59
|
+
raise ValueError("O valor real não pode ser zero para o cálculo do erro relativo.")
|
|
60
|
+
if not isinstance(valor_aprox, (int, float)) or not isinstance(valor_real, (int, float)):
|
|
61
|
+
raise TypeError("O valor real e o valor aproximado devem ser números reais.")
|
|
62
|
+
if not isinstance(casas_decimais, int) or casas_decimais<0:
|
|
63
|
+
raise ValueError("O número de casas decimais deve ser um inteiro não-negativo.")
|
|
64
|
+
|
|
65
|
+
return round(abs((valor_real-valor_aprox)/valor_real), casas_decimais)
|
|
66
|
+
|
|
67
|
+
def soma_de_kahan(lista_de_valores: List[float]) -> float:
|
|
68
|
+
"""
|
|
69
|
+
O algoritmo de soma de Kahan é um método de análise numérica que
|
|
70
|
+
visa minimizar o erro numérico (erro de arredondamento) ao somar
|
|
71
|
+
uma sequência de números de ponto flutuante de precisão finita.
|
|
72
|
+
Se o usuário decidir somar uma lista de números que possua valores
|
|
73
|
+
muito grandes e valores muito pequenos, como a precisão dos computadores
|
|
74
|
+
é limitida, os dígitos de baixa ordem (menos significativos) do número
|
|
75
|
+
pequeno podem ser perdidos durante a operação de adição devido ao
|
|
76
|
+
arrendondamento. Para minimizar essa falha, o algoritmo da soma de Kahan
|
|
77
|
+
mantém uma variável de "compensação" durante a realização da soma, a qual
|
|
78
|
+
acumula os dígitos de baixa ordem "perdidos" a cada etapa da operação. A
|
|
79
|
+
cada nova etapa de adição, esse erro é usado para "ajustar" o próximo número
|
|
80
|
+
que será somado, compensando a perda de precisão do anterior.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
lista_de_valores (List[float]): A lista dos valores de ponto fluante que se deseja somar
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
float: Retorna a soma compensada dos números de ponto flutuante fornecidos
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
if not isinstance(lista_de_valores, list):
|
|
90
|
+
raise TypeError ("a lista de valores fornecida deve ser uma lista")
|
|
91
|
+
|
|
92
|
+
soma_total = 0.0 # a soma corrente
|
|
93
|
+
compensação = 0.0 # a variável que será a compensação
|
|
94
|
+
|
|
95
|
+
for valor in lista_de_valores:
|
|
96
|
+
if not isinstance(valor, float) and not isinstance(valor, int): # se o valor fornecido não for um float ou um inteiro, a operação não é realizada
|
|
97
|
+
continue
|
|
98
|
+
|
|
99
|
+
v = valor - compensação # a cada valor, desconta-se a compensação
|
|
100
|
+
soma_auxiliar = soma_total + v # a soma auxiliar pega a soma total corrente e adicona o valor após a compensação
|
|
101
|
+
compensação = (soma_auxiliar - soma_total) - v # a compensação é atualizada
|
|
102
|
+
soma_total = soma_auxiliar # a soma total corrente é atualizada com o valor da soma armazenada na variável auxiliar
|
|
103
|
+
|
|
104
|
+
return soma_total
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
def grafico_ajuste_linear(valores_x:list, valores_y:list, coeficiente_angular:float, coeficiente_linear:float, r_quadrado:float) -> None:
|
|
5
|
+
"""Gera o gráfico de dispersão dos pontos e a reta de ajuste linear.
|
|
6
|
+
Args:
|
|
7
|
+
valores_x (list): Coordenada x de cada ponto.
|
|
8
|
+
valores_y (list): Coordenada y de cada ponto.
|
|
9
|
+
coeficiente_angular (float): Coeficiente angular da reta de ajuste linear.
|
|
10
|
+
coeficiente_linear (float): Coeficiente linear da reta de ajuste linear.
|
|
11
|
+
r_quadrado (float): Coeficiente de determinação R².
|
|
12
|
+
"""
|
|
13
|
+
plt.scatter(valores_x, valores_y, color='blue', label='Pontos de dados')
|
|
14
|
+
|
|
15
|
+
x_min = min(valores_x)
|
|
16
|
+
x_max = max(valores_x)
|
|
17
|
+
y_min = coeficiente_angular * x_min + coeficiente_linear
|
|
18
|
+
y_max = coeficiente_angular * x_max + coeficiente_linear
|
|
19
|
+
|
|
20
|
+
plt.plot([x_min, x_max], [y_min, y_max], color='red', label=f'Reta de Ajuste Linear (R² = {r_quadrado:.2f})')
|
|
21
|
+
|
|
22
|
+
plt.xlabel('Valores X')
|
|
23
|
+
plt.ylabel('Valores Y')
|
|
24
|
+
plt.title('Ajuste Linear')
|
|
25
|
+
plt.legend()
|
|
26
|
+
plt.grid(True)
|
|
27
|
+
plt.show()
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
#versão utilizando numpy - a reta de ajuste fica mais suave
|
|
32
|
+
def grafico_ajuste_polinomial(valores_x:list, valores_y:list, coeficientes:list, r_quadrado:float) -> None:
|
|
33
|
+
"""Gera o gráfico de dispersão dos pontos e a curva de ajuste polinomial.
|
|
34
|
+
Args:
|
|
35
|
+
valores_x (list): Coordenada x de cada ponto.
|
|
36
|
+
valores_y (list): Coordenada y de cada ponto.
|
|
37
|
+
coeficientes (list): Coeficientes do polinômio de ajuste.
|
|
38
|
+
r_quadrado (float): Coeficiente de determinação R².
|
|
39
|
+
"""
|
|
40
|
+
plt.scatter(valores_x, valores_y, color='blue', label='Pontos de dados')
|
|
41
|
+
|
|
42
|
+
#cria 200 pontos igualmente espaçados entre o min e o max de x para uma curva mais suave
|
|
43
|
+
intervalo_x = np.linspace(min(valores_x), max(valores_x), 200)
|
|
44
|
+
|
|
45
|
+
valores_y_ajustados = []
|
|
46
|
+
#calcula e adiciona os valores de y ajustados usando a expressão do polinomio
|
|
47
|
+
for x in intervalo_x:
|
|
48
|
+
y=0
|
|
49
|
+
for i in range(len(coeficientes)):
|
|
50
|
+
y += coeficientes[i] * (x ** i)
|
|
51
|
+
valores_y_ajustados.append(y)
|
|
52
|
+
|
|
53
|
+
plt.plot(intervalo_x, valores_y_ajustados, color='red', label=f'Curva de Ajuste Polinomial (R² = {r_quadrado:.2f})')
|
|
54
|
+
|
|
55
|
+
plt.xlabel('Valores X')
|
|
56
|
+
plt.ylabel('Valores Y')
|
|
57
|
+
plt.title('Ajuste Polinomial')
|
|
58
|
+
plt.legend()
|
|
59
|
+
plt.grid(True)
|
|
60
|
+
plt.show()
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Módulo de integração numérica — cálculo e visualização de integrais definidas.
|
|
3
|
+
|
|
4
|
+
Este módulo fornece ferramentas para o cálculo numérico de integrais definidas
|
|
5
|
+
de funções reais em um intervalo [a, b], utilizando dois métodos clássicos:
|
|
6
|
+
- Regra dos Trapézios
|
|
7
|
+
- Regra de Simpson (1/3)
|
|
8
|
+
|
|
9
|
+
Além de realizar o cálculo, gera representações gráficas
|
|
10
|
+
da área sob a curva, facilitando a visualização dos conceitos de integração.
|
|
11
|
+
|
|
12
|
+
Exemplo de uso:
|
|
13
|
+
---------------
|
|
14
|
+
>>> from CB2325NumericaG5.integracao import integral
|
|
15
|
+
>>> resultado = integral(lambda x: x**2, 0, 2, n=10, metodo="simpson", plot=True)
|
|
16
|
+
>>> print(resultado)
|
|
17
|
+
2.6667
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from typing import Callable, Union
|
|
21
|
+
import matplotlib.pyplot as plt
|
|
22
|
+
import numpy as np
|
|
23
|
+
|
|
24
|
+
def _plot_parabola(x0: float, x1: float, x2: float, y0: float, y1: float, y2: float) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Gera a representação gráfica de uma parábola que passa por (x0,y0), (x1,y1) e (x2,y2) no intervalo [x0,x2],
|
|
27
|
+
preenchendo a área entre a curva e o eixo x.
|
|
28
|
+
|
|
29
|
+
Esta função não retorna valor, apenas gera uma representação gráfica da parábola.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
x0 (float): x do primeiro ponto da parábola
|
|
33
|
+
x1 (float): x do segundo ponto da parábola
|
|
34
|
+
x2 (float): x do terceiro ponto da parábola
|
|
35
|
+
y0 (float): y do primeiro ponto da parábola
|
|
36
|
+
y1 (float): y do segundo ponto da parábola
|
|
37
|
+
y2 (float): y do terceiro ponto da parábola
|
|
38
|
+
"""
|
|
39
|
+
# Encontrando coeficientes a, b, c da parábola y = ax² + bx + c:
|
|
40
|
+
A = np.array([[x0**2, x0, 1],
|
|
41
|
+
[x1**2, x1, 1],
|
|
42
|
+
[x2**2, x2, 1]])
|
|
43
|
+
y_vec = np.array([y0, y1, y2])
|
|
44
|
+
a, b, c = np.linalg.solve(A, y_vec)
|
|
45
|
+
|
|
46
|
+
# Pontos da parábola
|
|
47
|
+
x_para = np.linspace(x0, x2, 50)
|
|
48
|
+
y_para = a*x_para**2 + b*x_para + c
|
|
49
|
+
|
|
50
|
+
plt.plot(x_para, y_para, 'r--', alpha=0.7, linewidth=1)
|
|
51
|
+
plt.fill_between(x_para, 0, y_para, alpha=0.2, color='red')
|
|
52
|
+
|
|
53
|
+
def integral(
|
|
54
|
+
funcao: Callable[[Union[float, np.ndarray]], Union[float, np.ndarray]],
|
|
55
|
+
a: float,
|
|
56
|
+
b: float,
|
|
57
|
+
n: int,
|
|
58
|
+
aprox: int = 4,
|
|
59
|
+
metodo: str = "simpson",
|
|
60
|
+
plot: bool = True
|
|
61
|
+
) -> float:
|
|
62
|
+
"""
|
|
63
|
+
Calcula numericamente a integral definida de uma função no intervalo [a, b],
|
|
64
|
+
utilizando o método dos trapézios ou a regra de Simpson (1/3) e
|
|
65
|
+
gera uma representação gráfica da integral.
|
|
66
|
+
|
|
67
|
+
Se `a > b`, o resultado será negativo, seguindo a convenção matemática.
|
|
68
|
+
|
|
69
|
+
O método dos trapézios aproxima a área sob a curva dividindo o intervalo em
|
|
70
|
+
`n` subintervalos igualmente espaçados e somando as áreas dos trapézios formados
|
|
71
|
+
entre os pontos consecutivos.
|
|
72
|
+
|
|
73
|
+
Já a regra de Simpson aproxima a integral pela soma das áreas sob polinômios quadráticos
|
|
74
|
+
que interpolam a função, proporcionando maior precisão com o mesmo número de
|
|
75
|
+
subdivisões — desde que `n` seja par.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
funcao (Callable[[Union[float, np.ndarray]], Union[float, np.ndarray]]): Função a ser integrada.
|
|
79
|
+
a (float): Limite inferior de integração.
|
|
80
|
+
b (float): Limite superior de integração.
|
|
81
|
+
n (int): Número de subdivisões (intervalos) utilizados na aproximação. Para o método de Simpson, `n` deve ser par.
|
|
82
|
+
aprox (int, optional): Número de casas decimais para arredondamento do resultado. O padrão é 4.
|
|
83
|
+
metodo (str, optional): Método de integração numérica a ser utilizado: `"trapezios"` ou `"simpson"`. O padrão é `"simpson"`.
|
|
84
|
+
plot (bool, optional): Se True, exibe a representação gráfica da integral. O padrão é True.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
ValueError: Se o método for `"simpson"` e `n` for ímpar.
|
|
88
|
+
ValueError: Se o argumento `metodo` não for `"trapezios"` nem `"simpson"`.
|
|
89
|
+
ValueError: Se `n` não for um inteiro positivo.
|
|
90
|
+
ValueError: Se `aprox` não for um inteiro não negativo.
|
|
91
|
+
TypeError: Se os limites de integração `a` e `b` não forem números reais.
|
|
92
|
+
TypeError: Se `funcao` não for chamável (callable).
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
float: Valor aproximado da integral definida de `funcao` no intervalo [a, b],
|
|
96
|
+
arredondado para o número de casas decimais especificado em `aprox`.
|
|
97
|
+
"""
|
|
98
|
+
# Validação da entrada
|
|
99
|
+
if not callable(funcao):
|
|
100
|
+
raise TypeError("O argumento 'funcao' deve ser chamável (callable).")
|
|
101
|
+
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
|
|
102
|
+
raise TypeError("Os limites de integração 'a' e 'b' devem ser números reais.")
|
|
103
|
+
if not isinstance(n, int) or n <= 0:
|
|
104
|
+
raise ValueError("O número de subdivisões 'n' deve ser um inteiro positivo (> 0).")
|
|
105
|
+
if not isinstance(aprox, int) or aprox < 0:
|
|
106
|
+
raise ValueError("O número de casas decimais 'aprox' deve ser um inteiro não negativo (>= 0).")
|
|
107
|
+
if metodo not in ("trapezios", "simpson"):
|
|
108
|
+
raise ValueError("Método inválido! Use 'trapezios' ou 'simpson'.")
|
|
109
|
+
|
|
110
|
+
funcao_vec = np.vectorize(funcao, otypes=[float])
|
|
111
|
+
|
|
112
|
+
# Cálculo da integral
|
|
113
|
+
dx = (b - a) / n
|
|
114
|
+
soma = 0.0
|
|
115
|
+
|
|
116
|
+
if metodo == "trapezios":
|
|
117
|
+
for i in range(n):
|
|
118
|
+
x1 = a + i * dx
|
|
119
|
+
x2 = a + (i + 1) * dx
|
|
120
|
+
soma += (float(funcao_vec(x1)) + float(funcao_vec(x2))) * dx / 2
|
|
121
|
+
|
|
122
|
+
else: # metodo == "simpson"
|
|
123
|
+
if n % 2 != 0:
|
|
124
|
+
raise ValueError("Para o método de Simpson, o número de subintervalos 'n' deve ser par.")
|
|
125
|
+
for i in range(n + 1):
|
|
126
|
+
x = a + i * dx
|
|
127
|
+
if i == 0 or i == n:
|
|
128
|
+
soma += float(funcao_vec(x))
|
|
129
|
+
elif i % 2 == 1:
|
|
130
|
+
soma += 4 * float(funcao_vec(x))
|
|
131
|
+
else:
|
|
132
|
+
soma += 2 * float(funcao_vec(x))
|
|
133
|
+
|
|
134
|
+
soma *= dx / 3
|
|
135
|
+
|
|
136
|
+
if plot:
|
|
137
|
+
x = np.linspace(a-0.11*(b-a), b + 0.11*(b-a), 100)
|
|
138
|
+
y = funcao_vec(x)
|
|
139
|
+
|
|
140
|
+
plt.figure(figsize=(10, 6))
|
|
141
|
+
|
|
142
|
+
plt.plot(x, y, label='f(x)', linewidth=2, linestyle='-', color='black')
|
|
143
|
+
|
|
144
|
+
plt.title(f"Integração de f(x) = {round(float(soma), aprox)} — método: {metodo.capitalize()}", fontsize=16, fontweight='bold')
|
|
145
|
+
plt.xlabel("x", fontsize=12)
|
|
146
|
+
plt.ylabel("y", fontsize=12)
|
|
147
|
+
plt.grid(True, alpha=0.3)
|
|
148
|
+
plt.legend(fontsize=12)
|
|
149
|
+
|
|
150
|
+
# Garantia do eixo x (y=0) estar sempre no gráfico
|
|
151
|
+
y_min = min(np.min(y), 0)
|
|
152
|
+
y_max = max(np.max(y), 0)
|
|
153
|
+
|
|
154
|
+
# Margem para visualização total do gráfico
|
|
155
|
+
margem_y = 0.1 * (y_max - y_min)
|
|
156
|
+
margem_x = 0.1 * (b - a)
|
|
157
|
+
plt.ylim(y_min - margem_y, y_max + margem_y)
|
|
158
|
+
plt.xlim(a-margem_x, b + margem_x)
|
|
159
|
+
|
|
160
|
+
#Eixos x e y
|
|
161
|
+
plt.axhline(y=0, color='black', linewidth=1.5, linestyle='-')
|
|
162
|
+
plt.axvline(x=0, color='black', linewidth=1.5, linestyle='-')
|
|
163
|
+
|
|
164
|
+
# Limites da integração
|
|
165
|
+
plt.plot([a, a], [0, funcao_vec(a)], color='black', linewidth=1.5, linestyle='-')
|
|
166
|
+
plt.plot([b, b], [0, funcao_vec(b)], color='black', linewidth=1.5, linestyle='-')
|
|
167
|
+
|
|
168
|
+
# Plot da integral
|
|
169
|
+
if metodo == "trapezios":
|
|
170
|
+
for i in range(n):
|
|
171
|
+
x_i = a + i * dx
|
|
172
|
+
x_i2 = a + (i + 1) * dx
|
|
173
|
+
|
|
174
|
+
x_trap = [x_i, x_i, x_i2, x_i2, x_i] # Pontos do trápezio (inf esquerdo, sup esquerdo, sup direito, inf direito)
|
|
175
|
+
y_trap = [0, funcao_vec(x_i), funcao_vec(x_i2), 0, 0] # 5º ponto para fechar o polígono
|
|
176
|
+
|
|
177
|
+
plt.fill(x_trap, y_trap, alpha=0.3, color='orange', edgecolor='black')
|
|
178
|
+
|
|
179
|
+
else: # metodo == "simpson"
|
|
180
|
+
for i in range(0,n,2):
|
|
181
|
+
x_i = a + i * dx
|
|
182
|
+
x_i2 = a + (i + 1) * dx
|
|
183
|
+
x_i3 = a + (i + 2) * dx
|
|
184
|
+
y_i, y_i2, y_i3 = float(funcao_vec(x_i)), float(funcao_vec(x_i2)), float(funcao_vec(x_i3))
|
|
185
|
+
|
|
186
|
+
_plot_parabola(x_i, x_i2, x_i3, y_i, y_i2, y_i3)
|
|
187
|
+
|
|
188
|
+
plt.show()
|
|
189
|
+
|
|
190
|
+
return round(float(soma), aprox)
|