Check if two values are both non-negative or both negative - python

Given a pair of integer values, I need to check if both are non-negative or both are negative.
The trivial way is:
def func(a, b):
return (a >= 0 and b >= 0) or (a < 0 and b < 0)
But I am looking for something "neater", which I believe to be possible, so I came up with this:
def func(a, b):
return (a >= 0) ^ (b >= 0) == 0
However, this one feels a little "obscure to the average reader".
Is there a cleaner way?

Multiply them and test against 0:
def func(a, b):
return a * b >= 0

This is Python. We're not about the most concise efficient possible way to do things in all cases - that's for the C++ lads to do.
If (a >= 0 and b >= 0) or (a < 0 and b < 0) is "fast enough", (which would surprise me if not the case), then stick with it. It works, and is VERY obvious what it does.
For either your second solution, or #coldspeed's, I personally would have to write some stuff down on paper to figure out what it's doing, unless the function name was a LOT better than func.

Related

Trying to sum numbers between numbers more efficiently

TLDR: Need to make code below more efficient.
I'm trying to solve a coding challenge that requires I sum all numbers between two numbers. My code shown below is passing the tests but is taking too long to run, causing me to fail due to a time out.
Is there any way to rewrite this to do the same thing in less time?
EDIT: solved, thank you so much for your solutions
def get_sum(a,b):
res = 0
if b>a:
for i in range(a,b):
res = sum(range(a,b+1))
return res
if a > b:
for i in range (b,a):
res = sum(range(b,a+1))
return res
elif a == b:
return a
a little math won't harm.
so this should work.
def get_sum(a,b):
return (b-a+1)*(a+b)/2
Maybe this?
def get_sum2(a, b):
if a == b:
return a
return sum([n for n in range(a, b+1)] if b > a else [n for n in range(b, a+1)])
if __name__=="__main__":
print(get_sum2(1, 3))
One suggestion, when you find yourself trying to check for the order of parameters do something like this so you don't have to write the same code twice:
if a>b:
a,b = b,a
# your code
Yup. Using the formula for the triangular numbers:
def get_sum(a,b):
if a > b:
b, a = a, b
sum_from_1_to_a = a * (a + 1) / 2
sum_from_1_to_b = b * (b + 1) / 2
return sum_from_1_to_b - sum_from_1_to_a
You can simplify this, obviously, but I left it this way so it is obvious how the formula is being applied.
Also, are you sure if a == b you should return a? Aren't there 0 numbers between them if they have the same value?

Is there a faster way to know if it's a real triangle?

The following code is intended to return 0 if it's not possible to form a triangle with three given sides and return 1 if it is possible. Taking into account that it's not possible for a triangle to have an area of zero or less, first I calculated the semiperimeter of this hypothetical triangle and then return 1 if the result is greater than the greatest value in the given list. I did the previous because if the semiperimeter is less than the greatest value in the list, then when calculating the area with the Heron formula it would be an undefined root.
def isTriangle(aList):
semiperimeter = (aList[0] + aList[1] + aList[2]) / 2
if semiperimeter > max(aList):
return 1
else:
return 0
So I want to know if there is a faster way in Python to perform this (or at least with fewer lines of code).
You can check if the sum of the two smaller sides is at least as large as the longest side:
def check(aList)
return sum(aList) - max(aList) > max(aList)
With python 3.8+, you can avoid recomputing the maximum twice using a walrus operator:
def check(aList):
return (m := max(aList)) < sum(aList) - m
Both solutions rely on numerical comparisons returning a big boolean. In python bool is a subclass of int that has only two possible singleton values: True == 1 and False == 0. It's standard to return a bool rather than 0 or 1 for something like this. In fact, your original conditional could be replaced by
return semiperimeter > max(aList)
Or, absorbing the previous line into the return:
return sum(aList) / 2 > max(aList)
You could also write
return sum(aList) > 2 * max(aList)
This version avoids any type conversions, regardless if whether you pass in floats or integers (/ 2 always results in a float).
You asked for shorter code. That one is possible to do as a oneliner.
def isTriangle(aList):
return ((aList[0] + aList[1] + aList[2]) / 2) > max(aList) and 1 or 0
Exatly the same code, but just written shorter
To determine if given 3 sides can form a valid triangle, I would suggest using Triangle Inequality Theorem. It roughly states that the sum of any two sides must always be equal or greater than the other side to be able to form a valid triangle.
Therefore, I would instead write something along this line. [Edited: initialization according to Avinash]
def isTriangle(aList):
a,b,c = aList
return (a + b >= c and a + c >= b and b + c >= a)
In case you really want to make it return 0 or 1 instead of boolean then you can use this return instead.
return 1 if a + b >= c and a + c >= b and b + c >= a else 0

lmfit: constraining parameters with respect to other ones

I am having troubles setting the min and max values of a parameter to be fitted in lmfit. Basically, I have two parameters, a and b which need to obey the following constraints:
0 < b < 1
0 < a+b < 1
-b < a < 1
While the first two are rather easy to implement as:
fit_params.add('b', min = 0, max = 1)
fit_params.add('a_plus_b', min = 0, max = 1)
fit_params.add('a', expr = 'a_plus_b-b')
I am missing now an idea on how to include in the system my third condition. Can you suggest a further expression?
Thank you very much,
Leo
The solution is pretty simple, and I should only have read better the lmfit manual here: https://lmfit.github.io/lmfit-py/constraints.html
Trying anyway to be helpful, the solution is given by implementing an if sentence in the parameter expression.
fit_params.add('b', min = 0, max = 1)
fit_params.add('a_plus_b', min = 0, max = 1)
fit_params.add('a', expr = 'a_plus_b-b if a_plus_b-b > 0 else 0.')
I think that you don't actually need your third condition here, as
-b < a < 1
can be re-written as
0 < a+b < 1+b
but since b>0, this condition will always be met with 0 < a+b < 1.
But, to answer the question more generally, you would probably need to introduce another "difference-or-sum variable" as you did with a_plus_b and use that.

Use z3Py to prove the equivalence/difference of ranges of two expressions

from z3 import *
s = Solver()
a, b = Ints("a b")
s.add(a > 2)
s.add(b > 0)
s.add(Or(Exists(a, ForAll(b, a != b)), Exists(b, ForAll(a, a != b))))
s.check() # print "unsat"
I am trying to prove the difference of ranges of a and b. This can be done by locating an assignment to b of value 1 which is beyond the range of a.
However, the program above gives unexpected unsat. I wonder why and whether there is more efficient way to achieve this goal.
ForAll means exactly that: all numbers, i.e. Exists(a, ForAll(b, a != b)) is always false because there is no Int that's different from all Ints and thus the third assertion is unsatisfiable all by itself. You want something like s.add(Exists(a, (Exists (b, And(Not(a > 2), b > 0))))).
Also, note that you use two different a and b. Exists(a, ...) does not quantify over an existing variable, but introduces a new variable that's accidentally called by the same name as your global (existential) a, b.

Logical precedence in Python

I have a question about python precedence. I have the following code:
def gcdIter(a, b):
ans = min(a,b)
while ((a%ans is not 0) and (b%ans is not 0)):
ans -= 1
return ans
My question is about the while logical statement. I added several parenthesis just to make sure that the expression would be evaluated the way I was thinking, but is not. The while loop is being breaked before the both expressions are true. Were I'm wrong?
I found a way to do the same thing without using two expressions, in:
def gcdIter(a, b):
ans = min(a,b)
while ((a%ans + b%ans is not 0)) :
ans -= 1
return ans
But I still wanna know why the first code isn't running the way I think it should.
Do not use identity testing (is or is not) to test for numerical equality. Use == or != instead.
while a%ans != 0 and b%ans != 0:
is tests for object identity (that both operators are the same python object), which is not the same thing as testing if the values are equivalent.
Since 0 is also considered False in a boolean context, you can even omit the != in this case:
while a % ans and b % ans:
The fractions module already has a gcd() function that implements the greatest common divisor algorithm correctly:
from fractions import gcd
print gcd(a, b)
It uses the Euclidian algorithm, python style:
def gcd(a, b):
"""Calculate the Greatest Common Divisor of a and b.
Unless b==0, the result will have the same sign as b (so that when
b is divided by it, the result comes out positive).
"""
while b:
a, b = b, a%b
return a

Categories