How do I calculate square root in Python? - python
I need to calculate the square root of some numbers, for example √9 = 3 and √2 = 1.4142. How can I do it in Python?
The inputs will probably be all positive integers, and relatively small (say less than a billion), but just in case they're not, is there anything that might break?
Related
Integer square root in python
How to find integer nth roots?
Is there a short-hand for nth root of x in Python?
Difference between **(1/2), math.sqrt and cmath.sqrt?
Why is math.sqrt() incorrect for large numbers?
Python sqrt limit for very large numbers?
Which is faster in Python: x**.5 or math.sqrt(x)?
Why does Python give the "wrong" answer for square root? (specific to Python 2)
calculating n-th roots using Python 3's decimal module
How can I take the square root of -1 using python? (focused on NumPy)
Arbitrary precision of square roots
Note: This is an attempt at a canonical question after a discussion on Meta about an existing question with the same title.
Option 1: math.sqrt()
The math module from the standard library has a sqrt function to calculate the square root of a number. It takes any type that can be converted to float (which includes int) as an argument and returns a float.
>>> import math
>>> math.sqrt(9)
3.0
Option 2: Fractional exponent
The power operator (**) or the built-in pow() function can also be used to calculate a square root. Mathematically speaking, the square root of a equals a to the power of 1/2.
The power operator requires numeric types and matches the conversion rules for binary arithmetic operators, so in this case it will return either a float or a complex number.
>>> 9 ** (1/2)
3.0
>>> 9 ** .5 # Same thing
3.0
>>> 2 ** .5
1.4142135623730951
(Note: in Python 2, 1/2 is truncated to 0, so you have to force floating point arithmetic with 1.0/2 or similar. See Why does Python give the "wrong" answer for square root?)
This method can be generalized to nth root, though fractions that can't be exactly represented as a float (like 1/3 or any denominator that's not a power of 2) may cause some inaccuracy:
>>> 8 ** (1/3)
2.0
>>> 125 ** (1/3)
4.999999999999999
Edge cases
Negative and complex
Exponentiation works with negative numbers and complex numbers, though the results have some slight inaccuracy:
>>> (-25) ** .5 # Should be 5j
(3.061616997868383e-16+5j)
>>> 8j ** .5 # Should be 2+2j
(2.0000000000000004+2j)
Note the parentheses on -25! Otherwise it's parsed as -(25**.5) because exponentiation is more tightly binding than unary negation.
Meanwhile, math is only built for floats, so for x<0, math.sqrt(x) will raise ValueError: math domain error and for complex x, it'll raise TypeError: can't convert complex to float. Instead, you can use cmath.sqrt(x), which is more more accurate than exponentiation (and will likely be faster too):
>>> import cmath
>>> cmath.sqrt(-25)
5j
>>> cmath.sqrt(8j)
(2+2j)
Precision
Both options involve an implicit conversion to float, so floating point precision is a factor. For example:
>>> n = 10**30
>>> x = n**2
>>> root = x**.5
>>> n == root
False
>>> n - root # how far off are they?
0.0
>>> int(root) - n # how far off is the float from the int?
19884624838656
Very large numbers might not even fit in a float and you'll get OverflowError: int too large to convert to float. See Python sqrt limit for very large numbers?
Other types
Let's look at Decimal for example:
Exponentiation fails unless the exponent is also Decimal:
>>> decimal.Decimal('9') ** .5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ** or pow(): 'decimal.Decimal' and 'float'
>>> decimal.Decimal('9') ** decimal.Decimal('.5')
Decimal('3.000000000000000000000000000')
Meanwhile, math and cmath will silently convert their arguments to float and complex respectively, which could mean loss of precision.
decimal also has its own .sqrt(). See also calculating n-th roots using Python 3's decimal module
SymPy
Depending on your goal, it might be a good idea to delay the calculation of square roots for as long as possible. SymPy might help.
SymPy is a Python library for symbolic mathematics.
import sympy
sympy.sqrt(2)
# => sqrt(2)
This doesn't seem very useful at first.
But sympy can give more information than floats or Decimals:
sympy.sqrt(8) / sympy.sqrt(27)
# => 2*sqrt(6)/9
Also, no precision is lost. (√2)² is still an integer:
s = sympy.sqrt(2)
s**2
# => 2
type(s**2)
#=> <class 'sympy.core.numbers.Integer'>
In comparison, floats and Decimals would return a number which is very close to 2 but not equal to 2:
(2**0.5)**2
# => 2.0000000000000004
from decimal import Decimal
(Decimal('2')**Decimal('0.5'))**Decimal('2')
# => Decimal('1.999999999999999999999999999')
Sympy also understands more complex examples like the Gaussian integral:
from sympy import Symbol, integrate, pi, sqrt, exp, oo
x = Symbol('x')
integrate(exp(-x**2), (x, -oo, oo))
# => sqrt(pi)
integrate(exp(-x**2), (x, -oo, oo)) == sqrt(pi)
# => True
Finally, if a decimal representation is desired, it's possible to ask for more digits than will ever be needed:
sympy.N(sympy.sqrt(2), 1_000_000)
# => 1.4142135623730950488016...........2044193016904841204
NumPy
>>> import numpy as np
>>> np.sqrt(25)
5.0
>>> np.sqrt([2, 3, 4])
array([1.41421356, 1.73205081, 2. ])
docs
Negative
For negative reals, it'll return nan, so np.emath.sqrt() is available for that case.
>>> a = np.array([4, -1, np.inf])
>>> np.sqrt(a)
<stdin>:1: RuntimeWarning: invalid value encountered in sqrt
array([ 2., nan, inf])
>>> np.emath.sqrt(a)
array([ 2.+0.j, 0.+1.j, inf+0.j])
Another option, of course, is to convert to complex first:
>>> a = a.astype(complex)
>>> np.sqrt(a)
array([ 2.+0.j, 0.+1.j, inf+0.j])
Newton's method
Most simple and accurate way to compute square root is Newton's method.
You have a number which you want to compute its square root (num) and you have a guess of its square root (estimate). Estimate can be any number bigger than 0, but a number that makes sense shortens the recursive call depth significantly.
new_estimate = (estimate + num/estimate) / 2
This line computes a more accurate estimate with those 2 parameters. You can pass new_estimate value to the function and compute another new_estimate which is more accurate than the previous one or you can make a recursive function definition like this.
def newtons_method(num, estimate):
# Computing a new_estimate
new_estimate = (estimate + num/estimate) / 2
print(new_estimate)
# Base Case: Comparing our estimate with built-in functions value
if new_estimate == math.sqrt(num):
return True
else:
return newtons_method(num, new_estimate)
For example we need to find 30's square root. We know that the result is between 5 and 6.
newtons_method(30,5)
number is 30 and estimate is 5. The result from each recursive calls are:
5.5
5.477272727272727
5.4772255752546215
5.477225575051661
The last result is the most accurate computation of the square root of number. It is the same value as the built-in function math.sqrt().
This answer was originally posted by gunesevitan, but is now deleted.
Python's fractions module and its class, Fraction, implement arithmetic with rational numbers. The Fraction class doesn't implement a square root operation, because most square roots are irrational numbers. However, it can be used to approximate a square root with arbitrary accuracy, because a Fraction's numerator and denominator are arbitrary-precision integers.
The following method takes a positive number x and a number of iterations, and returns upper and lower bounds for the square root of x.
from fractions import Fraction
def sqrt(x, n):
x = x if isinstance(x, Fraction) else Fraction(x)
upper = x + 1
for i in range(0, n):
upper = (upper + x/upper) / 2
lower = x / upper
if lower > upper:
raise ValueError("Sanity check failed")
return (lower, upper)
See the reference below for details on this operation's implementation. It also shows how to implement other operations with upper and lower bounds (although there is apparently at least one error with the log operation there).
Daumas, M., Lester, D., Muñoz, C., "Verified Real Number Calculations: A Library for Interval Arithmetic", arXiv:0708.3721 [cs.MS], 2007.
Alternatively, using Python's math.isqrt, we can calculate a square root to arbitrary precision:
Square root of i within 1/2n of the correct value, where i is an integer:Fraction(math.isqrt(i * 2**(n*2)), 2**n).
Square root of i within 1/10n of the correct value, where i is an integer:Fraction(math.isqrt(i * 10**(n*2)), 10**n).
Square root of x within 1/2n of the correct value, where x is a multiple of 1/2n:Fraction(math.isqrt(x * 2**(n)), 2**n).
Square root of x within 1/10n of the correct value, where x is a multiple of 1/10n:Fraction(math.isqrt(x * 10**(n)), 10**n).
In the foregoing, i or x must be 0 or greater.
Binary search
Disclaimer: this is for a more specialised use-case. This method might not be practical in all circumstances.
Benefits:
can find integer values (i.e. which integer is the root?)
no need to convert to float, so better precision (can be done that well too)
I personally implemented this one for a crypto CTF challenge (RSA cube root attack),where I needed a precise integer value.
The general idea can be extended to any other root.
def int_squareroot(d: int) -> tuple[int, bool]:
"""Try calculating integer squareroot and return if it's exact"""
left, right = 1, (d+1)//2
while left<right-1:
x = (left+right)//2
if x**2 > d:
left, right = left, x
else:
left, right = x, right
return left, left**2==d
EDIT:
As #wjandrea have also pointed out, **this example code can NOT compute **. This is a side-effect of the fact that it does not convert anything into floats, so no precision is lost. If the root is an integer, you get that back. If it's not, you get the biggest number whose square is smaller than your number. I updated the code so that it also returns a bool indicating if the value is correct or not, and also fixed an issue causing it to loop infinitely (also pointed out by #wjandrea). This implementation of the general method still works kindof weird for smaller numbers, but above 10 I had no problems with.
Overcoming the issues and limits of this method/implementation:
For smaller numbers, you can just use all the other methods from other answers. They generally use floats, which might be a loss of precision, but for small integers that should mean no problem at all. All of those methods that use floats have the same (or nearly the same) limit from this.
If you still want to use this method and get float results, it should be trivial to convert this to use floats too. Note that that will reintroduce precision loss, this method's unique benefit over the others, and in that case you can also just use any of the other answers. I think the newton's method version converges a bit faster, but I'm not sure.
For larger numbers, where loss of precision with floats come into play, this method can give results closer to the actual answer (depending on how big is the input). If you want to work with non-integers in this range, you can use other types, for example fixed precision numbers in this method too.
Edit 2, on other answers:
Currently, and afaik, the only other answer that has similar or better precision for large numbers than this implementation is the one that suggest SymPy, by Eric Duminil. That version is also easier to use, and work for any kind of number, the only downside is that it requires SymPy. My implementation is free from any huge dependencies if that is what you are looking for.
Arbitrary precision square root
This variation uses string manipulations to convert a string which represents a decimal floating-point number to an int, calls math.isqrt to do the actual square root extraction, and then formats the result as a decimal string. math.isqrt rounds down, so all produced digits are correct.
The input string, num, must use plain float format: 'e' notation is not supported. The num string can be a plain integer, and leading zeroes are ignored.
The digits argument specifies the number of decimal places in the result string, i.e., the number of digits after the decimal point.
from math import isqrt
def str_sqrt(num, digits):
""" Arbitrary precision square root
num arg must be a string
Return a string with `digits` after
the decimal point
Written by PM 2Ring 2022.01.26
"""
int_part , _, frac_part = num.partition('.')
num = int_part + frac_part
# Determine the required precision
width = 2 * digits - len(frac_part)
# Truncate or pad with zeroes
num = num[:width] if width < 0 else num + '0' * width
s = str(isqrt(int(num)))
if digits:
# Pad, if necessary
s = '0' * (1 + digits - len(s)) + s
s = f"{s[:-digits]}.{s[-digits:]}"
return s
Test
print(str_sqrt("2.0", 30))
Output
1.414213562373095048801688724209
For small numbers of digits, it's faster to use decimal.Decimal.sqrt. Around 32 digits or so, str_sqrt is roughly the same speed as Decimal.sqrt. But at 128 digits, str_sqrt is 2.2× faster than Decimal.sqrt, at 512 digits, it's 4.3× faster, at 8192 digits, it's 7.4× faster.
Here's a live version running on the SageMathCell server.
find square-root of a number
while True:
num = int(input("Enter a number:\n>>"))
for i in range(2, num):
if num % i == 0:
if i*i == num:
print("Square root of", num, "==>", i)
break
else:
kd = (num**0.5) # (num**(1/2))
print("Square root of", num, "==>", kd)
OUTPUT:-
Enter a number: 24
Square root of 24 ==> 4.898979485566356
Enter a number: 36
Square root of 36 ==> 6
Enter a number: 49
Square root of 49 ==> 7
✔ Output 💡 CLICK BELOW & SEE ✔
Related
Python innacuracies with large numbers?
I have to write a function that uses another function, but the other function has to return integers which get fairly innacurate with large numbers. My code: import math def reduce(n, d): m = min(n, d) for i in range(m, 1, -1): if n%i==0 and d%i==0: n = n//i d = d//i return (n, d) def almost_square(n, d): f = n/d c = math.ceil(f) n*=c return reduce(n, d) def destiny(n, d): b = n/d fraction = n, d while not b.is_integer(): breuk = almost_square(fraction[0], fraction[1]) b = fraction[0]/fraction[1] return int(b) What the functions are supposed to do: reduce: just simplifying the fraction, so 2/4 becomes 1/2 for example almost_square: multiplying the fraction with the rounded up integer of the fraction destiny: applying almost square on a fraction until it returns an integer. The thing is, my uni works with a program that tries 50 test cases for each function and you only completed the exercise when every function works for all 50 test cases, and they expect the function 'reduce' to return a tuple of integers, but making integers of the numbers there makes my function 'destiny' innacurate, or at least I think so. So out of the 50 test cases, all 50 work on the function reduce, all 50 work on the function almost_square, but 5 fail for the function destiny which are: destiny(10, 6), my output: 1484710602474311424, expected output: 1484710602474311520 destiny(17, 13), my output: 59832260230817688435680083968, expected output: 59832260230817687634146563200 destiny(10, 3), my output: 1484710602474311424, expected output: 1484710602474311520 destiny(15, 9), my output: 1484710602474311424, expected output: 1484710602474311520 destiny(11, 5), my output: 494764640798827343035498496, expected output: 494764640798827359861461484 Anything that could fix this?
There is some floating point arithmetic in that code, which can slightly throw off the results, and apparently it did. Forget about float, don't use any "floats, but larger" libraries either, integer arithmetic is the way to go. For example, f = n/d c = math.ceil(f) n*=c This code looks like it computes n * ⌈n / d⌉, but it only approximately computes that because it uses floating point arithmetic, requiring values to be rounded to the nearest float (for example, int(float(1484710602474311520)) is 1484710602474311424). It should be implemented using integer arithmetic, for example like this: n *= (n + d - 1) // d The destiny function should not use floating point division either, and it does not need to. The "is b an integer" test can be stated equivalently as "does d divide n", which can be implemented with integer arithmetic. Also for that reduce function you can use math.gcd, or implement gcd yourself, the implementation that you have now is very slow. With those changes, I get the right results for the test cases that you mentioned. I could show the code, but since it is an assignment, you should probably write the code yourself. Asking this question at all is already risky.
Integers don't get inaccurate with large numbers. Floating point numbers do. And you are using floating point numbers. Rewrite your algorithm to only use integers.
How to prevent automatic rounding in print function when printing a float number?
Let's consider this situation: from math import sqrt x = sqrt(19) # x : 4.358898943540674 print("{:.4f}".format(x)) # I don't want to get 4.3589 # I want to get 4.3588 The print() function rounds the number automatically, but I don't want this. What should I do?
If you want to round the number down to the 4th decimal place rather than round it to the nearest possibility, you could do the rounding yourself. x = int(x * 10**4) / 10**4 print("{:.4f}".format(x)) This gives you 4.3588 Multiplying and later dividing by 10**4 shifts the number 4 decimal places, and the int function rounds down to an integer. Combining them all accomplishes what you want. There are some edge cases that will give an unexpected result due to floating point issues, but those will be rare.
Here is one way. truncate function courtesy of #user648852. from math import sqrt, floor def truncate(f, n): return floor(f * 10 ** n) / 10 ** n x = sqrt(19) # x : 4.358898943540674 print("{0}".format(truncate(x, 4))) # 4.3588
Do more work initially and cut away a fixed number of excess digits: from math import sqrt x = sqrt(19) # x : 4.358898943540674 print(("{:.9f}".format(x))[:-5]) gives the desired result. This could still fail if x has the form ?.????999996 or similar, but the density of these numbers is rather small.
Exact Value after Floating point not rounding up [duplicate]
I want to remove digits from a float to have a fixed number of digits after the dot, like: 1.923328437452 → 1.923 I need to output as a string to another function, not print. Also I want to ignore the lost digits, not round them.
round(1.923328437452, 3) See Python's documentation on the standard types. You'll need to scroll down a bit to get to the round function. Essentially the second number says how many decimal places to round it to.
First, the function, for those who just want some copy-and-paste code: def truncate(f, n): '''Truncates/pads a float f to n decimal places without rounding''' s = '{}'.format(f) if 'e' in s or 'E' in s: return '{0:.{1}f}'.format(f, n) i, p, d = s.partition('.') return '.'.join([i, (d+'0'*n)[:n]]) This is valid in Python 2.7 and 3.1+. For older versions, it's not possible to get the same "intelligent rounding" effect (at least, not without a lot of complicated code), but rounding to 12 decimal places before truncation will work much of the time: def truncate(f, n): '''Truncates/pads a float f to n decimal places without rounding''' s = '%.12f' % f i, p, d = s.partition('.') return '.'.join([i, (d+'0'*n)[:n]]) Explanation The core of the underlying method is to convert the value to a string at full precision and then just chop off everything beyond the desired number of characters. The latter step is easy; it can be done either with string manipulation i, p, d = s.partition('.') '.'.join([i, (d+'0'*n)[:n]]) or the decimal module str(Decimal(s).quantize(Decimal((0, (1,), -n)), rounding=ROUND_DOWN)) The first step, converting to a string, is quite difficult because there are some pairs of floating point literals (i.e. what you write in the source code) which both produce the same binary representation and yet should be truncated differently. For example, consider 0.3 and 0.29999999999999998. If you write 0.3 in a Python program, the compiler encodes it using the IEEE floating-point format into the sequence of bits (assuming a 64-bit float) 0011111111010011001100110011001100110011001100110011001100110011 This is the closest value to 0.3 that can accurately be represented as an IEEE float. But if you write 0.29999999999999998 in a Python program, the compiler translates it into exactly the same value. In one case, you meant it to be truncated (to one digit) as 0.3, whereas in the other case you meant it to be truncated as 0.2, but Python can only give one answer. This is a fundamental limitation of Python, or indeed any programming language without lazy evaluation. The truncation function only has access to the binary value stored in the computer's memory, not the string you actually typed into the source code.1 If you decode the sequence of bits back into a decimal number, again using the IEEE 64-bit floating-point format, you get 0.2999999999999999888977697537484345957637... so a naive implementation would come up with 0.2 even though that's probably not what you want. For more on floating-point representation error, see the Python tutorial. It's very rare to be working with a floating-point value that is so close to a round number and yet is intentionally not equal to that round number. So when truncating, it probably makes sense to choose the "nicest" decimal representation out of all that could correspond to the value in memory. Python 2.7 and up (but not 3.0) includes a sophisticated algorithm to do just that, which we can access through the default string formatting operation. '{}'.format(f) The only caveat is that this acts like a g format specification, in the sense that it uses exponential notation (1.23e+4) if the number is large or small enough. So the method has to catch this case and handle it differently. There are a few cases where using an f format specification instead causes a problem, such as trying to truncate 3e-10 to 28 digits of precision (it produces 0.0000000002999999999999999980), and I'm not yet sure how best to handle those. If you actually are working with floats that are very close to round numbers but intentionally not equal to them (like 0.29999999999999998 or 99.959999999999994), this will produce some false positives, i.e. it'll round numbers that you didn't want rounded. In that case the solution is to specify a fixed precision. '{0:.{1}f}'.format(f, sys.float_info.dig + n + 2) The number of digits of precision to use here doesn't really matter, it only needs to be large enough to ensure that any rounding performed in the string conversion doesn't "bump up" the value to its nice decimal representation. I think sys.float_info.dig + n + 2 may be enough in all cases, but if not that 2 might have to be increased, and it doesn't hurt to do so. In earlier versions of Python (up to 2.6, or 3.0), the floating point number formatting was a lot more crude, and would regularly produce things like >>> 1.1 1.1000000000000001 If this is your situation, if you do want to use "nice" decimal representations for truncation, all you can do (as far as I know) is pick some number of digits, less than the full precision representable by a float, and round the number to that many digits before truncating it. A typical choice is 12, '%.12f' % f but you can adjust this to suit the numbers you're using. 1Well... I lied. Technically, you can instruct Python to re-parse its own source code and extract the part corresponding to the first argument you pass to the truncation function. If that argument is a floating-point literal, you can just cut it off a certain number of places after the decimal point and return that. However this strategy doesn't work if the argument is a variable, which makes it fairly useless. The following is presented for entertainment value only: def trunc_introspect(f, n): '''Truncates/pads the float f to n decimal places by looking at the caller's source code''' current_frame = None caller_frame = None s = inspect.stack() try: current_frame = s[0] caller_frame = s[1] gen = tokenize.tokenize(io.BytesIO(caller_frame[4][caller_frame[5]].encode('utf-8')).readline) for token_type, token_string, _, _, _ in gen: if token_type == tokenize.NAME and token_string == current_frame[3]: next(gen) # left parenthesis token_type, token_string, _, _, _ = next(gen) # float literal if token_type == tokenize.NUMBER: try: cut_point = token_string.index('.') + n + 1 except ValueError: # no decimal in string return token_string + '.' + '0' * n else: if len(token_string) < cut_point: token_string += '0' * (cut_point - len(token_string)) return token_string[:cut_point] else: raise ValueError('Unable to find floating-point literal (this probably means you called {} with a variable)'.format(current_frame[3])) break finally: del s, current_frame, caller_frame Generalizing this to handle the case where you pass in a variable seems like a lost cause, since you'd have to trace backwards through the program's execution until you find the floating-point literal which gave the variable its value. If there even is one. Most variables will be initialized from user input or mathematical expressions, in which case the binary representation is all there is.
The result of round is a float, so watch out (example is from Python 2.6): >>> round(1.923328437452, 3) 1.923 >>> round(1.23456, 3) 1.2350000000000001 You will be better off when using a formatted string: >>> "%.3f" % 1.923328437452 '1.923' >>> "%.3f" % 1.23456 '1.235'
n = 1.923328437452 str(n)[:4]
At my Python 2.7 prompt: >>> int(1.923328437452 * 1000)/1000.0 1.923
The truely pythonic way of doing it is from decimal import * with localcontext() as ctx: ctx.rounding = ROUND_DOWN print Decimal('1.923328437452').quantize(Decimal('0.001')) or shorter: from decimal import Decimal as D, ROUND_DOWN D('1.923328437452').quantize(D('0.001'), rounding=ROUND_DOWN) Update Usually the problem is not in truncating floats itself, but in the improper usage of float numbers before rounding. For example: int(0.7*3*100)/100 == 2.09. If you are forced to use floats (say, you're accelerating your code with numba), it's better to use cents as "internal representation" of prices: (70*3 == 210) and multiply/divide the inputs/outputs.
Simple python script - n = 1.923328437452 n = float(int(n * 1000)) n /=1000
def trunc(num, digits): sp = str(num).split('.') return '.'.join([sp[0], sp[1][:digits]]) This should work. It should give you the truncation you are looking for.
So many of the answers given for this question are just completely wrong. They either round up floats (rather than truncate) or do not work for all cases. This is the top Google result when I search for 'Python truncate float', a concept which is really straightforward, and which deserves better answers. I agree with Hatchkins that using the decimal module is the pythonic way of doing this, so I give here a function which I think answers the question correctly, and which works as expected for all cases. As a side-note, fractional values, in general, cannot be represented exactly by binary floating point variables (see here for a discussion of this), which is why my function returns a string. from decimal import Decimal, localcontext, ROUND_DOWN def truncate(number, places): if not isinstance(places, int): raise ValueError("Decimal places must be an integer.") if places < 1: raise ValueError("Decimal places must be at least 1.") # If you want to truncate to 0 decimal places, just do int(number). with localcontext() as context: context.rounding = ROUND_DOWN exponent = Decimal(str(10 ** - places)) return Decimal(str(number)).quantize(exponent).to_eng_string()
>>> from math import floor >>> floor((1.23658945) * 10**4) / 10**4 1.2365 # divide and multiply by 10**number of desired digits
If you fancy some mathemagic, this works for +ve numbers: >>> v = 1.923328437452 >>> v - v % 1e-3 1.923
I did something like this: from math import trunc def truncate(number, decimals=0): if decimals < 0: raise ValueError('truncate received an invalid value of decimals ({})'.format(decimals)) elif decimals == 0: return trunc(number) else: factor = float(10**decimals) return trunc(number*factor)/factor
You can do: def truncate(f, n): return math.floor(f * 10 ** n) / 10 ** n testing: >>> f=1.923328437452 >>> [truncate(f, n) for n in range(5)] [1.0, 1.9, 1.92, 1.923, 1.9233]
Just wanted to mention that the old "make round() with floor()" trick of round(f) = floor(f+0.5) can be turned around to make floor() from round() floor(f) = round(f-0.5) Although both these rules break around negative numbers, so using it is less than ideal: def trunc(f, n): if f > 0: return "%.*f" % (n, (f - 0.5*10**-n)) elif f == 0: return "%.*f" % (n, f) elif f < 0: return "%.*f" % (n, (f + 0.5*10**-n))
def precision(value, precision): """ param: value: takes a float param: precision: int, number of decimal places returns a float """ x = 10.0**precision num = int(value * x)/ x return num precision(1.923328437452, 3) 1.923
Short and easy variant def truncate_float(value, digits_after_point=2): pow_10 = 10 ** digits_after_point return (float(int(value * pow_10))) / pow_10 >>> truncate_float(1.14333, 2) >>> 1.14 >>> truncate_float(1.14777, 2) >>> 1.14 >>> truncate_float(1.14777, 4) >>> 1.1477
When using a pandas df this worked for me import math def truncate(number, digits) -> float: stepper = 10.0 ** digits return math.trunc(stepper * number) / stepper df['trunc'] = df['float_val'].apply(lambda x: truncate(x,1)) df['trunc']=df['trunc'].map('{:.1f}'.format)
int(16.5); this will give an integer value of 16, i.e. trunc, won't be able to specify decimals, but guess you can do that by import math; def trunc(invalue, digits): return int(invalue*math.pow(10,digits))/math.pow(10,digits);
Here is an easy way: def truncate(num, res=3): return (floor(num*pow(10, res)+0.5))/pow(10, res) for num = 1.923328437452, this outputs 1.923
def trunc(f,n): return ('%.16f' % f)[:(n-16)]
A general and simple function to use: def truncate_float(number, length): """Truncate float numbers, up to the number specified in length that must be an integer""" number = number * pow(10, length) number = int(number) number = float(number) number /= pow(10, length) return number
There is an easy workaround in python 3. Where to cut I defined with an help variable decPlace to make it easy to adapt. f = 1.12345 decPlace= 4 f_cut = int(f * 10**decPlace) /10**decPlace Output: f = 1.1234 Hope it helps.
Most answers are way too complicated in my opinion, how about this? digits = 2 # Specify how many digits you want fnum = '122.485221' truncated_float = float(fnum[:fnum.find('.') + digits + 1]) >>> 122.48 Simply scanning for the index of '.' and truncate as desired (no rounding). Convert string to float as final step. Or in your case if you get a float as input and want a string as output: fnum = str(122.485221) # convert float to string first truncated_float = fnum[:fnum.find('.') + digits + 1] # string output
I think a better version would be just to find the index of decimal point . and then to take the string slice accordingly: def truncate(number, n_digits:int=1)->float: ''' :param number: real number ℝ :param n_digits: Maximum number of digits after the decimal point after truncation :return: truncated floating point number with at least one digit after decimal point ''' decimalIndex = str(number).find('.') if decimalIndex == -1: return float(number) else: return float(str(number)[:decimalIndex+n_digits+1])
int(1.923328437452 * 1000) / 1000 >>> 1.923 int(1.9239 * 1000) / 1000 >>> 1.923 By multiplying the number by 1000 (10 ^ 3 for 3 digits) we shift the decimal point 3 places to the right and get 1923.3284374520001. When we convert that to an int the fractional part 3284374520001 will be discarded. Then we undo the shifting of the decimal point again by dividing by 1000 which returns 1.923.
use numpy.round import numpy as np precision = 3 floats = [1.123123123, 2.321321321321] new_float = np.round(floats, precision)
Something simple enough to fit in a list-comprehension, with no libraries or other external dependencies. For Python >=3.6, it's very simple to write with f-strings. The idea is to let the string-conversion do the rounding to one more place than you need and then chop off the last digit. >>> nout = 3 # desired number of digits in output >>> [f'{x:.{nout+1}f}'[:-1] for x in [2/3, 4/5, 8/9, 9/8, 5/4, 3/2]] ['0.666', '0.800', '0.888', '1.125', '1.250', '1.500'] Of course, there is rounding happening here (namely for the fourth digit), but rounding at some point is unvoidable. In case the transition between truncation and rounding is relevant, here's a slightly better example: >>> nacc = 6 # desired accuracy (maximum 15!) >>> nout = 3 # desired number of digits in output >>> [f'{x:.{nacc}f}'[:-(nacc-nout)] for x in [2.9999, 2.99999, 2.999999, 2.9999999]] >>> ['2.999', '2.999', '2.999', '3.000'] Bonus: removing zeros on the right >>> nout = 3 # desired number of digits in output >>> [f'{x:.{nout+1}f}'[:-1].rstrip('0') for x in [2/3, 4/5, 8/9, 9/8, 5/4, 3/2]] ['0.666', '0.8', '0.888', '1.125', '1.25', '1.5']
The core idea given here seems to me to be the best approach for this problem. Unfortunately, it has received less votes while the later answer that has more votes is not complete (as observed in the comments). Hopefully, the implementation below provides a short and complete solution for truncation. def trunc(num, digits): l = str(float(num)).split('.') digits = min(len(l[1]), digits) return l[0] + '.' + l[1][:digits] which should take care of all corner cases found here and here.
Am also a python newbie and after making use of some bits and pieces here, I offer my two cents print str(int(time.time()))+str(datetime.now().microsecond)[:3] str(int(time.time())) will take the time epoch as int and convert it to string and join with... str(datetime.now().microsecond)[:3] which returns the microseconds only, convert to string and truncate to first 3 chars
# value value to be truncated # n number of values after decimal value = 0.999782 n = 3 float(int(value*1en))*1e-n
How are data types interpreted, calculated, and/or stored?
In python, suppose the code is: import.math a = math.sqrt(2.0) if a * a == 2.0: x = 2 else: x = 1
This is a variant of "Floating Point Numbers are Approximations -- Not Exact". Mathematically speaking, you are correct that sqrt(2) * sqrt(2) == 2. But sqrt(2) can not be exactly represented as a native datatype (read: floating point number). (Heck, the sqrt(2) is actually guaranteed to be an infinite decimal!). It can get really close, but not exact: >>> import math >>> math.sqrt(2) 1.4142135623730951 >>> math.sqrt(2) * math.sqrt(2) 2.0000000000000004 Note the result is, in fact, not exactly 2. If you want the x = 2 branch to execute, you will need to use an epsilon value of "is the result close enough?": epsilon = 1e-6 # 0.000001 if abs(2.0 - a*a) < epsilon: x = 2 else: x = 1
Numbers with decimals are stored as floating point numbers and they can only be an approximation to the real number in some cases. So your comparison needs to be not "are these two numbers exactly equal (==)" but "are they sufficiently close as to be considered equal". Fortunately, in the math library, there's a function to do that conveniently. Using isClose(), you can compare with a defined tolerance. The function isn't too complicated, you could do it yourself. math.isclose(a*a, 2, abs_tol=0.0001) >> True
Wrong answer in SPOJ `CUBERT` [closed]
Closed. This question needs debugging details. It is not currently accepting answers. Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question. Closed 7 years ago. Improve this question I am getting a Wrong Answer for my solution to this problem on SPOJ. The problem asks to calculate the cube root of an integer(which can be upto 150 digits long), and output the answer truncated upto 10 decimal places. It also asks to calculate the sum of all the digits in the answer modulo 10 as a 'checksum' value. Here is the exact problem statement: Your task is to calculate the cube root of a given positive integer. We can not remember why exactly we need this, but it has something in common with a princess, a young peasant, kissing and half of a kingdom (a huge one, we can assure you). Write a program to solve this crucial task. Input The input starts with a line containing a single integer t <= 20, the number of test cases. t test cases follow. The next lines consist of large positive integers of up to 150 decimal digits. Each number is on its own separate line of the input file. The input file may contain empty lines. Numbers can be preceded or followed by whitespaces but no line exceeds 255 characters. Output For each number in the input file your program should output a line consisting of two values separated by single space. The second value is the cube root of the given number, truncated (not rounded!) after the 10th decimal place. First value is a checksum of all printed digits of the cube root, calculated as the sum of the printed digits modulo 10. Example Input: 5 1 8 1000 2 33076161 Output: 1 1.0000000000 2 2.0000000000 1 10.0000000000 0 1.2599210498 6 321.0000000000 Here is my solution: from math import pow def foo(num): num_cube_root = pow(num, 1.0 / 3) # First round upto 11 decimal places num_cube_root = "%.11f" % (num_cube_root) # Then remove the last decimal digit # to achieve a truncation of 10 decimal places num_cube_root = str(num_cube_root)[0:-1] num_cube_root_sum = 0 for digit in num_cube_root: if digit != '.': num_cube_root_sum += int(digit) num_cube_root_sum %= 10 return (num_cube_root_sum, num_cube_root) def main(): # Number of test cases t = int(input()) while t: t -= 1 num = input().strip() # If line empty, ignore if not num: t += 1 continue num = int(num) ans = foo(num) print(str(ans[0]) + " " + ans[1]) if __name__ == '__main__': main() It is working perfectly for the sample cases: Live demo. Can anyone tell what is the problem with this solution?
Your solution has two problems, both related to the use of floating-point arithmetic. The first issue is that Python floats only carry roughly 16 significant decimal digits of precision, so as soon as your answer requires more than 16 significant digits or so (so more than 6 digits before the point, and 10 digits after), you've very little hope of getting the correct trailing digits. The second issue is more subtle, and affects even small values of n. That's that your approach of rounding to 11 decimal digits and then dropping the last digit suffers from potential errors due to double rounding. For an example, take n = 33. The cube root of n, to 20 decimal places or so, is: 3.20753432999582648755... When that's rounded to 11 places after the point, you end up with 3.20753433000 and now dropping the last digit gives 3.2075343300, which isn't what you wanted. The problem is that that round to 11 decimal places can end up affecting digits to the left of the 11th place digit. So what can you do to fix this? Well, you can avoid floating-point altogether and reduce this to a pure integer problem. We need the cube root of some integer n to 10 decimal places (rounding the last place down). That's equivalent to computing the cube root of 10**30 * n to the nearest integer, again rounding down, then dividing the result by 10**10. So the essential task here is to compute the floor of the cube root of any given integer n. I was unable to find any existing Stack Overflow answers about computing integer cube roots (still less in Python), so I thought it worth showing how to do so in detail. Computing cube roots of integers turns out to be quite easy (with the help of a tiny bit of mathematics). There are various possible approaches, but one approach that's both efficient and easy to implement is to use a pure-integer version of the Newton-Raphson method. Over the real numbers, Newton's method for solving the equation x**3 = n takes an approximation x to the cube root of n, and iterates to return an improved approximation. The required iteration is: x_next = (2*x + n/x**2)/3 In the real case, you'd repeat the iteration until you reached some desired tolerance. It turns out that over the integers, essentially the same iteration works, and with the right exit condition it will give us exactly the correct answer (no tolerance required). The iteration in the integer case is: a_next = (2*a + n//a**2)//3 (Note the uses of the floor division operator // in place of the usual true division operator / above.) Mathematically, a_next is exactly the floor of (2*a + n/a**2)/3. Here's some code based on this iteration: def icbrt_v1(n, initial_guess=None): """ Given a positive integer n, find the floor of the cube root of n. Args: n : positive integer initial_guess : positive integer, optional. If given, this is an initial guess for the floor of the cube root. It must be greater than or equal to floor(cube_root(n)). Returns: The floor of the cube root of n, as an integer. """ a = initial_guess if initial_guess is not None else n while True: d = n//a**2 if a <= d: return a a = (2*a + d)//3 And some example uses: >>> icbrt_v1(100) 4 >>> icbrt_v1(1000000000) 1000 >>> large_int = 31415926535897932384626433 >>> icbrt_v1(large_int**3) 31415926535897932384626433 >>> icbrt_v1(large_int**3-1) 31415926535897932384626432 There are a couple of annoyances and inefficiencies in icbrt_v1 that we'll fix shortly. But first, a brief explanation of why the above code works. Note that we start with an initial guess that's assumed to be greater than or equal to the floor of the cube root. We'll show that this property is a loop invariant: every time we reach the top of the while loop, a is at least floor(cbrt(n)). Furthermore, each iteration produces a value of a strictly smaller than the old one, so our iteration is guaranteed to eventually converge to floor(cbrt(n)). To prove these facts, note that as we enter the while loop, there are two possibilities: Case 1. a is strictly greater than the cube root of n. Then a > n//a**2, and the code proceeds to the next iteration. Write a_next = (2*a + n//a**2)//3, then we have: a_next >= floor(cbrt(n)). This follows from the fact that (2*a + n/a**2)/3 is at least the cube root of n, which in turn follows from the AM-GM inequality applied to a, a and n/a**2: the geometric mean of these three quantities is exactly the cube root of n, so the arithmetic mean must be at least the cube root of n. So our loop invariant is preserved for the next iteration. a_next < a: since we're assuming that a is larger than the cube root, n/a**2 < a, and it follows that (2a + n/a**2) / 3 is smaller than a, and hence that floor((2a + n/a**2) / 3) < a. This guarantees that we make progress towards the solution at each iteration. Case 2. a is less than or equal to the cube root of n. Then a <= floor(cbrt(n)), but from the loop invariant established above we also know that a >= floor(cbrt(n)). So we're done: a is the value we're after. And the while loop exits at this point, since a <= n // a**2. There are a couple of issues with the code above. First, starting with an initial guess of n is inefficient: the code will spend its first few iterations (roughly) dividing the current value of a by 3 each time until it gets into the neighborhood of the solution. A better choice for the initial guess (and one that's easily computable in Python) is to use the first power of two that exceeds the cube root of n. initial_guess = 1 << -(-n.bit_length() // 3) Even better, if n is small enough to avoid overflow, is to use floating-point arithmetic to provide the initial guess, with something like: initial_guess = int(round(n ** (1/3.))) But this brings us to our second issue: the correctness of our algorithm requires that the initial guess is no smaller than the actual integer cube root, and as n gets large we can't guarantee that for the float-based initial_guess above (though for small enough n, we can). Luckily, there's a very simple fix: for any positive integer a, if we perform a single iteration we always end up with a value that's at least floor(cbrt(a)) (using the same AM-GM argument that we used above). So all we have to do is perform at least one iteration before we start testing for convergence. With that in mind, here's a more efficient version of the above code: def icbrt(n): """ Given a positive integer n, find the floor of the cube root of n. Args: n : positive integer Returns: The floor of the cube root of n, as an integer. """ if n.bit_length() < 1024: # float(n) safe from overflow a = int(round(n**(1/3.))) a = (2*a + n//a**2)//3 # Ensure a >= floor(cbrt(n)). else: a = 1 << -(-n.bit_length()//3) while True: d = n//a**2 if a <= d: return a a = (2*a + d)//3 And with icbrt in hand, it's easy to put everything together to compute cube roots to ten decimal places. Here, for simplicity, I output the result as a string, but you could just as easily construct a Decimal instance. def cbrt_to_ten_places(n): """ Compute the cube root of `n`, truncated to ten decimal places. Returns the answer as a string. """ a = icbrt(n * 10**30) q, r = divmod(a, 10**10) return "{}.{:010d}".format(q, r) Example outputs: >>> cbrt_to_ten_places(2) '1.2599210498' >>> cbrt_to_ten_places(8) '2.0000000000' >>> cbrt_to_ten_places(31415926535897932384626433) '315536756.9301821867' >>> cbrt_to_ten_places(31415926535897932384626433**3) '31415926535897932384626433.0000000000'
You may try to use the decimal module with a sufficiently large precision value. EDIT: Thanks to #DSM, I realised that decimal module will not produce very exact cube roots. I suggest that you check whether all digits are 9s and round it to a integer if that is a case. Also, I now perform the 1/3 division with Decimals as well, because passing the result of 1/3 to Decimal constructor leads to reduced precision. import decimal def cbrt(n): nd = decimal.Decimal(n) with decimal.localcontext() as ctx: ctx.prec = 50 i = nd ** (decimal.Decimal(1) / decimal.Decimal(3)) return i ret = str(cbrt(1233412412430519230351035712112421123121111)) print(ret) left, right = ret.split('.') print(left + '.' + ''.join(right[:10])) Output: 107243119477324.80328931501744819161741924145124146 107243119477324.8032893150 Output of cbrt(10) is: 9.9999999999999999999999999999999999999999999999998