Skip to content

Instantly share code, notes, and snippets.

@gabteles
Last active January 9, 2023 21:24
Show Gist options
  • Save gabteles/5471523 to your computer and use it in GitHub Desktop.
Save gabteles/5471523 to your computer and use it in GitHub Desktop.
Cálculo de logaritmo em qualquer base. Algoritmo lento, possivelmente pela quantidade exorbitante de divisões e utilizações de Math.sqrt (que não chegam a ser tão frequentes como o número de divisões, mas ainda é alto: por volta de 50 a cada cálculo de logaritmo)
# Algoritmo de Logaritmo
# Autor: Gabriel "Gab!" Teles <gab dot teles at hotmail dot com>
# Data: 2013-04-26
def log(n, m)
# Verifica valores de entrada
if m == 0 # Não existe logaritmo de 0, logo, adequa valor
# ao retornado pelo Math.log: -Infinity
return -1.0/0.0
elsif m < 0 # Logaritmos de negativos estão fora de questão, também.
# Adequa erro ao realizado pelo core.
raise(Math::DomainError, "Numerical argument is out of domain", caller)
end
z = 0.0 # Valor final
n = n.to_f # Converte para flutuante
# Cálculo de parte inteira:
# Divide m por n até que
# não seja mais possível
# encontrar um número maior
# que 1.
# Ao fim, n^z < m < n^(z+1)
until n > m
m /= n
z += 1
end
# Quando m não converge para 1,
# significa que o logaritmo possui
# parte decimal
if m != 1
c = 0.5 # Coeficiente (para cada volta abaixo,
# n^c deve convergir para 1,
# para ocasionar divisões
# menores em m, de modo que
# a precisão seja mantida
# ao convergir m para 1)
d = 0 # Coeficiente de divisão (Evita a divisão
# desnecessária. Faz somas e ao fim, quando
# o coeficiente (c) for utilizado, modifica-o
# para receber apenas uma divisão com 2^d)
until m == 1
n = Math.sqrt(n) # Atualiza valor de n para a próxima raiz
if m >= n # Pular divisões que ocasionem
# m como um número menor que 1
# afinal, a ideia é convergir
# para 1.
m /= n # Realiza a divisão que converge m para 1
c /= 2 ** d #
z += c
d = 0 # Reseta o coeficiente
end
d += 1 # Próximo coeficiente
end
end
return z # Resultado
end
# TESTES DE BENCHMARK
require 'benchmark'
p core = Benchmark.measure{1_000_000.times{|i| Math.log(i)}}
p mine = Benchmark.measure{1_000_000.times{|i| log(Math::E, i)}}
times = mine.real/core.real
strTimes = (times > 1 ? times : 1/times).round(2)
if times == 1
puts "Mine is equal core's log"
else
puts "Mine is #{strTimes} times #{times > 1 ? 'slower' : 'faster'} than core log. #{times < 1 ? ':)' : '):'}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment