Я в FAR Manager нажал F3 на папке и увидел «48 М» в строке статуса. Нажал Insert и увидел точное десятичное значение «50 510 690». Ни то, ни другое меня не вполне устраивали, поэтому я думал, как бы всё же совместить «честность» с точностью.
И вот, что получилось:
Код
Кибиричная Десятичная Шестнадцатеричная
1'000'000'000' 1 073 741 824 400 00000
1'000'000' 1 048 576 1 00000
4'000' 4 096 1000
2'000' 2 048 800
1'001' 1 025 401
1'000' 1 024 400
999' 1 023 3FF
750' 768 300
500' 512 200
499' 511 1FF
250' 256 100
125' 128 80
80' 82 52
7A' 81 51
79' 80 50
63' 64 40
40' 41 29
3A' 40 28
39' 39 27
32' 32 20
16' 16 10
10' 10 A
8' 8 8
4' 4 4
2' 2 2
1' 1 1
0' 0 0
1'000'000'000' 1 073 741 824 400 00000
1'000'000' 1 048 576 1 00000
4'000' 4 096 1000
2'000' 2 048 800
1'001' 1 025 401
1'000' 1 024 400
999' 1 023 3FF
750' 768 300
500' 512 200
499' 511 1FF
250' 256 100
125' 128 80
80' 82 52
7A' 81 51
79' 80 50
63' 64 40
40' 41 29
3A' 40 28
39' 39 27
32' 32 20
16' 16 10
10' 10 A
8' 8 8
4' 4 4
2' 2 2
1' 1 1
0' 0 0
Как можно видеть, эта система счисления хорошо передаёт величину. 750' — это три четверти от 1'000', а 125' — одна восьмая. И если вы видите в кибиричной системе запись 4'851'964', вы не сильно ошибётесь, если округлите на глаз это до 4,85 Миб. Для сравнения, в шестнадцатеричной системе счисления 210 вообще не является единицей с нулями.
Кибиричная система счисления — это 1024ричная система счисления и её особое представление в десятичных цифрах. «Киби» — это не прижившаяся в русском языке приставка для 1024. Кило = 1000, киби = 1024. Вот как раз хоть здесь пригодилась, потому что «1024ричная» тяжело произносить.
В кибиричной системе счисления 1024 истинных цифр, но представляются они группами по 3 цифры. Смешивать их нельзя, поэтому обязательным является разделение, например, апострофами. И в конец, чтобы отличалось от десятичной системы счисления, дописывается апостроф, что в десятичной точно не делается. Последовательностей цифр от 000 до 999, если использовать только цифры от 0 до 9, хватает только на 1000, а ещё остаётся 24. Если оставшиеся 24 равномерно вставить внутрь, они собой разрежут 1000 на 25 ровных частей по 40. На границе разрезов девятка в следующий разряд не переносится, а сначала переходит в цифру «десять» (записывается буквой A, как в шестнадцатеричной), а только потом — в следующий разряд.
Идею кибиричной системы счисления можно выразить так:
1000 = 40 * 25
1024 = (40 + 1) * 25 - 1
Совсем по-научному — было бы выразить через декартовы произведения, отношения и изоморфизмы.
Кстати, отброшенная последовательность — это 99A'. Вместо неё после 999' идёт сразу 1'000'.
Пример раскодировки:
189'094'35A' = (189 + 18/4) * 1 024 * 1 024 + (94 + 9/4) * 1 024 + (360 + 35/4) = 193 * 1 048 576 + 96 * 1 024 + 368 = 202 473 840.
Деление имеется в виду целочисленное.
В этой системе счисления можно даже производить арифметические операции. Достаточно декодировать каждую истинную цифру, остановиться на этом, а дальше производить над ними операции, как в любой другой позиционной системе счисления. Придётся брать остаток и частное от деления на 1024, но этим всё и ограничится, по модулю 1 048 576 уже необходимость не возникает. Для тех, кто учил таблицу умножения для десятичной системы счисления, а для шестнадцатеричной — не учил, то есть, практически для всех, в кибиричной системе счисления в конечном итоге научиться считать будет проще, чем в более известной шестнадцатеричной.
Числа в таком представлении я генерировал на Аде и Джаваскрипте и могу поделиться кодом на этих языках:
Kibimal_Digits : constant array (0 .. 10) of Character := ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A');
-------------------
-- Image_Kibimal --
-------------------
function Image_Kibimal (Arg : Interfaces.Integer_64) return String is
begin
if Arg = 0 then
return "0'";
end if;
declare
Result : Ada.Strings.Unbounded.Unbounded_String := Ada.Strings.Unbounded.To_Unbounded_String ("'");
Sign : constant String := (if Arg < 0 then "-" else "");
Abs_Value : constant Interfaces.Integer_64 := abs Arg;
Tail : Interfaces.Integer_64 := Abs_Value / 1024;
Head : Integer := Integer (Abs_Value mod 1024);
Head_Tail : Integer := (Head - (Head + 1) / 41) / 10;
Head_Head : Integer := Head - Head_Tail * 10 - Head_Tail / 4;
begin
loop
declare
New_Chunk : constant String :=
(if Head_Tail > 0 then
Ada.Strings.Fixed.Trim (Integer'Image (Head_Tail), Ada.Strings.Left)
else
"") & Kibimal_Digits (Head_Head);
begin
if Tail = 0 then
return Sign & New_Chunk & To_String (Result);
end if;
Insert (Result, 1, ''' & Ada.Strings.Fixed."*" (3 - New_Chunk'Length, '0') & New_Chunk);
Head := Integer (Tail mod 1024);
Tail := Tail / 1024;
Head_Tail := (Head - (Head + 1) / 41) / 10;
Head_Head := Head - Head_Tail * 10 - Head_Tail / 4;
end;
end loop;
end;
end Image_Kibimal;
function Image_Kibimal (Arg) {
var Result, Sign, Abs_Value, Tail, Head, Head_Tail, Head_Head, New_Chunk, Kibimal_Digits;
if (0 === Arg) {
return "0'";
}
Kibimal_Digits = '0123456789A';
Result = "'";
Sign = ((Arg < 0) ? "-" : "");
Abs_Value = Math.abs (Arg);
Tail = Abs_Value / 1024 | 0;
Head = Abs_Value % 1024;
Head_Tail = (Head - ((Head + 1) / 41 | 0)) / 10 | 0;
Head_Head = Head - Head_Tail * 10 - (Head_Tail / 4 | 0);
do {
New_Chunk = ((Head_Tail > 0) ? Head_Tail : "") + Kibimal_Digits.charAt (Head_Head);
if (0 === Tail) {
return Sign + New_Chunk + Result;
}
Result = "'" + "000".substring (New_Chunk.length) + New_Chunk + Result;
Head = Tail % 1024;
Tail = Tail / 1024 | 0;
Head_Tail = (Head - ((Head + 1) / 41 | 0)) / 10 | 0;
Head_Head = Head - Head_Tail * 10 - (Head_Tail / 4 | 0);
} while (true);
}
Здесь можно посмотреть, как бы могло выглядеть всё, если перейти на кибиричную систему счисления.