Could someone explain me what's the difference between round() and float() in Python, please?
For example
x = 9.09128239
x = float("{0:.2f}".format(x))
y = 9.09128239
y = round(y, 2)
As I see, both functions from the code above do the same job. However, round() seems more compact and appealing to me.
I'd like to know if there is something else behind these functions and if I should consider something in particular when choosing which one to use.
Thank you for your help in advance!
It is not the float function that is doing the rounding here.
As a general term, float and round do very different things. Float takes a valid input and attempts to typecast it into a floating point representation. Round just rounds up to n significant digits.
float(3) #works on numbers
float("5.2") #and strings too!
x = 9.09128239
#x = float("{0:.2f}".format(x)) #there are two steps here.
result = "{0:.2f}".format(x)
#result is a string "9.09" The rounding happened because of the precision listed during string formatting.
x = float(result) #just takes the string and converts to float
y = 9.09128239
y = round(y, 2) #directly works on the float and rounds it off.
Tl;Dr Just use round.
This formats and parses a string, which is a lot of unnecessary work:
x = float("{0:.2f}".format(x))
This simple rounds the float, and will be much faster:
y = round(y, 2)
One of the main differences is that float is a class and round is a function. Using float does not round a number:
float('0.12345') #0.12345
but round does:
round(0.12345, 2) #0.12
Use float to convert something to a float, and use round to round off a float.
float() is used for type conversion of data to the float-type, if applicable.
On the other hand, round() is used for rounding of the given value to the specified number of decimal places.
Just as a quick note, what you are doing above in the example for float() is taking a number, rounding it off to the specified number of digits (in your example, two), converting it into string, and then type casting it into float data type.
For more information on float(), you may visit this page:
[Built in Functions](https://docs.python.org/3/library/functions.html#float)
Related
import math
a = math.sqrt(25)
print(a)
My output is 5.0, how can I get a 5 (whole number) instead?
You have to check and explicitly convert to integer:
if x == (y := int(x)):
x = y
Or, without the assignment operator:
if x == int(x):
x = int(x)
As of python 3.8, you can use math.isqrt:
math.isqrt(25)
Keep in mind that this will always return an integer, even if the input is not a perfect square.
In a reduced manner, you can use a 1 line if operator to assign an integer value to the result of sqrt if both integer and decimal values are the same:
import math
a = math.sqrt(25)
a = int(a) if int(a)==a else a
print(a)
It depends a little on what exact behavior you want: do you want to just print the number without the decimal, or do you want to round a number to an integer?
For the print statement, Python tries to convert whatever is passed to it to a String in order to print it, and by default it gives floating point numbers decimal places. To stop that, we can use string formatting:
print("{:.0f}".format(a))
What this is doing is making a string (the double quotes "") that contains a special format marker (the curly braces {}). Inside the format marker is the code for the desired behavior (0 decimal places on a floating point number). Then we call the .format method of the string and pass the value (a) we want to be used inside the special format marker.
This looks somewhat arcane and ugly, but is the safest method to print what you want because it does not change 'a' and is easily customizable to other printing behaviors.
For rounding a number and converting it to an int, you can either use int() or round(): both will take in a float and output an integer that will print cleanly (and be an integer for future computation). There is no requirement for the thing being converted to actually be an integer but there is different behavior for the two functions: int returns the value of the first digit of a number, while round returns the rounded value (IE round(1.9) -> 2, int(1.9) -> 1, etc).
I have a function that makes pseudorandom floats, and I want to turn those into integers,
But I don't mean to round them.
For Example, If the input is:
1.5323665
Then I want the output to be:
15323665
and not 2 or 1, which is what you get with round() and int().
You can first convert the float to a string and then remove the decimal point and convert it back to an int:
x = 1.5323665
n = int(str(x).replace(".", ""))
However, this will not work for large numbers where the string representation defaults to scientific notation. In such cases, you can use string formatting:
n = int(f"{x:f}".replace(".", ""))
This will only work up to 6 decimal places, for larger numbers you have to decide the precision yourself using the {number: .p} syntax where p is the precision:
n = int(f"{1.234567891:.10f}".replace(".", ""))
Rather than creating your own pseudorandom engine, which almost-certainly won't have a good density distribution, especially if you coerce floats to ints in this way, strongly consider using a builtin library for the range you're after!
More specifically, if you don't have a good distribution, you'll likely have extreme or unexplained skew in your data (especially values tending towards some common value)
You'll probably be able to observer this if you graph your data, which can be a great way to understand it!
Take a look at the builtin random library, which offers an integer range function for your convenience
https://docs.python.org/3/library/random.html#random.randint
import random
result = random.randint(lowest_int, highest_int)
Convert it to string and remove a dot:
int(str(x).replace('.', ''))
x = 1.5323665
y= int (x)
z= str(x-y)[2:]
o = int(len(z))
print(int(x*10**o))
it will return 15323665
I have been trying to fix the precision issue in my code that has been breaking. I want the value to be presented exactly as i provided but it seems like Python is rounding up the number. Below is the sample.
x = 3069682093880544.81
print (x)
3069682093880545.0
x = Decimal(3069682093880544.81)
print (x)
3069682093880545
x = float(3069682093880544.81)
print(x)
3069682093880545.0
x = Decimal(str(3069682093880544.81))
print(x)
3069682093880545.0
3069682093880545.0
x = str(3069682093880544.81)
print(x)
3069682093880545.0
All i want is to be able to assign exact value to the variable and it provides me the same value when called. What am i doing wrong?
The number 3069682093880544.81 is being converted into a 64 bit floating point number according the IEEE format. The closest number in that format is 43910A47D717A69F. However, converting that number back will be 3069682093880544.64. As you can see, the last 2 digits after the comma have changed.
The number of significant digits in a IEEE 64 bit float is 16 digits. And that's likely why the printed output choses to stop printing after 16 digits, which is 3069682093880545.
If you want more decimal places, you need to chose a method which does not have a IEEE floating point number in the way of its processing. (Note that even the source code interpreter will parse numbers into floating point format already.) As mentioned by #LeopardShark,
from decimal import *
print(Decimal("3069682093880544.81"))
goes from String to Decimal without any processing as float.
The problem is that the literal 3069682093880544.81 is parsed as a float. So, your second statement, for example, is sort of equivalent to Decimal(float(3069682093880544.81)). What you want is Decimal("3069682093880544.81") which parses it as a string, and then converts it to a Decimal.
I have some number 0.0000002345E^-60. I want to print the floating point value as it is.
What is the way to do it?
print %f truncates it to 6 digits. Also %n.nf gives fixed numbers. What is the way to print without truncation.
Like this?
>>> print('{:.100f}'.format(0.0000002345E-60))
0.0000000000000000000000000000000000000000000000000000000000000000002344999999999999860343602938602754
As you might notice from the output, it’s not really that clear how you want to do it. Due to the float representation you lose precision and can’t really represent the number precisely. As such it’s not really clear where you want the number to stop displaying.
Also note that the exponential representation is often used to more explicitly show the number of significant digits the number has.
You could also use decimal to not lose the precision due to binary float truncation:
>>> from decimal import Decimal
>>> d = Decimal('0.0000002345E-60')
>>> p = abs(d.as_tuple().exponent)
>>> print(('{:.%df}' % p).format(d))
0.0000000000000000000000000000000000000000000000000000000000000000002345
You can use decimal.Decimal:
>>> from decimal import Decimal
>>> str(Decimal(0.0000002345e-60))
'2.344999999999999860343602938602754401109865640550232148836753621775217856801120686600683401464097113374472942165409862789978024748827516129306833728589548440037314681709534891496105046826414763927459716796875E-67'
This is the actual value of float created by literal 0.0000002345e-60. Its value is a number representable as python float which is closest to actual 0.0000002345 * 10**-60.
float should be generally used for approximate calculations. If you want accurate results you should use something else, like mentioned Decimal.
If I understand, you want to print a float?
The problem is, you cannot print a float.
You can only print a string representation of a float. So, in short, you cannot print a float, that is your answer.
If you accept that you need to print a string representation of a float, and your question is how specify your preferred format for the string representations of your floats, then judging by the comments you have been very unclear in your question.
If you would like to print the string representations of your floats in exponent notation, then the format specification language allows this:
{:g} or {:G}, depending whether or not you want the E in the output to be capitalized). This gets around the default precision for e and E types, which leads to unwanted trailing 0s in the part before the exponent symbol.
Assuming your value is my_float, "{:G}".format(my_float) would print the output the way that the Python interpreter prints it. You could probably just print the number without any formatting and get the same exact result.
If your goal is to print the string representation of the float with its current precision, in non-exponentiated form, User poke describes a good way to do this by casting the float to a Decimal object.
If, for some reason, you do not want to do this, you can do something like is mentioned in this answer. However, you should set 'max_digits' to sys.float_info.max_10_exp, instead of 14 used in the answer. This requires you to import sys at some point prior in the code.
A full example of this would be:
import math
import sys
def precision_and_scale(x):
max_digits = sys.float_info.max_10_exp
int_part = int(abs(x))
magnitude = 1 if int_part == 0 else int(math.log10(int_part)) + 1
if magnitude >= max_digits:
return (magnitude, 0)
frac_part = abs(x) - int_part
multiplier = 10 ** (max_digits - magnitude)
frac_digits = multiplier + int(multiplier * frac_part + 0.5)
while frac_digits % 10 == 0:
frac_digits /= 10
scale = int(math.log10(frac_digits))
return (magnitude + scale, scale)
f = 0.0000002345E^-60
p, s = precision_and_scale(f)
print "{:.{p}f}".format(f, p=p)
But I think the method involving casting to Decimal is probably better, overall.
I know that questions about rounding in python have been asked multiple times already, but the answers did not help me. I'm looking for a method that is rounding a float number half up and returns a float number. The method should also accept a parameter that defines the decimal place to round to. I wrote a method that implements this kind of rounding. However, I think it does not look elegant at all.
def round_half_up(number, dec_places):
s = str(number)
d = decimal.Decimal(s).quantize(
decimal.Decimal(10) ** -dec_places,
rounding=decimal.ROUND_HALF_UP)
return float(d)
I don't like it, that I have to convert float to a string (to avoid floating point inaccuracy) and then work with the decimal module.
Do you have any better solutions?
Edit: As pointed out in the answers below, the solution to my problem is not that obvious as correct rounding requires correct representation of numbers in the first place and this is not the case with float. So I would expect that the following code
def round_half_up(number, dec_places):
d = decimal.Decimal(number).quantize(
decimal.Decimal(10) ** -dec_places,
rounding=decimal.ROUND_HALF_UP)
return float(d)
(that differs from the code above just by the fact that the float number is directly converted into a decimal number and not to a string first) to return 2.18 when used like this: round_half_up(2.175, 2) But it doesn't because Decimal(2.175) will return Decimal('2.17499999999999982236431605997495353221893310546875'), the way the float number is represented by the computer.
Suprisingly, the first code returns 2.18 because the float number is converted to string first. It seems that the str() function conducts an implicit rounding to the number that was initially meant to be rounded. So there are two roundings taking place. Even though this is the result that I would expect, it is technically wrong.
Rounding is surprisingly hard to do right, because you have to handle floating-point calculations very carefully. If you are looking for an elegant solution (short, easy to understand), what you have like like a good starting point. To be correct, you should replace decimal.Decimal(str(number)) with creating the decimal from the number itself, which will give you a decimal version of its exact representation:
d = Decimal(number).quantize(...)...
Decimal(str(number)) effectively rounds twice, as formatting the float into the string representation performs its own rounding. This is because str(float value) won't try to print the full decimal representation of the float, it will only print enough digits to ensure that you get the same float back if you pass those exact digits to the float constructor.
If you want to retain correct rounding, but avoid depending on the big and complex decimal module, you can certainly do it, but you'll still need some way to implement the exact arithmetics needed for correct rounding. For example, you can use fractions:
import fractions, math
def round_half_up(number, dec_places=0):
sign = math.copysign(1, number)
number_exact = abs(fractions.Fraction(number))
shifted = number_exact * 10**dec_places
shifted_trunc = int(shifted)
if shifted - shifted_trunc >= fractions.Fraction(1, 2):
result = (shifted_trunc + 1) / 10**dec_places
else:
result = shifted_trunc / 10**dec_places
return sign * float(result)
assert round_half_up(1.49) == 1
assert round_half_up(1.5) == 2
assert round_half_up(1.51) == 2
assert round_half_up(2.49) == 2
assert round_half_up(2.5) == 3
assert round_half_up(2.51) == 3
Note that the only tricky part in the above code is the precise conversion of a floating-point to a fraction, and that can be off-loaded to the as_integer_ratio() float method, which is what both decimals and fractions do internally. So if you really want to remove the dependency on fractions, you can reduce the fractional arithmetic to pure integer arithmetic; you stay within the same line count at the expense of some legibility:
def round_half_up(number, dec_places=0):
sign = math.copysign(1, number)
exact = abs(number).as_integer_ratio()
shifted = (exact[0] * 10**dec_places), exact[1]
shifted_trunc = shifted[0] // shifted[1]
difference = (shifted[0] - shifted_trunc * shifted[1]), shifted[1]
if difference[0] * 2 >= difference[1]: # difference >= 1/2
shifted_trunc += 1
return sign * (shifted_trunc / 10**dec_places)
Note that testing these functions brings to spotlight the approximations performed when creating floating-point numbers. For example, print(round_half_up(2.175, 2)) prints 2.17 because the decimal number 2.175 cannot be represented exactly in binary, so it is replaced by an approximation that happens to be slightly smaller than the 2.175 decimal. The function receives that value, finds it smaller than the actual fraction corresponding to the 2.175 decimal, and decides to round it down. This is not a quirk of the implementation; the behavior derives from properties of floating-point numbers and is also present in the round built-in of Python 3 and 2.
I don't like it, that I have to convert float to a string (to avoid
floating point inaccuracy) and then work with the decimal module. Do
you have any better solutions?
Yes; use Decimal to represent your numbers throughout your whole program, if you need to represent numbers such as 2.675 exactly and have them round to 2.68 instead of 2.67.
There is no other way. The floating point number which is shown on your screen as 2.675 is not the real number 2.675; in fact, it is very slightly less than 2.675, which is why it gets rounded down to 2.67:
>>> 2.675 - 2
0.6749999999999998
It only shows in string form as '2.675' because that happens to be the shortest string such that float(s) == 2.6749999999999998. Note that this longer representation (with lots of 9s) isn't exact either.
However you write your rounding function, it is not possible for my_round(2.675, 2) to round up to 2.68 and also for my_round(2 + 0.6749999999999998, 2) to round down to 2.67; because the inputs are actually the same floating point number.
So if your number 2.675 ever gets converted to a float and back again, you have already lost the information about whether it should round up or down. The solution is not to make it float in the first place.
After trying for a very long time to produce an elegant one-line function, I ended up getting something that is comparable to a dictionary in size.
I would say the simplest way to do this is just to
def round_half_up(inp,dec_places):
return round(inp+0.0000001,dec_places)
i would acknowledge that this is not accurate in every cases, but should work if you just want a simple quick workaround.