8 votes

Python compter les chiffres significatifs

J'ai marqué cette question comme javascript parce que même si je l'ai actuellement écrite en Python, s'il serait plus facile à implémenter en Javascript, je pourrais facilement le faire en Javascript.

Mon devoir est de créer un vérificateur de calcul de chiffres significatifs pour le département de chimie. Cela signifie que l'étudiant entre ses données dans les champs, l'application web effectuera des opérations prédéfinies sur leurs champs et suivra les chiffres significatifs pour voir si leur réponse a le nombre correct de chiffres significatifs.

Quand j'ai décomposé le problème en ce que je pense être un bon flux de travail, j'ai réalisé que j'aurais besoin d'une façon pour soit Python (le backend puisque c'est une application web faite en Django) soit Javascript (car vous pourriez toujours le valider en front end sans problème) de déterminer le nombre de chiffres significatifs. J'ai fait un peu de recherche et je suis tombé sur cette question qui me dit que j'avais besoin de travailler avec des chaînes de caractères Python au lieu de float. Mon code python actuel est PRESQUE complet, mais il reste un défi majeur que je rencontre

import re
def find_sigfigs(x):
    # change the 'E' to lower case if the student typed it in as uppercase
    x = x.lower()
    if ('e' in x):
        myStr = x.split('e')
        # this function assumes that the number on the left of the 'e' is
        # the number of sigfigs. That would be true for user input but not
        # true when python converts a float to scientific notation
        return len( (re.search('[0-9]+', myStr[0])).group() )
    else:
        # put it in e format and return the result of that
        ### problem: python makes me hard code the number of sigfigs as '2'
        ### without the 2 there it always defaults to 6
        return find_sigfigs('%.*e' %(2,float(x)))

>>> find_sigfigs('1.3e-4')
>>> 2
>>> find_sigfigs('1234')
>>> 3
>>> find_sigfigs('123456')
>>> 3
>>> find_sigfigs('1.2345e3')
>>> 5

then without the 2

return find_sigfigs('%.e' %(float(x)))

#Because it changes it to 1.234000e3
>>> find_sigfigs('1234')
>>> 7

#Because it changes it to 1.234560e5
>>> find_sigfigs('123456')
>>> 7

Donc en résumé, mon problème est que j'ai besoin d'une façon simple de compter les chiffres significatifs quand ils ne sont pas explicitement déclarés par l'étudiant (c'est-à-dire quand ils sont en notation scientifique). Y a-t-il une manière simple pour moi de supprimer tous les zéros avant le 'e' jusqu'à ce qu'il atteigne le premier chiffre non nul. Je suppose que je dois commencer à partir de la fin de la chaîne séparée et supprimer les zéros jusqu'à atteindre un chiffre non nul?

EDIT: Donc après un peu de bidouillage, j'espère que c'est une solution appropriée au problème. Je l'ai testé plusieurs fois, mais pas trop rigoureusement (c'est probablement fonctionnel mais qui sait! Je ne suis pas très doué en sigfigs...)

def find_sigfigs(x):
    '''Returns the number of significant digits in a number. This takes into account
       strings formatted in 1.23e+3 format and even strings such as 123.450'''
    # change all the 'E' to 'e'
    x = x.lower()
    if ('e' in x):
        # return the length of the numbers before the 'e'
        myStr = x.split('e')
        return len( myStr[0] ) - 1 # to compenstate for the decimal point
    else:
        # put it in e format and return the result of that
        ### NOTE: because of the 8 below, it may do crazy things when it parses 9 sigfigs
        n = ('%.*e' %(8, float(x))).split('e')
        # remove and count the number of removed user added zeroes. (these are sig figs)
        if '.' in x:
            s = x.replace('.', '')
            #number of zeroes to add back in
            l = len(s) - len(s.rstrip('0'))
            #strip off the python added zeroes and add back in the ones the user added
            n[0] = n[0].rstrip('0') + ''.join(['0' for num in xrange(l)])
        else:
            #the user had no trailing zeroes so just strip them all
            n[0] = n[0].rstrip('0')
        #pass it back to the beginning to be parsed
    return find_sigfigs('e'.join(n))

3voto

durden2.0 Points 1367

Je pense qu'il y a une solution plus simple qui ne nécessite pas de récursion. De plus, la solution ci-dessus ne fonctionne que lorsque des chaînes de caractères sont passées en paramètre. Il me semble étrange de demander les chiffres significatifs dans une chaîne de caractères, donc il semble logique que la fonction fasse cette transformation en interne ou du moins accepte les chaînes de caractères et les nombres en paramètre.

Voici ce que j'ai développé :

def find_sigfigs(number):
    """Retourne le nombre de chiffres significatifs dans un nombre"""

    # Convertir d'abord en float pour prendre en compte les notations exponentielles
    # et mettre toutes les entrées sur un même pied d'égalité. Ensuite, le nombre de
    # chiffres significatifs est le nombre de chiffres non nuls après avoir supprimé
    # les zéros supplémentaires à gauche du nombre entier et à droite du décimal
    number = repr(float(number))

    tokens = number.split('.')
    whole_num = tokens[0].lstrip('0')

    if len(tokens) > 2:
        raise ValueError('Nombre invalide "%s" un seul décimal autorisé' % (number))

    if len(tokens) == 2:
        decimal_num = tokens[1].rstrip('0')
        return len(whole_num) + len(decimal_num)

    return len(whole_num)

Est-ce que j'ai oublié certains cas particuliers ?

2voto

aganders3 Points 2707

Je pense que les expressions régulières sont un peu exagérées ici, mais votre méthode devrait fonctionner et je suis sûr que ce n'est pas un problème de performance.

Je pense que vous êtes sur la bonne voie avec ce que vous décrivez à la fin. J'utiliserais split('e') suivi de rstrip('0'), ce qui supprimera les 'zéros de fin'. Vous pouvez ensuite reconstituer la chaîne si vous souhaitez conserver l'appel récursif.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X