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

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

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.

Python round a value to 3 decimal places

For some reasons the code below doesn't round the value to 3 decimal places but only 1. Any ideas?
for y in range(len(candidates_list)):
analysis.write(f"\n{candidates_list[y]}: {round(percentages_list[y],3)}% ({candidates_votes[y]})")
Thanks!
Due you are using f-strings (and thats very cool instead of old .format style ), this is not a rounding representation of the number because the previous answer gives you the right way to do it, this is a truncated representation of the number on the f strings, but this answer may help to others.
Instead of printing
f'{round(percentages_list[y],3)}'
you can do:
f'{percentages_list[y]:.3f}'
Instead of using the round() function, use the appropriate formatting operations. This will including trailing zero digits after the decimal.
And use zip() to iterate through multiple lists in parallel, rather than list indexing.
for candidate, percentage, vote in zip(candidates_list, percentages_list, candidates_votes):
analysis.write(f"\n{candidate}: {percentage:.3f}% ({vote}")

Getting a slice of a float from an irrational number

I am trying to find a way to slice an arbitrary index of an irrational number, eg. getting a slice of 5 digits of the Euler's number starting at the decimal index 100. This is not a practical task, just a thing I was wondering about.
I was trying to find an answer here
and sliced my number after converting my float into string:
z=str(format(math.e, '.105f'))[-6:-1]
It does work with floats with smaller precision (till around .50f), but with bigger it returns zeros. I was wondering how could I possibly represent and slice long floats.
Python has a package bigfloat for this very high precision arithmetics.

Does Python document its behavior for rounding to a specified number of fractional digits?

Is the algorithm used for rounding a float in Python to a specified number of digits specified in any Python documentation? The semantics of round with zero fractional digits (i.e. rounding to an integer) are simple to understand, but it's not clear to me how the case where the number of digits is nonzero is implemented.
The most straightforward implementation of the function that I can think of (given the existence of round to zero fractional digits) would be:
def round_impl(x, ndigits):
return (10 ** -ndigits) * round(x * (10 ** ndigits))
I'm trying to write some C++ code that mimics the behavior of Python's round() function for all values of ndigits, and the above agrees with Python for the most part, when translated to equivalent C++ calls. However, there are some cases where it differs, e.g.:
>>> round(0.493125, 5)
0.49312
>>> round_impl(0.493125, 5)
0.49313
There is clearly a difference that occurs when the value to be rounded is at or very near the exact midpoint between two potential output values. Therefore, it seems important that I try to use the same technique if I want similar results.
Is the specific means for performing the rounding specified by Python? I'm using CPython 2.7.15 in my tests, but I'm specifically targeting v2.7+.
Also refer to What Every Programmer Should Know About Floating-Point Arithmetic, which has more detailed explanations for why this is happening as it is.
This is a mess. First of all, as far as float is concerned, there is no such number as 0.493125, when you write 0.493125 what you actually get is:
0.493124999999999980015985556747182272374629974365234375
So this number is not exactly between two decimals, it's actually closer to 0.49312 than it is to 0.49313, so it should definitely round to 0.49312, that much is clear.
The problem is that when you multiply by 105, you get the exact number 49312.5. So what happened here is the multiplication gave you an inexact result which by coincidence canceled out the rounding error in the original number. Two rounding errors canceled each other out, yay! But the problem is that when you do this, the rounding is actually incorrect... at least if you want to round up at midpoints, but Python 3 and Python 2 behave differently. Python 2 rounds away from 0, and Python 3 rounds towards even least-significant digits.
Python 2
if two multiples are equally close, rounding is done away from 0
Python 3
...if two multiples are equally close, rounding is done toward the even choice...
Summary
In Python 2,
>>> round(49312.5)
49313.0
>>> round(0.493125, 5)
0.49312
In Python 3,
>>> round(49312.5)
49312
>>> round(0.493125, 5)
0.49312
And in both cases, 0.493125 is really just a short way of writing 0.493124999999999980015985556747182272374629974365234375.
So, how does it work?
I see two plausible ways for round() to actually behave.
Choose the closest decimal number with the specified number of digits, and then round that decimal number to float precision. This is hard to implement, because it requires doing calculations with more precision than you can get from a float.
Take the two closest decimal numbers with the specified number of digits, round them both to float precision, and return whichever is closer. This will give incorrect results, because it rounds numbers twice.
And Python chooses... option #1! The exactly correct, but much harder to implement version. Refer to Objects/floatobject.c:927 double_round(). It uses the following process:
Write the floating-point number to a string in decimal format, using the requested precision.
Parse the string back in as a float.
This uses code based on David Gay's dtoa library. If you want C++ code that gets the actual correct result like Python does, this is a good start. Fortunately you can just include dtoa.c in your program and call it, since its licensing is very permissive.
The Python documentation for and 2.7 specifies the behaviour:
Values are rounded to the closest multiple of 10 to the power minus
ndigits; if two multiples are equally close, rounding is done away
from 0.
For 3.7:
For the built-in types supporting round(), values are rounded to the
closest multiple of 10 to the power minus ndigits; if two multiples
are equally close, rounding is done toward the even choice
Update:
The (cpython) implementation can be found floatobjcet.c in the function float___round___impl, which calls round if ndigits is not given, but double_round if it is.
double_round has two implementations.
One converts the double to a string (aka decimal) and back to a double.
The other one does some floating point calculations, calls to pow and at its core calls round. It seems to have more potential problems with overflows, since it actually multiplies the input by 10**-ndigits.
For the precise algorithm, look at the linked source file.

Moving the point downwards in a floating point number

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 :-)

Categories

Resources