tags:

views:

672

answers:

16

What is the simplest way to calculate the amount of even numbers in a range of unsigned integers?

An example: if range is [0...4] then the answer is 3 (0,2,4)

I'm having hard time to think of any simple way. The only solution I came up involved couple of if-statements. Is there a simple line of code that can do this without if-statements or ternary operators?

A: 

Pseudo code (i'm no C coder):

count = 0;
foreach(i in range){
    if(i % 2 == 0){
      count++;
    }
}
Chris
loop is overkill here
iPhone beginner
O(n) is way too expensive (...and ugly)
Fdr
+6  A: 

Hint 1: The modulo operator will return the remainder of the current number
Hint 2: You don't need a for loop
Hint 3: A range is continuous
Hint 4: The number of even numbers in a continuous range are half even (sometimes half + 1, sometimes half - 1)
Hint 5: Building on Hint1: Consider also what (being + end + 1) % 2 gives
Hint 6: Most or all of the answers in this thread are wrong
Hint 7: Make sure you try your solution with negative number ranges
Hint 8: Make sure you try your solution with ranges spanning both negative and positive numbers

Brian R. Bondy
that I know, but putting it in a clear sentence is bit difficult. Depending on range there can be n/2 or n/2 + 1 even numbers.
Fdr
@Fdr: See hint #1.
Brian R. Bondy
@Fdr: And consider what would happen if you used it on an endpoint.
Brian R. Bondy
@Fdr: See hint 5 above
Brian R. Bondy
@Brian: your calculation doesn't work for `end = beg = -1`.
Vlad
@Vlad: Yes he can put some extra thinking for negative solutions. I added a hint 7 about that thanks for the suggestion.
Brian R. Bondy
@Brian In a range beginning with odd and ending with odd, your Hint 4 is incorrect.
Kirk Broadhurst
@Kirk: Thanks fixed, I put sometimes -1 as well.
Brian R. Bondy
Fdr
+12  A: 
int even = (0 == begin % 2) ? (end - begin) / 2 + 1 : (end - begin + 1) / 2;

Which can be converted into:

int even = (end - begin + (begin % 2)) / 2 + (1 - (begin % 2));

EDIT: This can further simplified into:

int even = (end - begin + 2 - (begin % 2)) / 2;

EDIT2: Because of the in my opinion somewhat incorrect definition of integer division in C (integer division truncates downwards for positive numbers and upwards for negative numbers) this formula won't work when begin is a negative odd number.

EDIT3: User 'iPhone beginner' correctly observes that if begin % 2 is replaced with begin & 1 this will work correctly for all ranges.

Andreas Brinck
Doesn't work for the OP's example, i.e. 0..4 should return 3.
Paul R
@Paul R Fencepost error, fixed.
Andreas Brinck
Seems to be wrong. For given example [0..4] `even = (4 - 0 - (0%2)) /2 = 4/2 = 2`. I think `int even = (end - begin - (begin % 2)) / 2 + 1;` is a proper answer
iPhone beginner
This only seems to work for ranges starting at 0? Try 10 .. 1
Greg K
@Greg K with `end = 10` and `begin = 1` this gives 5 which I think is the correct answer.
Andreas Brinck
`(10 - 1 - (1%2))/2 + 1 = (8)/2+1 = 5` : 2,4,6,8,10@Andreas, what do you mean by empty range? There is no such thing as empty inclusive range. This method works for `[a,a]` as well for both odd and even `a`. What's the issue?
iPhone beginner
@Andreas You are correct, I had (end - begin + (begin % 2)) / 2 + 1, doh! +1
Greg K
@iPhone beginner Ok, empty range isn't the correct term. A range with a single odd element in doesn't work like `[1, 1]` this will incorrectly report 1.
Andreas Brinck
Surely he can afford a check for that? if (max == min) { ... } else { your answer }
Greg K
@Andreas What about new idea:`int even = (end - begin) / 2 + (!(begin%2)|!(end%2));`It seems that we need to add +1 to range if either of ranges is even. Edit: Actually it seems to be what Andrei Ciobanu propose
iPhone beginner
@iPhone beginner See my updated answer
Andreas Brinck
Yes, it is almost the same as previous one, but 0 is irregular value. (x+2)/2-x/2 = 1 unless x=-1 and (x+2)=1
iPhone beginner
@Andreas: Your formula doesn't work for `end = begin = -1`
Vlad
@Brian [3..4] Converts into `(4 - 3 + 2 - (3 % 2)) / 2 == 1` which is the correct answer.
Andreas Brinck
@Vlad You can't create a closed formula when the interval straddles zero because of the (incorrect) discontinuous behavior of integer division in c.
Andreas Brinck
@Andreas: You can, look at my answer :-)
Vlad
KennyTM
@Vlad But not with C integer division.
Andreas Brinck
@Andreas: yes. Is that somehow bad?
Vlad
@Vlad I don't put any moral aspects on it, but I dont like converting a problem that should be solvable in the integer domain to finite precision floating point numbers. If the actual range do straddle zero, I would add an if-statement (or ternary operator).
Andreas Brinck
@Andreas: you can code `floor(a/2.0)` as `( a - (a%2)*(a%2) ) / 2`, if you wish to stay at integers. Or any other hack. This would however not add any readability. [Note that the original post asks explicitly for no ternary operators.]
Vlad
Nice and simple solution. Now that I see it it seems so simple. This was a good learning experience at least for me. Thanks.
Fdr
@Fdr No problem, I think this was an interesting problem as well!
Andreas Brinck
@Andreas could you give an example of "this formula won't work when the interval straddles 0."? AFAICS it works fine in any case if `end >= begin`, but you can't move `+2` out from `/2` as `+1` because this will break the formula for odd [a,a] ranges. This is the only case I can see when `-(begin % 2)` will make value in `/2` negative and "strange" division rules will apply. Did I miss something?
iPhone beginner
Christoffer Hammarström
@Christoffer Easier in what way?
Andreas Brinck
@iPhone beginner I was slightly incorrect, I should have written when `begin` is odd and negative. Try it with `[-1, 1]` it should evaluate to 2 on your favorite C compiler.
Andreas Brinck
iPhone beginner
A: 

I'd say

(max - min + 1 + (min % 2)) / 2

Edit: Erm okay for some reason I thought that (min % 2) returns 1 for even numbers.... :). The correct version is

(max - min + 1 + 1 - (min % 2)) / 2

or rather

(max - min + 2 - (min % 2)) / 2
Bus
What if `min` and `max` are both 1?
Arkku
Yes you're right, silly me. See above.
Bus
Doesn't work for (-3, -2)
Kirk Broadhurst
The requirements talk about unsigned integers ;). (Btw none of the methods here work for negative numbers because of the way division and modulo are handled for negative numbers in C.)
Bus
+2  A: 
int start, stop;
start = 0;
stop = 9;
printf("%d",(stop-start)/2+((!(start%2) || !(stop%2)) ? 1 : 0));

Where start and stop can hold any value. No need to iterate to to determine this number.

Andrei Ciobanu
+2  A: 

The count of even numbers between 0 and n is [n/2] + 1. Therefore the count of even numbers between (n + 1) and m is ([m/2] + 1) - ([n/2] + 1) = [m/2] - [n/2].

For count of even numbers between m and n the answer therefore would be [m/2] - [(n - 1)/2].

The [x] is taken to the direction of -\infty. Beware that the usual C integer division is not doing right in our case: a/2 is rounded towards zero, not -\infty, so the result will be not [a/2] for teh case of negative a.

This should be the simplest calculation; works for negative numbers, too. (Needs however that m >= n.) Doesn't contain ifs and ?:s.

If you don't consider negative numbers, you can use just m/2 - (n+1)/2 + 1, otherwise floor(m/2.0) - floor((n-1)/2.0)

Vlad
A: 

The range is always [2a+b, 2c+d] with b,d = {0,1}. Make a table:

b d | #even
0 0 | c-a+1
0 1 | c-a+1
1 0 | c-a
1 1 | c-a+1

Now a = min/2, b = min % 2, c = max/2 and d = max % 2.

So int nEven = max/2 - min/2 + 1 - (min%2)

Tobias Kienzler
Doesn't work for (-3,-2)
Kirk Broadhurst
nope, I didn't consider negative numbers, my mistake
Tobias Kienzler
A: 

The first even number in the range is: (begin + 1) & ~1 (round begin up to even number).

The last even number in the range is: end & ~1 (round end down to even number).

The total number of even numbers in the range is therefore: (end & ~1) - ((begin + 1) & ~1) + 1.

int num_evens = (end & ~1) - ((begin + 1) & ~1) + 1;
Paul R
Is the ~1 function defined? Nice clean algorithm but I do not know of such a function.
Kirk Broadhurst
@Kirk: `~` is the bitwise unary NOT operator in C/C++. So `~1` is an int with all but the LS bit set to 1.
Paul R
A: 

Let's look at this logically ...

We have four cases ...

odd -> odd     eg.  1 -> 3  answer: 1
odd -> even    eg.  1 -> 4  answer: 2
even -> odd    eg.  0 -> 3  answer: 2
even -> even   eg.  0 -> 4  answer: 3

The first three cases can be handled simply as ...

(1 + last - first) / 2

The fourth case does not fall quite so nicely into this, but we can fudge around a little bit for it quite easily ...

answer = (1 + last - first) / 2;
if (both first and last are even)
    answer++;

Hope this helps.

Sparky
+2  A: 

This'll do the trick, even for ranges with negative numbers.

int even = (last - first + 2 - Math.abs(first % 2) - Math.abs(last % 2)) / 2;

Tested with the following code:

public static void main(String[] args) {
    int[][] numbers = {{0, 4}, {0, 5}, {1, 4}, {1, 5}, {4, 4}, {5, 5},
                       {-1, 0}, {-5, 0}, {-4, 5}, {-5, 5}, {-4, -4}, {-5, -5}};

    for (int[] pair : numbers) {
        int first = pair[0];
        int last = pair[1];
        int even = (last - first + 2 - Math.abs(first % 2) - Math.abs(last % 2)) / 2;
        System.out.println("[" + first + ", " + last + "] -> " + even);
    }
}

Output:

[0, 4] -> 3
[0, 5] -> 3
[1, 4] -> 2
[1, 5] -> 2
[4, 4] -> 1
[5, 5] -> 0
[-1, 0] -> 1
[-5, 0] -> 3
[-4, 5] -> 5
[-5, 5] -> 5
[-4, -4] -> 1
[-5, -5] -> 0
Toon Van Acker
A: 

Oh well, why not:

#include <cassert>

int ecount( int begin, int end ) {
    assert( begin <= end );
    int size = (end - begin) + 1;
    if ( size % 2 == 0  || begin % 2 == 1 ) {
        return size / 2;
    }
    else {
        return size / 2 + 1;
    }
}

int main() {
    assert( ecount( 1, 5 ) == 2 );
    assert( ecount( 1, 6 ) == 3 );
    assert( ecount( 2, 6 ) == 3 );
    assert( ecount( 1, 1 ) == 0 );
    assert( ecount( 2, 2 ) == 1 );
}
anon
It makes sense but it's not a single line of code with `if` statements.
Kirk Broadhurst
It's the "easiest" solution, IMHO - which was the headline question. I can't see any possible reason for writing it as a one-liner.
anon
@Neil - there are plenty here! Surely one must be correct! ;) try mine, for example.
Kirk Broadhurst
@Kirk I didn't suggest they were incorrect.
anon
@Neil: My reason is curiosity. Not knowing a solution, doesn't mean that there isn't one.
Fdr
@Neil Without the one-line, no `if` requirement the problem is too easy.
Kirk Broadhurst
@Kirk artificially difficult problems are a waste of time, IMHO.
anon
A: 

The answer:

(max - min + 2 - (max % 2) - (min % 2)) / 2

A short explanation:

  • even..even yields (length + 1) / 2
  • even..odd yields length / 2
  • odd..even yields length / 2
  • odd..odd yields (length - 1) / 2

  • length = max - min + 1

Therefore, the answer is (length - 1) / 2 plus 1/2 for even min plus 1/2 for even max. Note that (length - 1) / 2 == (max - min) / 2, and the "bonuses" are (1 - (min % 2)) / 2 and (1 - (max % 2)) / 2. Sum this all up and simplify to obtain the answer above.

Bolo
Doesn't work for negatives, e.g. (-3,-2).
Kirk Broadhurst
Right. It should be: (max - min + 2 - (abs(max) % 2) - (abs(min) % 2)) / 2.
Bolo
On the other hand, the question explicitly states "a range of unsigned integers".
Bolo
+1  A: 

I'm a bit surprised that iteration was tried to solve this. The minimum number of even numbers possible in a range is equal to half of the length of the array of numbers, or, rangeEnd - rangeStart.
Add 1 if the first or last number is even.

So the method is: (using javascript)

function evenInRange(rangeStart, rangeEnd)
{
  return
    Math.floor(rangeEnd - rangeStart) + 
    ((rangeStart % 2 == 0) || (rangeEnd % 2 == 0) ? 1 : 0)
}


Tests:
0 1 2 3 4 5 6 7 8
8 - 0 = 8
8 / 2 = 4
4 + 1 = 5
Even numbers in range:
0 2 4 6 8

11 12 13 14 15 16 17 18 19 20
20 - 11 = 9
9 / 2 = 4
4 + 1 = 5
Even numbers in range
12 14 16 18 20

1 2 3
3 - 1 = 2
2 / 2 = 1
1 + 0 = 1
Even numbers in range
2

2 3 4 5
5 - 2 = 3
3 / 2 = 1
1 + 1 = 2
Even numbers in range
2 4

2 3 4 5 6
6 - 2 = 4
4 / 2 = 2
2 + 1 = 3
Even numbers in range
2 4 6
souLTower
Your tests all divide by 2 but your formula doesn't include a division at all.
Kirk Broadhurst
You're correct, it should say Math.floor((rangeEnd - rangeStart) / 2)Thanks
souLTower
A: 

There are (max - min + 1) numbers in the range for each case.

  • When the range is of an even length (starts with an even and ends with odd, or vice versa), there will be (max - min + 1)/2 even numbers in the range.
  • When the range begins and ends with an odd, there will be (max - min + 1 - 1)/2, but because (max - min + 1) is odd, (max - min + 1)/2 will round down to the correct answer.
  • When the range both begins and ends with an even, we need to add 1 to the answer. We need to test the max and min for 'evenness'. For a number i, if it's even then (i+1)%2 == 1. So if both max and min are even, then (max + 1)%2 * (min + 1)%2 == 1. Luckily we want to add 1 when both max and min are even, so we just add this to our (max + min + 1)/2 formula.

The nicely derived and easy to explain answer is

(max - min + 1)/2 + (max + 1)%2 * (min + 1)%2

edit:

(max - min + 1)/2 + Math.Abs((max + 1)%2 * (min + 1))%2

or (max - min + 1)/2 + |(max + 1)%2 * (min + 1)|%2

will fix the problem Vlad identifies, when min is negative and max is positive.

Kirk Broadhurst
@Kirk: for `i=-2`, `(i+1)%2 == -1`. :-(
Vlad
@Vlad - thanks, I didn't properly derive that part. Fixed now.
Kirk Broadhurst
A: 

In terms of start and length:

(length >> 1) + (1 & ~start & length)

half the length plus 1 if start is even and length is odd.

In terms of start and end:

((end - start + 1) >> 1) + (1 & ~start & ~end)

half the length plus 1 if start is even and end is even.

Christoffer Hammarström
I'm a bit proud of using bitwise AND as a conditional actually. :)
Christoffer Hammarström
A: 

This does not require any conditions at all:

evencount = floor((max - min)/2) + 1
jmucchiello