tags:

views:

1463

answers:

15

Hi Friends,

I am trying to write a method to calculate the sum of the odd numbers in all the numbers less than the given number. so eg. CalcOdd(7) would return 5 + 3 + 1 = 9. CalcOdd (10) would return 9 + 7 + 5 + 3 + 1 = 25 etc

The method needs to take in a number, subtract 1, then recursively work backwards adding all odd numbers until it reaches 0. This is what I have so far.

    private static int CalcOdd(int n)
    {            

        if (n <= 1)
            return 1;
        else
            if (n % 2 == 0)
                n--;

        return n + CalcOdd(n - 2);
    }

It doesn't work so well, it includes the number passed in in the addition which is not what I want. Can anyone suggest a better way of doing this ? I would also loke to be able to port the answer to work for even numbers and add the option to include the original passed in number in the answer.

Many thanks

+9  A: 

Why would you use recursion here? Just loop; or better, figure out the math to do it in a simple equation...

The fact is that C# doesn't make for excellent deep recursion for things like maths; the tail-call isn't really there at the moment.

Loop approach:

private static int CalcOdd(int n)
{
    int sum = 0, i = 1;
    while (i < n)
    {
        sum += i;
        i += 2;
    }
    return sum;
}
Marc Gravell
"Why would you use recursion here?" Maybe his professor wants him to use recursion ;)
AaronLS
Many thanks Marc, I realise the loop option but wanted to use recursion for fun. It provides some recursion challenges in that its conditional (only odd numbers) and it needs to subtract 1 on the first pass but not on subsequent passes.
Why would you want to use a recursion instead of simple math formula? It makes no sense for production code, unless I am missing something.
Filip Navara
Ooooh, let's do it with LINQ-y goodness: `private static int CalcOdd(int n){ return (from x in Enumerable.Range(0,n) where (x }`
hughdbrown
A: 
Havenard
You should be calling `CalcOdd(n)`, since you're subtracting one at the start of the function call. This is broken.
Matthew Scharley
Misstyped it. Fixed.
Havenard
A: 

Why use recursion?

private Int32 CalcOdd(Int32 value)
{
    Int32 r = 0;
    {
     while (value >= 1)
     {
      value--;
      if (value % 2 != 0)
      {
       r += value;
      }
     }    
    }
    return r;
}
ChaosPandion
Hi and many thanks - I realise we could use the loop option but wanted to use recursion for fun. It provides some recursion challenges in that its conditional (only odd numbers) and it needs to subtract 1 on the first pass but not on subsequent passes.
I should of known... :)
ChaosPandion
+4  A: 

the sum of odd numbers less than a given number is a perfect square.

get the whole part of (n/2) to get the number of odd number less than itself.

square that and voila!

private static int CalcSumOdd(int n)
{            
    int i;
    int.tryParse(n / 2, out i);
    return i*i;
}

for even numbers its:

int i = n/2;
return i*(i+1);

correction. The above "even number sum" includes the original number "n". ie fn(12) = 42 = 2 + 4 + 6 + 8 + 10 + 12

if you want to exclude it, you should either unilaterally exclude it, or remove it with logic based on a passed in parameter.

Joshua
`int i = n/2;`? Why use `TryParse`?
Matthew Scharley
it's a clumsy way to get the whole part of half of "n". Maybe there's a more efficient way to get the value in C#?
Joshua
That won't even compile. But eww, no `TryParse` please! You're doing integer division, so it's wholly unnecessary.
Noldorin
Hi Joshua, see my comment above about wanting to use recursion, also i would like to be able to port this to work for even no's and to have the option of including or excluding the original number in the answer. i.e. calcodd(4) -> 4 + 3 + 1 or calcodd(4) -> 3 + 1
Using TryParse doesn't even work as you need to provide a string as the first argument. For integers n / 2 will give you the whole number already, and for everything else you can use Math.Truncate().
Cameron MacFarland
A: 

Use a helper function. CalcOdd consists of testing n to see if it is even or odd; if it is even, return helper(n); if it is odd, return helper(n-2).

The helper function must handle three cases: 1) n is less than 1; in this case return 0. 2) n is even, in this case return helper(n-1). 3) n is odd, in this case return n+helper(n-1).

Brian
+4  A: 

You could do this with recursion as you say, but if you wish to do it quicker, then I can tell you that the sum of the n first odd numbers is equal to n*n.

private static int CalcOdd(int n) {
    if (n<=1)
     return 0;

    if (n%2 == 1)
     n--;

    int k = n/2;

    return k*k;
}

The reason this works is:

Every even number is of the form 2k, and the odd number before it is 2k-1.

Because 2*1-1 = 1, there are k odd numbers below 2k.

If n is odd, we don't want to include it, so we simply go down to the even number below it and we automatically have what we want.

Edited to fix broken code.

Sebastian P.
Ah, that'll be the math bit ;-p I had started on a scrap of paper with sum(1...n)=n(n+1)/2, but hadn't quite got to the end ;-p
Marc Gravell
It's pretty obvious if you look at 1, 1+3, 1+3+5, ... ;)
Sebastian P.
-1 He doesn't have the number of odd numbers to add, he has the one to start from, say you call CalcOdd(9), your function would return 9*9/4=20.25 (whats with the /4, with that it doesn't even return whole numbers, leaving it out returns the correct result IF you pass in the number of odds to add). Where as the OP wants it to return what 7+5+3+1=16 (or if you include the first number) 9+7+5+3+1=25. To work out how many odd numbers there are between 0 and the value entered would require a recursive function anyway (or some really cleaver math)
Grant Peters
The number of odd numbers to add is trivial to get when you remember that every other number is an odd number.I have modified my post to fix the previously broken code (spirit remains the same, however). Also took the chance to explain why it works and clarify it.
Sebastian P.
Hi Sebastian and many thanks for the reply. as per my comments to Joshua - see my comment above about wanting to use recursion, also i would like to be able to port this to work for even no's and to have the option of including or excluding the original number in the answer. i.e. calcodd(4) -> 4 + 3 + 1 or calcodd(4) -> 3 + 1
Add a `boolean` parameter then.
JG
A: 
int CalcOdd(int n)
{            
    n -= 1;

    if (n <= 0)
     return 0; 

    if (n % 2 == 0)
     n--;

    return n + CalcOdd(n);
}

This function is also recursive, and it has parameters which makes you able to decide wether to do even or odd number and wether you want to include the first number or not. If you are confused as to how it works, remember that bools also can be seen as 1 (true) and 0 (false)

int Calc(int n, bool even = false, bool includeFirst = false)
{           
    n -= !includeFirst;

    if (n <= 0)
        return 0; 

    if (n % 2 == even)
        n--;

    return n + Calc(n - includeFirst, even);
}
Håkon
works for odd's, now lets see if I can port it for evens and add an option to include the initial number. many thanks
Removing "n -= 1" and substituting "return n + CalcOdd(n)" with "return n + CalcOdd(n - 1)" will include the initial number. To do even numbers change "n % 2 == 0" to "n % 2 == 1"
Håkon
Hi HåkonEvens not working. i.e. Passing in 7 returns 15. if we are calcing only evens, the answer should always be even. any ideas?
Hm, yes, I had to modify it a tad more. It should work now.
Håkon
compile errors all over it in c# (VS 2008)
lemmie try to port it over
That might be, did it in c++ and supposed it was similar enough. Well, a least you got the idea.
Håkon
A: 
public static int CalcOdd(int n) {
    // Find the highest even number. (Either n, or n-1.)
    // Divide that by 2, and the answer should be the square of that number.
    n = (n & 0x3FFFFFFE) >> 1;
    return (int)Math.Pow(n, 2);
}
Simon Svensson
Math.Pow is a very expensive way of squaring an integer, btw. return n * n; would be **much** cheaper.
Marc Gravell
Great recursive solution!
David Grant
+2  A: 

Here is a correction,

int CalcOdd(int n)
{ 
        n--; // <----

        if (n <= 1)
            return 0; // <----
        else
            if (n % 2 == 0)
                n--;

        return n + CalcOdd(n); // <----
}
Nick D
Edited to correct the algorithm. returning n + CalcOdd(n-1) was incorrect as it skips numbers in the sequence, since n has been decremented already.
Jason
thank you Jason
Nick D
Nick, many thanks, but it doesn't work. e.g CalcOdd(5) is returning 5 when it should be 4 (3 + 1), if you run it 1 - 10. its wrong all over the place. but many thanks
Kieran, with my edits it should be returning valid data. Just tested it here from 1 to 10: 1, 0; 2, 0; 3, 1; 4, 4; 5, 4; 6, 9; 7, 9; 8, 16; 9, 16; 10, 25
Jason
A: 

Simple loop verion.

    private static int CalcOdd(int number)
    {
        if (number < 2)
            return 1;
        int i = (number & 1) == 1 ? number - 2 : number - 1, result = 0;
        for (; i > 0; i -= 2)
            result += i;
        return result;
    }
mykhaylo
A: 

Since you want the option of including or excluding the first answer (and, keeping your "recursion" constraint in mind):

int calcOdd(int n, bool includeN)
{
    if( !includeN )
        return calcOdd(n-1, true);
    if(n<=1)
        return 1;
    else
        if(n%2 == 0)
            n--;
    return n+calcOdd(n-1, true);
}

The includeFirst, if passed as true, will include n in the calculations. Otherwise, the next layer down will start "including N".

Granted, as others have said, this is a horribly inefficient use of recursion, but... If you like recursion, try Haskell. It's a language built almost entirely on the concept.

Quantumplation
A: 

Håkon, I have ported your code to c# in VS 2008 as follows

        static int Calc(int n, bool bEven, bool bIncludeFirst)
    {
        int iEven = Bool2Int(bEven);
        int iIncludeFirst = Bool2Int(bIncludeFirst);

        n -= 1 - iIncludeFirst;

        if (n <= 0)
            return 0;

        if (n % 2 == iEven)
            n--;

        return n + Calc(n - iIncludeFirst, bEven, bIncludeFirst);
    }


    private static int Bool2Int(bool b)
    {
        return b ? 1 : 0;
    }

It seems to be working. Now is there anything I can do to optomise ? i.e. I dont want to have to parse those bools to ints every time etc ?

+1  A: 

i'm new here but this seems like a silly recursion exercise, given it can be done with a simple equation:

int sum(n,isEven,notFirst) {
    int c=1; //skip the else
    if (isEven) c=2;
    if (notFirst) n-=2;
    return ((n+c)*((n+c)/2))/2; }

classic discrete math sum series.. sum from 1 to 100 (odds and evens) is ((100+1)*(100/2))=5050

edit: in my code here, if you're calculating the sum of odds with n being even, or vice versa, it doesn't work, but i'm not going to put the work into that (and slop the code) right now. i'll assume your code will take care of that by the time it hits the function.. for example 7/2 isn't an int (obviously)

jessehanson1981
A: 

I'd isolate the 'make it odd' part from the 'sum every other descending number' part: (forgive the Python)

def sumEveryTwoRecursive(n):
    if n <= 0:
        return 0
    return n + sumEveryTwoRecursive(n - 2)

def calcOdd(n):
    return sumEveryTwoRecursive(n - (2 if n % 2 else 1))
David Grant
A: 

Just because there isn't one here yet, I've decided to use the LINQ hammer on this nail...

(borrowed from Nick D and Jason's pair programmed answer here)

void Main()
{
    GetIterator(7, true, false).Sum().Dump();
    // Returns 9

    GetIterator(10, true, false).Sum().Dump();
    // Returns 25
}

public IEnumerable<int> GetIterator(int n, bool isOdd, bool includeOriginal)
{   
    if (includeOriginal)
        n++;

    if (isOdd)
        return GetIterator(n, 1);
    else
        return GetIterator(n, 0);
}

public IEnumerable<int> GetIterator(int n, int odd)
{
    n--;

    if (n < 0)
        yield break;

    if (n % 2 == odd)
        yield return n;

    foreach (int i in GetIterator(n, odd))
        yield return i;
}
Cameron MacFarland