python2.4.3: format bug? - python

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

Related

What is the meaning of this following piece of code({:.3f}) used in a Decision Tree tutorial? [duplicate]

I don't understand why, by formatting a string containing a float value, the precision of this last one is not respected. Ie:
'%f' % 38.2551994324
returns:
'38.255199'
(4 signs lost!)
At the moment I solved specifying:
'%.10f' % 38.2551994324
which returns '38.2551994324' as expected… but should I really force manually how many decimal numbers I want? Is there a way to simply tell to python to keep all of them?! (what should I do for example if I don't know how many decimals my number has?)
but should I really force manually how many decimal numbers I want? Yes.
And even with specifying 10 decimal digits, you are still not printing all of them. Floating point numbers don't have that kind of precision anyway, they are mostly approximations of decimal numbers (they are really binary fractions added up). Try this:
>>> format(38.2551994324, '.32f')
'38.25519943239999776096738060005009'
there are many more decimals there that you didn't even specify.
When formatting a floating point number (be it with '%f' % number, '{:f}'.format(number) or format(number, 'f')), a default number of decimal places is displayed. This is no different from when using str() (or '%s' % number, '{}'.format(number) or format(number), which essentially use str() under the hood), only the number of decimals included by default differs; Python versions prior to 3.2 use 12 digits for the whole number when using str().
If you expect your rational number calculations to work with a specific, precise number of digits, then don't use floating point numbers. Use the decimal.Decimal type instead:
Decimal “is based on a floating-point model which was designed with people in mind, and necessarily has a paramount guiding principle – computers must provide an arithmetic that works in the same way as the arithmetic that people learn at school.” – excerpt from the decimal arithmetic specification.
Decimal numbers can be represented exactly. In contrast, numbers like 1.1 and 2.2 do not have exact representations in binary floating point. End users typically would not expect 1.1 + 2.2 to display as 3.3000000000000003 as it does with binary floating point.
I would use the modern str.format() method:
>>> '{}'.format(38.2551994324)
'38.2551994324'
The modulo method for string formatting is now deprecated as per PEP-3101

Weird behaviour for Python is_integer from floor

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.

Python - round a float to 2 digits

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.

subtracting integer python weird results

basically what I'm doing is downloading some date from a website using urllib. That number comes to be in what I believe is Byte form. So I change it to an integer by doing the following. This seems to work fine.
real_value = (int(real_value) / 100)
Then I create another variable which should equal the difference between two values.
add_to_value = real_value - last_real_value
print(add_to_value)
The weird thing is, this sometimes works and other times I get results with a lot of extra digits on the end or it will say "9.999999999999996e-05".
So I'm really confused. Any ideas?
Floating-point numbers can't represent most numbers exactly. Even with a very simple example:
>>> 0.1 + 0.1
0.20000000000000001
You can see it's not exact. If you use floating-point numbers, this is just something you'll have to deal with. Alternatively, you can use Python's decimal module:
>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.1')
Decimal('0.2')
Even decimal can't represent every number exactly, but it should give you much more reasonable results when dealing with lots of base-10 operations.
read up on issues with floating points in python
assuming you are yousing python3: you may want to use a double / for classic python2's 'integer division' behaviour where the result gets rounded.
real_value = (int(real_value) // 100)
The weired values are normal and should be correct.
This is because you are using floating point arithmetic. You can always limit the precision of the results, by, e.g., setting the number of digits that are used for the representation.
Refer to: http://en.wikipedia.org/wiki/Floating_point

Python rounding problem

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

Categories

Resources