Last active
January 9, 2023 21:24
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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