Cyclomatic Complexity of switch case statement - cyclomatic-complexity

I'm confusing about the CC of switch statement
If I have following code:
if (n >= 0) {
switch(n) {
case 0:
case 1:
printf("zero or one\n");
break;
case 2:
printf("two\n");
break;
case 3:
case 4:
printf("three or four\n");
break;
}
}
else {
printf ("negative\n");
}
what is the CC?
I found a post said that it's 5, with this diagram
(the edges are 17, not 16, I think it's a typo)
It says that we only need to count case 0 and case 1 as one
But I think the diagram should be:
Edges: 17,
Nodes: 13,
17 - 13 + 2P = 6
I count every cases as 1
My OOSE professor said it's 6, but in different way
He said:
init => 1
if => 1
switch => 1
case 0 1 => 1
case 2 => 1
case 3 4 => 1
so it should be 6
What's the correct answer?
I'm really confused, thanks.
edited:
Now I think it's 7. yes, 7
Because if n is more than 5, will just do nothing and exit the switch statement.
then we get this diagram:
now E = 18
18 - 13 + 2 = 7
am I correct..?
really, really, really confused...

Code metric tools I've worked with count each case as a separate branch, even if it's a fall through case.
But this is an arbitrary choice. Code metric tools tend to err on the side of caution by default. The way the switch statement will ultimately be evaluated is an internal implementation detail that will vary based on the type of input and number of cases (at least in C#).
The go-to answer for reducing cyclomatic complexity caused by switch statements is to convert the cases/outputs into a dictionary. In your example, it would be something like the code sample below. Be aware that this is only for readability/maintainability. If your switch statement is long enough the .Net compiler will automatically convert it to a dictionary for you, so there is no performance gain.
var outputs = new Dictionary<int, string>()
{
{ 0, "zero or one\n" },
{ 1, "zero or one\n" },
{ 2, "two\n" },
{ 3, "three or four\n" },
{ 4, "three or four\n" }
};
if (n >= 0)
{
printf(outputs[n]);
}

Ok, I have found the answer.
from McCabe.com, page 26 and 27
The answer is 5, because the original version of CC by McCabe counts a fall-through case as 1.

The correct answer is 7.
Each case within the switch statement counts as 1, therefore 5 x 1 = 5.
The if counts as 1.
The else counts as 1.
So,
1 + (5 x 1) + 1 = 7.
If you would count this as a method's body the cc would be 8 as the method counts as a straight through path.
Please change your accepted answer to the correct one as 5 is an incorrect answer.

Related

Find a random number generator using a given random number generating function

This is an interview question:
Given a function which generates a random number in [1,5],we need to use this function to generate a random number in the range [1,9].
I thought about it a lot but am not able to write an equation where ramdomness is satisfied.
People please answer.This might be helpful maybe in some future interviews.
Adapted from "Expand a random range from 1–5 to 1–7"
It assumes rand5() is a function that returns a statistically random integer in the range 1 through 5 inclusive.
int rand9()
{
int vals[5][5] = {
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 1 },
{ 2, 3, 4, 5, 6 },
{ 7, 8, 9, 0, 0 },
{ 0, 0, 0, 0, 0 }
};
int result = 0;
while (result == 0)
{
int i = rand5();
int j = rand5();
result= vals[i-1][j-1];
}
return result;
}
How does it work? Think of it like this: imagine printing out this double-dimension array on paper, tacking it up to a dart board and randomly throwing darts at it. If you hit a non-zero value, it's a statistically random value between 1 and 9, since there are an equal number of non-zero values to choose from. If you hit a zero, just keep throwing the dart until you hit a non-zero. That's what this code is doing: the i and j indexes randomly select a location on the dart board, and if we don't get a good result, we keep throwing darts.
this can run forever in the worst case, but statistically the worst case never happens. :)
int rand9()
{
int t1,t2,res = 10;
do {
t1 = rand5();
do {
t2 = rand5();
}while(t2==5);
res = t1 + 5* (t2%2);
}while(res==10);
return res;
}
now 1 to 9 has the probability of 1/9.
make some explanation:
t1 has probability of 1/5 to be 1 to 5.
t2,too.but when t2==5,discarded.so t2 has probability of 1/4 to be 1 to 4.that' to say, probability of 1/2 to be odd or even,which makes t2%2 has probability of 1/2 to be 0 to 1.
thus, t1 + 5*(t2%2) has probability of 5/10 to be 1 to 5, and 5/10 to be 6 to 10.
but 10 is discarded again,so the rest 9 numbers' probability is 1/9.
You need to use rejection sampling. That is, reject results that don't fit your target distribution. In your case you could use the lower three bits of two successive calls to your rand15 function (− 1 if necessary), concatenate them and reject those results that are outside your target interval and retry until you find a number that's inside.

Logic behind code of number of divisors of a number

EDIT The question was finding the divisors of numbers like 1,3,6,10,15 which follows n*(n+1)/2 pattern. I got the answer, thanks
I was going through this following code snippet by an experienced programmer.
int number = 0;
int i = 1;
while(NumberOfDivisors(number) < 500){
number += i;
i++;
I tried a lot but I cannot understand about the following part of code.
number += i;
i++;
Why doesn't he just increment number itself? If he uses the same code, won't some numbers miss during the execution? What is the logic behind it?
Here is the rest of the code
private int NumberOfDivisors(int number) {
int nod = 0;
int sqrt = (int) Math.Sqrt(number);
for(int i = 1; i<= sqrt; i++){
if(number % i == 0){
nod += 2;
}
}
//Correction if the number is a perfect square
if (sqrt * sqrt == number) {
nod--;
}
return nod;
}
I understood the above part. Can't understand the first part.
As one of the answer said
The iteration would look like this:
NumberOfDivisors(0)
0 += 1
NumberOfDivisors(1)
1 += 2
NumberOfDivisors(3)
3 += 3
NumberOfDivisors(6)
etc.
Why did he eliminate 2,4,5 etc???
The original author did that to solve this problem : Triangle number with 500 divisors. Follow the link to get the explanations, the code you posted is even there ...
The sequence of triangle numbers is generated by adding the natural numbers.
So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28.
The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, …
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?
He's not just incrementing it. He's adding i which get's bigger every time.
+= 1;
+= 2;
etc.
The iteration would look like this:
NumberOfDivisors(0)
0 += 1
NumberOfDivisors(1)
1 += 2
NumberOfDivisors(3)
3 += 3
NumberOfDivisors(6)
etc.
That is some kind of heuristic, since number of divisors grows non-linearly, it is better to check numbers in non-linear order. I do not see how it is connected to approximate growth rate, may be it is just a random-intuitive pick of the author.

Modifying the range of a uniform random number generator

I am given a function rand5() that generates, with a uniform distribution, a random integer in the closed interval [1,5]. How can I use rand5(), and nothing else, to create a function rand7(), which generates integers in [1,7] (again, uniformly distributed) ?
I searched stackoverflow, and found many similar questions, but not exactly like this one.
My initial attempt was rand5() + 0.5*rand5() + 0.5*rand5(). But this won't generate integers from 1 to 7 with uniform probability. Any answers, or links to answers, are very welcome.
Note that a prefect uniform distribution cannot be achieved with a bounded number of draw5() invocations, because for every k: 5^k % 7 != 0 - so you will always have some "spare" elements.
Here is a solution with unbounded number of draw5() uses:
Draw two numbers, x1,x2. There are 5*5=25 possible outcomes for this.
Note that 25/7 ~= 3.57. Chose 3*7=21 combinations, such that each combination will be mapped to one number in [1,7], for all other 4 numbers - redraw.
For example:
(1,1),(1,2),(2,1) : 1
(3,1),(1,3),(3,2): 2
(3,3),(1,4),(4,1): 3
(2,4),(4,2)(3,4): 4
(4,3), (4,4), (1,5): 5
(5,1), (2,5), (5,2) : 6
(5,3), (3,5), (4,5) : 7
(5,4),(5,5),(2,3), (2,2) : redraw
Here's a simple way:
Use rand5() to generate a sequence of three random integers from the set { 1, 2, 4, 5 } (i.e., throw away any 3 that is generated).
If all three numbers are in the set { 1, 2 }, discard the sequence and return to step 1.
For each number in the sequence, map { 1, 2} to 0 and { 4, 5 } to 1. Use these as the three bit values for a 3-bit number. Because the bits cannot all be 0, the number will be in the range [1, 7]. Because each bit is 0 or 1 with equal probability, the distribution over [1, 7] should be uniform.
ok I had to think about it for a while but it is actually not that hard. Imagine instead of rand5 you had rand2 which either outputs 0 or 1. You can make rand2 our of rand5 by simply doing
rand2() {
if(rand5() > 2.5) return 1
else return 0
}
now using rand2 multiple times do a tree to get rand7. For example if you start rand7 can be in [1,2,3,4,5,6,7] after a throw of rand2 which gives 0 you now subset to [1,2,3,4] and after another throw or rand2 which is 1 you subset to [3,4] and a final throw of 1 gives the output of rand7 to be 4. In general this tree trick can work to take a rand2 and map to randx where x is any integer.
Here's one meta-trick which comes in handy for lots of these problems: the bias is introduced when we treat the terms differently in some fashion, so if we treat them all the same at each step and perform operations only on the set, we'll stay out of trouble.
We have to call rand5() at least once (obviously!), but if we branch on that bad things happen unless we're clever. So instead let's call it once for each of the 7 possibilities:
In [126]: import random
In [127]: def r5():
.....: return random.randint(1, 5)
.....:
In [128]: [r5() for i in range(7)]
Out[128]: [3, 1, 3, 4, 1, 1, 2]
Clearly each of these terms was equally likely to be any of these numbers.. but only one of them happened to be 2, so if our rule had been "choose whichever term rand5() returns 2 for" then it would have worked. Or 4, or whatever, and if we simply looped long enough that would happen. So there are lots of way to come up with something that works. Here (in pseudocode -- this is terrible Python) is one way:
import random, collections
def r5():
return random.randint(1, 5)
def r7():
left = range(1, 8)
while True:
if len(left) == 1:
return left[0]
rs = [r5() for n in left]
m = max(rs)
how_many_at_max = rs.count(m)
if how_many_at_max == len(rs):
# all the same: try again
continue
elif how_many_at_max == 1:
# hooray!
return left[rs.index(m)]
# keep only the non-maximals
left = [l for l,r in zip(left, rs) if r != m]
which gives
In [189]: collections.Counter(r7() for _ in xrange(10**6))
Out[189]: Counter({7: 143570, 5: 143206, 4: 142827, 2: 142673, 6: 142604, 1: 142573, 3: 142547})

find the repetition of duplicate numbers

this is my algorithm that I have written it with my friends (which are in stackoverflow site)
this algorithm will find just the first duplicate number and returns it.this works in O(n)
I want to complete this algorithm that helps me to get duplicate numbers with their repetition. consider that I have [1,1,3,0,5,1,5]
I want this algorithm to return 2 duplicate numbers which are 1 and 5 with their repetition which is 3 and 2 respectively .how can I do this with O(n)?
1 Algorithm Duplicate(arr[1:n],n)
2
3 {
4 Set s = new HashSet();i:=0;
5 while i<a.size() do
6 {
7 if(!s.add(a[i)) then
8 {
9 return a[i]; //this is a duplicate value!
10 break;
11 }
12 i++;
13 }
14 }
You can do this in Java:
List<Integer> num=Arrays.asList(1,1,1,2,3,3,4,5,5,5);
Map<Integer,Integer> countNum=new HashMap<Integer, Integer>();
for(int n:num)
{
Integer nu;
if((nu=countNum.get(n))==null)
{
countNum.put(n,1);
continue;
}
countNum.put(n,nu+1);
}
Instead of iterating each time to get count of duplicate it's better to store the count in map.
Use a Map/Dictionary data structure.
Iterate over the list.
For each item in list, do a map lookup. If the key (item) exists, increment its value. If the key doesn't exist, insert the key and initial count.
In this particular instance it's not so much about the algorithm, it's about the data structure: a Multiset is like a Set, except it doesn't store only unique items, instead it stores a count of how often each item is in the Multiset. Basically, a Set tells you whether a particular item is in the Set at all, a Multiset in addition also tells you how often that particular item is in the Multiset.
So, basically all you have to do is to construct a Multiset from your Array. Here's an example in Ruby:
require 'multiset'
print Multiset[1,1,3,0,5,1,5]
Yes, that's all there is to it. This prints:
#3 1
#1 3
#1 0
#2 5
If you only want actual duplicates, you simply delete those items with a count less than 2:
print Multiset[1,1,3,0,5,1,5].delete_with {|item, count| count < 2 }
This prints just
#1 3
#2 5
As #suihock mentions, you can also use a Map, which basically just means that instead of the Multiset taking care of the element counting for you, you have to do it yourself:
m = [1,1,3,0,5,1,5].reduce(Hash.new(0)) {|map, item| map.tap { map[item] += 1 }}
print m
# { 1 => 3, 3 => 1, 0 => 1, 5 => 2 }
Again, if you only want the duplicates:
print m.select {|item, count| count > 1 }
# { 1 => 3, 5 => 2 }
But you can have that easier if instead of counting yourself, you use Enumerable#group_by to group the elements by themselves and then map the groupings to their sizes. Lastly, convert back to a Hash:
print Hash[[1,1,3,0,5,1,5].group_by(&->x{x}).map {|n, ns| [n, ns.size] }]
# { 1 => 3, 3 => 1, 0 => 1, 5 => 2 }
All of these have an amortized worst case step complexity of Θ(n).

puzzle using arrays

My first array M + N size and second array of size N.
let us say m=4,n=5
a[ ]= 1,3,5,7,0,0,0,0,0
b[ ]= 2,4,6,8,10
Now , how can i merge these two arrays without using external sorting algorithms and any other temporary array(inplace merge) but complexity should be o(n).Resultant array must be in sorted order.
Provided a is exactly the right size and arrays are already sorted (as seems to be the case), the following pseudo-code should help:
# 0 1 2 3 4 5 6 7 8
a = [1,3,5,7,0,0,0,0,0]
b = [2,4,6,8,10]
afrom = 3
bfrom = 4
ato = 8
while bfrom >= 0:
if afrom == -1:
a[ato] = b[bfrom]
ato = ato - 1
bfrom = bfrom - 1
else:
if b[bfrom] > a[afrom]:
a[ato] = b[bfrom]
ato = ato - 1
bfrom = bfrom - 1
else:
a[ato] = a[afrom]
ato = ato - 1
afrom = afrom - 1
print a
It's basically a merge of the two lists into one, starting at the ends. Once bfrom hits -1, there are no more elements in b so the remainder in a were less than the lowest in b. Therefore the rest of a can remain unchanged.
If a runs out first, then it's a matter of transferring the rest of b since all the a elements have been transferred above ato already.
This is O(n) as requested and would result in something like:
[1, 2, 3, 4, 5, 6, 7, 8, 10]
Understanding that pseudo-code and translating it to your specific language is a job for you, now that you've declared it homework :-)
for (i = 0; i < N; i++) {
a[m+i] = b[i];
}
This will do an in-place merge (concatenation).
If you're asking for an ordered merge, that's not possible in O(N). If it were to be possible, you could use it to sort in O(N). And of course O(N log N) is the best known general-case sorting algorithm...
I've got to ask, though, looking at your last few questions: are you just asking us for homework help? You do know that it's OK to say "this is homework", and nobody will laugh at you, right? We'll even still do our best to help you learn.
Do you want a sorted array ? If not this should do
for(int i=a.length-1,j=0;i >=0; i--)
{
a[i] = b[j++];
}
You can take a look at in-place counting sort that works provided you know the input range. Effectively O(n).

Resources