Moving the point downwards in a floating point number - python

First off all, thanks for the attention, I'm new to this site ^^ so excuse me if I do something wrong...
I have a huge problem with my Python code... I'm new to programming, and I'm new to Python as well.
I need to take a floating point number and move the point right so it becomes an integer, like taking 60.27 and getting 6027.
The algorithm that I'm using is recursively multiplying num*10 until num%2==0, then getting the int(num).
The problem is, when I multiply (for example) 602.47*10 it returns 6024.700000000001 and it obviously doesn't work :-)
Is there any way to fix it, or any other technique or other way to do this recursively?? I'm allowed to use anything I need, but its got to be recursive: no for or while...
Thanks for the help!! My first language is not english, so I beg your pardon if it's hard to read...

>>> str(60.27).translate(None, '.')
'6027'
Use lstrip('0') to guard against decimals below 1.
From the docs:
S.translate(table [,deletechars]) -> string
Return a copy of the string S, where all characters occurring
in the optional argument deletechars are removed, and the
remaining characters have been mapped through the given
translation table, which must be a string of length 256.

Floating point representations have that issue.
Are you looking to change:
1.2345
12.345
123.45
1234.5
all to 12345?
For floats which have no exact representation (you mention 6024.70), do you expect to get 6024700000000001, since that's the output of the closest thing to 6024.70 which can be stored in float?

You could try something like:
x = 60.27
newx = int(str(x).replace('.',''))
Edit: as a side note, the string .replace and .translate have similar performance for various sized floats
%timeit int(str(4.73285).replace('.',''))
100000 loops, best of 3: 2.65 us per loop
%timeit int(str(4.73285).translate(None, '.'))
100000 loops, best of 3: 3.02 us per loop

It would be more reliable an algorithm to just parse the number as a string and do a string manipulation. Any numerical calculation involving floating-point numbers are bound to inaccuracy, as you've witnessed. There's no going around that.

Since you can't (reliably) use floating point to do what you want, an easy hack is to convert the number to a string then rip out the decimal point:
int(str(num).replace('.',''))
That will work with any number that isn't represented in scientific notation. If your numbers are big (or small) enough that they do end up represented in scientific notation, have a look at this.

Just taking a wild stab in the dark here, but do your numbers represent amounts of money that you're trying to convert between (say) dollars and cents? If so, you need to stop what you are doing and convert everything to cents, and only use "dollar" values when actually presenting things to the user. Using floating point numbers for money values is a very, very bad idea.
If not, ignore me :-)

Related

Convert float to Decimal with fixed digits after decimal

I want to convert some floats to Decimal retaining 5 digits after decimal place regardless of how many digits before the decimal place. Is using string formatting the most efficient way to do this?
I see in the docs:
The significance of a new Decimal is determined solely by the number of digits input. Context precision and rounding only come into play during arithmetic operations.
So that means I need to add 0 to force it to use the specified prec but the prec is total digits not after decimal so it doesn't actually help.
The best thing I can come up with is
a=[1.132434, 22.2334,99.33999434]
[Decimal("%.5f" % round(x,5)) for x in a]
to get [Decimal('1.13243'), Decimal('22.23340'), Decimal('99.33999')]
Is there a better way? It feels like turning floats into strings just to convert them back to a number format isn't very good although I can't articulate why.
Do all the formatting on the way out from your code, inside the print and write statements. There is no reason I can think of to lose precision (and convert the numbers to some fixed format) while doing numeric calculations inside the code.

What should np.arange(-1.6,-0.49,0.01) generate?

In python, why does np.arange(-1.6,-0.49,0.01) generate a list where the last element is -0.49 while np.arange(0,0.49,0.01) generates a list where the last element is 0.48?
Floating point arithmetic doesn't use base 10, so things that look perfectly simple often don't work that way in practice. The exception to this is integers as floating point, because for reasonable numbers the errors are all to the right of the decimal point. You can restructure your range to use integers and you'll get consistent results.
np.arange(-160, -49) * 0.01

How to avoid floating point arithmetics issues?

Python (and almost anything else) has known limitations while working with floating point numbers (nice overview provided here).
While problem is described well in the documentation it avoids providing any approach to fixing it. And with this question I am seeking to find a more or less robust way to avoid situations like the following:
print(math.floor(0.09/0.015)) # >> 6
print(math.floor(0.009/0.0015)) # >> 5
print(99.99-99.973) # >> 0.016999999999825377
print(.99-.973) # >> 0.017000000000000015
var = 0.009
step = 0.0015
print(var < math.floor(var/step)*step+step) # False
print(var < (math.floor(var/step)+1)*step) # True
And unlike suggested in this question, their solution does not help to fix a problem like next peace of code failing randomly:
total_bins = math.ceil((data_max - data_min) / width) # round to upper
new_max = data_min + total_bins * width
assert new_max >= data_max
# fails. because for example 1.9459999999999997 < 1.946
If you deal in discrete quantities, use int.
Sometimes people use float in places where they definitely shouldn't. If you're counting something (like number of cars in the world) as opposed to measuring something (like how much gasoline is used per day), floating-point is probably the wrong choice. Currency is another example where floating point numbers are often abused: if you're storing your bank account balance in a database, it's really not 123.45 dollars, it's 12345 cents. (But also see below about Decimal.)
Most of the rest of the time, use float.
Floating-point numbers are general-purpose. They're extremely accurate; they just can't represent certain fractions, like finite decimal numbers can't represent the number 1/3. Floats are generally suited for any kind of analog quantity where the measurement has error bars: length, mass, frequency, energy -- if there's uncertainty on the order of 2^(-52) or greater, there's probably no good reason not to use float.
If you need human-readable numbers, use float but format it.
"This number looks weird" is a bad reason not to use float. But that doesn't mean you have to display the number to arbitrary precision. If a number with only three significant figures comes out to 19.99909997918947, format it to one decimal place and be done with it.
>>> print('{:0.1f}'.format(e**pi - pi))
20.0
If you need precise decimal representation, use Decimal.
Sraw's answer refers to the decimal module, which is part of the standard library. I already mentioned currency as a discrete quantity, but you may need to do calculations on amounts of currency in which not all numbers are discrete, for example calculating interest. If you're writing code for an accounting system, there will be rules that say when rounding is applied and to what accuracy various calculations are done, and those specifications will be written in terms of decimal places. In this situation and others where the decimal representation is inherent to the problem specification, you'll want to use a decimal type.
>>> from decimal import Decimal
>>> rate = Decimal('0.0345')
>>> principal = Decimal('3412.65')
>>> interest = rate*principal
>>> interest
Decimal('117.736425')
>>> interest.quantize(Decimal('0.01'))
Decimal('117.74')
But most importantly, use data types and operations that make sense in context.
Several of your examples use math.floor, which takes a float and chops off the fractional part. In any situation where you should use math.floor, floating-point error doesn't matter. (If you want to round to the nearest integer, use round instead.) Yes, there are ways to use floating-point operations that have wrong results from a mathematical standpoint. But real-world quantities usually fall into one of these categories:
Exact, and therefore should not be put in a float;
Imprecise to a degree far exceeding the likely accumulation of floating-point error.
As a programmer, it's part of your job to know the quantities you're dealing with and choose appropriate data types. So there's no "fix" for floating point numbers, because there's no "problem" really -- just people using the wrong type for the wrong thing.
Let's talk about decimal. Actually, this library converts number into a string-like object, and then do any arithmetical operation based on chars.
So in this case, it can handle significantly huge number with almost perfect precision.
But, as it calculate number based on chars, it cost much more.
Further, if you want to use decimal, to ensure precision, you need consistently use it. If you mix decimal with normal types such as float, it may cause unexpected problems.
Finally, when you construct a Decimal object, it is better to pass a string but not a number.
>>> print(Decimal(99.99) - Decimal(99.973))
0.01699999999999590727384202182
>>> print(Decimal("99.99") - Decimal("99.973"))
0.017
It depends what your end goal is - there is no way to "perfectly" store floating point numbers. Only "good enough".
If you are working with money for example (dollars and cents) it is common practice to not store dollars - and only cents. (dollar = 100 cents) - this is how paypal stores your account balance on their servers.
There is also the python Decimal class for fixed point arithmetic.

Python rounding and inserting into array does not round [duplicate]

So I have a list of tuples of two floats each. Each tuple represents a range. I am going through another list of floats which represent values to be fit into the ranges. All of these floats are < 1 but positive, so precision matter. One of my tests to determine if a value fits into a range is failing when it should pass. If I print the value and the range that is causing problems I can tell this much:
curValue = 0.00145000000671
range = (0.0014500000067055225, 0.0020968749796738849)
The conditional that is failing is:
if curValue > range[0] and ... blah :
# do some stuff
From the values given by curValue and range, the test should clearly pass (don't worry about what is in the conditional). Now, if I print explicitly what the value of range[0] is I get:
range[0] = 0.00145000000671
Which would explain why the test is failing. So my question then, is why is the float changing when it is accessed. It has decimal values available up to a certain precision when part of a tuple, and a different precision when accessed. Why would this be? What can I do to ensure my data maintains a consistent amount of precision across my calculations?
The float doesn't change. The built-in numberic types are all immutable. The cause for what you're observing is that:
print range[0] uses str on the float, which (up until very recent versions of Python) printed less digits of a float.
Printing a tuple (be it with repr or str) uses repr on the individual items, which gives a much more accurate representation (again, this isn't true anymore in recent releases which use a better algorithm for both).
As for why the condition doesn't work out the way you expect, it's propably the usual culprit, the limited precision of floats. Try print repr(curVal), repr(range[0]) to see if what Python decided was the closest representation of your float literal possible.
In modern day PC's floats aren't that precise. So even if you enter pi as a constant to 100 decimals, it's only getting a few of them accurate. The same is happening to you. This is because in 32-bit floats you only get 24 bits of mantissa, which limits your precision (and in unexpected ways because it's in base2).
Please note, 0.00145000000671 isn't the exact value as stored by Python. Python only diplays a few decimals of the complete stored float if you use print. If you want to see exactly how python stores the float use repr.
If you want better precision use the decimal module.
It isn't changing per se. Python is doing its best to store the data as a float, but that number is too precise for float, so Python modifies it before it is even accessed (in the very process of storing it). Funny how something so small is such a big pain.
You need to use a arbitrary fixed point module like Simple Python Fixed Point or the decimal module.
Not sure it would work in this case, because I don't know if Python's limiting in the output or in the storage itself, but you could try doing:
if curValue - range[0] > 0 and...

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