From: Keith on
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





From: Chris Rebert on
On Sun, Apr 25, 2010 at 8:36 PM, Keith <keith.brafford(a)gmail.com> wrote:
> 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).
<snip>
> 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.

Relevant related information:
The Decimal datatype supports engineering format directly:
http://docs.python.org/library/decimal.html#decimal.Decimal.to_eng_string

Cheers,
Chris
--
http://blog.rebertia.com
From: Steven D'Aprano on
On Sun, 25 Apr 2010 20:36:22 -0700, Keith wrote:

> I am considering writing a PEP for the inclusion of an engineering
> format specifier, and would appreciate input from others.
[...]
> 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).

I'd be cautious about making claims about "no one", because not everyone
wants to see engineering notation. You may recall that the other common
display format on scientific calculators is Scientific Notation, which
*does* display 2.2e-2.


> 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:

I for one don't like %n. I already write %n for integer, at least now I
get an error immediately instead of code that silently does the wrong
thing. But I don't have a better idea of what letter to use.

However, for good or ill the general consensus among the Python language
developers is that % formatting is to be discouraged in favour of the
format() method. For this reason, I expect that there will be zero (or
negative) interest in extending the list of % format specifiers. But
there may be some interest in adding a specifier to format().

http://docs.python.org/library/string.html#formatstrings


It may be worth mentioning in the PEP that Decimals already have a method
for converting to engineering notation, to_eng_string.


--
Steven
From: Keith on
On Apr 26, 12:02 am, Chris Rebert <c...(a)rebertia.com> wrote:
> On Sun, Apr 25, 2010 at 8:36 PM, Keith <keith.braff...(a)gmail.com> wrote:
> > I am considering writing a PEP for the inclusion of an engineering
> > format specifier, and would appreciate input from others.
snip
> Relevant related information:
> The Decimal datatype supports engineering format directly:http://docs.python.org/library/decimal.html#decimal.Decimal.to_eng_st...
>
> Cheers,
> Chris

Thanks for pointing that out. Does the engineering community get by
with the decimal module?

Even though this uses the to_eng_string() function, and even though I
am using the decimal.Context class:

>>> c = decimal.Context(prec=5)
>>> decimal.Decimal(1234567).to_eng_string(c)
'1234567'

That is not an engineering notation string.

--Keith Brafford



From: Keith on
On Apr 26, 12:29 am, Steven D'Aprano <st...(a)REMOVE-THIS-
cybersource.com.au> wrote:
> On Sun, 25 Apr 2010 20:36:22 -0700, Keith wrote:
>>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).

>I'd be cautious about making claims about "no one"

Good point, and I don't intend to belittle scientific computing folks
for whom traditional floating point representation is expected.

Nor am I suggesting that any of the six format specifiers that we
already have for scientific notation (e, E, f, F, g, G) be altered in
any way.

I guess I wasn't clear about the F in the 4.7e-5F in the example.
People doing engineering don't use 4.7e-5 Farads. They typically have
to do extra work to get that number to print out correctly, as 47 e-6
Farads. The same goes for lots of signal processing entities. People
doing things with Hz, seconds, you name it, have the same problem.

--Keith