Что лучший способ состоит в том, чтобы сделать base36 арифметику в Perl?

Что лучший способ состоит в том, чтобы сделать base36 арифметику в Perl?

Чтобы быть точнее, я должен смочь сделать следующее:

  • Воздействуйте на положительные N-разрядные числа в основе 36 (например, цифры являются 0-9 A-Z),

    N конечен, скажите 9

  • Обеспечьте основную арифметику, по крайней мере следующие 3:

    • Дополнение (A+B)

    • Вычитание (A-B)

    • Целое подразделение, например, пол (A/B).

    • Строго говоря мне действительно не нужна base10 способность к преобразованию - числа будут 100% времени быть в base36. Таким образом, я довольно в порядке, если решение НЕ реализует преобразование из base36 назад к base10 и наоборот.

Я не очень забочусь, "в лоб" ли решение, "преобразовывают в основу 10 и назад" или преобразовывающий в двоичный файл или некоторый более изящный подход, "исходно" выполняющий операции бассейна (как указано выше, к/от base10 преобразованию не требование). Мои только 3 соображения:

  1. Это соответствует минимальным спецификациям выше

  2. Это "стандартно". В настоящее время мы используем и старый модуль собственной разработки на основе base10 преобразования, сделанного вручную, который является багги и сосет.

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

  3. Это должен быть быстрый выход (хотя не молния быстро). Что-то, что занимает 1 секунду для подведения 2 9-разрядных base36 чисел, хуже, чем что-нибудь, что я могу прокрутить самостоятельно :)

P.S. Только для обеспечения некоторого контекста в случае, если люди решают решить мою проблему XY для меня в дополнение к ответу на технический вопрос выше :)

У нас есть довольно большое дерево (сохраненный в DB как набор краев), и мы должны наложить порядок на подмножество того дерева. Дерево dimentions является большим и глубина - и ширина - мудрый. Дерево ОЧЕНЬ активно обновляется (вставляет и удаляет, и перейдите перемещения).

Это в настоящее время делается при наличии второй таблицы с 3 столбцами: parent_vertex, child_vertex, local_order, где local_order 9 символьных строк, созданных из A-Z0-9 (например, основывайте 36 чисел).

Дополнительные соображения:

  • Требуется, что локальный порядок уникален на ребенка (и очевидно уникален на родителя),

  • Любое полное переупорядочение родителя является несколько дорогим, и таким образом реализация должна попытаться присвоиться - для родителя с X детьми - заказы, которые несколько равномерно распределяются между 0 и 36 ** 10-1, так, чтобы почти никакое дерево не вставляло результат в полное переупорядочение.

6
задан brian d foy 19 April 2010 в 22:29
поделиться

3 ответа

А как насчет Math :: Base36 ?

12
ответ дан 8 December 2019 в 05:53
поделиться

Я предполагаю, что основные модули Perl в порядке?

Как насчет использования собственной (двоичной) целочисленной математики и преобразования из результата с основанием 36 с использованием POSIX :: strtol ()

Существует ОГРОМНАЯ скорость разницы в скорости в различных методах преобразования в / из базы 36. Strtol в 80 раз быстрее, чем, например, Math :: Base36: decode_base36, а подсистемы преобразования, которые у меня есть в листинге, в 2–4 раза быстрее, чем Math :: Base36. Они также поддерживают любую целочисленную базу до 62. (легко расширяется путем добавления символов в массив nums.)

Вот быстрый тест:

#!/usr/bin/perl
use POSIX;
use Math::BaseCnv;
use Math::Base36 ':all';
use Benchmark;

{
    my @nums = (0..9,'a'..'z','A'..'Z');
    $chr=join('',@nums);
    my %nums = map { $nums[$_] => $_ } 0..$#nums;

    sub to_base
    {
        my ($base, $n) = @_;
        return $nums[0] if $n == 0;
        return $nums[0] if $base > $#nums;
        my $str = ''; 
        while( $n > 0 )
        {
            $str = $nums[$n % $base] . $str;
            $n = int( $n / $base );
        }
        return $str;
    }

    sub fr_base
    {
        my ($base,$str) = @_;
        my $n = 0;

        return 0 if $str=~/[^$chr]/;

        foreach ($str =~ /[$chr]/g)
        {
            $n *= $base;
            $n += $nums{$_};
        }
        return $n;
    }
}

$base=36;   
$term=fr_base($base,"zzz");

for(0..$term) { push @numlist, to_base($base,$_); }

timethese(-10, {
        'to_base' => sub { for(0..$#numlist){ to_base($base,$_); }  },
        'encode_base36' => sub { for(0..$#numlist){ encode_base36($_); }  },
        'cnv->to 36' => sub { for(0..$#numlist){ cnv($_); }  },
        'decode_base36' => sub { foreach(@numlist){ decode_base36($_); }  }, 
        'fr_base' => sub { foreach(@numlist){ fr_base($base,$_); }  },
        'cnv->to decimal' => sub { foreach(@numlist){ cnv($_,$base,10); }  },
        'POSIX' => sub { foreach(@numlist){ POSIX::strtol($_,$base);}},
} );
9
ответ дан 8 December 2019 в 05:53
поделиться

Я бы поставил свои деньги на преобразование в base10 и обратно.

Если вам не нужно делать это очень часто и количество не очень велико, это самый простой (и, следовательно, наименее сложный => наименьшее количество ошибок) способ сделать это.

Конечно, есть еще один способ сделать это - также сохранить число base10 только для целей вычислений, однако я не уверен, возможно ли это или имеет ли это какое-либо преимущество в вашем случае

1
ответ дан 8 December 2019 в 05:53
поделиться
Другие вопросы по тегам:

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