Как я могу определить статистическую случайность двоичной строки?

Как я могу определить статистическую случайность двоичной строки?

Следовательно, как я могу кодировать свой собственный тест и возвратить единственное значение, которое соответствует статистической случайности, значению между 0 и 1.0 (0 являющийся не случайный, 1.0 являющийся случайным)?

Тест должен был бы работать над двоичными строками любого размера.

Когда Вы делаете это с пером и бумагой, Вы могли бы исследовать строки как это:
  0 (произвольная случайность, единственный другой выбор равняется 1),
  00 (не случайный, это - повторение и соответствует размеру),
  01 (лучше, два различных значения)
  010 (менее случайный, палиндром)
  011 (менее случайный, больше 1's, все еще приемлемый)
  0101 (менее случайный, шаблон)
  0100 (лучше, меньше, но любое другое распределение вызывает шаблоны),

Примеры случая:

Размер: 1, возможности: 2
  0: 1.0 (случайный)
  1: 1.0 (случайный)

Размер: 2, P:4
  00:?
  01: 1.0 (случайный)
  10: 1.0 (случайный)
  11:?

S:3, P:8
  000:? неслучайный
  001: 1.0 (случайный)
  010:? менее случайный
  011: 1.0 (случайный)
  100: 1.0 (случайный)
  101:? менее случайный
  110 1.0 (случайный)
  111:? неслучайный

И так далее.

Я чувствую, что это может играть много в повреждение строки во все возможные подстроки и сравнение частот, но кажется, что этот вид основы должен был уже быть сделан в первые годы информатики.

5
задан Tim 22 June 2010 в 23:39
поделиться

4 ответа

Это даст вам счет энтропии от 0 до 1.0:

Вы можете попробовать изучить энтропию Шеннона , которая является мерой энтропии в применении к данным и информации. Фактически, это фактически почти прямой аналог Физической формулы для энтропии, как это определено наиболее общепринятыми интерпретациями термодинамики.

Точнее, в вашем случае с двоичной строкой вы можете увидеть функцию двоичной энтропии , которая является частным случаем, включающим случайность в двоичных битах данных.

Это вычисляется по

H(p) = -p*log(p) - (1-p)*log(1-p)

(логарифмы по основанию 2; предположим, что 0 * log (0) равно 0)

Где p - ваш процент единиц (или нулей; график симметричен, поэтому ваш ответ будет одинаковым в любом случае)

Вот что дает функция:

Binary Entropy Function

Как видите, если p равно 0,5 (такое же количество единиц как 0), ваша энтропия максимальна (1.0). Если p равно 0 или 1.0, энтропия равна 0.

Кажется, это именно то, что вам нужно, не так ли?

Единственное исключение - ваши случаи Размер 1 , что можно было бы просто поставить как исключение. Однако 100% 0 и 100% 1 мне не кажутся слишком энтропийными. Но реализуйте их как хотите.

Кроме того, при этом не учитывается какой-либо «порядок» битов. Только их общая сумма. Таким образом, повторение / палиндромы не получат никакого толчка. Вы можете добавить для этого дополнительную эвристику.

Вот другие примеры из вашего дела:

00:   -0*log(0) - (1-0)*log(1-0)               = 0.0
01:   -0.5*log(0.5) - (1-0.5)*log(1-0.5)       = 1.0
010:  -(1/3)*log(1/3) - (2/3)*log(2/3)         = 0.92
0100: -0.25*log(0.25) - (1-0.25)*log(1-0.25)   = 0.81
9
ответ дан 18 December 2019 в 06:10
поделиться

Некоторое время назад я разработал простую эвристику, которая работала для моих целей.

Вы просто вычисляете "четность" нулей и единиц не только в самой строке, но и на производных от строки. Например, первая производная 01010101 - это 11111111, потому что каждый бит изменяется, а вторая производная - 00000000, потому что ни один бит в первой производной не изменяется. Тогда вам просто нужно взвесить эти «ровности» по своему вкусу.

Вот пример:

#include <string>
#include <algorithm>

float variance(const std::string& x)
{
    int zeroes = std::count(x.begin(), x.end(), '0');
    float total = x.length();
    float deviation = zeroes / total - 0.5f;
    return deviation * deviation;
}

void derive(std::string& x)
{
    char last = *x.rbegin();
    for (std::string::iterator it = x.begin(); it != x.end(); ++it)
    {
        char current = *it;
        *it = '0' + (current != last);
        last = current;
    }
}

float randomness(std::string x)
{
    float sum = variance(x);
    float weight = 1.0f;
    for (int i = 1; i < 5; ++i)
    {
        derive(x);
        weight *= 2.0f;
        sum += variance(x) * weight;
    }
    return 1.0f / sum;
}

int main()
{
    std::cout << randomness("00000000") << std::endl;
    std::cout << randomness("01010101") << std::endl;
    std::cout << randomness("00000101") << std::endl;
}

Входные данные вашего примера дают "случайность" 0,129032, 0,133333 и 3,2 соответственно.

Кстати, вы можете получить классную фрактальную графику, создав строки;)

int main()
{
    std::string x = "0000000000000001";
    for (int i = 0; i < 16; ++i)
    {
        std::cout << x << std::endl;
        derive(x);
    }
}

0000000000000001
1000000000000001
0100000000000001
1110000000000001
0001000000000001
1001100000000001
0101010000000001
1111111000000001
0000000100000001
1000000110000001
0100000101000001
1110000111100001
0001000100010001
1001100110011001
0101010101010101
1111111111111111
5
ответ дан 18 December 2019 в 06:10
поделиться

Вы, кажется, просите найти колмогорову сложность двоичной строки. К сожалению, это невычислимо. Размер вашей строки после ее запуска через алгоритм сжатия даст вам представление о том, насколько она случайна, в том, что более случайные строки менее сжимаемы.

11
ответ дан 18 December 2019 в 06:10
поделиться

Вы можете попробовать алгоритм сжатия строки. Чем больше повторений (меньше случайности), тем сильнее можно сжать строку.

1
ответ дан 18 December 2019 в 06:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: