2013-02-21 6 views
2

Voici le code sur Python3.3:Python3.3: optimisation racine carrée

import sys, re, math 
str1 = str(sys.stdin.readlines()) 
Data = re.findall('\\b\\d+\\b', str1) 

for i in reversed (Data): 
    print('%.4f' % math.sqrt(float(i))) 

comme vous pouvez le voir, ce programme grappins données (chaîne multi-ligne au hasard) d'entrée, et rechercher tous les chiffres cette chaîne contient. Après cela renvoie juste la racine carrée de chaque chiffre qu'il trouve.

Eh bien, l'algorithme fonctionne, mais pas assez vite, et je ne sais pas comment l'optimiser. S'il vous plaît aidez-moi avec ça. Ce que je dois faire pour optimiser le code ci-dessus?

+1

Par «chiffres», voulez-vous dire nombres? Aussi, pourriez-vous nous montrer quelques exemples d'entrées/sorties? – Volatility

+0

"mais pas assez vite" - Quelle est la taille du fichier sur lequel vous travaillez? À quelle vitesse est-ce? À quelle vitesse avez-vous besoin d'être? – mgilson

+0

Combien d'entrées avez-vous? Avez-vous profilé pour trouver le (s) hotspot (s)? – nneonneo

Répondre

2

Ceci est un résultat négatif. J'ai essayé d'utiliser quelques astuces pour le rendre plus rapide, mais c'est un peu plus rapide.

import sys, re, math 

def find_numbers(f): 
    for line in f: 
     for word in line.split(): 
      if word.isdigit(): 
       yield float(word) 

lst = list(find_numbers(sys.stdin)) 
lst.reverse() 
for x in lst: 
    print('%.4f' % math.sqrt(x)) 

Je pensais que l'inversion de la liste pourrait être fait lent, mais il n'a pas fait vraiment beaucoup de différence quand je viens d'imprimer les chiffres sans marche arrière.

La solution la plus rapide pour Python serait de simplement exécuter le code ci-dessus dans PyPy.

Ce n'est pas un problème très difficile, et si vous avez besoin de vitesse, vous pouvez écrire une solution en code C. Le code C sera à peu près aussi rapide que possible pour ce problème.

+1

Si le cas courant est des chiffres, essayez de remplacer 'if word.isdigit()' par 'try: yield int (word); sauf ValueError: pass'. Je ne sais pas pourquoi tout le monde cède des chars puisque les seuls résultats possibles sont des ints. –

+1

Vous pouvez également mémoriser 'math.sqrt' si des chiffres répétés sont attendus. –

+0

Voilà la solution fonctionne, merci beaucoup !!! il prend 1.85 secondes au travail, qui ofc. costumes pour mes objectifs. –

2

Vous pouvez essayer de charger et de traiter le fichier avec Numpy:

import numpy as np 
for i in reversed(np.fromfile(sys.stdin, sep=' ')**0.5): 
    print i 

En tant que bibliothèque numérique de haute performance pour Python, je pense que ce soit la solution la plus rapide pour vous.

+0

Semble être environ deux fois plus rapide que ma solution Python ou la solution d'origine. – steveha

+0

besoin de travailler python 3.3 comme je sais numpy encore pas dans python3.x –

+0

Il fonctionne maintenant en Python 3: http://www.scipy.org/FAQ#head-288204f886c0a120754d189f434864554a4a970d et par exemple. [win32-superpack-python3.3.exe] (http://sourceforge.net/projects/numpy/files/NumPy/1.7.0/numpy-1.7.0-win32-superpack-python3.3.exe/download) – nneonneo

0
import sys, re, math 
str1 = str(sys.stdin.readlines()) 
Data = re.findall('\\b\\d+\\b', str1) 

d2 = [round(math.sqrt(float(i)),4) for i in reversed (Data)] 

for i in d2: 
    print(i) 
+0

merci de nous avoir conseillé, mais ça ne marche toujours pas assez vite. –

1

Vous avez demandé Python, mais cela peut être fait assez bien en C. Ce programme C ne renverse pas les chiffres, mais vous pouvez simplement redirigez la sortie vers le programme tac, qui est comme cat mais inverse la lignes. Dans mes tests, il s'agit d'environ 3 fois la vitesse de la solution NumPy et environ 6 fois la vitesse de ma solution Python ou de la solution d'origine.

#include <ctype.h> 
#include <math.h> 
#include <stdio.h> 

int 
main() 
{ 
    char buf[1024]; 
    char ch; 
    float f; 
    int i, n; 

    for (i = 0;;) 
    { 
     ch = getchar(); 

     if (i > sizeof(buf)) 
     { 
      fprintf(stderr, "number too long!\n"); 
      return 1; 
     } 

     if (isspace(ch) || EOF == ch) 
     { 
      if (i > 0) 
      { 
       buf[i] = '\0'; 
       n = atoi(buf); 
       f = sqrtf(n); 
       printf("%0.4f\n", f); 
       i = 0; 
      } 

      if (EOF == ch) 
       return 0; 

      continue; 
     } 

     buf[i++] = ch; 
    } 
} 
+0

Vous devriez * simplement * utiliser simplement 'scanf' pour obtenir chacun des nombres sans déblocage avec toutes les affaires' isspace'. ('while (scanf ("% d ", & i) == 1) printf ("% 0.4f \ n ", sqrtf (i));') – nneonneo

+0

je sais comment le résoudre en C/C++, mais j'étais python nécessaire 3.3. de toute façon merci pour une aide :))) –

+0

@nneonneo, parfois quand vous êtes fatigué, vous écrivez juste ce que vous savez! J'ai écrit de petites machines d'état comme ça plusieurs fois. Mais oui, la solution 'scanf()' est plus facile! – steveha

1

Mise à jour: Toutes mes excuses pour l'affichage d'un double de steveha's much earlier answer. Parle de volumes sur mes compétences en lecture. Toujours en laissant cette réponse en ligne pour l'instant, juste à cause de mes réflexions sur les effets d'E/S/Buffering/Runtime.

Original post:

Je ne peux pas croire qu'il faut Python plus d'appliquer une expression régulière, et de calculer une racine carrée, qu'il ne faut pour lire une ligne d'entrée et la sortie standard d'un résultat sur la norme sortie (ou toute E/S d'ailleurs).

Comme les E/S à un moment donné proviendront d'un disque dur et iront soit à un autre disque dur, soit à l'œil d'un utilisateur, cela devrait être le facteur limitant.

Les E/S sont généralement tamponnées pour l'accélération. Habituellement, un tampon est rempli en rafales, puis le processeur reste inactif en attendant que le périphérique fournisse plus de données.

Cela conduit à un générateur pour votre application.Ecrire un générateur qui lit l'entrée ligne par ligne et fournit immédiatement un numéro de carré à la demande. Je doute que ce sera plus lent que la vitesse globale d'E/S sur tout matériel moderne raisonnable. Si vous êtes sur un périphérique spécial (comme embedded, uController, Raspberry Pi, etc, faites-le nous savoir)

La seule optimisation que vous pouvez faire est de précompiler l'expression régulière. Comme vous utilisez la même expression rationnelle pour chaque test, faisons l'analyse de l'expression rationnelle une seule fois. Votre exemple dans la question est bon parce que vous faites un re.findall(). Je suis en train d'élaborer pour d'autres lecteurs.

import sys, re, math 

pattern = re.compile(r'\b\d+\b') 

def fh_numbers_to_sqrt(fh): 
    for line in fh: 
     for i in re.findall(pattern, line): 
      yield math.sqrt(float(i)) 

numbers_g = fh_numbers_to_sqrt(sys.stdin) 
for num in numbers_g: 
    print('%.4f' % num) 

Cela permet à toutes les opérations mathématiques et expressions rationnelles d'être entrelacées avec les temps d'E/S.

Maintenant, la seule chose que nous ne pouvons pas vraiment optimiser et intégrer est le reverse. L'algorithme doit attendre jusqu'au dernier élément pour pouvoir inverser.

On pourrait donc changer le code appelant à:

numbers_g = fh_numbers_to_sqrt(sys.stdin) 
for num in reverse(list(numbers_g)): 
    print('%.4f' % num) 

et nous espérons que c'est plus rapide ce que vous aviez à l'origine. Encore une fois, la seule raison pour laquelle cela devrait être plus rapide est parce que nous avons caché l'exécution de l'analyse et du calcul de l'expression rationnelle dans l'horloge murale nécessaire pour lire les données de l'entrée standard. Cela devrait toujours être limité aux E/S. En fait, il se peut que le reverse ne soit pas réellement ajouté à l'exécution globale, car il peut simplement s'intercaler avec l'E/S qui se produit sur la sortie standard. En regardant une horloge murale, cet algorithme pourrait ne pas utiliser de temps du tout. :-)

Pour prouver ou annuler l'ensemble de mon article, vous pouvez mesurer avec time.time() combien de temps il faut entre le début de votre script et juste avant la ligne Data = re.findall, et à partir de là jusqu'à la fin. Si j'ai raison, la lecture des données prendra le plus de temps. Si ce n'est pas le cas, il est utile de mesurer également le temps requis pour toutes les recherches d'expressions régulières. Laissez nous savoir. Je suis curieux ...

+0

+1 pour toutes les explications. Je dois penser que ce qui ralentissait le code original était la construction inutile de grandes choses en mémoire: d'abord une liste de toutes les lignes d'entrée, puis une chaîne représentant cette liste, puis une autre liste de numéros de chaînes ... il vaut mieux analyser le texte au fur et à mesure, jeter le texte après l'avoir analysé et ne garder que les chiffres. C'est pourquoi un générateur est la voie à suivre, et vous avez mieux expliqué cela que moi. – steveha

Questions connexes