В зависимости от версии мантисса целых чисел в perl 40 бит (5 байт) или 64 бита (8 байт).
Проверить сколько бит отводится на число в текущем perl довольно просто:
$ perl -e 'sub logn { log($_[1])/log($_[0]) } print "Мантисса целого числа — ", logn(2, ~0+1), " (бит)\n"'
Мантисса целого числа — 64 (бит)
В случае превышения мантиссы в математической операции результат будет вещественным числом с плавающей точкой.
Я столкнулся с таким различным поведением perl, когда работал с идентификатором сессии — 64-битным числом, которое сохранялось в куку в 64-ричной системе счисления.
Такие же идентификаторы использует ютюб для своих видео.
Для записи числа в 64-ричной СС в качестве цифр используются: цифры, большие и малые буквы латинского алфавита, а так же знаки _ (подчёрк) и - (тире).
Например: _m9ZDg8Ve7w64 = 7234851255909079500210.
На сервере стоял perl c 40-битными целыми. В результате алгоритм считывания числа из 64-ричной системы счисления (from_radix) переполнял мантиссу и число превращалось в число с плавающей точкой и точностью. Результат — совсем другой идентификатор.
Конечно, знающие люди скажут, что в наш просвещённый век стоит использовать docker в том числе и на сервере. Полностью с этим согласен и, как только docker станет безопасным (научится запускать контейнеры с пользователем root не от рута, чтобы через /proc нельзя было из контейнера пробраться на хостовую машину с рутовыми правами), то сразу же на него и перейду. Пока же остаются lxc/lxd (умеет подменять идентификатор нерутового пользователя на рутового в контейнере) и тяжёлые решения вроде виртуальных машин. Впрочем, vagrant поддерживает и lcx и virtualbox, так что — есть, где развернуться.
Положение спас use bigint. Эта прагма всем целочисленные константам в блоке, в котором указана, придаёт блеск Math::BigInt и следит за тем, чтобы они имели 64-битную мантиссу вне зависимости от версии perl-а:
$ perl -e 'use bigint; print ref 10'
Math::BigInt
Напоследок приведу алгоритмы для перевода чисел в различные системы счисления:
use utf8;
# Использованы символы из кодировки cp1251, что нужно для корректной записи в таблицы
our $CIF = join "", "0".."9", "A".."Z", "a".."z", "_-", # 64 символа для 64-ричной системы счисления
(map chr, ord "А" .. ord "Я"), "ЁЂЃЉЊЌЋЏЎЈҐЄЇІЅ",
(map chr, ord "а" .. ord "я"), "ёђѓљњќћџўјґєїіѕ",
"‚„…†‡€‰‹‘’“”•–—™›¤¦§©«¬®°±µ¶·№»", do { no utf8; chr 0xa0 }, # небуквенные символы из cp1251
"!\"#\$%&'()*+,./:;<=>?\@[\\]^`{|}~", # символы пунктуации ASCII
" ", # пробел
(map chr, 0 .. 0x1F, 0x7F), # управляющие символы ASCII
# символ 152 (0x98) в cp1251 отсутствует.
;
# Переводит натуральное число в заданную систему счисления
sub to_radix(@) {
use bigint;
my ($n, $radix) = @_;
$radix //= 64;
die "to_radix: Слишком большая система счисления $radix. Используйте СС до " . (1 + length $CIF) if $radix > length $CIF;
$n += 0; $radix += 0;
my $x = "";
for(;;) {
my $cif_idx = $n % $radix;
my $cif = substr $CIF, $cif_idx, 1;
$x =~ s/^/$cif/;
last unless $n = int($n / $radix);
}
return $x;
}
# Парсит натуральное число в указанной системе счисления
sub from_radix(@) {
use bigint;
my ($s, $radix) = @_;
$radix //= 64;
$radix += 0;
die "from_radix: Слишком большая система счисления $radix. Используйте СС до " . length $CIF if $radix > length $CIF;
my $x = 0;
for my $ch (split "", $s) {
$x = $x*$radix + index $CIF, $ch;
}
return $x;
}
Как Вы можете видеть, приходящие в параметрах функций числа никак прагмой use bigint не преобразуются. Поэтому они преобразуются к числу Math::BigInt прибавлением нуля ($radix += 0).
Что касается подбора символов для цифр в больших системах счисления (в $CIF содержится достаточно чисел для СС до 255 включительно) на основе кодировки cp1251, то я планировал использовать приведённые функции для кодирования юникодовских символов в базу с COLLATE cp1251_general_ci. Это должно сократить место в базе, ввиду того, что русские буквы используются гораздо чаще юникодовских символов.
Если интересно — дайте знать в комментариях и я напишу статью и об этом.
Тезаурус
CC — система счисления.
nuclight
Эти "знающие люди" недостаточно знающие. Собственно, docker — одна из ошибок в индустрии, проистекающая из подхода нанятия неграмотных "мы не знаем, что со всем этим (мусором) делать по-правильному, поэтому давайте по-быстренькому заметем его под ковёр (в контейнер), а то бизнес стоит" (вечная отмазка такая, про бизнес). Правильный подход же давно известен — целостная система из пакетов, то есть то, что делают дистрибутивы. Подход попроще — поселить проект с нужными модулями в отдельной хоме, это всё равно предполагает понимание, что в нём внутри происходит, вместо "скачай образ незнамо чего".
В данном конкретном случае (у автора дистрибутив со старым перлом, видимо) вместо докеров можно посоветовать, например, perlbrew.
darviarush Автор
docker нужен, чтобы сделать одинаковые версии всех программ. В статье же идёт рассказ о том, что разные версии perl ведут себя по-разному. Бывают так же ошибки связанные с разными версиями операционок, драйверов, системных утилит и т.п.
Контейнер docker-a содержит программу (например сайт) со всем, что ему нужно для работы. Контейнер уже протестирован и будет работать одинаково на любых хост-машинах.
Собственно, имея такой контейнер, можно его практически мгновенно развернуть на тысяче разных машин не тратя время на тестирование, настройку и прочее.
Хотя, всё равно, могут быть баги связанные с ядром и драйверами: с отображаемыми им файловыми системами (/proc, /dev). Но зато docker позволяет более полно использовать ресурсы хост-машины, чем виртуальные машины, которым выделяется указанная часть памяти и количество процессоров в безраздельное пользование.