Professional Documents
Culture Documents
November 8, 2021
[ ]: %load_ext cython
[ ]: %%cython
import numpy as np
from libc.math cimport abs
#############################
## RANDOM NUMBER GENERATOR ##
#############################
cdef Parameters p
p.a = 16807
p.m = 2147483647
1
O código Cython seguiu o padrão de língua inglesa porque foi inicialmente concebido como um módulo indepen-
dente.
1
p.b = 0
p.x = seed
def reset():
set_parameters(16807, 2147483647, 0, 1)
#######################
## Special functions ##
#######################
2
for i in range(1,len(array)):
if upwards and array[i] < array[i - 1]:
upwards = False
a += 1
elif not upwards and array[i] > array[i - 1]:
upwards = True
a += 1
return a
def mode(double[:] A, double epsilon = 1e-4, bint ordered = False) -> float:
"""Efficiently calculates the mode of an 1-dimensional array of floats.
Args:
A (double): The array of floats on which to compute the mode.
epsilon (double, optional): Two values are equal if their difference is␣
,→smaller than epsilon. Defaults to 1e-6.
Returns:
double: The mode of A.
3
"""
cdef Py_ssize_t n = len(A), i = 0
cdef double[:] B = np.zeros(n)
for k in range(n): B[k] = A[k]
i += 1
return mode
if printar:
print("-------- Teste do qui-quadrado ----------")
print(
"Estatística: {}\nValor crítico: {}".format(estatistica_qui,␣
,→valor_critico)
)
if estatistica_qui >= valor_critico:
print("Rejeita-se H0.")
else:
print("Aceita-se H0.")
4
if printar:
print("-------- Teste de normalidade ----------")
print(
"Estatística (|z|): {}\nValor crítico: {}".
,→format(abs(estatistica_z), valor_critico)
)
if abs(estatistica_z) >= valor_critico:
print("Rejeita-se H0.")
else:
print("Aceita-se H0.")
A rotina testar_metodo abaixo encapsula todo o processo de teste do nosso gerador de números
aleatórios. Ela segue os passos:
1. Para cada tamanho de amostra N :
1. Cria uma sequência de N números aleatórios.
2. Executa um teste de uniformidade e guarda os resultados.
3. Executa um teste de aleatoriedade e guarda os resultados.
2. Formata os resultados guardados e printa no console, junto com os parâmetros utilizados pelo
método testado.
[ ]: # obs: é preciso instalar o pacote "tabulate" para printar tabelas em forma de␣
,→string
def testar_metodo():
print("----------------------------------\n"
+ "--- Parâmetros: {} ---\n".format(get_parameters())
+ "----------------------------------")
testes_qui = []
testes_Z = []
for n in N:
# O vetor de números aleatórios precisa ser um array do Numpy
sequencia = np.array([ random() for i in range(n) ])
5
##### TESTES DE ALEATORIEDADE (EXECUÇÕES) ######
# Em seguida contamos o número de execuções e realizamos um
# teste de normalidade na quantidade de execuções.
n_execucoes = number_of_runs(sequencia)
mu_execucoes = (2 * n - 1) / 3
sigma_execucoes = np.sqrt((16 * n - 29) / 90)
z = (n_execucoes - mu_execucoes) / sigma_execucoes
testes_Z.append(
teste_normal_padrao(z, 0.05)
)
1.1.1 Teste 1
reset garante que utilizamos os parâmetros padrão definidos no início.
[ ]: reset()
testar_metodo()
----------------------------------
--- Parâmetros: {'a': 16807, 'm': 2147483647, 'b': 0, 'x': 1} ---
----------------------------------
-------- Teste do qui-quadrado ----------
| Amostras | Estatística | Valor crítico | Rejeita H0 |
|------------|---------------|-----------------|--------------|
| 1000 | 6.45 | 16.919 | 0 |
| 10000 | 6.777 | 16.919 | 0 |
| 1000000 | 5.55134 | 16.919 | 0 |
-------- Teste de normalidade ----------
| Amostras | Estatística | Valor crítico | Rejeita H0 |
|------------|---------------|-----------------|--------------|
| 1000 | -2.72747 | 1.64485 | 1 |
| 10000 | -0.719483 | 1.64485 | 0 |
| 1000000 | -1.98828 | 1.64485 | 1 |
6
1.1.2 Teste 2
[ ]: set_parameters(2**18 + 1, 2**35, 0, 1)
testar_metodo()
----------------------------------
--- Parâmetros: {'a': 262145, 'm': 34359738368, 'b': 0, 'x': 1} ---
----------------------------------
-------- Teste do qui-quadrado ----------
| Amostras | Estatística | Valor crítico | Rejeita H0 |
|------------|---------------|-----------------|--------------|
| 1000 | 8900 | 16.919 | 1 |
| 10000 | 89000 | 16.919 | 1 |
| 1000000 | 2896.19 | 16.919 | 1 |
-------- Teste de normalidade ----------
| Amostras | Estatística | Valor crítico | Rejeita H0 |
|------------|---------------|-----------------|--------------|
| 1000 | -49.9453 | 1.64485 | 1 |
| 10000 | -158.097 | 1.64485 | 1 |
| 1000000 | -1581.1 | 1.64485 | 1 |
1.1.3 Teste 3
[ ]: set_parameters(4*20 + 1, 2**35 - 1, 17, 1)
testar_metodo()
----------------------------------
--- Parâmetros: {'a': 81, 'm': 34359738367, 'b': 17, 'x': 1} ---
----------------------------------
-------- Teste do qui-quadrado ----------
| Amostras | Estatística | Valor crítico | Rejeita H0 |
|------------|---------------|-----------------|--------------|
| 1000 | 10.68 | 16.919 | 0 |
| 10000 | 6.777 | 16.919 | 0 |
| 1000000 | 68.8694 | 16.919 | 1 |
-------- Teste de normalidade ----------
| Amostras | Estatística | Valor crítico | Rejeita H0 |
|------------|---------------|-----------------|--------------|
| 1000 | 1.25113 | 1.64485 | 0 |
| 10000 | -1.00411 | 1.64485 | 0 |
| 1000000 | -10.7494 | 1.64485 | 1 |
7
Vamos nos assegurar de que estamos com os parâmetros desejados.
[ ]: for i in range(30):
set_seed(i)
for n in N:
amostras[i][str(n)] = random_array(n)
Feita a simulação, vamos fazer outra estrutura de dados, resultado, para guardar as estatística
referentes a cada amostra.
for i in range(30):
for n in list(map(str, N)):
variancia = np.var(amostras[i][n])
mediana = np.median(amostras[i][n])
amostra_ordenada = amostras[i][n].copy()
merge_sort(amostra_ordenada)
q1 = np.median(amostra_ordenada[:(int(n) // 2)])
q3 = np.median(amostra_ordenada[(int(n) // 2):])
quartis = [q1, mediana, q3]
resultados[i][n] = {
'média': np.mean(amostras[i][n]),
'mediana': mediana,
'moda': mode(amostra_ordenada, 1e-5, True),
'assimetria': skew(amostras[i][n]),
'kurtose': kurtosis(amostras[i][n]),
'variância': variancia,
'desvio-padrão': np.sqrt(variancia),
'quartis': quartis
}
[ ]: medias = []
medianas = []
modas = []
8
assimetrias = []
kurtoses = []
variancias = []
desvios_padrao = []
quartis = []
for i in range(30):
for n in map(str, N):
medias.append(resultados[i][n]['média'])
medianas.append(resultados[i][n]['mediana'])
modas.append(resultados[i][n]['moda'])
assimetrias.append(resultados[i][n]['assimetria'])
kurtoses.append(resultados[i][n]['kurtose'])
variancias.append(resultados[i][n]['variância'])
desvios_padrao.append(resultados[i][n]['desvio-padrão'])
quartis.append(resultados[i][n]['quartis'])
[ ]: plt.style.use('ggplot')
fig, ax = plt.subplots(4, 2)
fig.set_size_inches(10, 12)
ax[0][0].set_title('Médias')
ax[0][0].plot(medias)
ax[0][0].plot([0,90], [0.5, 0.5])#, 'r')
#ax[0][0].xaxis.set_visible(False)
ax[0][0].set_xticklabels([])
ax[0][1].set_title('Medianas')
ax[0][1].plot(medianas)
ax[0][1].plot([0,90], [0.5, 0.5])#, 'r')
ax[0][1].set_xticklabels([])
ax[1][0].set_title('Modas')
ax[1][0].plot(modas, 'o')
ax[1][0].set_xticklabels([])
ax[1][1].set_title('Assimetrias')
ax[1][1].plot(assimetrias)
ax[1][1].plot([0,90], [0, 0])#, 'r')
ax[1][1].set_xticklabels([])
ax[2][0].set_title('Kurtoses')
9
ax[2][0].plot(kurtoses)
ax[2][0].plot([0,90], [-6/5, -6/5])#, 'r')
ax[2][0].set_xticklabels([])
ax[2][1].set_title('Variâncias')
ax[2][1].plot(variancias)
ax[2][1].plot([0,90], [1/12, 1/12])#, 'r')
ax[2][1].set_xticklabels([])
ax[3][0].set_title('Desvios-padrão')
ax[3][0].plot(desvios_padrao)
ax[3][0].plot([0,90], [np.sqrt(1/12), np.sqrt(1/12)])#, 'r')
ax[3][0].set_xlabel('Amostra')
ax[3][1].set_title('Quartis')
quartis = np.array(quartis).T
p = ax[3][1].plot(quartis[0])
ax[3][1].plot(quartis[1], color=p[0].get_color())
ax[3][1].plot(quartis[2], color=p[0].get_color())
q = ax[3][1].plot([0,90], [0.25, 0.25])#, 'r')
ax[3][1].plot([0,90], [0.50, 0.50], color=q[0].get_color())#, 'r')
ax[3][1].plot([0,90], [0.75, 0.75], color=q[0].get_color())#, 'r')
ax[3][1].set_xlabel('Amostra');
10
1.2.1 Conclusões
De um modo geral, a atual implementação do MCL com o conjunto de parâmetros a = 4 · 20 + 1,
m = 235 − 1 e b = 17 apresenta uma concordância muito boa com a distribuição uniforme contínua.
Note que a moda de uma amostra de números de ponto flutuante varia com o grau de “precisão”
considerado na igualdade. Por exemplo, vamos variar esse grau abaixo. De qualquer modo, o valor
teórico da moda da distribuição U (0, 1) é qualquer x ∈ [0, 1].
11
[ ]: modas_teste = [[], [], []]
for i in range(30):
for n in map(str, N):
amostra_ordenada = amostras[i][n].copy()
merge_sort(amostra_ordenada)
modas_teste[0].append(mode(amostra_ordenada, 1e-4, True))
modas_teste[1].append(mode(amostra_ordenada, 5e-5, True))
modas_teste[2].append(mode(amostra_ordenada, 1e-5, True))
[ ]: fig, ax = plt.subplots(1,3)
fig.set_size_inches(14, 4)
fig.suptitle('Modas')
for i in range(3):
ax[i].set_title(r'$\varepsilon$ = {}'.format([r'$10^{-4}$',␣
,→r'$5\times10^{-5}$', r'$10^{-5}$'][i]))
ax[i].set_ylim(-0.05, 1.05)
ax[i].plot(modas_teste[i], 'o')
12