I want to get desired number of digits after decimal point while keeping answer in scientific format (e.g. 2.989e+10). I know the method format: "{:0.Ae}".format(given_number) where A is number of digits after decimal. However, I'm getting number of digits after the decimal (A) through a variable.
Can someone please help me how can I implement it to get the desired result?
My code: Consider A as number of digits after decimal point.
for val in [1.049666666666667e-08, 4.248944444444444e+05]:
val_log = math.log10(val);
val_e = round(val_log - (0.5 if val_log<0 else 0));
A = abs(val_e +3);
valstr = "{:0.Ae}".format(val)
print(valstr)
It is basically number of digits after decimal point(A) = |3 + the value after e|. How should I use value of A in {:0.xe}.format(val) ?
You can nest a variable in the precision field, as the documentation of formatted string literals points out in an example with the comment "nested fields".
Below is a more simplified example that limits the precision to 3 digits (or 2 digits after the decimal point):
>>> f = 123.12345
>>> n = 3
>>> print(f'{f:.{n}}')
1.23e+02
>>>
Related
I'm really curious about why the behaviour is so different when add this "f" to the end of the number which I want to display:
# CASE with f
float1 = 10.1444786
print(f"{float1:.4f}")
# print out: 10.1445
# CASE without f
print(f"{float1:.4}")
# print out: 10.14
Why only 2 characters are displayed in the second example?
The implied type specifier is g, as given in the documentation Thanks #Barmar for adding a comment with this info!
None: For float this is the same as 'g', except that when fixed-point notation is used to format the result, it always includes at least one digit past the decimal point. The precision used is as large as needed to represent the given value faithfully.
For Decimal, this is the same as either 'g' or 'G' depending on the value of context.capitals for the current decimal context.
The overall effect is to match the output of str() as altered by the other format modifiers.
An experiment:
for _ in range(10000):
r = random.random() * random.randint(1, 10)
assert f"{r:.6}" == f"{r:.6g}"
Works every time
From https://docs.python.org/3/library/string.html#formatstrings,
General format. For a given precision p >= 1, this rounds the number to p significant digits and then formats the result in either fixed-point format or in scientific notation, depending on its magnitude. A precision of 0 is treated as equivalent to a precision of 1.
So in your second example, you ask for 4 sigfigs, but in your first you ask for 4 digits of precision.
Assume I have a float:
x = 0.0005953829144211724
I have to round it after the decimal to:
x = 0.00059
Similarly, if
x = 0.00000046605219739046376
then the result should be
x = 0.00000046
Is there any inbuild function in python to do this?
You can use a nested format with Decimal. The first format does the rounding using the "g" specifier. The second one prints all the digits, without scientific notation, using the decimal value of the rounded string:
from decimal import Decimal
x = 0.0005953829144211724
print(f"{Decimal(f'{x:.2g}'):f}") # 0.0006
print(f"{Decimal(f'{x:.3g}'):f}") # 0.000595
print(f"{Decimal(f'{x:.4g}'):f}") # 0.0005954
x = 0.00000046605219739046376
print(f"{Decimal(f'{x:.2g}'):f}") # 0.00000047
print(f"{Decimal(f'{x:.3g}'):f}") # 0.000000466
print(f"{Decimal(f'{x:.4g}'):f}") # 0.0000004661
Note that this DOES round the value to the specified precision, contrary to your examples which truncate the mantissa instead of rounding it
As shown in the other answer, if you want a certain number of significant digits, you should format the number in scientific notation. If, however, you want those significant digits in the "normal" format, you might either convert that scientific notation back to float (thus "forgetting" all the "insignificant" digits) and then back to string and rstrip all excess zeros, or maybe use a regular expression:
>>> x = 0.00000046605219739046376
>>> f'{float(f"{x:.2g}"):.20f}'.rstrip("0")
'0.00000047'
>>> re.match(r"0\.0*[^0]{2}", f"{x:.20f}").group()
'0.00000046'
Note: i) The .20f here means "print in normal decimal format with 20 places after the decimal", where the 20 is kind of arbitrary. ii) The regex will not round but just trim the number.
You can do something close with the g specifier in an f-string:
x = 0.00000046605219739046376
print(f'{x:.2g}')
This will print the result in "scientific notation"
4.7e-07
Similarly:
x = 0.0005953829144211724
print(f'{x:.2g}')
results in
0.0006
since it rounds up.
I found this which covers how to suppress scientific notation, but I'd like to go a step further and also work out the formatting string (i.e. the number of required decimal points to represent a number).
My idea so far is to assume a very high resolution (20 in this example) and reduce trailing zeroes as suggested in the accepted answer here. Is there perhaps a better way to achieve this?
>>> f = 0.00000008
>>> s = '{:.20f}'.format(f)
>>> s
'0.00000008000000000000'
>>> s.rstrip('0')
'0.00000008'
Note, I don't want scientific notation either (which you would get with a formatting string of {:g}).
The max number of significant digits in a float is 15 (the power is separate from this). So there's no point in accounting for more digits past that, as they wouldn't be right. Knowing what the power of ten for a given number will tell you how many zeros to pad out in the front.
If what you're formatting will never get above one, then the following will suffice:
from math import log10
def floatformat(f):
pwr = log10(f)
return '{:.0{}f}'.format(f, int(abs(pwr)) + 15).rstrip('0')
But if you're parsing any possible float value, you'll have to handle large numbers a bit differently to get trailing zeros and not random inaccurate digits.
def floatformat(f):
sigs = 15 # number of accurate digits that a float can contain
pwr = log10(f)
if pwr > sigs: # power above accurate digits
s = '{:.{}f}'.format(f / 10 ** int(pwr), sigs)
s = s.replace('.', '') # remove decimal point, no longer necessary here
s = s + '0' * (int(pwr) - sigs) # add in trailing zeros
elif 0 < pwr <= sigs: # power within accurate digits
s = '{:.{}f}'.format(f, sigs - int(pwr)).rstrip('0')
else: # power below accurate digits
s = '{:.0{}f}'.format(f, int(abs(pwr)) + sigs).rstrip('0')
if s[-1] == '.': s = s[:-1] # remove trailing decimal point if needed
return s
All this is doing is keeping the accurate digits, then shuffling them around to have the correct power without the scientific notation.
Examples:
>>> floatformat(0.00000008)
'0.00000008'
>>> floatformat(0.0000000000000000000000000000008)
'0.0000000000000000000000000000008'
>>> floatformat(0.00000000000000000000000000000080067)
'0.00000000000000000000000000000080067'
>>> floatformat(2.31451103e7)
'23145110.3'
>>> floatformat(2.31451103e3)
'2314.51103'
>>> 935.16087e203 == float(floatformat(935.16087e203)) # conversion check to see if power is handled correctly
True
>>> import sys
>>> floatformat(sys.float_info.max)
'179769313486231600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
>>> floatformat(sys.float_info.min)
'0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072'
I can't quite understand what the difference is between the two print statements below for the number I am trying to express in scientific notation. I thought the the bottom one is supposed to allow 2 spaces for the printed result, and move the decimal place 4 times, but the result I get does not corroborate that understanding. As far as the first one, What does 4e mean?
>>> print('{:.4e}'.format(3454356.7))
3.4544e+06
>>> print('{:2.4}'.format(3454356.7))
3.454e+06
All help greatly appreciated.
In the first example , 4e means, 4 decimal places in scientific notation. You can come to know that by doing
>>> print('{:.4e}'.format(3454356.7))
3.4544e+06
>>> print('{:.5e}'.format(3454356.7))
3.45436e+06
>>> print('{:.6e}'.format(3454356.7))
3.454357e+06
In the second example, .4 , means 4 significant figures. And 2 means to fit the whole data into 2 characters
>>> print('{:2.4}'.format(3454356.7))
3.454e+06
>>> print('{:2.5}'.format(3454356.7))
3.4544e+06
>>> print('{:2.6}'.format(3454356.7))
3.45436e+06
Testing with different value of 2
>>> print('-{:20.6}'.format(3454356.7))
- 3.45436e+06
You can learn more from the python documentation on format
If you want to produce a float, you will have to specify the float type:
>>> '{:2.4f}'.format(3454356.7)
'3454356.7000'
Otherwise, if you don’t specify a type, Python will choose g as the type for which precision will mean the precision based on its significant figures, the digits before and after the decimal point. And since you have a precision of 4, it will only display 4 digits, falling back to scientific notation so it doesn’t add false precision.
The precision is a decimal number indicating how many digits should be displayed after the decimal point for a floating point value formatted with 'f' and 'F', or before and after the decimal point for a floating point value formatted with 'g' or 'G'. For non-number types the field indicates the maximum field size - in other words, how many characters will be used from the field content. The precision is not allowed for integer values.
(source, emphasis mine)
Finally, note that the width (the 2 in above format string) includes the full width, including digits before the decimal point, digits after it, the decimal point itself, and the components of the scientific notation. The above result would have a width of 12, so in this case, the width of the format string is simply ignored.
I have a normal float number such as "1234.567" or "100000". I would like to convert it to a string such that the precision is fixed and the number is in scientific notation. For example, with 5 digits, the results would be "1.2346e003 and "1.0000e005", respectively. The builtin Decimal number -> string functions will round it if it can, so the second number would be only "1e005" even when I want more digits. This is undesirable since I need all numbers to be the same length.
Is there a "pythonic" way to do this without resorting to complicated string operations?
precision = 2
number_to_convert = 10000
print "%0.*e"%(precision,number_to_convert)
is that what you are asking for?
You can use the %e string formatter:
>>> '%1.5e'%1234.567
'1.23457e+03'
>>> "%1.5e"%100000
'1.00000e+05'
%x.ye where x = min characters and y = max precision.
If you need to keep the 3-digit exponent like in your example, you can define your own function. Here's an example adapted from this answer:
def eformat(f, prec, exp_digits):
s = "%.*e"%(prec, f)
mantissa, exp = s.split('e')
return "%se%0*d"%(mantissa, exp_digits, int(exp))
>>> print eformat(1234.567, 4, 3)
1.2346e003