- Encapsule o código do algoritmo de raiz quadrada em uma função. Essa função deve retornar um número de ponto flutuante (float), de forma que possa ser usada em expressões matemáticas (por exemplo, para calcular
). Ou seja, a assinatura dessa função deve ser compatível com o math. sqrt.
Passo 1
O que o enunciado pede e quais são as informações dadas.
- Pede para encapsular o algoritmo de raiz quadrada em uma função que:
- tenha assinatura compatível com
math.sqrt(ou seja, receba um único argumento e retorne umfloat); - possa ser usada em expressões matemáticas como, por exemplo,
.
- tenha assinatura compatível com
- Informação implícita importante: a função deve aceitar números não negativos e devolver a raiz quadrada como ponto flutuante; para entradas inválidas (por exemplo, números negativos) devemos sinalizar erro, tal como
math.sqrtfaz.
Passo 2
Escolha do método para calcular a raiz quadrada (explicação sucinta e por que escolhi esse método).
- Vou usar o método de Newton–Raphson (também chamado de método babilônico para raízes quadradas). Motivos:
- É simples e rápido (converge quadráticamente perto da solução);
- Só precisa de operações básicas (adição, divisão, multiplicação), então pode ser implementado sem bibliotecas especiais;
- É fácil controlar tolerância e número máximo de iterações para garantir retorno em tempo finito.
- Não usei métodos mais complicados (por exemplo, aproximações por séries ou manipulação bit a bit) porque Newton é suficiente, claro e fácil de explicar.
Passo 3
Princípio matemático do método Newton para raiz quadrada (aula curta e intuitiva).
- Queremos encontrar
tal que , onde é o número cuja raiz queremos. - Definimos a função
. A raiz de é a raiz quadrada de . - A iteração de Newton para resolver
é - Aqui
. Substituindo: - Essa fórmula é a iteração babilônica:
- Intuição: cada iteração combina o chute atual
com (um outro chute), fazendo uma média que tende rapidamente à raiz.
Passo 4
Critério de parada e cuidados numéricos (como saber quando parar e tratar casos especiais).
- Critério prático: parar quando a mudança entre iterações for pequena o suficiente, por exemplo quando
onde tolé uma tolerância pequena (por exemplo). Usei esse critério relativo para funcionar bem tanto para números grandes quanto pequenos. - Também posso checar o erro relativo em termos de
: . Ambos funcionam; escolhi o primeiro por simplicidade de implementação. - Casos especiais:
- Se
devolvemos imediatamente. - Se
devemos levantar um erro (no Python math.sqrtlevantaValueError: math domain error). - Converge rápido, mas vou colocar um limite máximo de iterações (por exemplo, 100) para garantir que a função sempre retorne em tempo finito.
- Se
Passo 5
Detalhamento linha-a-linha do que a função fará (decisões de implementação que você precisa entender na prova).
- Entrada:
- Receber um argumento
x. Converter parafloatpara garantir que o retorno sejafloate para permitir entrada de inteiros. - Se a conversão falhar (por exemplo, string não numérica), propagar um
TypeError/ValueErrorapropriado.
- Receber um argumento
- Verificações iniciais:
- Se
x < 0: levantarValueError("math domain error"). - Se
x == 0.0: retornar0.0.
- Se
- Chute inicial (
t0):- Uma escolha simples e eficiente é
t0 = xquandox >= 1.0, caso contráriot0 = 1.0. Isso evita divisão por zero e melhora a convergência para números pequenos.
- Uma escolha simples e eficiente é
- Iteração:
- Aplicar a fórmula
até o critério de parada ou até atingir o número máximo de iterações.
- Aplicar a fórmula
- Retorno:
- Retornar o valor final como
float.
- Retornar o valor final como
- Mensagem de erro:
- Para números negativos use
ValueError("math domain error")para ficar coerente commath.sqrt.
- Para números negativos use
Passo 6
Observações práticas rápidas para a prova e uso em expressões.
- A função com essa assinatura (
def sqrt(x): ...) pode ser usada diretamente em expressões comoem Python escrevendo, por exemplo: x * sqrt(2) + z * sqrt(y)
- O método é robusto para maioria dos casos reais que aparecerão numa prova de programação numérica; se quiser maior precisão, basta reduzir
tol(mas cuidado com o número de iterações).
Resposta
def sqrt(x):
"""Compute the square root of x (similar signature to math.sqrt).
Returns a float. Raises ValueError("math domain error") for x < 0.
"""
# tentativa de conversão para float (levanta TypeError/ValueError se inválido)
try:
x = float(x)
except Exception:
raise TypeError("must be a real number") from None
if x < 0.0:
raise ValueError("math domain error")
if x == 0.0:
return 0.0
# parâmetros do método
tol = 1e-12
max_iter = 100
# chute inicial: escolha simples que funciona bem na prática
t = x if x >= 1.0 else 1.0
for _ in range(max_iter):
next_t = 0.5 * (t + x / t)
# critério de parada relativo
if abs(next_t - t) <= tol * max(1.0, next_t):
return float(next_t)
t = next_t
# se não convergir dentro de max_iter, devolve o melhor chute
return float(t)