>>> num = 4.123456
>>> round(num, 3) # expecting 4.123
4.1230000000000002
I'm expecting 4.123 as a result, Am I wrong?
This is not a mistake. You need to read What Every computer Scientist Should Know About Floating Point Arithmetic:
http://docs.sun.com/source/806-3568/ncg_goldberg.html
Yep, your expectations don't match the design intent of your tools.
Check out this section of the Python tutorial.
Using math.round is actually pretty rare. if you're trying to display a number as a string to a certain precision, you might want something more like
>>> num = 4.123456
>>> print "%.3f" % num
4.123
You might be interested in the documentation on string formatting.
Why do you care? (That's a serious question.)
The answer that you're getting is so close to 4.123 as to make no difference. It can't be exactly 4.123, since there are only finitely many numbers (around 2**64 on a typical machine) that Python can represent exactly, and without going into detail about floating-point representations, it just so happens that 4.123 isn't one of those numbers. By the way, 4.1230000000000002 isn't one of the numbers that can be exactly represented, either; the actual number stored is 4.12300000000000022026824808563105762004852294921875, but Python truncates the decimal representation to 17 significant digits for display purposes. So:
If you're doing mathematics with the result, then the difference between 4.123 and what you're getting is so tiny as to make no real difference. Just don't worry about it.
If you just care about the output looking pretty (i.e., what you're after here is a string rather than a number) then use str, or string formatting.
In the unlikely case that the difference really does matter, e.g., because you're doing financial work and this affects the direction that something rounds later on, use the decimal module.
Final note: In Python 3.x and Python 2.7, the repr of a float has changed so that you will actually get 4.123 as you expect here.
If you want to have an exact representation of your floating point number, you have to use decimal.
Related
When checking if a floor is an int, the recommend method would be is_integer:
However, I get a weird behaviour with the results of the log function:
print(log(9,3)); #2.0
print((log(9,3)).is_integer()); #True
print((log(243,3))); #5.0
print((log(243,3)).is_integer()); #False
Furthermore:
print((int) (log(9,3))); #2
print((int) (log(243,3))); #4
Is this normal?
log(243,3) simply doesn't give you exactly 5:
>>> '%.60f' % log(243,3)
'4.999999999999999111821580299874767661094665527343750000000000'
As the docs say, log(x, base) is "calculated as log(x)/log(base)". And neither log(243) nor log(3) can be represented exactly, and you get rounding errors. Sometimes you're lucky, sometimes you're not. Don't count on it.
When you want to compare float numbers, use math.isclose().
When you want to convert a float number that is close to an integer, use round().
Float numbers are too subject to error for "conventional" methods to be used. Their precision (and the precision of functions like log) is too limited, unfortunately. What looks like a 5 may not be an exact 5.
And yes: it is normal. This is not a problem with Python, but with every language I'm aware of (they all use the same underlying representation). Python offers some ways to work around float problems: decimal and fractions. Both have their own drawbacks, but sometimes they help. For example, with fractions, you can represent 1/3 without loss of precision. Similarly, with decimal, you can represent 0.1 exactly. However, you'll still have problems with log, sqrt, irrational numbers, numbers that require many digits to be represented and so on.
I would need to have a float variable rounded to 2 significant digits and store the result into a new variable (or the same of before, it doesn't matter) but this is what happens:
>>> a
981.32000000000005
>>> b= round(a,2)
>>> b
981.32000000000005
I would need this result, but into a variable that cannot be a string since I need to insert it as a float...
>>> print b
981.32
Actually truncate would also work I don't need extreme precision in this case.
What you are trying to do is in fact impossible. That's because 981.32 is not exactly representable as a binary floating point value. The closest double precision binary floating point value is:
981.3200000000000500222085975110530853271484375
I suspect that this may come as something of a shock to you. If so, then I suggest that you read What Every Computer Scientist Should Know About Floating-Point Arithmetic.
You might choose to tackle your problem in one of the following ways:
Accept that binary floating point numbers cannot represent such values exactly, and continue to use them. Don't do any rounding at all, and keep the full value. When you wish to display the value as text, format it so that only two decimal places are emitted.
Use a data type that can represent your number exactly. That means a decimal rather than binary type. In Python you would use decimal.
Try this :
Round = lambda x, n: eval('"%.' + str(int(n)) + 'f" % ' + repr(x))
print Round(0.1, 2)
0.10
print Round(0.1, 4)
0.1000
print Round(981,32000000000005, 2)
981,32
Just indicate the number of digits you want as a second kwarg
I wrote a solution of this problem.
Plz try
from decimal import *
from autorounddecimal.core import adround,decimal_round_digit
decimal_round_digit(Decimal("981.32000000000005")) #=> Decimal("981.32")
adround(981.32000000000005) # just wrap decimal_round_digit
More detail can be found in https://github.com/niitsuma/autorounddecimal
There is a difference between the way Python prints floats and the way it stores floats. For example:
>>> a = 1.0/5.0
>>> a
0.20000000000000001
>>> print a
0.2
It's not actually possible to store an exact representation of many floats, as David Heffernan points out. It can be done if, looking at the float as a fraction, the denominator is a power of 2 (such as 1/4, 3/8, 5/64). Otherwise, due to the inherent limitations of binary, it has to make do with an approximation.
Python recognizes this, and when you use the print function, it will use the nicer representation seen above. This may make you think that Python is storing the float exactly, when in fact it is not, because it's not possible with the IEEE standard float representation. The difference in calculation is pretty insignificant, though, so for most practical purposes it isn't a problem. If you really really need those significant digits, though, use the decimal package.
I've spent countless hours researching, reading, testing, and ultimately confused and dismayed at Python's Decimal object's lack of the most fundamental concept: Formatting a Decimal's output to a string.
Let's assume we have some strings or Decimal objects with the following values:
0.0008
11.1111
222.2222
3333.3333
1234.5678
The goal is to simply set the Decimal's precision to the second decimal place. Eg, 11.1111 would be formatted as 11.11, and 1234.5678 as 1234.57.
I envision code similar to the following:
import decimal
decimals = [
decimal.Decimal('0.0008'),
decimal.Decimal('11.1111'),
decimal.Decimal('222.2222'),
decimal.Decimal('3333.3333'),
decimal.Decimal('1234.5678'),
]
for dec in decimals:
print dec.as_string(precision=2, rounding=ROUND_HALF_UP)
The resulting output would be:
0.00
11.11
222.22
3333.33
1234.57
Obviously we cannot make use of the Decimal's context's precision, because this takes into consideration the TOTAL number of digits, not just decimal precision.
I'm also not interested in converting the Decimal to a float to output its value. The ENTIRE reason behind Decimal is to avoid storing and running calculations on floats.
What other solutions are there? I understand there are many other similar questions on stack overflow, but none of them have I found to resolve the underlying issue I am inquiring of.
Thanks much!
Just use string formatting or the format() function:
>>> for dec in decimals:
... print format(dec, '7.2f')
...
0.00
11.11
222.22
3333.33
1234.57
decimal.Decimal supports the same format specifications as floats do, so you can use exponent, fixed point, general, number or percentage formatting as needed.
This is the official and pythonic method of formatting decimals; the Decimal class implements the .__format__() method to handle such formatting efficiently.
def d(_in, decimal_places = 3):
''' Convert number to Decimal and do rounding, for doing calculations
Examples:
46.18271 to 46.183 rounded up
46.18749 to 46.187 rounded down
117.34999999999999 to 117.350
_rescale is a private function, bad practice yet works for now.
'''
return Decimal(_in)._rescale(-decimal_places, 'ROUND_HALF_EVEN')
Edit: Again, _rescale() is not meant to be used by us regular bipeds, it works in Python 2.7, is not available in 3.4.
I am depending on some code that uses the Decimal class because it needs precision to a certain number of decimal places. Some of the functions allow inputs to be floats because of the way that it interfaces with other parts of the codebase. To convert them to decimal objects, it uses things like
mydec = decimal.Decimal(str(x))
where x is the float taken as input. My question is, does anyone know what the standard is for the 'str' method as applied to floats?
For example, take the number 2.1234512. It is stored internally as 2.12345119999999999 because of how floats are represented.
>>> x = 2.12345119999999999
>>> x
2.1234511999999999
>>> str(x)
'2.1234512'
Ok, str(x) in this case is doing something like '%.6f' % x. This is a problem with the way my code converts to decimals. Take the following:
>>> d = decimal.Decimal('2.12345119999999999')
>>> ds = decimal.Decimal(str(2.12345119999999999))
>>> d - ds
Decimal('-1E-17')
So if I have the float, 2.12345119999999999, and I want to pass it to Decimal, converting it to a string using str() gets me the wrong answer. I need to know what are the rules for str(x) that determine what the formatting will be, because I need to determine whether this code needs to be re-written to avoid this error (note that it might be OK, because, for example, the code might round to the 10th decimal place once we have a decimal object)
There must be some set of rules in python's docs that hopefully someone here can point me to. Thanks!
In the Python source, look in "Include/floatobject.h". The precision for the string conversion is set a few lines from the top after an comment with some explanation of the choice:
/* The str() precision PyFloat_STR_PRECISION is chosen so that in most cases,
the rounding noise created by various operations is suppressed, while
giving plenty of precision for practical use. */
#define PyFloat_STR_PRECISION 12
You have the option of rebuilding, if you need something different. Any changes will change formatting of floats and complex numbers. See ./Objects/complexobject.c and ./Objects/floatobject.c. Also, you can compare the difference between how repr and str convert doubles in these two files.
There's a couple of issues worth discussing here, but the summary is: you cannot extract information that is not stored on your system already.
If you've taken a decimal number and stored it as a floating point, you'll have lost information, since most decimal (base 10) numbers with a finite number of digits cannot be stored using a finite number of digits in base 2 (binary).
As was mentioned, str(a_float) will really call a_float.__str__(). As the documentation states, the purpose of that method is to
return a string containing a nicely printable representation of an object
There's no particular definition for the float case. My opinion is that, for your purposes, you should consider __str__'s behavior to be undefined, since there's no official documentation on it - the current implementation can change anytime.
If you don't have the original strings, there's no way to extract the missing digits of the decimal representation from the float objects. All you can do is round predictably, using string formatting (which you mention):
Decimal( "{0:.5f}".format(a_float) )
You can also remove 0s on the right with resulting_string.rstrip("0").
Again, this method does not recover the information that has been lost.
Here is an example:
>>> "%.2f" % 0.355
'0.35'
>>> "%.2f" % (float('0.00355') *100)
'0.36'
Why they give different result?
This isn't a format bug. This is just floating point arithmetic. Look at the values underlaying your format commands:
In [18]: float('0.00355')
Out[18]: 0.0035500000000000002
In [19]: float('0.00355')*100
Out[19]: 0.35500000000000004
In [20]: 0.355
Out[20]: 0.35499999999999998
The two expressions create different values.
I don't know if it's available in 2.4 but you can use the decimal module to make this work:
>>> import decimal
>>> "%.2f" % (decimal.Decimal('0.00355')*100)
'0.35'
The decimal module treats floats as strings to keep arbitrary precision.
Because, as with all floating point "inaccuracy" questions, not every real number can be represented in a limited number of bits.
Even if we were to go nuts and have 65536-bit floating point formats, the number of numbers between 0 and 1 is still, ... well, infinite :-)
What's almost certainly happening is that the first one is slightly below 0.355 (say, 0.3549999999999) while the second is slightly above (say, 0.3550000001).
See here for some further reading on the subject.
A good tool to play with to see how floating point numbers work is Harald Schmidt's excellent on-line converter. This was so handy, I actually implemented my own C# one as well, capable of handling both IEEE754 single and double precision.
Arithmetic with floating point numbers is often inaccurate.
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems