Scientific Notation precision normalizing
Asked Answered
R

3

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.

Regazzi answered 6/4, 2011 at 20:38 Comment(8)
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.Gantz
@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.Tweeter
@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.Gantz
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.Tweeter
@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.Gantz
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.Tweeter
@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.Gantz
Same question 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.Trochanter
R
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.

Regazzi answered 23/5, 2011 at 13:53 Comment(2)
You may know this by now, but the formatting language allows this: '{:.{}e}'.format(float(text), get_precision(text)-1)Athal
Unfortunately, this only works if the number is >= 1e-04.Ezana
T
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.

Tweeter answered 6/4, 2011 at 20:47 Comment(4)
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: #3019258Regazzi
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.Shiest
@Shiest "The amount of precision you want must be determined by yourself." I never said anything about significant digits, only output precision.Tweeter
You're correct. I got here by a different search and misread the problem.Shiest
R
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.

Regazzi answered 23/5, 2011 at 13:53 Comment(2)
You may know this by now, but the formatting language allows this: '{:.{}e}'.format(float(text), get_precision(text)-1)Athal
Unfortunately, this only works if the number is >= 1e-04.Ezana
L
1

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]))
Lowspirited answered 4/12, 2015 at 21:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.