Scientific Notation precision normalizing

Question:

My goal is simply to convert a string such as “1.2” to scientific notation without adding additional precision. The problem is that I always end up with superfluous 0s at the end of my output.

>>> input = "1.2"
>>> print '{:e}'.format(float(input))
1.200000e+00

I’m trying to figure out how to get just 1.2e+00. I realize I can specify precision in my format statement, but I don’t want to truncate longer strings unnecessarily. I just want to suppress the training 0s.

I’ve tried using Decimal.normalize(), which works in all cases, except where e < 2.

>>> print Decimal("1.2000e+4").normalize()
1.2E+4
>>> print Decimal("1.2000e+1").normalize()
12

So that’s better, except I don’t want 12, I want 1.2e+1. 😛

Any suggestions would be greatly appreciated!

Edit:
To clarify, the input value has already been rounded appropriately to a predetermined length that is now unknown. I’m trying to avoid recalculating the appropriate formatting precision.

Basically, I could have input values of “1.23” and “1234.56”, which should come out as “1.23e+0” and “1.23456e+3”.

I may have to just check how long the input string is and use that to specify a precision manually, but I wanted to check and make sure I just wasn’t missing something that could just prevent the exponential format from arbitrarily adding 0s.

Asked By: Alex Pritchard

||

Answers:

You can specify precision in the format:

print '{:.2e}'.format(float(input))

This will always give 2 decimals of precision. The amount of precision you want must be determined by yourself. If you need any help with that post in the comments.

Answered By: orlp

Just going back through and cleaning up old questions. I ended up solving this by writing a little function to intuit the initial precision of a number and then using it to format the output result.

#used to determine number of precise digits in a string
def get_precision(str_value):
    vals =  str_value.split('.')
    if (vals[0] == '0'):
        return len(vals[1])
    else:
        return len(str_value) -1

# maintain same precision of incoming string on output text
class ExpDecorator(CurrencyDecorator):
    def get_text(self):
        text = self.decoratedCurrency.get_text()
        return ('{:.' + str(get_precision(text)-1) + 'e}').format(float(text))

Not really the most elegant solution, but the task was kind of obnoxious to begin with and it got the job done.

Answered By: Alex Pritchard

It took a bit of tweaking Alex’s solution but I wrote a function that would remove all trailing zeros from any number in python.

def remove_trailing_zeros(value):
  value = str(value)
  if value.find('e') != -1:
      vals = value.split('e')
      e = vals[1]
      return '{:g}'.format(float(vals[0]))+'e'+e
  vals = value.split('.')
  if (vals[0] == '0'):
      i = 0
      while vals[1][i] == '0':
          i += 1
      return '{:.{}e}'.format(float(value), len(vals[1][i:]) - 1)
  else:
      j = len(vals[0]) - 1
      while vals[0][j] == '0':
          j -= 1
      return '{:.{}e}'.format(float(value), len(vals[0][:j]))
Answered By: jimh