6
votes

Quelle est la meilleure façon de faire de la base36 arithmétique à Perl?

Quelle est la meilleure façon de faire de la base36 arithmétique à Perl?

Pour être plus précis, j'ai besoin de pouvoir faire ce qui suit:

  • fonctionne sur des nombres N-chiffres positifs dans la base 36 (par exemple, les chiffres sont 0-9 A-Z)

    n est fini, dis 9

  • Fournissez des arithmétiques de base, au moins les 3 suivants:

    • Ajout (A + B)

    • Soustraction (A-B)

    • division entière, par exemple étage (A / B).

    • Strictement parler, je n'ai pas vraiment besoin d'une capacité de conversion de base10 - les chiffres seront 100% du temps en base36. Donc, je suis bien acceptable si la solution ne met pas en œuvre la conversion de Base36 Retour à BASE10 et inversement.

      Je ne me soucie pas de si la solution est une force brute "Convertir en Base 10 et en arrière" ou de la conversion en binaire, ou une approche plus élégante "de manière nativement" opérations de base (comme indiqué ci-dessus, vers / depuis la conversion de base10 n'est pas une exigence). Mes seules considérations sont:

      1. Il convient aux spécifications minimales ci-dessus

      2. C'est "standard". Actuellement, nous utilisons et ancien module à la maison basé sur la conversion de base10 effectuée à la main qui est buggy et craint.

        Je préfère beaucoup remplacer cela avec une solution de CPANON couramment utilisée au lieu de ré-écrire mon propre vélo à partir de zéro, mais je suis parfaitement capable de la construire si aucune meilleure possibilité standard n'existe.

      3. Il doit être rapide-ish (bien que pas foudre rapide). Quelque chose qui prend 1 seconde pour résumer 2 chiffres à 9 chiffres36 est pire que tout ce que je peux rouler seul :)

        P.s. Juste pour fournir un contexte au cas où les gens décident de résoudre mon problème XY pour moi en plus de répondre à la question technique ci-dessus :)

        Nous avons un arbre assez grand (stocké dans DB comme bande d'arêtes) et nous devons superposer l'ordre sur un sous-ensemble de cet arbre. Les Dimensions des arbres sont grandes à la fois de profondeur et de largeur. L'arborescence est très activement mise à jour (inserts et suppressions et mouvements de succursales).

        Ceci est actuellement effectué en ayant une deuxième table avec 3 colonnes: parent_vertex, enfant_vertex, local_order , où local_order est une chaîne de 9 caractères construite en A-Z0- 9 (par exemple, numéro de base 36).

        Considérations supplémentaires:

        • Il est nécessaire que l'ordre local soit unique par enfant (et évidemment unique par parent),

        • Toute réchrographie complète d'un parent est quelque peu chère et que la mise en œuvre est donc d'essayer d'assigner - pour un parent avec x enfants - les commandes qui sont quelque peu réparties entre 0 et 36 ** 10- 1, de sorte que presque aucun insert d'arbre ne donne lieu à une réchérature complète.


4 commentaires

Au fait, dans le cas où vous me le direz "mais vous pouvez facilement faire cela dans SQL, pourquoi demandez-vous cela comme une question Perl", la réponse est: J'adorerais une solution SQL-Seule !!! Je ne pense tout simplement pas que cela puisse être fait dans Pure SQL avec tout degré d'efficacité et l'efficacité est importante lorsque vous traitez avec SQL Server utilisé comme ressource Singleton par une entreprise totale :(


En outre, je sais sur Math :: BASECNV et MATH :: BASECALC - Je ne sais pas à quel point ils sont stables / rapides, alors mon demandeur à la So Communitty pour quelles sont les meilleures pratiques. Nous n'avons pas d'entre eux installés et l'installation d'un nouveau module CPAN est une grosse affaire avec l'équipe d'ingénierie logicielle nécessitant une bonne justification des entreprises et un signe que le module est stable.


Techniquement "Convertir en Base 10 and Back" est la même chose que la conversion en binaire - ce n'est pas comme en interne, la machine convertit tous les entiers aux chaînes de base-10 pour effectuer des mathématiques, puis de retour à nouveau. Base 10 n'est qu'un concept utilisé pour les numéros de rendu d'affichage et rien de plus.


Serait une représentation d'ensemble imbriquée ( dev.mysql.com/tech-Resources/ Articles / hiérarchical-data.htm l ) être pratique? Les insertions et les greffons peuvent signifier que la réponse est "non", mais cela déplacerait le fardeau vers le serveur SQL et simplifierait d'autres opérations nécessitant l'utilisation de la commande.


3 Réponses :


1
votes

Je parierais mon argent sur la conversion à la base10 et à l'arrière.

Si vous n'avez pas à le faire très souvent et que les chiffres ne sont pas très importants, c'est le moyen le plus facile (et le moins complexe => moins de bugs) de le faire.

Bien entendu, une autre façon de le faire est de sauvegarder le numéro de base10 à des fins de calcul uniquement, cependant, je ne suis pas sûr que cela soit possible ou que ce soit avantage dans votre cas


3 commentaires

Les ordinateurs préfèrent binaires ou hexagonaux, mais je pense que le point se tient avec cette mise en garde. Convertissez en un numéro natif, faites votre calcul, puis le ballez-le.


Hex est pour l'homme? Je préfère compter en décimal. Hex est juste pour une représentation compacte des décimales. De plus, Hex (= 16) est une puissance de deux, et la puissance de deux n'est pas destinée aux humains en général. 2 nibiles hexadécimaux = 1 octet, ce n'est pas par coïncidence. ;)


Hex est un moyen plus facile pour les humains de voir des groupes de 8 bits. L'ordinateur ne se soucie pas du tout à propos de HEX, mais les humains ne lisent pas très bien binaire. J'ai lu des hexdumps assez fréquemment. Il est beaucoup plus facile de traiter des personnages (même unicode) en examinant leur représentation hexagonale plutôt que leur représentation décimale.



12
votes

Qu'en est-il de math :: base36 ?


2 commentaires

Merci - j'étais tellement sûr que "base36" est une chose étrange jamais utilisée pour quoi que ce soit de pratique, je n'ai même pas envisagé de chercher ce terme! Duh.


Toujours chercher d'abord, demandez plus tard.



9
votes

Je suppose que les modules Perl Core sont ok?

Que diriez-vous d'utiliser des mathématiques entier natif (binaire) et convertir de la base 36 résultat en utilisant POSIX: : strtol () p>

Il y a la variabilité énorme em> à la vitesse dans les différentes méthodes pour convertir / depuis la base 36. Strtol est 80x plus rapide qu'un mathématique :: base36 : Decod_Base36 Par exemple et les sous-marins de conversion que j'ai dans la liste sont de 2 à 4 fois plus rapidement que les mathématiques :: base36. Ils supportent également toute base entière jusqu'à 62. (facilement étendu en ajoutant des caractères au tableau des nums.) P>

Voici un indice de référence rapide: p>

#!/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);}},
} );


1 commentaires

Maintenant que vous le mentionnez, je me souviens de parcourir les documents de la bibliothèque standard pour C de nombreux lunes et que vous étiez agréablement surpris que Strol () Base de base 36. Donc, maintenant, je n'ai même pas pensé à regarder dans la bibliothèque POSIX . Puisque Pose est juste une fine enveloppe autour du C, elle n'est pas surprenante que c'est si vite. Bon appel.