Why am I getting float division by zero? - python

I want to find the potential value and optimize it using the minimize function but when I run the codes, I get an error saying float division by zero. Does anyone know what's the problem?
Below are my codes.
def LennardJones(r):
"""
return Potential at input x for a polynomial with input r
"""
Potential = 0
for i in range(len(r)):
Potential += 4 * 0.41 * ((2.4 / i)**12 - (2.4 / i)**6)
return Potential
Answer = minimize(LennardJones, 1)

for i in range(len(r)):
for i in range(...) usually starts with 0.

The range() function returns a sequence of numbers, starting from 0 by default, and increments by 1 (by default)
At the start, i is 0, and division by zero is not possible.
however, it is possible to specify the starting value by adding a parameter: range(2, 6), which means values from 2 to 6 (but not including 6)

I think the 'i' value begins with 0 when you don't specify the range explicitly. You can use
range(1, len(r)), and check if the problem still persists!
Check the documentation for more details.

Maybe you should check why not add a parameter in method LennardJones.

Related

Am I doing something wrong trying to #jit this Python function

I've got this Python function which I'm trying to #jit, but I can't really get around it (it's the first time I try jitting something, so I'm here to learn more than anything). I'll include the code (commented) and I'll explain what it does briefly:
def pwrchk(n, m):
no_prob = [] #The list that will contain the exponents
for i in range(2, m+1): #Start from 2 because 1 is useless
power = n**i
is_good = True #If this becomes false later, there's a zero.
for j in range(math.floor(math.log(power, 10)) + 1):
#The formula in the range is the number of digits of 'power'
digit = power % 10 #Returns the last digit so it can be checked
if digit in digits:
is_good = False #This is the check
power = 0
break
power = power // 10 #Gets rid of the digit just checked
if is_good:
no_prob.append(i) #Append to the list of "good" exponents
return no_prob
This function computes n^i , with 2 < i < m, and checks if n^i contains a zero in its digits, and then returns a list of which exponents are such that n^i contains no zeros. It works absolutely fine in normal Python compilation.
Since for big values of m the execution time gets really long (I've tried m = 10^6 and it goes to a crawl), I thought of putting it in Anaconda to #jit it. The problem is that when I use the #jit decorator it tells me that it keeps falling back to object mode, so I can't compile it in nopython mode.
I tried changing the lists to numpy arrays and populating them with the powers of n out of the for cycle, changing math.floor(math.log(power, 10)) using numpy to manage the arrays, nothing.
Am I doing something wrong? I'm sure there's a simple explanation to it that's just going over my head, but as said before I'm kinda new to Numba, so if I'm doing something really dumb please tell me, so I won't do it again in the future, and if I need to provide something else I'll update with anything needed.

Numerical solution of exponential equation using Python or other software

I want to find numerical solutions to the following exponential equation where a,b,c,d are constants and I want to solve for r, which is not equal to 1.
a^r + b^r = c^r + d^r (Equation 1)
I define a function in order to use Scipy.optimize.fsolve:
from scipy.optimize import fsolve
def func(r,a,b,c,d):
if r==1:
return 10**5
else:
return ( a**(1-r) + b**(1-r) ) - ( c**(1-r) + d**(1-r) )
fsolve(funcp,0.1, args=(5,5,4,7))
However, the fsolve always returns 1 as the solution, which is not what I want. Can someone help me with this issue? Or in general, tell me how to solve (Equation 1). I used an online numerical solver long time ago, but I cannot find it anymore. That's why I am trying to figure it out using Python.
You need to apply some mathematical reasoning when choosing the initial guess. Consider your problem f(r) = (51-r + 51-r) − (41-r + 71-r)
When r ≤ 1, f(r) is always negative and decreasing (since 71-r is growing much faster than other terms). Therefore, all root-finding algorithms will be pushed to right towards 1 until reaching this local solution.
You need to pick a point far away from 1 on the right to find the nontrivial solution:
>>> scipy.optimize.fsolve(lambda r: 5**(1-r)+5**(1-r)-4**(1-r)-7**(1-r), 2.0)
array([ 2.48866034])
Simply setting f(1) = 105 is not going to have any effect, as the root-finding algorithm won't check f(1) until the very last step(note).
If you wish to apply a penalty, the penalty must be applied to a range of value around 1. One way to do so, without affecting the position of other roots, is to divide the whole function by (r − 1):
>>> scipy.optimize.fsolve(lambda r: (5**(1-r)+5**(1-r)-4**(1-r)-7**(1-r)) / (r-1), 0.1)
array([ 2.48866034])
(note): they may climb like f(0.1) → f(0.4) → f(0.7) → f(0.86) → f(0.96) → f(0.997) → … and stop as soon as |f(x)| < 10-5, so your f(1) is never evaluated
First of your code seems to uses a different equation than your question: 1-r instead of just r.
Valid answers to the equation is 1 and 2.4886 approximately as can be seen here. With the second argument of fsolve you specify a starting estimate. I think due to 0.1 being close to 1 you get that result. Using the 2.1 as starting estimate I get the other answer 2.4886.
from scipy.optimize import fsolve
def func(r,a,b,c,d):
if r==1:
return 10**5
else:
return ( a**(1-r) + b**(1-r) ) - ( c**(1-r) + d**(1-r) )
print(fsolve(func, 2.1, args=(5,5,4,7)))
Chosing a starting estimate is tricky as many give the following error: ValueError: Integers to negative integer powers are not allowed.

Mean of Absolute differences in Python

I am trying to write a programme in Python 3which calculates the mean of the absolute differences between successive values.
EDIT: As the code was removed from the question, updating answer, moving the issues with code to bottom.
As given in comments you can use enumerate() to get the index as well as element from the array and then use that to calculate the mean. Example -
>>> def absolute_difference(v):
... sum_diff = 0
... for i,x in enumerate(v):
... if i+1 < len(v):
... sum_diff += abs(v[i+1] - x)
... r = sum_diff/len(v)
... return r
...
>>> absolute_difference([4.0, 4.2, 4.1, 4.4, 4.3])
0.1400000000000004
Lots of issues in the code (that you seem to have removed) -
Why are you converting your absolute difference to float ? float mathematics is not accurate , as you can see from the sum of difference in your code - 0.20000000000000018 . In your case you do not need to convert them to float.
The main issue of 0.0 for r occurs because you are using // to divide, // truncates the division to the nearest integer, so diving 7.0 by something grater than that using // would always result in 0.0 . Example -
>>> 7.0 // 8.0
0.0
>>> 7.0/8.0
0.875
For your case, you should divide using / .
You are taking the mean in each iteration of the loop, though that is not an issue , it may not be completely needed. If you do not want to take the mean in each iteration of the loop, you should indent it outside the loop.
You are using // which means integer division in python 3
That is
i.e)
2/4 =0.5
2//4=0
Just replace the // with / when calculating r
Here is another approach:
def absolute_difference(values):
last = values[0]
total = 0
for value in values[1:]:
total += abs(value - last)
last = value
return total/(len(values)-1)
print('{:.5f}'.format(absolute_difference([4.0, 4.2, 4.1, 4.4, 4.3])))
Giving the answer: 0.17500
Also, to prevent None from appearing at the end, you must have return at the end of your definition. This happens if you make another variable "equal to" (=) your definition. This was shown in the other posts, but I'm stating this just to highlight things out.

How to find index of a given Fibonacci number

I tried to use the following formula
to find the index of a fibonacci number() in a programming question and all the smaller test cases passed but some cases in which F was close to 10^18 failed. I did some dry-run and found out that if F = 99194853094755497 (82nd Fibonacci number) the value of n according to the above formula is 81. I coded this in Python and C++ which can be found here and here respectively. I want to know whether the formula works for every value of F or has some limitations?
Note: After doing some more tests, I found out that the code is giving correct answers till 52nd fibonacci number.
Update: The question has t test cases that's why I used a for loop. The given number F might not necessarily be a Fibonacci number. For ex- If F = 6, then it lies between two fibonacci numbers 5 and 8. Now the index of '5' in the fibonacci sequence is 4 so the answer is 4.
The formula works just fine:
import math
n = 99194853094755497
print math.log(n * math.sqrt(5) + 0.5) / math.log(1.61803398875) - 1
Output:
82.0
A remark on your code:
Using int(...) for rounding off to an integer might cause trouble if the floating point result is very close to 82.0. Numerical issues might cause it to be slightly larger, even though mathematically it would be smaller.
I think your formula is causing a stack overflow because the number is too large to hold in int.
F = 99194853094755497 is 84 Fibonacci number and hence the index for it is 83. Use the below script to get the correct index (integer instead of float).
eps = 10**-10
phi = (1+math.sqrt(5))/2 # golden search ratio
fibonacci_index = int(round(math.log(n * math.sqrt(5)+eps)/math.log(phi)))
Additional Info, code
See this https://github.com/gvavvari/Python/tree/master/Fibonacci_index for more detailed documentation on the implementation

Python find smallest multiple of numbers from 1-20. What is the issue in my code?

Yes, it's Euler problem 5. I'm new to python and I'm trying to solve a couple of problems to get used to the syntax. And yes I know that there are other question regarding the same problem, but I have to know why my code is not working:
import sys
def IsEvDivBy1to20(n):
for i in range(1,21):
if n%i!=0:
return 0
return 1
SmallMultiple = 0
for i in range(sys.maxsize**10):
if IsEvDivBy1to20(i) == 1:
SmallMultiple = i
break
print(SmallMultiple)
It returns 0.
range() by default starts at 0. The first time through your loop, then, i is 0: and so the first time through your (horribly-named) function, the values being compared against are 0.
Your code fails because,
range(sys.maxsize**10)
The first value returned by range is 0 and every number between 1 and 21 divides 0 without leaving any remainder. So, 0 is considered as the solution.
Also: Euler problems are not about brute forcing, it's also about finding an efficient solution.
For example, if a number is evenly divisible by the numbers 1 - 20 you can simply multiply 1 * 2 * ... * 20 = ... to find an upper bound. This number would clearly satisfy the conditions but it's likely not the smallest number.
You can then reason as follows: if the number can be divided by 6 then it can also be divided by 2 and 3. So I don't really need to include 6 in the 1 * 2 * ... * 20 multiplication. You can repeatedly apply this reasoning to find a much smaller upper bound and work your way towards the final answer.

Categories

Resources