Turn floats to integers in sympy - python

Is there a fast way to turn floats that are actually integers, to integers in python? For example: 2.0*x+3.1, I would like to appear as 2*x+3.1. I could loop through the numbers in the expression and check one by one if x = int(x) and then replace them (or something like that), but I was wondering if there is a faster, built-in method to do so.
Thank you!

There are a few ways to do this. You could nsimplify(expr, rational=True) but that will change the 3.1 to 31/10 and then you would have to undo that. The use of replace does not replace thing which are tested as equal. So the only one-pass solution that I know of is a custom function:
>>> def intify(expr):
... floats = S(expr).atoms(Float)
... ints = [i for i in floats if int(i) == i]
... return expr.xreplace(dict(zip(ints, [int(i) for i in ints])))
...
>>> intify(2.0*x+3.1)
2*x + 3.1

Related

What's the most efficient way to compare 2 numbers (16bit) bit by bit in Python?

I wonder what would be the most efficient way to compare 2 number (16bit) bit by bit in python? The order of the comparison does not matter.
In pseudo code I need something like this:
IF NUMBER1_BIT1 != NUMBER2_BIT1 THEN do something
IF NUMBER1_BIT2 != NUMBER2_BIT2 THEN do something
IF NUMBER1_BIT3 != NUMBER2_BIT3 THEN do something
…..
IF NUMBER1_BIT16 != NUMBER2_BIT16 THEN do something
This part of my program will be executed a lot so I want to be as efficient as python can allow it.
You can use xor and and operators:
num3 = num1 ^ num2
if num3 & 1: # bits 0 are different
...
if num3 & 2: # bits 1 are different
...
if num3 & 4: # bits 2 are different
...
You could convert this into a switch-statement using a helper function:
def bitSwitch(v): yield lambda b: v & (1<<b)
Which you could then use like this:
for case in bitSwitch(number1 ^ number2):
if case(0):
# do something ...
if case(1):
# do something else ...
if case(2):
# do some other thing ...
if case(3):
# do something different ...
...
if case(15):
# do that last thing ...
To be more efficient, you could replace v & (1<<b) with just v & b in the switch function and use the pre-computed powers of 2 in the case(..) calls: case(1): case(2) case(4) case(8) ... At that point napuzba's solution will be better because it does the same thing with less function call overhead.
Sounds like you are creating a bit mask. It is very common to see this done in C with 32 bit numbers and each bit is represented by a constant.
The cool thing about this method is that the mask will only produce some output if the bit is set in the input, otherwise the output will be 0.
Anyways, this is not C; this is python, so we can use the bin(x) method to convert each number to binary string, then compare each character in the string.
b_num1 = bin(num1).replace('0b', '')
b_num2 = bin(num2).replace('0b', '')
for i in range(num1.bit_length()):
if b_num1[i] != b_num2[i]:
pass # do something
...
Edit
In python3, we can use f-strings to create the binary numbers:
b_num1 = f'{num1:b}'
b_num2 = f'{num2:b}'

How to not double count sympy numbers

I need for a project to calculate some sort of simplicity of some expressions and among other things I need to assign to each number appearing in the expression a complexity (something like log2(x), such that the complexity is measured in bits, i.e. log2(4)=2 bits). Anyway, for a give sympy expression I have this piece of code:
is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
eq_numbers = [subexpression for subexpression in preorder_traversal(expr) if is_atomic_number(subexpression)]
It mainly works, but if I have something of the form 2*(x+y), that returns as the numbers appearing in the expression (2,2) instead of just 2, which is what I want. Is there a way to make sure that when something gets factored out, I count it only once? Thank you!
The atoms method might be what you want:
>>> (2*(x+y)).atoms(Number)
{2}
The replace method has the option too keep track of the mapping used, but it doesn't handle identical items that were replaced by different values
>>> (2*x + x**2).replace(lambda x:x.is_Number, lambda x: Dummy(), map=True)
(Dummy_1*x + x**Dummy_2, {2: Dummy_2})
So the following might work:
>>> def flatargs(expr):
... if expr.is_Atom: yield expr
... else:
... for a in expr.args:
... for i in flatargs(a): yield i
>>> list(flatargs(2*x+x**2))
[x, 2, 2, x]
>>> from sympy.utilities.iterables import multiset
>>> multiset([i for i in flatargs(2*x+x**2+y/2) if i.is_Number)
{1/2: 1, 2: 2}
If you want the numerator and denominator separately from flatargs you would have to handle the Rational atom as a special case and deal with the cases when numerator or denomitor is 1. But hopefully what is here will get you on your way.

Should I use float literals to represent integer numbers as floats in Python?

Consider a function that is to return a half of a float argument. Should it better be the first or the second?
def half_a(x: float) -> float:
return x / 2
def half_b(x: float) -> float:
return x / 2.0
Is there any performance difference or is there a style convention that would say one of these is better than the other?
Clearly half_a looks better and a more complex piece of code may get more readable written this way but in some other languages it is either necessary or preferable to use the half_b version to avoid run-time type conversion.
It's hard to know if there's a performance difference (and if there is, it's definitely negligible). Regarding style, there is also no common convention. However, I would choose the first one, if you are on python 3+. Python 3 has a different operator for integer division. See below
x = 2
print(type(x)) # int
print(type(x / 2)) # float
print(type(x // 2)) # int
On the other hand, if you are on python 2, you should probably choose the second one, because if your argument happens to be an int
print(2/5) # 0
float divided by float is slightly faster than float divided by int:
>>> timeit.timeit('n/2', 'n=123456.789')
0.04134701284306175
>>> timeit.timeit('n/2.0', 'n=123456.789')
0.03455621766488548
>>> timeit.timeit('[n/2 for n in r]', 'r = [n*5/1.1 for n in range(1, 10001)]', number=10000)
5.177127423787169
>>> timeit.timeit('[n/2.0 for n in r]', 'r = [n*5/1.1 for n in range(1, 10001)]', number=10000)
4.067747102254316

applying for loop such that counters are multiplied rather than being added in python

hello I am relatively new to python! Is there a way to do this using for loops in python?
This is a java implementation of something i want to do in python
for (i=1;i<20; i*= 2)
{System.out.println(i);}
Solution in while loop in python`
while i<20:
print i
i*=2
I cannot figure out a way to do this using for loops. Implemented it using while loop obviously, but still curious to know whether there is a method to do so or not
There are lots of ways to do this, e.g.
for i in range(5):
i = 2 ** i
print i
or using generators
from itertools import count, takewhile
def powers_of_two():
for i in count():
yield 2 ** i
for i in takewhile(lambda x: x < 20, powers_of_two()):
print i
But in the end, it depends on your use case what version gives the clearest and most readbale code. In most cases, you would probably just use a while-loop, since it's simple and does the job.
You think of for loops like they would be in other languages, like C, C++, Java, JavaScript etc.
Python for loops are different; they work on iterables, and you always have to read them like:
for element in iterable
instead of the C'ish
for(start_condition; continue_condition; step_statement)
Hence, you would need iterable to generate your products.
I like readability, so here's how I'd do it:
for a in (2**i for i in range(20)):
print a
But that mainly works because we mathematically know that the i'th element of your sequence is going to be 2**i.
There is not a real way to do this in Python. If you wanted to mimic the logic of that for loop exactly, then a manual while loop would definitely be the way to go.
Otherwise, in Python, you would try to find a generator or generator expression that produces the values of i. Depending on the complexity of your post loop expression, this may require an actual function.
In your case, it’s a bit simpler because the numbers you are looking for are the following:
1 = 2 ** 0
2 = 2 ** 1
4 = 2 ** 2
8 = 2 ** 3
...
So you can generate the numbers using a generator expression (2 ** k for k in range(x)). The problem here is that you would need to specify a value x which happens to be math.floor(math.log2(20)) + 1 (because you are looking for the largest number k for which 2 ** k < 20 is true).
So the full expression would be this:
for i in (2 ** k for k in range(math.floor(math.log2(20)) + 1)):
print(i)
… which is a bit messy, so if you don’t necessarily need the i to be those values, you could move it inside the loop body:
for k in range(math.floor(math.log2(20)) + 1):
i = 2 ** k
print(i)
But this still only fits your purpose. If you wanted a “real” C-for loop expression, you could write a generator function:
def classicForLoop (init, stop, step):
i = init
while i < stop:
yield i
i = step(i)
Used like this:
for i in classicForLoop(1, 20, lambda x: x * 2):
print(i)
Of course, you could also modify the generator function to take lambdas as the first and second parameter, but it’s a bit simpler like this.
Use range() function to define iteration length.You can directly use print() than system.out.println
Alexander mentioned it and re-iterating
for i in range(1,20):print(i*2)
You can also consider while loop here-
i=0
while (i<20):
print(2**i)
i=i+1
Remember indentation in python

Python: Is this the most efficient way to reverse order without using shortcuts?

x = [1,2,3,4,5,6,7,8,9,10]
#Random list elements
for i in range(int(len(x)/2)):
value = x[i]
x[i] = x[len(x)-i-1]
x[len(x)-i-1] = value
#Confusion on efficiency
print(x)
This is a uni course for first year. So no python shortcuts are allowed
Not sure what counts as "a shortcut" (reversed and the "Martian Smiley" [::-1] being obvious candidates -- but does either count as "a shortcut"?!), but at least a couple small improvements are easy:
L = len(x)
for i in range(L//2):
mirror = L - i - 1
x[i], x[mirror] = x[mirror], x[i]
This gets len(x) only once -- it's a fast operation but there's no reason to keep repeating it over and over -- also computes mirror but once, does the swap more directly, and halves L (for the range argument) directly with the truncating-division operator rather than using the non-truncating division and then truncating with int. Nanoseconds for each case, but it may be considered slightly clearer as well as microscopically faster.
x = [1,2,3,4,5,6,7,8,9,10]
x = x.__getitem__(slice(None,None,-1))
slice is a python builtin object (like range and len that you used in your example)
__getitem__ is a method belonging to iterable types ( of which x is)
there are absolutely no shortcuts here :) and its effectively one line.

Categories