What's wrong with my solution about Sqrt(x) - python

The webpage to test the code is here:
https://leetcode.com/problems/sqrtx/description/
I handed in these code and passed:
class Solution(object):
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
if x==1:
return 1
lowest=0.0
uppest=x*1.0
count=1
middle=(lowest+uppest)*0.5
while (abs(middle*middle-x)>0.001) and (count<=10000):
if middle*middle>x:
uppest=middle
else:
lowest=middle
middle=(lowest+uppest)*0.5
count=count+1
return int(middle)
but when I change
while (abs(middle*middle-x)>0.001) and (count<=10000):
into
while (abs(middle*middle-x)>0.0001) and (count<=10000):
or add more '0' like 0.00000000001 and use '9' as an input to test, it gets wrong
The output should be 3, but I got 2
How can I solve this kind of problem while using the Bisection Method?
I don't want to use the library (I know that using library is the easiest way but I want to learn more)

It is more like a math problem rather than python, just insert
print(middle,middle**2>x)
for debugging purposes.
class Solution(object):
def mySqrt(self, x):
"""
:type x: int
:rtype: int
"""
if x==1:
return 1
lowest=0.0
uppest=x*1.0
count=1
middle=(lowest+uppest)*0.5
while (abs(middle*middle-x)>0.0001) and (count<=10000):
if middle*middle>x:
uppest=middle
else:
lowest=middle
middle=(lowest+uppest)*0.5
count=count+1
print(middle,middle**2>x)
return int(middle)
sol=Solution()
print(sol.mySqrt(9))
The output
2.25 False
3.375 True
2.8125 False
3.09375 True
2.953125 False
3.0234375 True
2.98828125 False
3.005859375 True
2.9970703125 False
3.00146484375 True
2.999267578125 False
3.0003662109375 True
2.99981689453125 False
3.000091552734375 True
2.9999542236328125 False
3.0000228881835938 True
2.999988555908203 False
2
You can see the reason already.
Also I wonder why cannot you just use
round(middle)

The culprit is
return int(middle)
The reason you obtain 2 is because your are casting a number such as 2.99998855591 into int, which is the equivalent of floor(x)
After a number of iteration n0, the error sqrt(x) - middle between the target value and the value of middle follow a damped oscillation.
Just round to the closest integer instead
return round(middle)

See other answers for what is happening. The solution is:
return int(middle + 0.5)
which is rounding towards the nearest integer.
A bigger problem is of course that you're converting intermediate values to float when calculating an integer square root. Floats have a very limited range compared to Python ints. Try something like this instead:
def int_sqrt(n):
"""Return integer square root of integer ``n``.
"""
x = n
y = (x + 1) >> 1
while y < x:
x = y
y = (x + n // x) >> 1
return x
and e.g. run it on int_sqrt(2**12345-1) which should return a 1858 digit number.

Related

Python RecursionError

(I'm a total beginner)
I want to write a recursive function which can tell me if a number is a prime number or not: but I keep getting the same recursion error :
here is my code :
from math import *
def has_a_divider(n,p):
if n%p==0:
return True
elif has_a_divider(n,(p-1))!= True:
return False
else:
return False
def is_prime(a):
if has_a_divider(a,sqrt(a))==False:
return True
else:
return False
Your problem is sqrt(a) which returns a float instead of the int your code requires.
You can replace it by ceil(sqrt(a)) to get an int from it.
Also, this code does not work for finding if the number is prime as all numbers will have at least 1 has a divider. A possible solution is to update has_a_divider to check for dividers bigger than 1.
A possible implementation:
from math import ceil, sqrt
def has_a_divider(n,p):
if p < 2:
return False
if n % p==0:
return True
return has_a_divider(n,(p-1))
def is_prime(a):
if a == 1:
return False
return not has_a_divider(a,ceil(sqrt(a)))
print(is_prime(3))
print(is_prime(5))
print(is_prime(4))

Python classes and definitions

Here is my python code:
class Solution():
def isPalindrome(self):
return str(self.x) == str(self.x)[::-1]
s1 = Solution()
s1.x = 121
s1.isPalindrome()
It checks to see if the input is a palindrome. I want to create a new object that has the x value 121 and when I execute the isPalindrom function, I want it to return either a true or false boolean answer.
Currently when I run this program, nothing gets outputted. I am a bit lost as to where to go from here, would appreciate help.
Just print out the return value of isPalindrome(), because if you have a line with only a return value (this case being a boolean), the compiler won't know what to do with it.
class Solution():
def isPalindrome(self):
return str(self.x) == str(self.x)[::-1]
s1 = Solution()
s1.x = 121
print(s1.isPalindrome())
You're not telling the program to print anything. Try using print to make it reveal the answer.
Along with printing results we can also make class more pythonic.
class Solution:
def __init__(self):
self.input = None
def is_palindrome(self):
if isinstance(self.input, str):
return self.input == self.input[::-1]
print("Error: Expects str input")
return False # or leave blank to return None
s1 = Solution()
print(s1.is_palindrome())
s1.input = "121"
print(s1.is_palindrome())
output
Error: Expects str input
False
True
The main idea here is divide number. let's take number 122. First of all you need store it in a variable, in this case r_num. While loop is used and the last digit of the number is obtained by using the modulus operator %. The last digit 2 is then stored at the one’s place, second last at the ten’s place and so on. The last digit is then removed by truly dividing the number with 10, here we use //. And lastly the reverse of the number is then compared with the integer value stored in the temporary variable tmp if both are equal, the number is a palindrome, otherwise it is not a palindrome.
def ispalindrom(x):
r_num = 0
tmp = x
while tmp > 0:
r_num = (r_num * 10) + tmp % 10
tmp = tmp // 10
if x == r_num:
return True
return False

Determining validity if sum divisible by 10

Outline:
Find out if id is acceptable. Acceptable parameters is the sum of the
digits for each part of the id. If each sum is evenly divisible by 10
then the function returns the string "Acceptable", otherwise it
returns the string "Unacceptable".
Example:
isValid('123-12-134') → 'Unacceptable'
isValid('550-55-055') → 'Acceptable'
isValid('123-55-055') → 'Unacceptable'
I've tried converting the entire string into an int, but get some differing results in determining divisible by 10.
My attempted code is:
def isValid(id) :
id=id.replace('-','0')
id=int(id)
if id % 10==0:
return "Valid"
else:
return "Invalid"
Thanks in advance!
You might as well return boolean variables and just compare the output to determine what to print:
def summation(item):
return sum([int(i) for i in item])
def isValid(id_) :
id_part = id_.split('-')
result = [summation(item) % 10 == 0 for item in id_part]
return all(result)
Essentially this loops through all the characters in the split string and determines their sum - 3 sums per provided id.
Then we convert the summed list to a boolean list using your condition of x%10 == 0.
Finally we look at all() the elements of this boolean list to determine if it all True or contains a False.
If all are True then the return of isValid(id_) is True else it is False.
Usage:
ids = ['123-12-134', '550-55-055', '123-55-055']
for id_ in ids:
validity = isValid(id_)
print("Acceptable") if validity else print("Unacceptable")
Output:
Unacceptable
Acceptable
Unacceptable
you mean like this?
sentence = "123-123-123"
a = sum(int(x) for x in sentence if x.isdigit())
Hope this code can help you.
Found on this answer
you mean like this?
sentence = "123-123-123"
a = sum(int(x) for x in sentence if x.isdigit())
return a % 10 == 0
Hope this code can help you.
Found on this answer
We want to short-circuit the 'Unacceptable'.
def isValid(ID):
s = 0
for x in ID:
if x.isdigit():
s += int(x)
else:
if s % 10 == 0:
s = 0
else:
return 'Unacceptable'
return 'Acceptable' if s%10 == 0 else 'Unacceptable'
The solution requires splitting the string into parts using hyphens as separators, which are tested to ensure that the sum of each part's characters is a multiple of 10. The test fails if any of the parts are not a multiple of ten, so each part must be greater than or equal to ten. If any part fails, the string fails, so, there is no need to continue testing if a failed part is found. Acceptable must be returned if the string passes, or Unacceptable if it fails.
This single function solution is easy to read:
def teststring(test):
for part in test.split('-'):
part_failed = int(part)<10
if not part_failed:
sum_chars = 0
for char in part:
sum_chars += int(char)
part_failed = ((sum_chars % 10) != 0)
if part_failed: break
return 'Acceptable' if not part_failed else 'Unacceptable'
This solution uses list comprehension in two functions:
def testpart_comprehended(part):
return ((int(part)>=10) and ((sum(int(char) for char in part) % 10) == 0))
def acceptable_comprehended(test):
return 'Acceptable' if all(testpart_comprehended(part) for part in test.split("-")) else 'Unacceptable'
This solution uses list comprehension in one function:
def all_comprehended(test):
return 'Acceptable' if all(((int(part)>=10) and ((sum(int(char) for char in part) % 10) == 0)) for part in test.split("-")) else 'Unacceptable'
These answers are all too understandable. Please use
isValid = lambda x: (any(sum(map(int, s)) % 10 for s in x.split('-'))
* 'un' + 'acceptable').title()
Unacceptable
for example
>>> isValid('123-123')
'Unacceptable'
>>> isValid('123-127')
'Unacceptable'
>>> isValid('127-127')
'Acceptable'

Python, check if sets check out

I have made the function, but I need to make a guess so it will run through the function and check if it fits, if not, start over again with new numbers.
If I find a set that works, the loop should break, the problem is that I am new to python and math programming.
def checkStuff(X):
ok = True
#i.
if(min(X) <= 0):
ok = False
#ii.A
A = set()
for x in X:
A.add(x % 2)
#ii.B
B = set()
for y in X:
B.add(y**2)
#ii.C
C = set()
for z in X & B:
C.add(z**0.5)
#ii.D
D = set()
for w in C:
D.add(w**2)
#iii.
if(len(X)<=0):
ok = False
#iv.
if(len(X) not in X):
ok = False
#v.
if len(A) in X:
ok = False
#vi.
if sum(X) not in B:
ok = False
#vii.
if sum(X&B) in B:
ok = False
#viii.
if sum(C.union(D)) not in X:
ok = False
return ok
without giving you the exact code, try looking at the while loop and the random function
Your function can be simplified and optimized, returning as soon as possible, avoiding further computations... for compactness I used set comprehensions instead of your loops
def checkStuff(X):
if(min(X) <= 0): return False
if(len(X)<=0): return False
if(len(X) not in X): return False
A = {x % 2 for x in X}
if len(A) in X: return False
B = {x**2 for x in X}
if sum(X) not in B: return False
if sum(X&B) in B: return False
C = {xb**0.5 for xb in X&B}
D = {c**2 for c in C}
if sum(C.union(D)) not in X: return False
return True
Assuming that you have a function that returns a list of trial sets or, possibly better, yields a new trial set for each loop, and that you want to use ONLY the first X that matches your conditions, then you can write your stuff like this
for X in generate_trial_sets():
if checkStuff(X):
do_stuff(X)
break
else:
print("No X was generated matching the criteria")
...
Note that the else clause is aligned correctly, because Python has a for ... else .. control flow construct.
Blind Attempt at a generate_trial_sets Function
Given that each X is a set of numbers (integers? reals? complex numbers? who knows? you, but you didn't care to tell...) and that we don't know how many numbers you want in the set, and also that you want to stop the iteration somehow, I'd write
def generate_trial_sets(nmin=1, nmax=5,
xmin=0.0, xmax=10.0, iterations=10):
from random import randint
for _ in range(iterations):
n = randint(nmin,nmax+1)
x = {n}
for i in range(1,n):
x.add((xmax-xmin)*random()+xmin)
yield x
When you call it like
for X in generate_trial_sets():
without modifying the default args, you get back 10 sets of length comprised between 1 and 5, with real values comprised between 0 and 10 (one of the values is equal to the length, so one of your tests is automatically fulfilled).
To use different parameters, specify them at the invocation:
for X in generate_trial_sets(nmin=6,nmax=6,xmax=100.0,iterations=200):
This is not a solution of your problem but if you understand the logic you'll get started in the right direction or, at least, I hope so...

approximate comparison in python

I want to make '==' operator use approximate comparison in my program: float values x and y are equal (==) if
abs(x-y)/(0.5(x+y)) < 0.001
What's a good way to do that? Given that float is a built-in type, I don't think I can redefine the == operator, can I?
Note that I would like to use other features of float, the only thing that I'd like to change is the equality operator.
EDIT:
Thank you for the answers, and I understand your arguments about readability and other issues.
That said, I really would prefer, if possible, to actually keep using the regular float type, instead of having a new class or a new comparison function. Is it even possible to redefine == operator for regular floats?
My reasons are::
(a) everyone using the program I'm writing wants the floats to be compared this way
(b) there's no way in the world anyone would ever want to use the default == for floats.. Why is it even in the language???
(c) I dislike extra words in the code; obviously using the existing float results in no changes in the code whatsoever
EDIT 2.
Now that I know I can't overload the == operator for float, I have to change my question. It will become so different that I'll make a new one at custom comparison for built-in containers
You can create a new class deriving from the builtin float type, and then overwrite the necessary operators:
class InexactFloat(float):
def __eq__(self, other):
try:
return abs(self.real - other) / (0.5 * (abs(self.real) + abs(other))) < 0.001
except ZeroDivisionError:
# Could do another inexact comparison here, this is just an example:
return self.real == other
def __ne__(self, other):
return not self.__eq__(other)
print 5.2 == 5.20000000000001 # False
print 5.2 != 5.20000000000001 # True
print InexactFloat(5.2) == InexactFloat(5.20000000000001) # True
print InexactFloat(5.2) != InexactFloat(5.20000000000001) # False
print InexactFloat(-5) == -5 # True
# Works for InexactFloat <-> float comparison
print 5.0 == InexactFloat(5.0) # True
print InexactFloat(5.0) == 5.0 # True
# Zero division case (note how I implemented it above!)
print InexactFloat(-0.00001) == InexactFloat(0.00001) # False
print InexactFloat(-0.000000001) == InexactFloat(0.000000001) # False
print InexactFloat(-5) == InexactFloat(5) # False
# Unit test for fixed negative numbers problem
print InexactFloat(-5) == InexactFloat(-10) # False
You may also want to overwrite operators like <= etc.
Your definition has two problems:
Missing an *
Will attempt to divide by zero if x + y == 0.0 (which covers a possibly frequent case x == y == 0.0)
Try this instead:
define approx_Equal(x, y, tolerance=0.001):
return abs(x-y) <= 0.5 * tolerance * (x + y)
Edit: Note the use of <= instead of < ... needed to make the x == y == 0.0 case work properly.
I wouldn't try to override ==
Edit 2: You wrote:
there's no way in the world anyone would ever want to use the default
== for floats.. Why is it even in the language???
No way? Suppose you have a function that returns a float, and you have a brainwave about an algorithm that would produce the same answers faster and/or more elegantly; how do you test it?
If you wrap the numbers in a class you can overload "==" with:
def __eq__(self, x):
return abs(x - self.x) / (0.5 * (x + self.x)) < 0.001
however you should rewrite the expression to
abs(x - self.x) < 0.0005 * (x + self.x)
to avoid zero division.

Categories