0

I'm trying to write a code that calculates integrals using the rectangular rule and also allows the user to input the integral limits and number of divions(rectangles). I've written the function, but for certain values it just returns "None". Any idea why?

Here's my code so far:

def integral(f, a, b, N):
h = int((b-a)/N)
result = 0
result += h * f(a)
for i in range(1, N-1):
    result += h * f(a + i*h)
    return result

def f(x):          
return x**3

string_input1 = input("Please enter value for a: ") 
a = int(string_input1)


string_input2 = input("Please enter value for b: ")
b = int(string_input2)

while True: 
string_input3 = input("Please enter integer positive value for N: ") 
N = int(string_input3)
if N>0:       
    break


print(integral(f, a, b, N))

an example of values that return "None" is a=0 b=1 N=2

user2357112
  • 260,549
  • 28
  • 431
  • 505
Eve
  • 13
  • 2
  • 2
    `h` is an `int`? – Willem Van Onsem Mar 21 '17 at 19:09
  • 3
    @WillemVanOnsem Are you sure about the indentation of `return result`? it might explain the `None` if `N=2`. – DeepSpace Mar 21 '17 at 19:11
  • 1
    @DeepSpace: well the program was badly intended in the first place. I had the idea I fixed it, but I cannot know for sure. Based on the old indentation it was **in the loop**, but who can know for sure? – Willem Van Onsem Mar 21 '17 at 19:12
  • I now realise the h int was silly, changed it to a float but still getting the None – Eve Mar 21 '17 at 19:13
  • 1
    @Eve: is the `return` statement **inside** or **outside** the `for` loop? – Willem Van Onsem Mar 21 '17 at 19:14
  • 1
    @WillemVanOnsem the return should be outside the for loop, I tried it and I now get 0 instead of the None which is still not correct – Eve Mar 21 '17 at 19:22
  • If this is Python 2, then `(b-a)/N` would be integer division, rounding to 0 in your case. Use `float` to convert `a` and `b` to numbers. Conceptually -- it should be a float anyway. Why insist that limits of integration are integers? – John Coleman Mar 21 '17 at 19:30
  • @JohnColeman it's because I'm using the range, I had them as floats first but I was getting an error – Eve Mar 21 '17 at 19:35
  • `N` should be an int, but `a`, `b` should be floats. – John Coleman Mar 21 '17 at 19:57

3 Answers3

2
for i in range(1, N-1):
    result += h * f(a + i*h)
    return result

If N = 2 then for i in range(1, 1) is not going to execute, thus integral returns None.

But even if N > 2, having return inside the for loop doesn't make any sense since it will only run the first iteration and then return whatever result is.

DeepSpace
  • 78,697
  • 11
  • 109
  • 154
1

The first problem was the variable h as an int, then the loop until N-1 and after that the return inside the loop.

def integral(f,a,b,N):
    h = float(b-a)/float(N)
    result = 0.
    result += h*f(a)
    for i in range(1,N):
        result += h*f(a+i*h)
    return result
sebacastroh
  • 608
  • 4
  • 13
0

You already have a good answer, but your code could be refined a bit:

There is no reason to treat the leftmost endpoint any differently that the other sample points. Since a = a + 0, if you start the loop with i=0, you pick up a in the first pass through the loop:

def integral(f,a,b,N):
    h = (b-a)/float(N)
    result = 0.0
    for i in range(N):
        result += h*f(a+i*h)
    return result

Furthermore, it would be more Pythonic to replace the explicit loop by directly applying sum to a comprehension:

def integral(f,a,b,N):
    h = (b-a)/float(N)
    return h*sum(f(a + i*h) for i in range(N))

This is functionally the same as the first definition. For example:

>>> integral(lambda x: x**2,0,1,100)
0.32835000000000003

Finally, if you are using Python 2, the above should be changed so that it uses xrange() rather than range().

John Coleman
  • 51,337
  • 7
  • 54
  • 119
  • Thank you so much! One more question if you don't mind, how would you rewrite the loop for N so that instead of getting an error if the user enters a float value, it forces the user to enter valid input? – Eve Mar 21 '17 at 21:08
  • @Eve You could use something like `N = int(float(input("Enter number of subintervals: ")))` – John Coleman Mar 21 '17 at 21:33
  • This solves the error problem but it's not making the user re-enter a valid number – Eve Mar 21 '17 at 21:53
  • @Eve If you really want to force a user to enter an int: see this: http://stackoverflow.com/q/23294658/4996248 – John Coleman Mar 22 '17 at 18:16
  • I managed to do it, is there an alternative to try-except though? I was trying to write a simple while loop using if-else but couldn't get it right. It's probably because I attempted to check whether the number is an integer and did it wrong: if string_input == int. Even if I enter an integer the loop won't break. Is there a way to do that properly? – Eve Mar 22 '17 at 19:57