Python Dezimal – Engineering Notation für Mili (10e-3) und Mikro (10e-6)

Hier ist das Beispiel, das mich stört:

>>> x = decimal.Decimal('0.0001') >>> print x.normalize() >>> print x.normalize().to_eng_string() 0.0001 0.0001 

Gibt es einen Weg, um Engineering-Notation für die Darstellung von Mili (10e-3) und Mikro (10e-6)?

4 Solutions collect form web for “Python Dezimal – Engineering Notation für Mili (10e-3) und Mikro (10e-6)”

Hier ist eine Funktion, die Dinge explizit macht, und hat auch Unterstützung für die Verwendung von SI-Suffixen für den Exponenten:

 def eng_string( x, format='%s', si=False): ''' Returns float/int value <x> formatted in a simplified engineering format - using an exponent that is a multiple of 3. format: printf-style string used to format the value before the exponent. si: if true, use SI suffix for exponent, eg k instead of e3, n instead of e-9 etc. Eg with format='%.2f': 1.23e-08 => 12.30e-9 123 => 123.00 1230.0 => 1.23e3 -1230000.0 => -1.23e6 and with si=True: 1230.0 => 1.23k -1230000.0 => -1.23M ''' sign = '' if x < 0: x = -x sign = '-' exp = int( math.floor( math.log10( x))) exp3 = exp - ( exp % 3) x3 = x / ( 10 ** exp3) if si and exp3 >= -24 and exp3 <= 24 and exp3 != 0: exp3_text = 'yzafpnum kMGTPEZY'[ ( exp3 - (-24)) / 3] elif exp3 == 0: exp3_text = '' else: exp3_text = 'e%s' % exp3 return ( '%s'+format+'%s') % ( sign, x3, exp3_text) 

Das decimal Modul folgt der Dezimal-Arithmetik-Spezifikation , die besagt:

To-science-string – Umwandlung in numerische Zeichenfolge

[…]

Der Koeffizient wird zuerst in einen String in Basis zehn mit den Zeichen 0 bis 9 ohne führende Nullen konvertiert (außer wenn sein Wert Null ist, wobei in diesem Fall ein einzelnes 0 Zeichen verwendet wird). Als nächstes wird der eingestellte Exponent berechnet; Dies ist der Exponent, plus die Anzahl der Zeichen im umgewandelten Koeffizienten, weniger eins. Das heißt, Exponent + (Clength-1), wobei clength die Länge des Koeffizienten in Dezimalstellen ist.

Wenn der Exponent kleiner oder gleich Null ist und der eingestellte Exponent größer oder gleich -6 ist, wird die Zahl in eine Zeichenform umgewandelt, ohne eine exponentielle Notation zu verwenden.

[…]

To-Engineering-String – Umwandlung in numerische Zeichenfolge

Diese Operation konvertiert eine Zahl in einen String, wobei die Engineering-Notation verwendet wird, wenn ein Exponent benötigt wird.

Die Umwandlung folgt genau den Regeln für die Umwandlung in die wissenschaftliche numerische Zeichenfolge, außer bei endlichen Zahlen, bei denen exponentielle Notation verwendet wird.

Oder mit anderen Worten:

 >>> for n in (10 ** e for e in range(-1, -8, -1)): ... d = Decimal(str(n)) ... print d.to_eng_string() ... 0.1 0.01 0.001 0.0001 0.00001 0.000001 100E-9 

Das «volle» Zitat zeigt, was falsch ist!

Das decimal Modul folgt in der Tat der proprietären (IBM) Decimal Arithmetic Specification. Das Zitieren dieser IBM Spezifikation in ihrer Gesamtheit zeigt deutlich, was falsch ist mit decimal.to_eng_string() (Hervorhebung hinzugefügt):

To-Engineering-String – Umwandlung in numerische Zeichenfolge

Diese Operation konvertiert eine Zahl in einen String, wobei die Engineering-Notation verwendet wird, wenn ein Exponent benötigt wird.

Die Umwandlung folgt genau den Regeln für die Umwandlung in die wissenschaftliche numerische Zeichenfolge, außer bei endlichen Zahlen, bei denen exponentielle Notation verwendet wird. In diesem Fall wird der umgewandelte Exponent als ein Vielfaches von drei (Engineering-Notation) durch Positionieren des Dezimalpunktes mit einem, zwei oder drei Zeichen vorangestellt, dh dem Teil, bevor der Dezimalpunkt von 1 bis 999 reicht ). Dies kann die Addition von ein oder zwei nachlaufenden Nullen erfordern.

Wenn nach der Einstellung der Dezimalpunkt nicht von einer Ziffer gefolgt wäre, dann wird es nicht hinzugefügt. Ist der endgültige Exponent null, so ist kein Indikator und Exponent suffixiert.

Diese proprietäre IBM Spezifikation gibt tatsächlich zu, dass sie die Ingenieur-Notation für unendliche (dezimale Darstellung) Zahlen nicht anwendet ! Dies ist offensichtlich falsches Verhalten, für das ein Python-Fehlerbericht geöffnet wurde.

Lösung

 from math import * def powerise10(x): """ Returns x as a*10**b with 0 <= a < 10 """ if x == 0: return 0,0 Neg = x < 0 if Neg: x = -x a = 1.0 * x / 10**(floor(log10(x))) b = int(floor(log10(x))) if Neg: a = -a return a,b def eng(x): """Return a string representing x in an engineer friendly notation""" a,b = powerise10(x) if -3 < b < 3: return "%.4g" % x a = a * 10**(b % 3) b = b - b % 3 return "%.4gE%s" % (a,b) 

Quelle: https://code.activestate.com/recipes/578238-engineering-notation/

Testergebnis

 >>> eng(0.0001) 100E-6 

Basierend auf der hervorragenden Antwort von Julian Smith (und dieser Antwort) habe ich die Funktion geändert, um folgende Punkte zu verbessern:

  • Python3-kompatibel (Integer-Division)
  • Kompatibel für 0 Eingang
  • Rundung auf signifikante Anzahl von Ziffern, standardmäßig 3, keine nachlaufenden Nullen gedruckt

Also hier ist die aktualisierte Funktion:

 import numpy as np def eng_string( x, sig_figs=3, si=True): """ Returns float/int value <x> formatted in a simplified engineering format - using an exponent that is a multiple of 3. sig_figs: number of significant figures si: if true, use SI suffix for exponent, eg k instead of e3, n instead of e-9 etc. """ x = np.float(x) sign = '' if x < 0: x = -x sign = '-' elif x == 0: exp = 0 exp3 = 0 x3 = 0 else: exp = int( np.floor( np.log10( x))) exp3 = exp - ( exp % 3) x3 = x / ( 10 ** exp3) x3 = round( x3, -int(np.floor(np.log10(abs( x3 ))) - (sig_figs-1)) ) if x3 == int(x3): # prevent from displaying .0 x3 = int(x3) if si and exp3 >= -24 and exp3 <= 24 and exp3 != 0: exp3_text = 'yzafpnum kMGTPEZY'[ exp3 // 3 + 8] elif exp3 == 0: exp3_text = '' else: exp3_text = 'e%s' % exp3 return ( '%s%s%s') % ( sign, x3, exp3_text) 
  • Importfehler: Kein Modul namens django_orm
  • Python regelmäßiger Ausdruck mit utf8 Problem
  • Vigenere cipher 'String Index außerhalb des Bereichs' für die Entschlüsselung
  • Wann und wie man Pythons RLock benutzt
  • Liste einfügen bei Index, der sich außerhalb des Bereichs befindet - verhält sich wie append
  • Warum python 2.7 auf Windows benötigen ein Leerzeichen vor Unicode-Zeichen beim Drucken?
  • Wie man ein Python datetime Objekt in Sekunden umwandelt
  • Numpy - erstellen Matrix mit Zeilen von Vektor
  • Python: Sortieren von Dateien nach datetime in mehr Details
  • Wie drucke ich mit Python?
  • Warum passt das Zeitfenster auf, bevor es öffnet
  • Python ist die beste Programmiersprache der Welt.