Last active
January 27, 2018 21:55
-
-
Save YoukaiCat/0e376e7c4744c57cc27fb3d411ac1d7e to your computer and use it in GitHub Desktop.
Random Sequence Analysis
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
class Analyzer | |
attr_reader :name | |
def initialize name, numbers, bits_count = 16 | |
@name = name | |
@numbers = numbers | |
@bits_count = bits_count | |
end | |
# Случайность распределения | |
# Сколько в отрезок входит чисел. | |
# Например, массив из 13473467 чисел, значениями от 1 до 100 | |
# Делим на 10 интервалов, получается по 10 возможных чисел в интервале | |
# Найти сколько чисел принадлежит этим интервалам | |
def randomness_of_distribution | |
min = @numbers.min | |
max = @numbers.max | |
intervals_num = 10 | |
step = (max - min) / intervals_num | |
# Нижние границы, границы интервалов без хвоста списка | |
# Например, [1, 11, 21, 31, 41] -> [1, 11, 21, 31] | |
lower = (min..max).step(step).to_a[0..-2] #init | |
# Верхние границы, границы интервалов без головы списка | |
# Например, [1, 11, 21, 31, 41] -> [11, 21, 31, 41] | |
upper = (min..max).step(step).to_a[1..-1] #tail | |
# Массив границ для каждого интервала | |
# Например, [[1, 11], [11, 21], [21, 31], [31, 41]] | |
bounds = lower.zip upper | |
# Количество значений для каждого интервала | |
counts = bounds.map do |lower_bound, upper_bound| | |
# Фильтрация значений, входящих в интервал и подсчёт их количества | |
@numbers.count { |number| number.between? lower_bound, upper_bound - 1 } | |
end | |
{ results: counts, x: x_randomness_of_distribution(counts, @numbers.size, intervals_num) } | |
end | |
# Магическая формула Хиквадрата | |
def x_randomness_of_distribution m, n, intervals_num | |
m.map do |mi| | |
p = 1.0 / intervals_num | |
pn = p * n | |
dividend = (mi - pn) ** 2 | |
dividend / pn | |
end.reduce(&:+) | |
end | |
# Случайность разрядов | |
# Количество чисел, имеющих единицу в n бите (разряде) | |
# Числа по битам | |
def randomness_of_bits | |
ones_at_bits = Array.new @bits_count, 0 | |
# Трансформация всех чисел в массивы битов см. #to_bit_array | |
numbers = @numbers.map { |number| to_bit_array number } | |
numbers.each do |number| | |
# Для каждого значения бита и индекса бита каждого числа | |
number.each_with_index do |bit, index| | |
# Увеличить счётчик единиц бита | |
ones_at_bits[index] += 1 if bit == 1 | |
end | |
end | |
{ results: ones_at_bits, x: x_randomness_of_bits(ones_at_bits, @numbers.size) } | |
end | |
def x_randomness_of_bits m, n | |
m.map do |mi| | |
p = 1.0 / 2.0 | |
pn = p * n | |
dividend = (mi - pn) ** 2 | |
dividend / pn | |
end.reduce(&:+) | |
end | |
# Случайность числа | |
# Количество чисел, содержащих n битов (разрядов) со значением 1 | |
# Числа по количеству | |
def randomness_of_number | |
# Может быть ноль битов с единицами, поэтому 17 элементов (16 возможных битов + 1) | |
counts = Array.new @bits_count + 1, 0 | |
# Трансформация всех чисел в массивы битов см. #to_bit_array | |
numbers = @numbers.map { |number| to_bit_array number } | |
# Количество битов с единицами для каждого числа | |
n_ones = numbers.map do |number| | |
# Отфильтровать биты с единицами, посчитать количество | |
number.count { |bit| bit == 1 } | |
end | |
# Увеличить счётчик для такого-то количества | |
n_ones.each { |n| counts[n] += 1 } | |
{ results: counts, x: x_randomness_of_number(counts, @numbers.size, @bits_count) } | |
end | |
def x_randomness_of_number m, n, bits_count | |
pis = Array.new m.size | |
pis.each_index do |i| | |
if i == 0 | |
pis[i] = 2.0 ** (- bits_count) | |
else | |
pis[i] = (bits_count - i + 1.0) * pis[i - 1] / i | |
end | |
end | |
m.zip(pis).map do |tuple| | |
mi, pi = tuple | |
pn = pi * n | |
dividend = (mi - pn) ** 2 | |
dividend / pn | |
end.reduce(&:+) | |
end | |
# Трансформация числа в двоичное строковое представление | |
# 5 => "0000000101" | |
def to_binary_string number | |
"%0#{@bits_count}b" % number | |
end | |
# Трансформация числа в массив битов | |
# 5 => [0,0,0,0,0,0,0,1,0,1] | |
def to_bit_array number | |
to_binary_string(number).split('').map(&:to_i) | |
end | |
def unique_persentage | |
count = @numbers.uniq.size | |
{ results: count, x: "#{count * 100 / @numbers.size}%" } | |
end | |
end | |
data = {} | |
data[:lcg] = File.readlines "/home/natsuo/Development/Current/Cypher/Second/Data/Task1_example/Метод вычетов" | |
data[:msp430] = File.readlines "/home/natsuo/Development/Current/Cypher/Second/Data/Task1_example/msp430" | |
data[:random_sharp] = File.readlines "/home/natsuo/Development/Current/Cypher/Second/Data/Task1_example/Random_c#" | |
data[:rngcrypto] = File.readlines "/home/natsuo/Development/Current/Cypher/Second/Data/Task1_example/RNGCrypto" | |
data[:_0] = File.readlines "/home/natsuo/Development/Current/Cypher/Second/Data/Task1/0" | |
data[:_1] = File.readlines "/home/natsuo/Development/Current/Cypher/Second/Data/Task1/1" | |
data[:_2] = File.readlines "/home/natsuo/Development/Current/Cypher/Second/Data/Task1/2" | |
data[:_3] = File.readlines "/home/natsuo/Development/Current/Cypher/Second/Data/Task1/3" | |
analyzers = data.map { |name, strings| strings.map!(&:to_i); Analyzer.new(name, strings) } | |
# Просто метод, который печатает результаты, | |
# вызвая у анализатора заданный метод | |
def analyzer_print analyzer, method | |
print '%-15.15s' % "#{analyzer.name}:" | |
result = analyzer.method(method).call | |
print result[:results] | |
puts " = #{result[:x]}" | |
end | |
puts 'Случайность распределения:' | |
analyzers.each { |a| analyzer_print a, :randomness_of_distribution } | |
puts | |
puts 'Случайность разрядов:' | |
analyzers.each { |a| analyzer_print a, :randomness_of_bits } | |
puts | |
puts 'Случайность числа:' | |
analyzers.each { |a| analyzer_print a, :randomness_of_number } | |
puts | |
puts 'Процент уникальных чисел:' | |
analyzers.each { |a| analyzer_print a, :unique_persentage } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
0 - LCG
1 - MSP430
2 - ? (Random C#)
3 - ? (RNGCrypto)