Engineering numerical format PEP discussion

Keith keith.brafford at gmail.com
Mon Apr 26 05:36:22 CEST 2010


I am considering writing a PEP for the inclusion of an engineering
format specifier, and would appreciate input from others.

Background (for those who don't already know about engineering
notation):

Engineering notation (EN) is type of floating point representation.
The idea with EN is that the powers of 10 are all multiples of 3,
which correspond to the familiar Greek unit prefixes that engineers
use when describing the different sizes of all sorts of real-world
devices and phenomena:

1e-12 == pico
1e-9  == nano
1e-6  == micro
1e-3  == milli
1e+3  == kilo
1e+6  == mega
1e+9  == giga

When people are talking about Ohms, Farads, Henries, Hz, and many
others, they routinely have to normalize to EN.  Fancy calculators
from HP and TI routinely allow the users to go into engineering mode,
but mysteriously things like C, Python, Excel, etc. don't

For instance, no one talks about 4.7e-5F, as they would rather see
47e-6 (micro).  Instead of 2.2e-2, engineers need to see 22.0e-3
(milli).

Originally to address this issue, I wrote for myself an "EFloat" class
that subclassed float:

import math
class EFloat(float):
    """EFloat(x) -> floating point number with engineering
representation when printed
       Convert a string or a number to a floating point number, if
possible.
       When asked to render itself for printing (via str() or print)
it is normalized
       to engineering style notation at powers of 10 in multiples of 3
       (for micro, milli, kilo, mega, giga, etc.)
    """

    def __init__(self, value=0.0, prec=12):
        super(EFloat, self).__init__(value)
        self.precision = prec

    def _get_precision(self):
        return self._precision
    def _set_precision(self, p):
        self._precision = p
        self.format_string = "%3." + ("%d" % self._precision) + "fe%
+d"
        return
    precision = property(_get_precision, _set_precision, doc="The
number of decimal places printed")

    def _exponent(self):
        if self == 0.0:
           ret = 0
        else:
           ret = math.floor(math.log10(abs(self)))
        return ret

    def _mantissa(self):
        return self/math.pow(10, self._exponent())

    def _asEng(self):
        shift = self._exponent() % 3
        retval = self.format_string % (self._mantissa()*math.pow(10,
shift), self._exponent() - shift)
        return retval

    def __str__(self):
        return self._asEng()

    def __repr__(self):
        return str(self)

    def __add__(self, x):
        return EFloat(float.__add__(self, float(x)))

    def __radd__(self, x):
        return EFloat(float.__add__(self, float(x)))

    def __mul__(self, x):
        return EFloat(float.__mul__(self, float(x)))

    def __rmul__(self, x):
        return EFloat(float.__mul__(self, float(x)))

    def __sub__(self, x):
        return EFloat(float.__sub__(self, float(x)))

    def __rsub__(self, x):
        return EFloat(float.__rsub__(self, float(x)))

    def __div__(self, x):
        return EFloat(float.__div__(self, float(x)))

    def __rdiv__(self, x):
        return EFloat(float.__rdiv__(self, float(x)))

    def __truediv__(self, x):
        return EFloat(float.__truediv__(self, float(x)))

    def __rtruediv__(self, x):
        return EFloat(float.__rtruediv__(self, float(x)))

    def __pow__(self, x):
        return EFloat(float.__pow__(self, float(x)))

    def __rpow__(self, x):
        return EFloat(float.__rpow__(self, float(x)))

    def __divmod__(self, x):
        return EFloat(float.__divmod__(self, float(x)))

    def __neg__(self):
        return EFloat(float.__neg__(self))

    def __floordiv__(self, x):
        return EFloat(float.__floordiv__(self, float(x)))


which works well for working with interactive Python.

There are places on the web where I've read that people have to work
their butts off trying to "trick" Excel or OpenOffice to do
engineering notation, or there is some work-around that is purported
to work if you use the right version of the spreadsheet.

After many months of using my EFloat class extensively with lots of
apps dealing with embedded engineering tasks, it dawns on me that what
we really need is simply a new format specifier.

I am thinking that if we simply added something like %n (for eNgineer)
to the list of format specifiers that we could make life easier for
engineers:

("%n" % 12345)  == "12.345e+03"
("%n" %  1234)  == "1.234e+03"
("%n" %   123)  == "123e+00"
("%n" % 1.2345e-5)  == "12.345e+06"

Of course, the normal dot fields would be put to use to allow us to
specify how many total digits or digits of precision we wanted, or if
we want zero prepend. (whatever makes the most sense, and keeps the
standard most like what is already in the language):

("%.12n" % 12345678)  == "12.345678000000e+06"

Do you think this idea has enough merit to make it to PEP status?

--Keith Brafford








More information about the Python-list mailing list