11
votes

Moyen le plus rapide de trouver la plus grande puissance de 10 plus petite que x

Y a-t-il un moyen rapide de trouver la puissance la plus importante de 10 plus petite qu'un nombre donné?

J'utilise cet algorithme, pour le moment, mais quelque chose à moi meurt à tout moment, je le vois: < pré> xxx

i peut implémenter simple log10 et pow fonctionne pour mes problèmes avec une boucle chacune, mais je me demande toujours s'il y en a quelques Bit Magic pour les nombres décimaux.


5 commentaires

Quel est le problème avec ça? Il faut .0161 microsecondes en moyenne pour effectuer 10 ** (int (math.log10 (987654321987654321))) , qui est en fait plutôt impressionnant.


Parlons-nous des entiers ou des flotteurs?


L'algorithme le plus rapide va probablement dépendre de la taille de x . Vous voudrez probablement profiler une approche hybride.


Dans mon cas, x est un entier, mais je suppose que cela ne devrait pas changer autant (pourrait lancer un flotteur x dans une valeur intégrale et inversement).


Ma réponse était plus rapide que d'autres théoriquement, elle est utile pour les gros chiffres pas 10 chiffres.


8 Réponses :


6
votes

Le journal et la puissance sont des opérations coûteuses. Si vous voulez rapidement, vous voulez probablement regarder l'exposant binaire IEEE dans le tableau pour obtenir la puissance approximative de dix, puis vérifier si la Mantissa oblige une modification de +1 ou non. Cela devrait être 3 ou 4 integer em> instructions de la machine (alternativement O (1) avec une jolie petite constante).

Tableaux donnés: P>

  power_of_ten=IEEE_exponent_to_power_of_10[IEEE_Exponent(x)+1023];
  if (x>=next_power_of_ten[power_of_ten]) power_of_ten++;
  answer=next_power_of_ten[power_of_ten];


5 commentaires

Non, je ne fais pas que dans Python, c'est supposé un algorithme indépendant de la langue - je voulais juste montrer mon algorithme actuel dans deux langues pour que cela ne soit plus clair, mauvaise idée, probablement ...


LOG et POWER sont des opérations coûteuses. C'est évidemment le cas en l'absence de support matériel pour les opérations transcendantaux. Mais, à quel point parlez-nous de la CPU à usage général de la qualité de consommation (X86, Power, X86_64 ...)?


Si vous ne voulez pas utiliser de point flottant, un système d'entier similaire fonctionne en utilisant une instruction d'assemblage du comte-Zeros.


@DMCKEE: Même avec un point flottant intégré, les transcendains prennent un certain temps. Les fournisseurs de puces ne veulent plus vous dire que des comptes d'horloge précis sur quoi que ce soit, mais il est difficile de croire que vous mettez en place un point flottant de haute précision longtemps dans quelques horloges. Mon schéma, seulement peu d'instructions entière (même la comparaison flottante de flottante peut en réalité effectuée avec des instructions entière en raison de la définition d'IEEE!) Semblait probablement difficile à battre. Est-ce la peine? Probablement pas, à moins que l'OP ne fasse que cela à plusieurs reprises dans une boucle intérieure. Mais il n'a pas demandé si cela valait la peine: -}


Belle solution! Je ne vais pas mettre en œuvre ceci maintenant: cela semble assez compliqué, mais je devrai, au cas où vous devrez optimiser encore plus la solution que j'ai choisie.



7
votes

Un algorithme alternatif est:

i = 1;
while((i * 10) < x)
    i *= 10;


5 commentaires

C'est une approche terrible en termes de complexité de calcul. Votre méthode est O (n) en termes de nombre de bits, tandis que O (log (n)) est suffisant.


Tout est un compromis. Pour les chiffres avec une plage finie, O (N) pourrait très bien être très bien, et cette option n'utilise aucun espace supplémentaire (comparé à la présentation d'une grande table de recherche, précontrant une séquence de carrés, etc.). La complexité informatique n'est pas la totalité du tout et de la fin, si un algorithme est "bon" ou non. Il serait relativement simple de la modifier sur carré au lieu de multiplier naïf-multiplier jusqu'à ce qu'il soit proche, mais cela impliquerait plus de code et pourrait, en fait, ralentissez-le sur des intrants plus petits. Le bon choix dépend des données d'entrée attendues, pas uniquement sur la performance de Big-O.


Il vaut mieux le faire alors que ((i = i * 10)


La complexité informatique n'est pas la totalité du tout et de la fin, mais dans ce cas, il a spécifiquement demandé le moyen le plus rapide ...


La plupart (tous?) Des réponses que j'ai obtenues sont beaucoup moins chères que mon ancien code. Cette solution est la plus simple à être mise en œuvre, propre et vraiment facile à comprendre. Je suis en train de mettre en œuvre celui-ci depuis que je pense que pour mon cas moyen (en ce moment), il n'aurai pas besoin de itérer plus de 4 ou 5 fois, donc une solution FAST O (N) devrait être correcte; Si je vois que ça ne suffit pas encore, je vais essayer de mettre en œuvre d'autres algorithmes aussi.



3
votes

Le moyen le plus rapide asymptotiquement, autant que je sache, implique une querelle répétée.

func LogFloor(int value, int base) as int
    //iterates values of the form (value: base^(2^i), power: 2^i)
    val superPowers = iterator
                          var p = 1
                          var c = base
                          while c <= value
                              yield (c, p)
                              c *= c
                              p += p
                          endwhile
                      enditerator

    //binary search for the correct power
    var p = 0
    var c = 1
    for val ci, pi in superPowers.Reverse()
        if c*ci <= value
            c *= ci
            p += pi
        endif
    endfor

    return p


2 commentaires

@Yonatan L'indentation est destinée. Il conserve le contenu du bloc d'itérateur à droite des délimiteurs de bloc.


Quant à la solution précédente, c'est un bon! Je ne vais pas mettre en œuvre ceci maintenant: cela semble assez compliqué, mais je devrai, au cas où vous devrez optimiser encore plus la solution que j'ai choisie.



0
votes

étant donné qu'il s'agit de la langue indépendante, si vous pouvez obtenir la puissance de deux que ce nombre est significatif, par exemple Y en x * 2 ^ y (qui est la façon dont le nombre est stocké, bien que je ne suis pas sûr que je ne suis pas sûr de ont vu un moyen facile d'accéder à Y dans n'importe quelle langue que j'ai utilisée) alors si xxx

(une division point flottante)

10 ^ z ou 10 ^ (z + 1) sera votre réponse, bien que 10 ^ z ne soit toujours pas si simple (prie d'être corrigée).


1 commentaires

Si vous pouvez obtenir la puissance de deux, vous pouvez simplement rechercher Z dans le tableau (ma réponse) au coût d'un accès à la mémoire qui est beaucoup moins cher qu'un fracture de flotteur.



1
votes

Je pense que le moyen le plus rapide est O (journal (journal (n)) ^ 2), la boucle tandis que prend o (journal (log (n)) et peut être une heure de récursification finie (nous pouvons dire O (C ) Où voir constante), le premier appel récursif est devenu journal (journal (sqrt (n))) Temps seconde prend .. et le nombre de SQRT dans SQRT (sqrt (sqrt .... (n)) <10 est un journal (journal (n)) et constant, en raison de limitations de la machine.

 XXX                                  

0 commentaires

4
votes

Créer une gamme de pouvoirs de 10. La recherche de la plus grande valeur inférieure à x.

Si X est assez petit, vous constaterez peut-être qu'une recherche linéaire offre de meilleures performances qu'une recherche binaire, dû en partie à moins de prévisions erronées de branche.


0 commentaires

1
votes

en python:

10 ** (len (STR (int (x))) - 1)


0 commentaires

0
votes

J'ai chronométré les méthodes avec les variantes suivantes de C ++ pour la valeur A code> étant un Taille_t code> Type (l'allusion améliore les performances, mais ne change pas la commande relative).

Essayez 1: Multiplier jusqu'à la recherche du numéro. P>

# where we previously define lookuptable = ( 1, 10, 100, ..... )
scalar = [i for i in lookuptable if i < a][-1]


1 commentaires

Lorsque vous devez écrire du code qui commence à ressembler à l'art ASCII d'un voilier, vous devriez vous demander si vous vraiment besoin de ce type d'optimisation.