9
votes

Déterminer la précision et l'échelle de nombre particulier en python

J'ai une variable en python contenant un numéro de point flottant (par exemple, num = 24654.123 ), et j'aimerais déterminer les valeurs de précision et d'échelle du nombre (dans le sens Oracle), donc 123.45678 devrait me donner (8,5), 12,76 devraient me donner (4,2), etc.

Je pensais d'abord à utiliser la représentation de chaîne (via str ou REC ), mais ceux-ci échouent pour de grands nombres (bien que je comprends maintenant, ce sont les limites de la représentation de points flottante qui est le problème ici): xxx

EDIT:

bons points ci-dessous. Je devrais clarifier. Le nombre est déjà un flotteur et est poussé à une base de données via cx_oracle. J'essaie de faire de la meilleure chose que je puisse en python pour gérer des flotteurs trop volumineux pour le type de base de données correspondant à l'exécution des erreurs d'insertion et de manipulation d'Oracle (car je veux faire face aux numéros de champ, pas d'enregistrement, pas à un temps). Je suppose que carte (len, rep. (Num) .split ('.')) est le plus proche que je vais arriver à la précision et à l'échelle du flotteur?


0 commentaires

9 Réponses :


3
votes

Je pense que vous devriez envisager d'utiliser le Type Decimal au lieu d'un flotteur . Le type float donnera des erreurs d'arrondi car les chiffres sont représentés en interne en binaire mais de nombreux nombres décimaux n'ont pas une représentation binaire exacte.


0 commentaires

1
votes

En gros, vous ne pouvez pas utiliser des chiffres de points flottants. à l'aide du type décimal aiderait et si vous voulez vraiment une grande précision, envisagez d'utiliser GMPY , le port de la bibliothèque de précision de GNU à Python.


0 commentaires

19
votes

Obtenir le nombre de chiffres à gauche du point décimal est facile:

import math

def precision_and_scale(x):
    max_digits = 14
    int_part = int(abs(x))
    magnitude = 1 if int_part == 0 else int(math.log10(int_part)) + 1
    if magnitude >= max_digits:
        return (magnitude, 0)
    frac_part = abs(x) - int_part
    multiplier = 10 ** (max_digits - magnitude)
    frac_digits = multiplier + int(multiplier * frac_part + 0.5)
    while frac_digits % 10 == 0:
        frac_digits /= 10
    scale = int(math.log10(frac_digits))
    return (magnitude + scale, scale)


5 commentaires

Par curiosité, où vient le numéro 14? Est-ce indépendant de la plate-forme?


C'est une plate-forme dépendante, mais la plupart des plates-formes utiliseront IEEE-754. EN.Wikipedia.org/wiki/... aurait probablement pu faire Il 15, mais je voulais être conservateur et que mon arrondi fonctionnait correctement.


Au lieu d'avoir 14 codé dur, serait-il possible d'obtenir de la distribution de Python?


@aaragon Ce pourrait être possible, je ne sais pas. Étant donné que chaque version de Python que je connaisse est basée sur IEEE-754, je ne suis pas motivé pour le savoir.


@Aragon Curiosity a finalement eu le meilleur de moi, alors je l'ai regardé. Le numéro que vous recherchez est sys.float_info.dig , qui est 15 sur ma version de Python.



2
votes

(0) Veuillez confirmer ou refuser: vous avez des flotteurs à utiliser, il est inévitable, vous ne pouvez pas obtenir vos données comme décimale, les types de fichiers Oracle comprennent des types à base décimale et cette inadéquation fondamentale est inévitable. Veuillez expliquer tout déni complet ou partiel.

(1) Votre remarque "échec du grand nombre" est trompeuse / non pertinente / erronée - vous dites que votre point de départ est un flotteur, mais 1234567890.0987654321 ne peut pas être représenté comme un flotteur, comme le montre le résultat de la REP ().

(2) peut-être que vous pourriez peut-être utiliser la nouvelle REC (Python 2.7 et 3.1) qui fournit la précision minimale possible de REC (x) qui satisfait toujours float (REC (x)) == x

E.g. Ancien REC (1.1) produit "1.1000000000000001", nouvelle REC (1.1) produit "1.1"

À propos de "Je suppose que la carte (len, rep. (Num) .split (". ') est le plus proche que je vais arriver à la précision et à l'échelle du flotteur? ": Vous avez besoin d'une stratégie pour gérer (A) Numéros négatifs et zéro (B) des nombres tels que 1.1e20

creuser dans des objets / floatobject.c doit augmenter le code C pour la nouvelle REC () d'un objet flottant, si vous devez utiliser Python 2.6 ou antérieur.

(3) Peut-être que si vous nous avez dit les spécifications des types de données Oracle correspondants, nous pourrions vous aider à concevoir des contrôles pour choisir quel type peut contenir une valeur de flotteur donnée.


1 commentaires

0. Confirmer, essentiellement. Tout est configuré pour utiliser des flotteurs et je ne crois pas que CX_oracle traitera des types décimaux, au moins comme je l'ai mis en place. 1. édité pour corriger. 2. Intéressant, malheureusement je suis derrière 2,7. 3. J'essaie d'écrire du code qui fonctionnera dynamiquement même si les types de colonne Oracle changent de précision ou d'échelle. (Ouch, désolé pour le mauvais formatage)



6
votes

impossible avec des variables à virgule flottante. Par exemple, la typing xxx

donne: xxx

donc, pour obtenir 6,4 sur ceci, vous devrez trouver un moyen de trouver un moyen Pour distinguer un utilisateur entrant 10.2345 et 10.234500000000001 , ce qui est impossible à l'aide de flotteurs. Cela a trait à la façon dont les numéros de points flottants sont stockés. Utilisez décimal . xxx


2 commentaires

Est possible avec des flotteurs; voir ma réponse.


Ma réponse fonctionne aussi. La clé est de limiter le nombre de chiffres à la précision connue du type à flotteur et autour du résultat.



4
votes

semble que str est meilleur choix que REC : xxx


3 commentaires

Fonction Lambda pour trouver le nombre de chiffres à droite du décimal lambda x: len (str (x) .split (". ') [- 1]) Si len (str (x) .split ('. '))> 1 autre 0


Si nous voulons retourner 0 pour 100,0 entrée lambda x: len (str (x) .split ('.') [- 1]) Si int (x) 1 autre 0


En commençant par Python 3.2, il n'y a plus une différence entre REC et str pour float numéros. Voir Pourquoi Str (flotter) retourner plus de chiffres dans Python 3 que Python 2?



0
votes

J'ai trouvé une autre solution qui semble être plus simple, mais je ne sais pas exactement si cela fonctionnera pour tous les cas.

   import math
   x = 1.2345678

   def flip(string):
       result = ""
       for ch in string:
           result = ch + result
      return result

   prec = int(math.log10(float(flip(str(x)))) + 1   # precision as int


0 commentaires

0
votes

Si vous devez vérifier la précision, vous pouvez essayer:

def prec_check(a,b)
  a = str(a)
  b = str(b)
  do = bool(True)
  n = 0
  while do == True:
    if a and b and a[n] == a[b]:
      n += 1
    else:
      do = false
  return n


0 commentaires

0
votes

Si vous devez vérifier le nombre de chiffres correspondants (d'A et B) xxx

Notez que cela ne fonctionne pas avec le module "décimal".


0 commentaires