amarao: (Default)
[personal profile] amarao
Терминология:

Бит = base2
Трит = base3
N-ит = baseN

Я сам себе придумал простую задачку: посчитать распределение разных цифр файле в заданной системе счисления. На входе, по понятным причинам, всегда файлы двоичные. На выходе распределение цифр N-ричной системы так, как если бы тот же файл был записан в N-ричной системе.

В начале я думал, что это тривиально. Потом залез в математику и нашёл формулу log_a(b) = log_c(b)/log_c(a)

log_a(b) и log_c(b) - это число итов в разных системах счисления.

И из этой формулы очевидно вытекает, что кратно совпадать иты могут только если log_c(a) (логарифм по основанию одной системы счисления и основания другой счисления) - это рациональное число. Если этот логарифм иррациональный, то мы никогда не сможем найти такое количество итов одной системы, чтобы точно выразить сколько итов другой системы.

Например, в base4 можно легко представить base2 - мы просто кодируем два бита одним числом в base4. А вот, например, для base3 и base2 не существует такого конечного числа битов, которые бы можно было превратить в триты точно. Точно означает, что любое число с указанным числом тритов превратится в число с указанным числом битов и наоборот. Всегда будут "лишние значения".

Если не понятно, вот простой пример:

3^2=9, максимальное представимое число в два трита - это 8. Чтобы закодировать 8 нам надо 4 бита. Но четыре бита позволяют закодировать число 15, а число 15 требует три трита. Три трита позволяют закодировать число 26, а для этого нам уже нужно 5 бит, а это число 32, которое требует...

Ну вы поняли. До нахождения формулы я почему-то был уверен, что существует "наименьшее общее кратное" для двух разных ритов. Оказалось, что нет (оно называется не "наименьше общее кратное", но я пытаюсь провести аналогию).

Хорошо, мы теперь знаем, что для общего случая мы не можем для двух итов искать "наибольшее общее число".

Как же конвертировать? Мы говорим про поток итов, у нас нет "порядка байт".

... А как не конвертировать? Что такое поток битов? Каждый следующий бит добавляется к "сумме" с новой степенью двойки. То есть, имея счётчик битов pos, мы можем делать sum+=2^pos * value.

Для тройки эквивалентная формула - это sum += 3^pos * value. Поскольку мы работаем с сложением, мы можем уменьшать сумму по мере печати и не перживать по этому поводу:

sum = printed_value + leftover_value.

Для печати нового бита мы должны sum // 2^pos (где // - целочисленное деление).
Для печати нового трита мы должны sum // 3^pos.

Выглядит как алгоритм, но у него есть фатальный недостаток n^pos - число размером с читаемый нами файл, то есть никакого стриминга не получается. При этом мы из sum вычитаем всё большие цифры, то есть sum с одной стороны растёт, с другой стороны всё время ограничена n^(pos+1).

И что-то у меня пока не получается придумать memory bound алгоритма. А, казалось, простая задачка...

Date: 2023-03-25 08:32 pm (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi

А, целый файл превратить в триты? Да, логично.

Date: 2023-03-26 05:59 pm (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi

Да, не похоже, чтоб линейно было. Там умножение на степень двойки Ну типа берем k=log2(N), с округлением вверх; и нужно в процессе умножать большое число на N-2^k... что-то такое. Поэкспериментировать бы надо, конечно.

Date: 2023-03-26 09:32 pm (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi

Ну да; дело в переносе, и, похоже, там нелинейно. Хотя... наверно, можно найти что-то быстрее, чем квадрат.

Date: 2023-03-25 10:28 pm (UTC)
From: [personal profile] ichthuss
По-моему, тут стрим вообще никак не получится. В лучшем случае путем размена памяти на процессорное время можно обойтись ограниченной оперативной памятью, но при условии доступа ко всему уже напечатанному.

Кстати, лично я бы рассматривал файл не как целое число, а как fixed point value из [0;1).

Date: 2023-03-26 09:42 pm (UTC)
From: [personal profile] ichthuss
Самый простой способ переводить целое число в другое основание - делить много раз в столбик на новое основание и выписывать остатки от деления. При этом результаты получаются "с конца": вначале самый младший знак, затем все более старшие.

Чтобы переводить в другое основание дробное число <1, нужно каждый раз умножать его на новое основание, выписывать и отбрасывать целую часть. При этом результаты получаются "с начала" - начиная со старшего знака.

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

Date: 2023-03-27 03:30 pm (UTC)
From: [personal profile] ichthuss
А, да, еще забыл отметить: при целом представлении дописывание разряда в начало/конец файла полностью меняет все разряды в другом основании. При дробном же представлении дописывание разрядов в конец файла меняет в среднем только самые последние разряды в другом основании.

Date: 2023-04-01 01:06 pm (UTC)
From: [personal profile] ichthuss
Верно, с одной поправкой: для обратимости преобразования достаточно конечного числа знаков даже бесконечной дроби. Скажем, любая дробь, принадлежащая интервалу [0,(3)..0.(6)), будет в троичном представлении начинаться с 0.1, поэтому для представления троичного числа 0.1 можно выбрать любую из них, например, 0.4 (дес.).

Date: 2023-04-01 03:38 pm (UTC)
yurikhan: (Default)
From: [personal profile] yurikhan

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

Алгоритм, знающий входную последовательность 4, входное основание 10 и выходное основание 3, без дополнительной информации, сгенерирует на выход бесконечную последовательность 10121012….

Edited Date: 2023-04-01 03:40 pm (UTC)

Date: 2023-04-01 04:40 pm (UTC)
From: [personal profile] ichthuss
Исходная постановка и в случае целых чисел не обеспечит взаимно однозначное преобразование без дополнительного задания длины, т.к. непонятно, что делать с нулями в старших разрядах.

Date: 2023-04-01 04:57 pm (UTC)
yurikhan: (Default)
From: [personal profile] yurikhan

Можно сказать, что преобразование обратимо с точностью до незначащих ведущих нулей. А в случае дроби придётся либо задавать требуемую точность представления на входе, либо расширять алфавит скобками и учить алгоритм находить период дроби.

Date: 2023-04-01 06:29 pm (UTC)
From: [personal profile] ichthuss
Думаю, несложно доказать, что это невозможно. Но если иметь доступ до уже напечатанного вывода - возможно, какой-то экзотический алгоритм и справится.

Date: 2023-04-01 09:48 pm (UTC)
From: [personal profile] ichthuss
Ну как раз частота символов с вероятностью 1 будет одинаковая.

Читерство, конечно, но все равно любопытно, сработает такой чит или нет.

Date: 2023-04-01 05:57 pm (UTC)
From: [personal profile] ichthuss
Так требуемая точность примерно известна из длины исходного числа (она в пределах последнего значащего знака).

Date: 2023-04-01 06:12 pm (UTC)
yurikhan: (Default)
From: [personal profile] yurikhan

Гм. В том смысле, что 1, 10 и 100 — это разные входные строки, задающие число 0.110 с точностью ±0.05, ±0.005 и ±0.0005 соответственно? Да, такая постановка непротиворечива.

Date: 2023-03-26 09:33 pm (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi

Об этом и речь.

Profile

amarao: (Default)
amarao

February 2026

S M T W T F S
123456 7
8910111213 14
15161718192021
22232425262728

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Feb. 26th, 2026 01:53 am
Powered by Dreamwidth Studios