24

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

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.

Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
Alex Pritchard
  • 4,260
  • 5
  • 33
  • 48
  • How do you know what the "right" number of digits is? Please update the question with the rule for knowing this. Be sure to cover the 3.33333333 case. – S.Lott Apr 06 '11 at 20:42
  • @S.Lott: In science we use "significance". So if I have input value of 10 meters I can not give an answer of 3.3333 meters. That's an increase of significance which is illegal. 3.3m would be the correct answer. – orlp Apr 06 '11 at 20:55
  • @nightcracker. But my 3.33333 m/s wasn't an increase in precision. It was 1.0m/3.0s. Both with precisions of just 1 decimal point. – S.Lott Apr 06 '11 at 20:57
  • 5
    It is. First you measure a wooden stick with a measuring stick only capable of measuring up to one tenths of a meter precise. You measure 1.0m. And with some stopwatch you measure 3.0s. You do some physics and come to a result of 1.0/3.0. Now the result MUST be 0.33 m/s. Why? Because it's bullshit to say that you know the difference between 0.33 and 0.333 m/s (0.003 m/s) while you only measured in tenths of seconds and meters. – orlp Apr 06 '11 at 21:20
  • @nightcracker: My software said 0.33333333. The question is how to format this number in some desirable way. You have a rule. I don't know how to get your rule to match this question. – S.Lott Apr 06 '11 at 21:27
  • I don't have a rule. This is the common rule in all of physics. I see "rounded" and "scientific notation" in the question, so this is the first that comes to my mind. – orlp Apr 06 '11 at 21:28
  • @Alex Pritchard: "predetermined length that is now unknown. I'm trying to avoid recalculating the appropriate formatting precision"? How can you avoid recalculating the missing data? I'm unclear on the question. – S.Lott Apr 07 '11 at 11:02
  • [Same question](https://stackoverflow.com/q/703396/119775) but in Java. It's surprising that languages don't have this as a built-in formatting option, given how this is a recurring issue everywhere, apparently. – Jean-François Corbett Nov 22 '17 at 09:04

3 Answers3

40

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.

orlp
  • 112,504
  • 36
  • 218
  • 315
  • 2
    The problem is just that I may not know in the method what precision to expect. Considering using methods here to identify precision and adjust accordingly: http://stackoverflow.com/questions/3018758/determine-precision-and-scale-of-particular-number-in-python – Alex Pritchard Apr 07 '11 at 00:36
  • Using `.2` doesn't work for scientific significant digits: `5.7 * 6.4 = 36.48` but since the inputs both have two digits of significance, the correct output (with two digits of significance) is `36`. – Harvey Aug 08 '22 at 12:57
  • 1
    @Harvey _"The amount of precision you want must be determined by yourself."_ I never said anything about significant digits, only output precision. – orlp Aug 08 '22 at 14:34
  • You're correct. I got here by a different search and misread the problem. – Harvey Aug 09 '22 at 00:25
9

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.

Alex Pritchard
  • 4,260
  • 5
  • 33
  • 48
0

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]))
jimh
  • 1,651
  • 2
  • 15
  • 28