Skip to content

Commit 6be5bf7

Browse files
committed
Não é ainda uma solução, mas está chegando lá.
1 parent 8f35377 commit 6be5bf7

8 files changed

+345
-10
lines changed

c/a.out

0 Bytes
Binary file not shown.

c/primospi.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ int main()
220220
{
221221
FILE *fs = NULL;
222222

223-
fs = fopen("pi-1M.txt", "r"); // abrir o arquivo e alocar na memória para processar
223+
fs = fopen("../pi-100.txt", "r"); // abrir o arquivo e alocar na memória para processar
224224
if (!fs)
225225
{
226226
printf("Erro ao ler o arquivo\n");

go/desafio11.go

+252
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
// Adriano Roberto de Lima
2+
// Solução do desafio 11 - osprogramadores.com
3+
// Otimizada para rodar o mais rapido possível
4+
// Processa as sequências sem espaços entre os primos encontrados
5+
6+
package main
7+
8+
import (
9+
"flag"
10+
"fmt"
11+
"io/ioutil"
12+
"log"
13+
"math"
14+
"os"
15+
"runtime"
16+
"runtime/pprof"
17+
)
18+
19+
// Estrutura para ser enviada no canal de requests da função startWorkers.
20+
type (
21+
sRequest struct {
22+
posInicial int
23+
palavra []byte
24+
posicao int
25+
sequencia string
26+
dados []byte
27+
lenDados int
28+
testaPrimo []bool
29+
lenMaiorSeq int
30+
}
31+
32+
// Estrutura que vamos usar para retornar as sequencias e a posição onde foram
33+
// encontradas. Precisamos registrar as posições pois não sabemos a ordem
34+
// de finalização dos requests que serão processados pelos workers (goroutines)
35+
sSequencia struct {
36+
sequencia string
37+
posInicial int
38+
}
39+
)
40+
41+
// geraprimos é uma função para geração de um array que identifica se um
42+
// número é primo ou não. Vamos usar esse array para acelerar a identificação
43+
// de números primos na busca das soluções.
44+
// Referência: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
45+
// Só vamos rodar uma vez.
46+
func geraPrimos(n int64) []bool {
47+
var (
48+
i, j int64
49+
)
50+
51+
flag1 := make([]bool, n)
52+
for i = 0; i < n; i++ {
53+
flag1[i] = true
54+
}
55+
56+
flag1[0] = false
57+
flag1[1] = false
58+
59+
for i = 2; i < int64(math.Sqrt(float64(n)))+1; i++ {
60+
if flag1[i] {
61+
for j = i * i; j < n; j += i {
62+
flag1[j] = false
63+
}
64+
}
65+
}
66+
return flag1
67+
}
68+
69+
// palavraToInt converte um array de bytes para um inteiro. Não faz nenhum tipo
70+
// de verificação. Serve para converter a palavra que está na função "geraSequencias".
71+
// É bem mais rápido do que fazer um strconv.Atoi(string(b))
72+
func palavraToInt(b []byte) int {
73+
n := 0
74+
for _, ch := range b {
75+
ch -= '0'
76+
n = n*10 + int(ch)
77+
}
78+
return n
79+
}
80+
81+
// geraSequencias é a função utilizada para encontrar sequencias de numeros primos,
82+
// de no máximo 4 digitos, maiores que lenMaiorSeq, partindo de uma posição p
83+
// de uma sequência de digidos "dados".
84+
func geraSequencias(posInicial int, palavra []byte, posicao int, sequencia string, dados []byte, lenDados int, testaPrimo []bool, lenMaiorSeq int) []sSequencia {
85+
ret := []sSequencia{}
86+
novapalavra := append(palavra, dados[posicao])
87+
88+
// Se o tamanho da palavra é maior que quatro bytes então já ultrapassamos o limite
89+
// para encontrar um numero primo. Por isso
90+
// retornamos a sequência que encontramos se ela for maior ou igual a lenMaiorSeq.
91+
if posicao >= lenDados || len(novapalavra) > 4 {
92+
if len(sequencia) >= lenMaiorSeq {
93+
ret = append(ret, sSequencia{sequencia, posInicial})
94+
}
95+
return ret
96+
}
97+
98+
// Aqui disparamos a busca por novas soluções considerando a novapalavra, partindo
99+
// da nova posição e a sequencia que já temos.
100+
r := geraSequencias(posInicial, novapalavra, posicao+1, sequencia, dados, lenDados, testaPrimo, lenMaiorSeq)
101+
ret = append(ret, r...)
102+
103+
// Se a nova palavra for um primo, podemos colocá-la na sequencia e continuar
104+
// a busca por novas palavras válidas.
105+
if testaPrimo[palavraToInt(novapalavra)] {
106+
r = geraSequencias(posInicial, []byte{}, posicao+1, sequencia+string(novapalavra), dados, lenDados, testaPrimo, lenMaiorSeq)
107+
ret = append(ret, r...)
108+
}
109+
110+
return ret
111+
}
112+
113+
// worker é a função que faz as chamadas da nossa função geraSequencias usando
114+
// os canais de entrada e retornando as respostas nos canais de saída.
115+
// Eles ficam sempre ativos esperando jobs (ou requests) chegarem para serem
116+
// processados.
117+
func worker(id int, req <-chan sRequest, res chan<- []sSequencia) {
118+
for c := range req {
119+
r := geraSequencias(c.posInicial, c.palavra, c.posicao, c.sequencia, c.dados, c.lenDados, c.testaPrimo, c.lenMaiorSeq)
120+
res <- r
121+
}
122+
}
123+
124+
// startWorkers é a nossa função que dispara os workers, dispara os requests para
125+
// os workers e consolida as respostas que vem pelos canais de saída. Retorna todas
126+
// as sequencias encontradas.
127+
func startWorkers(workers int, batchSize int, dados []byte, lenDados int) []sSequencia {
128+
var (
129+
sequencias []sSequencia
130+
batchResults []sSequencia
131+
)
132+
133+
lenMaiorSeq := 1
134+
testaPrimo := geraPrimos(10000)
135+
jobs := make(chan sRequest, batchSize) // Bufferizado no tamanho do batch.
136+
results := make(chan []sSequencia, batchSize) // Bufferizado no tamanho do batch.
137+
138+
// Colocando no ar todos os workers.
139+
for w := 0; w < workers; w++ {
140+
go worker(w, jobs, results)
141+
}
142+
143+
// Disparando os jobs para serem processados pelos workers. Vamos disparar
144+
// em lotes de tamanho batchSize para podermos pegar resultados intermediarios.
145+
// Fazemos isso para encontrar o tamanho da maior sequencia e minimizar a
146+
// quantidade de sequencias obtidas na funçao recursiva. Nos interessam somente
147+
// as maiores.
148+
149+
a := 2 //Todo arquivo começa com "3." . Precisamos desconsiderar.
150+
for a < lenDados {
151+
if a+batchSize >= lenDados {
152+
batchSize = lenDados - a
153+
}
154+
for b := 0; b < batchSize; b++ {
155+
req := sRequest{
156+
posInicial: a + b,
157+
palavra: []byte{},
158+
posicao: a + b,
159+
sequencia: "",
160+
dados: dados,
161+
lenDados: lenDados,
162+
testaPrimo: testaPrimo,
163+
lenMaiorSeq: lenMaiorSeq,
164+
}
165+
jobs <- req
166+
}
167+
168+
// Coletando os resultados dos canais de saída.
169+
batchResults = []sSequencia{}
170+
for b := 0; b < batchSize; b++ {
171+
r := <-results
172+
batchResults = append(batchResults, r...)
173+
}
174+
175+
// Coletando apenas as maiores sequencias e o valor de lenMaiorSeq para usar.
176+
// nos proximos batches
177+
for _, v := range batchResults {
178+
l := len(v.sequencia)
179+
if l > lenMaiorSeq {
180+
lenMaiorSeq = l
181+
sequencias = []sSequencia{v}
182+
} else {
183+
if l == lenMaiorSeq {
184+
sequencias = append(sequencias, v)
185+
}
186+
}
187+
}
188+
a += batchSize
189+
}
190+
return sequencias
191+
}
192+
193+
func main() {
194+
var (
195+
optCPUProfile string
196+
optBatchSize int
197+
)
198+
199+
runtime.GOMAXPROCS(runtime.NumCPU())
200+
log.SetFlags(0)
201+
202+
flag.StringVar(&optCPUProfile, "cpuprofile", "", "escreve a profile de cpu em arquivo")
203+
flag.IntVar(&optBatchSize, "batchsize", 0, "tamanho do batch de processamento paralelo")
204+
flag.Parse()
205+
206+
if len(flag.Args()) != 1 {
207+
log.Fatalln("Use: desafio 11 <arquivo>")
208+
}
209+
210+
if optCPUProfile != "" {
211+
f, err := os.Create(optCPUProfile)
212+
if err != nil {
213+
log.Fatal(err)
214+
}
215+
pprof.StartCPUProfile(f)
216+
defer pprof.StopCPUProfile()
217+
}
218+
219+
batchSize := 1000
220+
if optBatchSize != 0 {
221+
batchSize = optBatchSize
222+
}
223+
224+
dados, err := ioutil.ReadFile(flag.Args()[0])
225+
if err != nil {
226+
fmt.Println("ERRO! Não consegui ler o arquivo !")
227+
log.Fatal(err)
228+
}
229+
230+
lenDados := len(dados)
231+
// Adicionando alguns bytes ao final dos dados para gaarantir que toda
232+
// a sequência será tratada.
233+
extras := []byte{0, 0, 0, 0}
234+
dados = append(dados, extras...)
235+
236+
// Começando o trabalho de busca das soluções.
237+
sequencias := startWorkers(runtime.NumCPU(), batchSize, dados, lenDados)
238+
239+
// Procurando a maior sequencia na menorPosicao.
240+
menorPosicao := lenDados
241+
sequenciaMenorPosicao := ""
242+
for _, v := range sequencias {
243+
if v.posInicial < menorPosicao {
244+
menorPosicao = v.posInicial
245+
sequenciaMenorPosicao = v.sequencia
246+
}
247+
}
248+
249+
fmt.Println(sequenciaMenorPosicao)
250+
251+
fmt.Print("\n\n")
252+
}

lib/primos_em_pi.ex

+65-3
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,15 @@ defmodule PrimosEmPi do
6868
def max_digits(numbers) when length(numbers) < @max_digits_constant, do: length(numbers)
6969
def max_digits(_), do: @max_digits_constant
7070

71-
def biggest_sequence(number) when is_list(number) do
71+
@spec biggest_sequence(binary) :: {<<>>, binary, bitstring}
72+
73+
def old_biggest_sequence(number) when is_list(number) do
7274
number
7375
|> as_string()
74-
|> biggest_sequence()
76+
|> old_biggest_sequence()
7577
end
7678

77-
def biggest_sequence(number) do
79+
def old_biggest_sequence(number) do
7880
number
7981
|> number_to_slices()
8082
|> get_all_primes()
@@ -216,4 +218,64 @@ defmodule PrimosEmPi do
216218
|> number_to_slices()
217219
|> get_all_primes()
218220
end
221+
222+
# 04/12/2020
223+
224+
def biggest_sequence(number_as_string) do
225+
do_biggest_sequence(number_as_string, [])
226+
|> Enum.reverse()
227+
|> IO.inspect()
228+
|> Enum.join()
229+
end
230+
231+
def do_biggest_sequence("", list_of_primes) do
232+
list_of_primes
233+
end
234+
235+
def do_biggest_sequence(number_as_string, list_of_primes) do
236+
# IO.inspect(list_of_primes)
237+
{first_n, rest} = split_at_first_n_characters(number_as_string, @max_digits_constant)
238+
{before_prime, prime, after_prime} = split_at_biggest_prime(first_n)
239+
# {before_prime, prime, after_prime} |> IO.inspect()
240+
continue_sequence({before_prime, prime, after_prime}, rest, list_of_primes)
241+
end
242+
243+
def continue_sequence({_, prime, ""}, "", list_of_primes) do
244+
[prime | list_of_primes]
245+
end
246+
247+
def continue_sequence({_before_prime, "", after_prime}, rest, list_of_primes) do
248+
do_biggest_sequence(String.slice(after_prime <> rest, 1..-1), list_of_primes)
249+
end
250+
251+
def continue_sequence({_before_prime, prime, after_prime}, rest, list_of_primes) do
252+
# IO.inspect(after_prime)
253+
# IO.inspect(rest)
254+
# IO.inspect(prime)
255+
# IO.inspect([prime | list_of_primes])
256+
do_biggest_sequence(after_prime <> rest, [prime | list_of_primes])
257+
end
258+
259+
def split_at_biggest_prime(string) do
260+
do_split_at_biggest_prime(string, "", "", "")
261+
end
262+
263+
def do_split_at_biggest_prime("", before_prime, prime, after_prime) do
264+
{before_prime, prime, after_prime}
265+
end
266+
267+
def do_split_at_biggest_prime(origin, before_prime, prime, after_prime) do
268+
cond do
269+
is_prime?(origin) ->
270+
{"", origin, after_prime}
271+
272+
true ->
273+
{new_origin, last_char} = String.split_at(origin, String.length(origin) - 1)
274+
do_split_at_biggest_prime(new_origin, before_prime, prime, last_char <> after_prime)
275+
end
276+
end
277+
278+
defp split_at_first_n_characters(string, n) do
279+
String.split_at(string, min(n, String.length(string)))
280+
end
219281
end

pi-100.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067

pi-1000.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198

pi-baby.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.14159265358979323846

test/primos_em_pi_test.exs

+24-6
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,36 @@ defmodule PrimosEmPiTest do
6969

7070
@tag timeout: :infinity
7171
test "Teste de geração da sequencia de primos" do
72+
challenge = "14159"
73+
assert PrimosEmPi.biggest_sequence(challenge) == "4159"
74+
75+
challenge = "265358979323846"
76+
assert PrimosEmPi.biggest_sequence(challenge) == "265358979323"
77+
7278
challenge = "14159265358979323846"
7379
assert PrimosEmPi.biggest_sequence(challenge) == "4159265358979323"
7480

75-
assert PrimosEmPi.biggest_sequence("2220123") == "222"
76-
assert PrimosEmPi.biggest_sequence("44444253125478000") == "4253"
81+
entrada_arquivo = PrimosEmPi.clean(String.trim(File.read!("pi-100.txt"))) |> Enum.join("")
7782

78-
resposta = PrimosEmPi.biggest_sequence(PrimosEmPi.clean(File.read!("pi-1M.txt")))
83+
resposta = PrimosEmPi.biggest_sequence(entrada_arquivo)
84+
IO.inspect(entrada_arquivo)
7985

8086
assert resposta ==
81-
"14590431451723416161791510706177671741511297009743626357169179809791310760755"
87+
"4159265358979323"
88+
89+
# entrada_arquivo = PrimosEmPi.clean(String.trim(File.read!("pi-1000.txt"))) |> Enum.join("")
90+
91+
# resposta = PrimosEmPi.biggest_sequence(entrada_arquivo)
92+
93+
# assert resposta ==
94+
# "4639522473719070217986094370277053"
95+
96+
# entrada_arquivo = PrimosEmPi.clean(String.trim(File.read!("pi-1M.txt"))) |> Enum.join("")
97+
98+
# resposta = PrimosEmPi.biggest_sequence(entrada_arquivo)
8299

83-
# f = File.open!("./resposta.txt", [:write] )
84-
File.write!("./resposta.txt", resposta, [:write])
100+
# IO.inspect(resposta)
101+
# assert resposta ==
102+
# "14590431451723416161791510706177671741511297009743626357169179809791310760755"
85103
end
86104
end

0 commit comments

Comments
 (0)