Display floating point number in decimal form in Python? - python

Let's say I have the following float point number in Python
>>>a = 10 ** -10
>>>print a
1e-10
How can I display .0000000001 instead of 1e-10?

>>> a = "%0.10f" % (10 ** -10)
>>> a
'0.0000000001'

Maybe a bit more readable:
a = float("1e-10")
format(a, ".10f")
Output
'0.0000000001'

Or using format
>>> a = 10 ** -10
>>> '{a:0.10f}'.format(a=a)

Related

How to display a very accurate number?

I want to output two numbers that differ very slightly from each other.
1.0000000000
1.0000000001
I don't want a long line. Rounding or scientific notation doesn't help me.
>>> round(1.0000000000, 6)
1.0
>>> round(1.0000000001, 6)
1.0
>>> f"{1.0000000001:e}"
'1.000000e+00'
>>> f"{1.0000000000:e}"
'1.000000e+00'
I like the solution in matplotlib. There, the number is presented as the sum of the major part and fractional. So the numbers presented above will look like this:
1 + 0 * 1e-10,
1 + 1 * 1e-10
I can implement this myself, but suddenly you know any libraries or standard tools for this.
Do you know the existing tools for this?
Maybe library decimal is useful. For example:
>>> from decimal import Decimal
>>> a = Decimal(1.0000000000)
>>> b = Decimal(1.0000000001)
>>>
>>> a
Decimal('1')
>>> b
Decimal('1.0000000001000000082740370999090373516082763671875')
>>>
>>> a == b
False
I never got an answer.
So far I tried to implement the functionality of matplotib.
True, the code is crude, but I'll save it here, suddenly it will be useful to someone.
Pass the list of objects to Decimal!!!
def prepare_display(numbers, accuracy):
from decimal import Decimal
ACCURACY = 3
numbers_sorted = sorted(numbers)
diffs = []
for i in range(1, len(numbers)):
diffs.append(numbers_sorted[i] - numbers_sorted[i - 1])
if min(diffs) > 1 * 10 ** (-ACCURACY):
return '', numbers
total_part = min(numbers)
differents = []
exps = []
for number in numbers:
diff = number - total_part
differents.append(diff)
exps.append(fexp(diff))
min_exp = min(exps)
different_parts = []
for diff in differents:
different_parts.append(round(diff / Decimal(10 ** min_exp)))
total_part = Decimal(total_part)
return str(round(total_part, - min_exp - 1)) + ' + x * 1e' \
str(min_exp),
different_parts
def fexp(number):
"""Returns the exponent of a decimal number"""
from decimal import Decimal
(sign, digits, exponent) = Decimal(number).as_tuple()
return len(digits) + exponent - 1
Then for the following cases there will be a corresponding result.
For numbers less than one
>>>> numbers = [Decimal('0.999990'), Decimal('0.999992')]
>>>> total_part, different_parts = prepare_display(numbers)
>>>> print(total_part)
>>>> print(different_parts)
0.99999 + x * 1e-6
[0, 2]
If no conversion is needed
>>>> numbers = [1, 2]
>>>> total_part, different_parts = prepare_display(numbers, 3)
>>>> print(total_part)
>>>> print(different_parts)
[1, 2]
The code is very crude

Fix float precision with decimal numbers

a = 1
for x in range(5):
a += 0.1
print(a)
This is the result:
1.1
1.2000000000000002
1.3000000000000003
1.4000000000000004
1.5000000000000004
How can I fix this? Is the round() function the only way? Can I set the precision of a variable before setting its value?
can i set the precision of a variable before setting the value?
Use the decimal module which, unlike float(), offers arbitrary precision and can represent decimal numbers exactly:
>>> from decimal import Decimal, getcontext
>>>
>>> getcontext().prec = 5
>>>
>>> a = Decimal(1)
>>>
>>> for x in range(5):
... a += Decimal(0.1)
... print(a)
...
1.1000
1.2000
1.3000
1.4000
1.5000
You could format your output like this;
a=1
for x in range(5):
a += 0.1
print("{:.9f}".format(a) )
Assuming that your problem is only displaying the number, #Jaco 's answer does the job. However if you're concern about using that variable and potentially make comparisons or assigning to dictionary keys, I'd say you have to stick to round(). For example this wouldn't work:
a = 1
for x in range(5):
a += 0.1
print('%.1f' % a)
if a == 1.3:
break
1.1
1.2
1.3
1.4
1.5
You'd have to do:
a = 1
for x in range(5):
a += 0.1
print('%.1f' % a)
if round(a, 1) == 1.3:
break
1.1
1.2
1.3
Formatted output has been duly suggested by #Jaco. However, if you want control of precision in your variable beyond pure output, you might want to look at the decimal module.
from decimal import Decimal
a = 1
for x in range(3):
a += Decimal('0.10') # use string, not float as argument
# a += Decimal('0.1000')
print(a) # a is now a Decimal, not a float
> 1.10 # 1.1000
> 1.20 # 1.2000
> 1.30 # 1.3000

Python setting Decimal Place range without rounding?

How can I take a float variable, and control how far out the float goes without round()? For example.
w = float(1.678)
I want to take x and make the following variables out of it.
x = 1.67
y = 1.6
z = 1
If I use the respective round methods:
x = round(w, 2) # With round I get 1.68
y = round(y, 1) # With round I get 1.7
z = round(z, 0) # With round I get 2.0
It's going to round and alter the numbers to the point where there no use to me. I understand this is the point of round and its working properly. How would I go about getting the information that I need in the x,y,z variables and still be able to use them in other equations in a float format?
You can do:
def truncate(f, n):
return math.floor(f * 10 ** n) / 10 ** n
testing:
>>> f=1.923328437452
>>> [truncate(f, n) for n in range(7)]
[1.0, 1.9, 1.92, 1.923, 1.9233, 1.92332, 1.923328]
A super simple solution is to use strings
x = float (str (w)[:-1])
y = float (str (w)[:-2])
z = float (str (w)[:-3])
Any of the floating point library solutions would require you dodge some rounding, and using floor/powers of 10 to pick out the decimals can get a little hairy by comparison to the above.
Integers are faster to manipulate than floats/doubles which are faster than strings. In this case, I tried to get time with both approach :
timeit.timeit(stmt = "float(str(math.pi)[:12])", setup = "import math", number = 1000000)
~1.1929605630000424
for :
timeit.timeit(stmt = "math.floor(math.pi * 10 ** 10) / 10 ** 10", setup = "import math", number = 1000000)
~0.3455968870000561
So it's safe to use math.floor rather than string operation on it.
If you just need to control the precision in format
pi = 3.14159265
format(pi, '.3f') #print 3.142 # 3 precision after the decimal point
format(pi, '.1f') #print 3.1
format(pi, '.10f') #print 3.1415926500, more precision than the original
If you need to control the precision in floating point arithmetic
import decimal
decimal.getcontext().prec=4 #4 precision in total
pi = decimal.Decimal(3.14159265)
pi**2 #print Decimal('9.870') whereas '3.142 squared' would be off
--edit--
Without "rounding", thus truncating the number
import decimal
from decimal import ROUND_DOWN
decimal.getcontext().prec=4
pi*1 #print Decimal('3.142')
decimal.getcontext().rounding = ROUND_DOWN
pi*1 #print Decimal('3.141')
I think the easiest answer is :
from math import trunc
w = 1.678
x = trunc(w * 100) / 100
y = trunc(w * 10) / 10
z = trunc(w)
also this:
>>> f = 1.678
>>> n = 2
>>> int(f * 10 ** n) / 10 ** n
1.67
Easiest way to get integer:
series_col.round(2).apply(lambda x: float(str(x).split(".",1)[0]))

drop trailing zeros from decimal

I have a long list of Decimals and that I have to adjust by factors of 10, 100, 1000,..... 1000000 depending on certain conditions. When I multiply them there is sometimes a useless trailing zero (though not always) that I want to get rid of. For example...
from decimal import Decimal
# outputs 25.0, PROBLEM! I would like it to output 25
print Decimal('2.5') * 10
# outputs 2567.8000, PROBLEM! I would like it to output 2567.8
print Decimal('2.5678') * 1000
Is there a function that tells the decimal object to drop these insignificant zeros? The only way I can think of doing this is to convert to a string and replace them using regular expressions.
Should probably mention that I am using python 2.6.5
EDIT
senderle's fine answer made me realize that I occasionally get a number like 250.0 which when normalized produces 2.5E+2. I guess in these cases I could try to sort them out and convert to a int
You can use the normalize method to remove extra precision.
>>> print decimal.Decimal('5.500')
5.500
>>> print decimal.Decimal('5.500').normalize()
5.5
To avoid stripping zeros to the left of the decimal point, you could do this:
def normalize_fraction(d):
normalized = d.normalize()
sign, digits, exponent = normalized.as_tuple()
if exponent > 0:
return decimal.Decimal((sign, digits + (0,) * exponent, 0))
else:
return normalized
Or more compactly, using quantize as suggested by user7116:
def normalize_fraction(d):
normalized = d.normalize()
sign, digit, exponent = normalized.as_tuple()
return normalized if exponent <= 0 else normalized.quantize(1)
You could also use to_integral() as shown here but I think using as_tuple this way is more self-documenting.
I tested these both against a few cases; please leave a comment if you find something that doesn't work.
>>> normalize_fraction(decimal.Decimal('55.5'))
Decimal('55.5')
>>> normalize_fraction(decimal.Decimal('55.500'))
Decimal('55.5')
>>> normalize_fraction(decimal.Decimal('55500'))
Decimal('55500')
>>> normalize_fraction(decimal.Decimal('555E2'))
Decimal('55500')
There's probably a better way of doing this, but you could use .rstrip('0').rstrip('.') to achieve the result that you want.
Using your numbers as an example:
>>> s = str(Decimal('2.5') * 10)
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
25
>>> s = str(Decimal('2.5678') * 1000)
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
2567.8
And here's the fix for the problem that #gerrit pointed out in the comments:
>>> s = str(Decimal('1500'))
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
1500
Answer from the Decimal FAQ in the documentation:
>>> def remove_exponent(d):
... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5.00'))
Decimal('5')
>>> remove_exponent(Decimal('5.500'))
Decimal('5.5')
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
Answer is mentioned in FAQ (https://docs.python.org/2/library/decimal.html#decimal-faq) but does not explain things.
To drop trailing zeros for fraction part you should use normalize:
>>> Decimal('100.2000').normalize()
Decimal('100.2')
>> Decimal('0.2000').normalize()
Decimal('0.2')
But this works different for numbers with leading zeros in sharp part:
>>> Decimal('100.0000').normalize()
Decimal('1E+2')
In this case we should use `to_integral':
>>> Decimal('100.000').to_integral()
Decimal('100')
So we could check if there's a fraction part:
>>> Decimal('100.2000') == Decimal('100.2000').to_integral()
False
>>> Decimal('100.0000') == Decimal('100.0000').to_integral()
True
And use appropriate method then:
def remove_exponent(num):
return num.to_integral() if num == num.to_integral() else num.normalize()
Try it:
>>> remove_exponent(Decimal('100.2000'))
Decimal('100.2')
>>> remove_exponent(Decimal('100.0000'))
Decimal('100')
>>> remove_exponent(Decimal('0.2000'))
Decimal('0.2')
Now we're done.
Use the format specifier %g. It seems remove to trailing zeros.
>>> "%g" % (Decimal('2.5') * 10)
'25'
>>> "%g" % (Decimal('2.5678') * 1000)
'2567.8'
It also works without the Decimal function
>>> "%g" % (2.5 * 10)
'25'
>>> "%g" % (2.5678 * 1000)
'2567.8'
I ended up doing this:
import decimal
def dropzeros(number):
mynum = decimal.Decimal(number).normalize()
# e.g 22000 --> Decimal('2.2E+4')
return mynum.__trunc__() if not mynum % 1 else float(mynum)
print dropzeros(22000.000)
22000
print dropzeros(2567.8000)
2567.8
note: casting the return value as a string will limit you to 12 significant digits
Slightly modified version of A-IV's answer
NOTE that Decimal('0.99999999999999999999999999995').normalize() will round to Decimal('1')
def trailing(s: str, char="0"):
return len(s) - len(s.rstrip(char))
def decimal_to_str(value: decimal.Decimal):
"""Convert decimal to str
* Uses exponential notation when there are more than 4 trailing zeros
* Handles decimal.InvalidOperation
"""
# to_integral_value() removes decimals
if value == value.to_integral_value():
try:
value = value.quantize(decimal.Decimal(1))
except decimal.InvalidOperation:
pass
uncast = str(value)
# use exponential notation if there are more that 4 zeros
return str(value.normalize()) if trailing(uncast) > 4 else uncast
else:
# normalize values with decimal places
return str(value.normalize())
# or str(value).rstrip('0') if rounding edgecases are a concern
You could use :g to achieve this:
'{:g}'.format(3.140)
gives
'3.14'
This should work:
'{:f}'.format(decimal.Decimal('2.5') * 10).rstrip('0').rstrip('.')
Just to show a different possibility, I used to_tuple() to achieve the same result.
def my_normalize(dec):
"""
>>> my_normalize(Decimal("12.500"))
Decimal('12.5')
>>> my_normalize(Decimal("-0.12500"))
Decimal('-0.125')
>>> my_normalize(Decimal("0.125"))
Decimal('0.125')
>>> my_normalize(Decimal("0.00125"))
Decimal('0.00125')
>>> my_normalize(Decimal("125.00"))
Decimal('125')
>>> my_normalize(Decimal("12500"))
Decimal('12500')
>>> my_normalize(Decimal("0.000"))
Decimal('0')
"""
if dec is None:
return None
sign, digs, exp = dec.as_tuple()
for i in list(reversed(digs)):
if exp >= 0 or i != 0:
break
exp += 1
digs = digs[:-1]
if not digs and exp < 0:
exp = 0
return Decimal((sign, digs, exp))
Why not use modules 10 from a multiple of 10 to check if there is remainder? No remainder means you can force int()
if (x * 10) % 10 == 0:
x = int(x)
x = 2/1
Output: 2
x = 3/2
Output: 1.5

How Can I limit bit number in the integer variable in Python?

I want to realize IDEA algorithm in Python. In Python we have no limits for variable size, but I need limit bit number in the integer number, for example, to do cyclic left shift. What do you advise?
One way is to use the BitVector library.
Example of use:
>>> from BitVector import BitVector
>>> bv = BitVector(intVal = 0x13A5, size = 32)
>>> print bv
00000000000000000001001110100101
>>> bv << 6 #does a cyclic left shift
>>> print bv
00000000000001001110100101000000
>>> bv[0] = 1
>>> print bv
10000000000001001110100101000000
>>> bv << 3 #cyclic shift again, should be more apparent
>>> print bv
00000000001001110100101000000100
An 8-bit mask with a cyclic left shift:
shifted = number << 1
overflowed = (number & 0x100) >> 8
shifted &= 0xFF
result = overflowed | shifted
You should be able to make a class that does this for you. With a bit more of the same, it can shift an arbitrary amount out of an arbitrary sized value.
The bitstring module might be of help (documentation here). This example creates a 22 bit bitstring and rotates the bits 3 to the right:
>>> from bitstring import BitArray
>>> a = BitArray(22) # creates 22-bit zeroed bitstring
>>> a.uint = 12345 # set the bits with an unsigned integer
>>> a.bin # view the binary representation
'0b0000000011000000111001'
>>> a.ror(3) # rotate to the right
>>> a.bin
'0b0010000000011000000111'
>>> a.uint # and back to the integer representation
525831
If you want a the low 32 bits of a number, you can use binary-and like so:
>>> low32 = (1 << 32) - 1
>>> n = 0x12345678
>>> m = ((n << 20) | (n >> 12)) & low32
>>> "0x%x" % m
'0x67812345'

Categories