Elias Granja Jr. Free as in free speech

11Jul/111

Ainda falando em primos – Python

No último post sobre números primos, citei uma forma que ainda utiliza fatoração, que não é uma maneira rápida de se descobrir se um número é ou não primo, apesar das várias formas de "pular" alguns números.

Como voltei a ler o livro Algoritmos do Dasgupta, Sanjoy et al. achei mais uma forma de se fazer isso pulando a parte chata da fatoração.
Essa formula se baseia no fato que para todo número primo p e todo a, 1<= a < p tem a seguinte afirmação como verdade:

a^( p - 1 ) mod p = 1 mod p

Dessa forma pode-se evitar a fatoração que é algo absurdamente lento. Em python ficaria da seguinte forma:

def primo( num ):
	if( 2**(num-1) % num == 1 % num):
		print "primo"
	else:
		print "nao primo"

O problema do teorema é que ele não afirma que "se e somente se" a igualdade for verdadeira teremos um número primo, ou seja, poderia haver números compostos que passariam no teste. E existem.  Os números de Carmichael passam no teste e por isso, de acordo com a wikipedia, eles também são chamados de pseudoprimos. Porém eles são raros e dependendo de tão grande é o primo que você necessita, como na criptografia RSA, vale a pena o risco de se usar um pseudoprimo ao invés de fatorar um número gigantesco.

Além disso, existem casos em que o valor de a também deixaria a igualdade verdadeira para números compostos, Sanjoy afirma que metade dos valores possíveis de a fazem isso se desconsiderarmos os números de Carmichael.

Uma forma de se evitar falsos positivos é testar o número com diferentes e aleatórios valores para a. Quanto mais testes, menor é a probabilidade de erro. Testar 100 valores para a faria com que seja mais fácil um raio cósmico queimar o computador do que obter um falso positivo, brinca Sanjoy.

18Feb/110

Exponenciação Modular

Durante o projeto de criptografia do semestre passado, tivemos várias dificuldades para trabalhar com números grandes. Desde a limitação do long(contornamos usando BigInteger no java) a vagarosidade de se trabalhar com exponenciação modular.

Para evitar que x^y crescesse demais a ponto de ficar incalculável, resolvemos multiplicar x mod N, y vezes. Porém ainda assim o algoritmo era lento. No livro de Algoritmos do Sanjoy Dasgupta, Christos Papadimitriou e Umesh Vazirani, temos um exemplo muito mais prático que toma o tempo de O(log² N) que é multiplicar por potências que correspondem aos 1 da representação binária de y. Exemplo:

x^25 = x^11001 = x^16 * x^8 * x^1
Em python:

def exponenciacao(x,y,n):
    if y == 0:
        return 1
    z = exponenciacao(x,y/2,n)
    if y % 2 == 0:
        return (z**2) % n
    else:
        return ( x*z**2 ) % n
20Dec/101

Soma de 1 até n inteiros

Estou lendo um livro sobre a teoria dos números e um dos princípios básicos do livro é a regra de soma de n inteiros positivos. Para somar de 1 até n basta seguir a regra:

S(n) = n * ( n -1 )

Exemplo:

S(3) = 3 * ( 3-1 )

S(3) = 3 * 2

S(3) = 6 = 1 + 2 +3

Implementado em python:

15Dec/102

Lista encadeada em Python

Estou aproveitando o tempo livre ocasionado pelas férias na Unip para estudar um pouco mais alguns conceitos de computação. Um deles é a lista encadeada. Para quem não sabe o que é, lista encadeada é uma espécie de array, porém com a possiblidade de se adaptar ao tamanho correto automaticamente. Quem tem o interesse de aprender sobre ela recomendo esse post

Falta organizar várias coisas no código, mas o básico é isso. Neste exemplo uso a posição zero apenas para marcar a variável na memória do computador:

class Lista():
	__valor = None
	__proximo = None
 
	def __init__(self,valor = None):
		self.__valor = valor
 
	def getProximo(self):
		return self.__proximo
 
	def setProximo(self,pro):
		self.__proximo = pro
 
	def getValor(self):
		return self.__valor
 
	def adicionar(self,valor):
		temporario = None
		if self.__proximo == None:
			self.__proximo = Lista(valor)
			return None
		proximo = self.__proximo
		temporario = proximo
		while not proximo ==  None:
			proximo = proximo.getProximo()
			if not proximo == None:
				temporario = proximo
		temporario.setProximo(Lista(valor))
		#proximo.setProximo(ok)
 
	def posicao(self,pos):
		proximo = self.__proximo
		if pos == 0:
			return self.getValor()
		for i in range(0,pos-1):
			proximo = proximo.getProximo()
		return proximo.getValor()
 
	def remover(self,pos):
		temporario = None
		proximo = self.__proximo
		j=0
		for i in range(0,pos-2):
			temporario = proximo
			if i == pos - 2:
				break
			proximo = proximo.getProximo()
		if proximo.getProximo().getProximo() == None:
			proximo.setProximo(None)
		else:
			proximo.setProximo(proximo.getProximo().getProximo())
19Aug/100

Função totiente de Euler – Python

Estou trabalhando em um trabalho de criptografia para a universidade e precisava saber o phi do produto de dois primos. O phi deste número é bem simples de se conseguir, basta subtrair os dois primos por um, aqui chamados de p e q, e multiplica-los( (p - 1) x (q - 1) ). Exemplo em python usado no algoritmo:

# http://eliasgranja.com
def phi(p,q):
	aux = (p - 1) * (q - 1)
	return aux
17Aug/100

Calculando números primos – Python

Um clássico problema de programação é o calculo para descobrir números primos de forma rápida e precisa. Por isso, decidi fazer no meu tempo ocioso uma função em python que retorne se um número é ou não primo.
Usei o teorema que diz que todo o número não primo é divisivel por outro menor ou igual a sua raiz quadrada e o resultado foi o seguinte:

import math
def primo(a):
	for i in xrange(2,int(math.sqrt(a)+1)):
		if(a%i==0):
			print("%d nao e primo" % a)
			return 0
	print("%d e primo" % a)
	return 1