Compare two strings containing "expressions" for equality - python

I have two strings, the one is "K <- L * 5" and the other is "K <- 5 * L"
Is there a way to say in Python 3 to compare these and return True ? ( because they are the same but in different order )
I'm looking for a solution to compare only the 2nd part, after <-
Specifically I'd like the second part to give the same result.
E.g.
"5 % 3" and "3 % 5" are not the same
"L * 5" and "5 * L" are the same
Maybe a dictionary could help, but I'm not familiar with Python.

As explained in the comments, the check of semantics in this is an obstacle. You could probably build your own (or find someone else's) grammatical parser for these kind of mathematical expressions.
A workaround would be to use the mathematical capability that is already built in and converting the expression to valid expressions. I chose here to convert all numbers and letters to their Ascii equivalent. You can choose yourself how picky you want to be in the conversion (lower all caps, use only certain alphabets etc...) but here is a working example.
def main():
opt1_raw = "K <- N * 5"
opt2_raw = "K <- 5 * N"
opt1 = opt1_raw.split("<-")[1]
opt2 = opt2_raw.split("<-")[1]
ascii_exp = ''.join([str(ord(char)) if char.isdigit() or char.isalpha() else char for char in opt1])
s = eval(ascii_exp)
ascii_exp = ''.join([str(ord(char)) if char.isdigit() or char.isalpha() else char for char in opt2])
p = eval(ascii_exp)
print(opt1 +" and " + opt2 +": " + str(s==p))
main()
In the loop, I am converting all digits and alphas (letters) to their ascii equivalent, letting operators such as '*' and '/' be where they are. Then I use eval() to let python evaluate the expression. The result of an evaluation can then look like this: 76*53 instead of "L*5" Then I just compare the result. I'm sure you can find a more elegant way to incorporate this but its an example of evaluating such abstract expressions.
The output:
L*5 and 5*L: True
L*5 and 5 % 3: False
5 % 3 and 3 % 5: False
L*5 and 5 % 3: False

Related

The logic behind implementation of ord() in Lutz's "Learning Python "

I can't wrap my head around the example implementation of ord() function given in this book:
>>> B = '1101' # Convert binary digits to integer with ord
>>> I = 0
>>> while B != '':
... I = I * 2 + (ord(B[0]) - ord('0'))
... B = B[1:]
...
>>> I
13
Particurlarly I can't understand what are we achieving with this calculation 'I = I * 2 + (ord(B[0]) - ord('0'))'? Can anybody please explain step by step what this program does?
The expression (ord(B[0]) - ord('0')) is a very cumbersome way of doing int(B[0]).
The ord function returns the numeric value of the Unicode codepoint for a single character string. For digits and characters from the Latin alphabet, that's the ASCII value, somewhere between 0 and 127. For more exotic characters (like accented vowels, or Chinese characters), you'll get a larger number. A feature of the ASCII character set is the the numeric characters are arranged in order. Zero is character 48, one is character 49 and so on. That means you can do math on the ord values and it may correspond to doing math on the numbers themselves. If you subtract ord('0') from the ord of some other digit character, you'll get that other character's value.
But Python has better ways to do that, most of the time. It's a whole lot clearer if you convert a string into an integer with int, rather than using math with ord. I have no idea why the book you're reading would suggest doing it that way, unless learning about ord was the point of the exercise. And actually there's a lot of weird stuff in that code example. Using a for loop is a much more natural way to iterate over the characters of a string, rather than using slicing and a while loop, while constantly looking up the string's first character.
If I couldn't use int(some_string, 2) to covert a binary string to a number, I'd write:
def convert_binary_to_int(bin_str):
val = 0
for char in bin_str:
val *= 2
val += int(char) # or maybe use char == '1', if you can't call int at all
return val
As I commented in the code, if you can't use int at all, an alternative for converting each binary digit might be char == '1', which will be True or False. Those values are equal to 1 and 0, respectively, which is in fact the numerical value you want!
So I've figured out the answer to my question. I couldn't understand the math behind this code, why we need to start with 0 and then multiply by 2, etc. Turns out it's just the reverse of repeating division-by-2 method. E.g 13 is 1101 in binary, and one way of converting it is below
13|2 rem 1
6 |2 rem 0
3 |2 rem 1
1 |2 rem 1
0
Now we just have to start from the bottom, that means
0 * 2 + rem 1 = 1
1 * 2 + rem 1 = 3
3 * 2 + rem 0 = 6
6 * 2 + rem 1 = 13
Guess I have probably worded my question incorrectly.

HackerRank "AND product"

When I submit the below code for testcases in HackerRank challenge "AND product"...
You will be given two integers A and B. You are required to compute the bitwise AND amongst all natural numbers lying between A and B, both inclusive.
Input Format:
First line of the input contains T, the number of testcases to follow.
Each testcase in a newline contains A and B separated by a single space.
from math import log
for case in range(int(raw_input())):
l, u = map(int, (raw_input()).split())
if log(l, 2) == log(u, 2) or int(log(l,2))!=int(log(l,2)):
print 0
else:
s = ""
l, u = [x for x in str(bin(l))[2:]], [x for x in str(bin(u))[2:]]
while len(u)!=len(l):
u.pop(0)
Ll = len(l)
for n in range(0, len(l)):
if u[n]==l[n]:
s+=u[n]
while len(s)!=len(l):
s+="0"
print int(s, 2)
...it passes 9 of the test cases, Shows "Runtime error" in 1 test case and shows "Wrong Answer" in the rest 10 of them.
What's wrong in this?
It would be better for you to use the Bitwise operator in Python for AND. The operator is: '&'
Try this code:
def andProduct(a, b):
j=a+1
x=a
while(j<=b):
x = x&j
j+=1
return x
For more information on Bitwise operator you can see: https://wiki.python.org/moin/BitwiseOperators
Yeah you can do this much faster.
You are doing this very straightforward, calculating all ands in a for loop.
It should actually be possible to calculate this in O(1) (I think)
But here are some optimisations:
1) abort the for loop if you get the value 0, because it will stay 0 no matter what
2)If there is a power of 2 between l and u return 0 (you don't need a loop in that case)
My Idea for O(1) would be to think about which bits change between u and l.
Because every bit that changes somewhere between u and l becomes 0 in the answer.
EDIT 1: Here is an answer in O(same leading digits) time.
https://math.stackexchange.com/questions/1073532/how-to-find-bitwise-and-of-all-numbers-for-a-given-range
EDIT 2: Here is my code, I have not tested it extensively but it seems to work. (O(log(n))
from math import log
for case in [[i+1,j+i+1] for i in range(30) for j in range(30)]:
#Get input
l, u = case
invL=2**int(log(l,2)+1)-l
invU=2**int(log(u,2)+1)-u
#Calculate pseudo bitwise xnor of input and format to binary rep
e=format((u&l | invL & invU),'010b')
lBin=format(l,'010b')
#output to zero
res=0
#boolean to check if we have found any zero
anyZero=False
#boolean to check the first one because we have leading zeros
firstOne=False
for ind,i in enumerate(e):
#for every digit
#if it is a leading one
if i=='1' and (not anyZero):
firstOne=True
#leftshift result (multiply by 2)
res=res<<1
#and add 1
res=res+int(lBin[ind])
#else if we already had a one and find a zero this happens every time
elif(firstOne):
anyZero=True
#leftshift
res=res<<1
#test if we are in the same power, if not there was a power between
if(res!=0):
#print "test",(int(log(res,2))!=int(log(l,2))) | ((log(res,2))!=int(log(u,2)))
if((int(log(res,2))!=int(log(l,2))) or (int(log(res,2))!=int(log(u,2)))):
res=0
print res
Worked for every but a single testcase. Small change needed to get the last one. You'll have to find out what that small change is yourself. Seriously

Checking odd/even numbers and changing outputs on number size

I have a couple of problems to solve for an assignment, and am a bit stuck.
The question is to write a program that gets the user to input an odd number (check it's odd), then print an upside down pyramid of stars based on the size of the input.
For example, if you enter 5, it comes up with
*****
***
*
My problem is therefore two-fold.
1) How do I check if it's even or odd? I tried if number/2 == int in the hope that it might do something, and the internet tells me to do if number%2==0, but that doesn't work.
2) How do I change the asterisks in the middle of each line?
Any help with either problem is greatly appreciated.
Giving you the complete answer would have no point at all since this is homework, so here are a few pointers :
Even or Odd:
number % 2 == 0
definitely is a very good way to find whether your number is even.
In case you do not know %, this does modulo which is here the remainder of the division of number by 2. http://en.wikipedia.org/wiki/Modulo_operation
Printing the pyramid:
First advice: In order to print *****, you can do print "*" * 5.
Second advice: In order to center the asterisks, you need to find out how many spaces to write before the asterisks. Then you can print a bunch of spaces and asterisks with print " "*1 + "*"*3
The modulo 2 solutions with %2 is good, but that requires a division and a subtraction. Because computers use binary arithmetic, a much more efficient solution is:
# This first solution does not produce a Boolean value.
is_odd_if_zero = value & 1
# or
is_odd = (value & 1) == 1
# or
is_even = (value & 1) == 0
A few of the solutions here reference the time taken for various "is even" operations, specifically n % 2 vs n & 1, without systematically checking how this varies with the size of n, which turns out to be predictive of speed.
The short answer is that if you're using reasonably sized numbers, normally < 1e9, it doesn't make much difference. If you're using larger numbers then you probably want to be using the bitwise operator.
Here's a plot to demonstrate what's going on (with Python 3.7.3, under Linux 5.1.2):
Basically as you hit "arbitrary precision" longs things get progressively slower for modulus, while remaining constant for the bitwise op. Also, note the 10**-7 multiplier on this, i.e. I can do ~30 million (small integer) checks per second.
Here's the same plot for Python 2.7.16:
which shows the optimisation that's gone into newer versions of Python.
I've only got these versions of Python on my machine, but could rerun for other versions of there's interest. There are 51 ns between 1 and 1e100 (evenly spaced on a log scale), for each point I do the equivalent of:
timeit('n % 2', f'n={n}', number=niter)
where niter is calculated to make timeit take ~0.1 seconds, and this is repeated 5 times. The slightly awkward handling of n is to make sure we're not also benchmarking global variable lookup, which is slower than local variables. The mean of these values are used to draw the line, and the individual values are drawn as points.
Simple but yet fast:
>>> def is_odd(a):
... return bool(a - ((a>>1)<<1))
...
>>> print(is_odd(13))
True
>>> print(is_odd(12))
False
>>>
Or even simpler:
>>> def is_odd(a):
... return bool(a & 1)
1) How do I check if it's even or odd? I tried "if number/2 == int" in the hope that it might do something, and the internet tells me to do "if number%2==0", but that doesn't work.
def isEven(number):
return number % 2 == 0
if number%2==0
will tell you that it's even. So odd numbers would be the else statement there. The "%" is the mod sign which returns the remainder after dividing. So essentially we're saying if the number is divisible by two we can safely assume it's even. Otherwise it's odd (it's a perfect correlation!)
As for the asterisk placing you want to prepend the asterisks with the number of spaces correlated to the line it's on. In your example
***** line 0
*** line 1
* line 2
We'll want to space accordingly
0*****
01***
012*
la = lambda x : "even" if not x % 2 else "odd"
I guess the easiest and most basic way is this
import math
number = int (input ('Enter number: '))
if number % 2 == 0 and number != 0:
print ('Even number')
elif number == 0:
print ('Zero is neither even, nor odd.')
else:
print ('Odd number')
Just basic conditions and math. It also minds zero, which is neither even, nor odd and you give any number you want by input so it's very variable.
Regarding the printout, here's how I would do it using the Format Specification Mini Language (section: Aligning the text and specifying a width):
Once you have your length, say length = 11:
rowstring = '{{: ^{length:d}}}'.format(length = length) # center aligned, space-padded format string of length <length>
for i in xrange(length, 0, -2): # iterate from top to bottom with step size 2
print rowstring.format( '*' * i )
there are a lot of ways to check if an int value is odd or even.
I'll show you the two main ways:
number = 5
def best_way(number):
if number%2==0:
print "even"
else:
print "odd"
def binary_way(number):
if str(bin(number))[len(bin(number))-1]=='0':
print "even"
else:
print "odd"
best_way(number)
binary_way(number)
hope it helps
This is simple code. You can try it and grab the knowledge easily.
n = int(input('Enter integer : '))
if n % 2 == 3`8huhubuiiujji`:
print('digit entered is ODD')
elif n % 2 == 0 and 2 < n < 5:
print('EVEN AND in between [2,5]')
elif n % 2 == 0 and 6 < n < 20:
print('EVEN and in between [6,20]')
elif n % 2 == 0 and n > 20:
print('Even and greater than 20')
and so on...
Here's my solution:
def is_even(n):
r=n/2.0
return True if r==int(r) else False
Sample Instruction
Given an integer, n, performing the following conditional actions:
If n is odd, print Weird
If n is even and in the inclusive range of 2 to 5, print Not Weird
If n is even and in the inclusive range of 6 to 20, print Weird
If n is even and greater than 20, print Not Weird
import math
n = int(input())
if n % 2 ==1:
print("Weird")
elif n % 2==0 and n in range(2,6):
print("Not Weird")
elif n % 2 == 0 and n in range(6,21):
print("Weird")
elif n % 2==0 and n>20:
print("Not Weird")
def main():
n = float(input('odd:'))
while n % 2 == 0:
#if n % 2 == 1: No need for these lines as if it were true the while loop would not have been entered.
#break not required as the while condition will break loop
n = float(input('odd:'))
for i in range(int((n+1)/2)):
print(' '*i+'*'*int((n-2*i))+' '*i)
main()
#1st part ensures that it is an odd number that was entered.2nd part does the printing of triangular
Modulus method is the usual method. We can also do this to check if odd or even:
def f(a):
if (a//2)*2 == a:
return 'even'
else:
return 'odd'
Integer division by 2 followed by multiplication by two.
My solution basically we have two string and with the & we get the right index:
res = ["Even", "Odd"]
print(res[x & 1])
Please note that it seems slower than other alternatives:
#!/usr/bin/env python3
import math
import random
from timeit import timeit
res = ["Even", "Odd"]
def foo(x):
return res[x & 1]
def bar(x):
if x & 1:
return "Odd"
return "Even"
la = lambda x : "Even" if not x % 2 else "Odd"
iter = 10000000
time = timeit('bar(random.randint(1, 1000))', "from __main__ import bar, random", number=iter)
print(time)
time = timeit('la(random.randint(1, 1000))', "from __main__ import la, random", number=iter)
print(time)
time = timeit('foo(random.randint(1, 1000))', "from __main__ import foo, random", number=iter)
print(time)
output:
8.05739480999182
8.170479692984372
8.892275177990086
1. another odd testing function
Ok, the assignment was handed in 8+ years ago, but here is another solution based on bit shifting operations:
def isodd(i):
return(bool(i>>0&1))
testing gives:
>>> isodd(2)
False
>>> isodd(3)
True
>>> isodd(4)
False
2. Nearest Odd number alternative approach
However, instead of a code that says "give me this precise input (an integer odd number) or otherwise I won't do anything" I also like robust codes that say, "give me a number, any number, and I'll give you the nearest pyramid to that number".
In that case this function is helpful, and gives you the nearest odd (e.g. any number f such that 6<=f<8 is set to 7 and so on.)
def nearodd(f):
return int(f/2)*2+1
Example output:
nearodd(4.9)
5
nearodd(7.2)
7
nearodd(8)
9
This the function
def oddOrEven(num):
if num%2 == 0:
print("even")
else:
for i in range(num):
for j in range(i+1):
print(" ", end="")
for m in range(num-i, 0, -1):
print("* ", end="")
print()
but there is a catch because it is almost impossible to return a pattern so we have to print instead of return it then use it directly oddOrEven(5) will print:
* * * * *
* * * *
* * *
* *
*
Determining even/odd:
is_odd = num & 1
is_even = (num & 1) == 0 # slowly: bitwise and number comparison
is_even = (num & 1) is 0 # faster: bitwise and pointer comparsion
is_even = ~num & 1 # fastest: two bitwise operations
Using is is faster than the comparisons with double equals, but negation with ~ is even faster.

Why is i++++++++i valid in python?

I "accidentally" came across this weird but valid syntax
i=3
print i+++i #outputs 6
print i+++++i #outputs 6
print i+-+i #outputs 0
print i+--+i #outputs 6
(for every even no: of minus symbol, it outputs 6 else 0, why?)
Does this do anything useful?
Update (Don't take it the wrong way..I love python):
One of Python's principle says
There should be one-- and preferably only one --obvious way to do it. It seems there are infinite ways to do i+1
Since Python doesn't have C-style ++ or -- operators, one is left to assume that you're negating or positivating(?) the value on the left.
E.g. what would you expect i + +5 to be?
i=3
print i + +(+i) #outputs 6
print i + +(+(+(+i))) #outputs 6
print i + -(+i) #outputs 0
print i + -(-(+i)) #outputs 6
Notably, from the Python Grammar Specification, you'll see the line:
factor: ('+'|'-'|'~') factor | power
Which means that a factor in an expression can be a factor preceded by +, -, or ~. I.e. it's recursive, so if 5 is a factor (which it is because factor->power->NUMBER), then -5 is a factor and so are --5 and --------5.
The plus signs are considered unary operators to the right most i variable, as in +(-3) = -3, or +(+(+3))) = 3. Just the left most sign (plus or minus) are parsed as binary, so i+++i = i + (+(+i)), which translates to i + i = 3 + 3 = 6, in your example.
The other expressions follow the same principle.
That should read
print i + (+ (+i) )
that is, the first sign is the addition operator, the other ones are infix signs
+i
and (unfortunately)
++i
are thus valid statements.

Bitwise subtraction in Python

This is a follow-up to my question yesterday:
CMS kindly provided this example of using bitwise operators to add two numbers in C:
#include<stdio.h>
int add(int x, int y) {
int a, b;
do {
a = x & y;
b = x ^ y;
x = a << 1;
y = b;
} while (a);
return b;
}
int main( void ){
printf( "6 + 3 = %d", add(6,3));
printf( "6 - 3 = %d", add(6,-3));
return 0;
}
It works great and I then ported it to Python as follows:
def add(x, y):
while True:
a = x & y
b = x ^ y
x = a << 1
y = b
if a == 0:
break
return b
print "6 + 3 = %d" % add(6,3)
print "6 - 3 = %d" % add(6,-3)
They both work for addition and the C program works for subtraction as well. However, the Python program enters an infinite loop for subtraction. I am trying to get to the bottom of this and have posted the program here for further experimentation: http://codepad.org/pb8IuLnY
Can anyone advise why there would be a difference between the way C handles this and the way CPython handles this?
As I pointed out in my response to CMS' answer yesterday, left-shifting a negative number is undefined behavior in C so this isn't even guaranteed to work in C (the problem is how to handle the signed bit, do you shift it like a value bit or is it not affected by a shift? The standards committee couldn't agree on a behavior so it was left undefined).
When this happens to work in C it relies on fixed bit-width integers so that the leftmost bit gets pushed off the end when you do a shift (it also requires the sign bit to be treated as a value bit for shifting purposes). All integer types in C are fixed-bit but Python numbers can be arbitrarily large. Left-shifting a number in Python just causes it to keep getting larger:
>>> 1 << 100
1267650600228229401496703205376L
You could try something like this:
x = (a << 1) & 0xffffffff
To limit the result to 32-bits, the problem is that the left shift operator in Python doesn't shift the sign bit of a signed number (which is part of what is required to make this particular solution work). There might be a way to change the behavior of the shift operator but I don't know how.
Shifting negative numbers doesn't have consistent interpretation between python and C.
if i, j are two integers:
addition:
printf("%d",(i^j)|((i&j)<<1));
I've noticed that you're assuming that python works with numbers the same way as C does.
Thats not entirely true. Meaning C's int numbers have a fixed length of 16 bits. For detailed info on C datatypes you can refer to C_data_types on en.wikipedia.org
Python, on the other hand, is said to have a virtually infinite length for int numbers.
Adding positive integers may work the same way. But subtracting or adding negative integers shouldn't be a simple mapping translation.
An easy way to understand this is a little example on negative numbers:
Imagine a fixed length integer representation of 3 bits:
#Unsigned#
000 : 0
001 : 1
010 : 2
011 : 3
100 : 4
101 : 5
110 : 6
111 : 7
#Signed:#
000 : 0
001 : 1
010 : 2
011 : 3
100 : -4
101 : -3
110 : -2
111 : -1
This works cool because you can see that 1-3=1+(-3), -3 is 101 that's 5 if unsigned. So 1+5=6, 6 : 110 : -2. This means that 1-3=-2.
it also becomes buggy when overflowing:
-4 + -1 = 3 not -5 because it's out of range!
3 + 1 = -4 not 4 because it's out of range!
As you may see this works for fixed length but it doesn't work this way in Python.
For anyone are still interested, to resolve issue in python, just add a new case and switch the order of x and y inside the function, and return the negative value, though this put "-" in the function, but this presented a way using bit-wise operator. For anyone still wish to argue using operator "-" in the following question, I could argue that for the case of 2 - 6, the right answer is -4 where "-" exists in the answer, so it might be okay to add it when x is smaller than y. Hope this helps.
#A substract to substract two integers using bits operators
#refer to: https://www.geeksforgeeks.org/subtract-two-numbers-without-using-arithmetic-operators/
def subtractBits(x, y):
xRAW = x
yRAW = y
if x < y:
x = y
y = xRAW
# Iterate till there
# is no carry
while (y != 0):
# borrow contains common
# set bits of y and unset
# bits of x
borrow = (~x) & y
# Subtraction of bits of x
# and y where at least one
# of the bits is not set
x = x ^ y
# Borrow is shifted by one
# so that subtracting it from
# x gives the required sum
y = borrow << 1
if xRAW < yRAW:
return -x
else:
return x
print(subtractBits(100, 50))
print(subtractBits(1, 3))
print(subtractBits(40, 0))
print(subtractBits(0, 40))
print(subtractBits(5, 5))

Categories