Cyclomatic Complexity in Visual Studio - c#

I do some tests with Visual Studio Code Metrics. As I can calculate the Cyclomatic Complexity, each if, while, for - operators increase the complexity with 1. I have the next simple method:
static bool ContainsNegative(int a, int b, int c, int d)
{
if (a < 0 || b < 0 || c < 0 || d < 0) return false;
return true;
}
But for it, the Cyclomatic Complexity is 5, instead of 2 (1 for the method + 1 for the if).
My question is - this is because the Code Metrics calculate each condition in if operator as a different if? I.e. my method is equivalent to:
static bool ContainsNegative(int a, int b, int c, int d)
{
if (a < 0) return false;
if (b < 0) return false;
if (c < 0) return false;
if (d < 0) return false;
return true;
}
Here is a screen with results:
Also, is there a list with all rules described in details?
Thank you!

Cyclomatic Complexity measures the number of paths through a function. As you suggest that means that a 1 is added for each control flow statement plus 1 for each logical NOT, AND and OR in each condition.
What the value of 5 is telling you is that you will need 5 unit tests in order to get 100% code coverage of your function.

Related

Test a subtraction and apply it if the result is greater than zero

I'm minimalist and I want that my code has as less lines as possible. In every code I write, my goal is to use as much one-lined instructions as possible and avoiding any recurrent code.
Today I'm facing a problem, I'm not able to reduce an instruction even if I'm convinced it's possible.Let's have a look at my instruction :
if((level - 2) >= 0)
{
level -= 2;
}
If know I can use a one-lined affectation in the if like that :
if((level -= 2) >= 0)
But the subtraction while be always applied even if the test is false.
How can I compact this instruction in one line ?
EDIT
I can't use ternary operator because I have to keep the if instruction. Basically I have to execute several operations if the test is true, I just simplified my code to post it.
You could use the ternary operator like this
level -= level - 2 >= 0 ? 2 : 0;
or simpler
level -= level >= 2 ? 2 : 0;
But I don't think that making everything as "short " as possible is the right way to go.
Only subtract when the level is larger or equal to the value you would subtract.
if(level >= 2)
{
level -= 2;
}
Write a general function:
public static bool TryToSubtract(ref int from, int value)
{
bool result = false;
if (from >= value)
{
from -= value;
result = true;
}
return result;
}
and then use that
TryToSubtract(ref level, 2);
You can then even make further statements based on the outcome:
if(TryToSubtract(ref level, 2))
{
Console.WriteLine("Your level was reduced!");
Console.WriteLine("You loser!");
}
If you can live without curlies and newlines, then this could be the shortest, and still very readable (IMHO):
if (level >= 2) level -= 2;

Can't understand the code snippet

I am doing some basic C# exercises to learn C#.The website provides the solutions to the problems too however, I am unable to understand the code.
Problem:
Write a C# program to check if an integer is within 20 of 100 or 200.
Sample Output:
Input an integer
25
False
Solution:
public class Exercise22
{
static void Main(string[] args)
{
Console.WriteLine("\nInput an integer:");
int x = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(result(x));
}
public static bool result(int n)
{
//Can't understand the code below -
//why is the "<=10" and "return false" used
if (Math.Abs(n - 100) <= 10 || Math.Abs(n - 200) <= 10)
return true;
return false;
}
}
Math.Abs() gives you the absolute value of the argument.
If n is between 90 and 110 (within 20 around 100), then n-100 is between -10 and 10, so Math.Abs() will return a value between 0 and 10.
The same is done for 200.
You could however simplify this to:
return Math.Abs(n-100) <= 10 || Math.Abs(n-200) <= 10;
So if n is in one of the ranges, true is returned and the function ends.
Otherwise, the function skips the return true and continues to return false.
if is obviously a condition, following statements are only executed when the condition passes. In your case execution will leave the method by executing return true.
I assume you think you´d need an else to indicate what happens when the condition does not pass. Usually this is right. However in this special case there´s no way to reach the return false-statement when the if passes, as in this case (as described earlier) the method will terminate.
So you could also write this, which is completely identical:
if (Math.Abs(n - 100) <= 10 || Math.Abs(n - 200) <= 10)
return true;
else
return false;
So all in all there´s no other way that the return false-statement is executed than the condition evaluating to false.

Compare strings in C# like in SQL

Good day for all ;)
Can anyone help me to find algorithms or already resolved solutions for comparing strings like SQL do it.
For instance
In SQL I can compare strings for
= or <=, >, <
e.t.c.
In C# as known we can't do it.
I want to compare something like
"aa" > "b" "ab" < "aa" "abc" >= "bca" and so on..
Also, maybe someone knows by what logic SQL does it?
Strings implement IComparable, so you can use CompareTo.
void Main()
{
if ("a".CompareTo("b") < 0)
{
Console.WriteLine("A is less than B");
}
if ("a".CompareTo("b") <= 0)
{
Console.WriteLine("A is less than or equal to B");
}
if ("a".CompareTo("a") == 0)
{
Console.WriteLine("A equals A");
}
if ("c".CompareTo("b") > 0)
{
Console.WriteLine("C is greater than B");
}
if ("c".CompareTo("b") >= 0)
{
Console.WriteLine("C is greater than or equal to B");
}
}
However, if you want case-insensitive comparison then you will need to use the overload of string.Compare that allows you to ignore case. The logic is the same though.
Well, "aa" < "ab" equals to
bool result = String.Compare("aa", "ab") < 0;
and so on:
// "abc" >= "bca"
bool result = String.Compare("abc", "bca") >= 0;
the general pattern for "left" <=> "right" is
String.Compare("left", "right") <=> 0
since String.Compare(left, right) returns
negative value (say, -123) when left < right
zero when left == right
postivie value (e.g. 789) when 'left > right'

C# Multiple If statement replacement

I am trying to make a practice program that calculates a persons overall grade. The test consists of three parts each with different weightings. Part 1 is worth 5 grades, part two 3 grades and part 3 is worth 2 grades.
So if a person got A B C they would receive 5A 3B and 2C.
Now, in order to receive and A/B/C overall requires a certain amount of each grade. For example in order to receive an A overall you need to have at least 5A's and 7 of the grades must be B or higher and all the grades need to be C or or higher.
B, C, D etc all have their own requirements too.
What is the best way to code this as at the moment I am using a counter for each grade and then doing if/else if statements to check the amount of each grade a person has got like so:
if (aGradeCount >= 5)
{
//Add total grade
}
}
}
//To receive a B
if(bGradeCount >= 3 && aGradeCount <5 && cGradeCount >=2)
{
if(bGradeCount + cGradeCount +dGradeCount + aGradeCount>= 7)
{
if(dGradeCount <= 3)
{
//Add new total grade
}
}
}
Now I understand this is terrible practice, but how can I code this better? Using a switch statement? If so how do I go about doing that?
how can I code this better?
Write a specification. Then for every concept mentioned in the specification, write a method. Here's part of a specification; you already wrote it:
in order to receive an A overall you need to have at least 5 A's and least 7 of the grades must be B or higher and all the grades need to be C or better.
Break it down
in order to receive an A overall
at least 5 A's AND
at least 7 of the grades must be B or higher AND
all the grades need to be C or better
OK, now we can start turning that into a method:
static bool QualifiesForA(int aCount, int bCount, int cCount, int dCount)
{
// In order to receive an A overall we require:
// TODO: at least 5 A's AND
// TODO: at least 7 of the grades must be B or higher AND
// TODO: all the grades need to be C or better
// If these conditions are not met then an A is not earned.
return false;
}
All right we have turned our specification into code. Wrong code, but code. Let's keep going. We have a line of a specification. Write a method:
static bool AtLeastFiveA(int aCount)
{
return aCount >= 5;
}
Hey, that was a correct method. We are making progress. Now use it:
static bool QualifiesForA(int aCount, int bCount, int cCount, int dCount)
{
// In order to receive an A overall we require:
// at least 5 A's AND
// TODO: at least 7 of the grades must be B or higher AND
// TODO: all the grades need to be C or better
bool atLeast5A = AtLeastFiveA(aCount);
// If these conditions are not met then an A is not earned.
return false;
}
Now we have another problem. At least 7 are B or higher. OK, write a method:
static bool AtLeastSevenB(int aCount, int bCount)
{
return aCount + bCount >= 7;
}
Another correct method! Use it!
static bool QualifiesForA(int aCount, int bCount, int cCount, int dCount)
{
// In order to receive an A overall we require:
// at least 5 A's AND
// at least 7 of the grades must be B or higher AND
// TODO: all the grades need to be C or better
bool atLeast5A = AtLeastFiveA(aCount);
bool atLeast7B = AtLeastSevenB(aCount, bCount);
// If these conditions are not met then an A is not earned.
return false;
}
Now we need the last bit:
static bool NoD(int dCount)
{
return dCount == 0;
}
Put it together.
static bool QualifiesForA(int aCount, int bCount, int cCount, int dCount)
{
// In order to receive an A overall we require:
// at least 5 A's AND
// at least 7 of the grades must be B or higher AND
// all the grades need to be C or better
bool atLeast5A = AtLeastFiveA(aCount);
bool atLeast7B = AtLeastSevenB(aCount, bCount);
bool noD = NoD(dCount);
if (atLeast5A && atLeast7B && noD)
return true;
// If these conditions are not met then an A is not earned.
return false;
}
Now, the question to ask yourself is:
Is this code correct? GET IT CORRECT FIRST. This code is very verbose but I'll tell you right now, it exactly matches the specification you gave.
Once the code is correct, can we make it more clear?
Yes; we could for instance say:
static bool QualifiesForA(int aCount, int bCount, int cCount, int dCount)
{
// In order to receive an A overall we require:
// at least 5 A's AND
// at least 7 of the grades must be B or higher AND
// all the grades need to be C or better
bool atLeast5A = AtLeastFiveA(aCount);
bool atLeast7B = AtLeastSevenB(aCount, bCount);
bool noD = NoD(dCount);
return atLeast5A && atLeast7B && noD;
}
And now maybe you will say, you know, some of these methods are unnecessary abstractions, maybe I can just replace them with their bodies:
static bool QualifiesForA(int aCount, int bCount, int cCount, int dCount)
{
// In order to receive an A overall we require:
// at least 5 A's AND
// at least 7 of the grades must be B or higher AND
// all the grades need to be C or better
bool atLeast5A = aCount >= 5;
bool atLeast7B = aCount + bCount >= 7;
bool noD = dCount == 0;
return atLeast5A && atLeast7B && noD;
}
The point is: we start from a very verbose, CLEARLY CORRECT program, and then we make small, simple, clearly correct transformations to make it more concise. When you think you have a good balance of concision and readability, stop.
OK, now you have solved the problem of "did we earn an A?" Now you do "did we earn a B?" and so on. Write a specification for every part, and then write code that clearly implements the specification.
This sounds like a heavyweight process, but this will pay huge dividends as you learn how to program. Your code will be better organized, it will be less buggy, it will be easier to read and understand and modify.
The point of this technique is to focus on obvious correctness of every part. Always concentrate on obvious correctness. A program which is correct but you cannot tell it is correct is a program that might not be correct! Always concentrate on correctness first. Making a wrong program more elegant, or faster, or more feature complete means that you have an elegant, fast, rich-featured bug farm.
Summing up:
Write clear specifications.
Write code to clearly match the spec.
Tiny methods are A-OK. You can always eliminate them later.
Correctness is more important than everything else; make the code better once you know it is correct.
I don't know if that's terrible practice. It's a little unnecessary, since there's nothing else in the block, but another if statement. You can use more && operators and parenthesis if you just want to use one if statement.
if ((bGradeCount >= 3 && aGradeCount <5 && cGradeCount >=2) &&
(bGradeCount + cGradeCount +dGradeCount + aGradeCount>= 7) &&
(dGradeCount <= 3))
{
char b = 'B';
person.TotalGrade = b.ToString();
}
For code clarity I would do this that way :
//Main function
{
///code
if(MethodWhichDescribesLogic(aGradeCOunt,bGradeCount,cGradeCount,dGradeCount){
char b = 'B';
person.TotalGrade = b.ToString();
}
}
Then in some place else :
bool MethodWhichDescribesLogic(type aGradeCount, type bGradeCount, type cGradeCount, type dGradeCount){
return
(PassingGrade(bGradeCount,aGradeCount,cGradeCount) &&
GoodGradesType(bGradeCount,cGradeCount,dGradeCount,aGradeCount) &&
dGradeCount <= 3);
}
bool PassingGradesCount(type bGradeCount,type aGradeCount,type cGradeCount)
{
return bGradeCount >= 3 && aGradeCount <5 && cGradeCount >=2;
}
bool GoodGradesCount(type cGradeCount,type bGradeCount,type aGradeCount,type dGradeCount)
{
return bGradeCount + cGradeCount +dGradeCount + aGradeCount>= 7;
}
Remember that every if-else switches can be replaced by conditional table.
So if overall grades count would be like 10. It could be
A B C Overall
5 7 10 A
4 7 10 B
Then you make array of it and find where you are in the array.
For example (I admit that I'm puzzled by your example so I might get it wrong here.):
var grades = new[]{
new { A = 5. B = 7, C = 10, Overall = "A"},
new { A = 4, B = 7, C = 10, Overall = "B"},
...
}
var myGrade = grades.FirstOrDefault(g => myA >= g.A && myB >= g.B && enoughC)
With proper formatting it looks much better than tons of if's. And you always have your choice table in front of you.
Firstly, make use of Boolean Algebra in the OverallGrade() to see which cases you don't need to consider. For example, if for checking an A grade you have already seen that gradeDistribution.A >= 5, don't test gradeDistribution.A < 5 when testing for grade 'B' as it is obvious that if you are testing the case for B, you have already tested gradeDistribution.A < 5 as true.
Next, put the grade calculation in another method and make that method return as early as possible.
Finally, in order to get the overall grade, you may write the method as:
private static char OverallGrade(int partA, int partB, int partC)
{
//Now in this method, check one by one which
//overall grade the provided values fall in
//Call another method to get count of individual As, Bs, Cs etc
var gradeDistribution = GetIndividualCount(partA, partB, partC);
//Now, first check for A and return immediately if true
if (gradeDistribution.A >= 5) return 'A';
//Now, check for B and again return if the values satisfy for B
if (gradeDistribution.B >=3
&& gradeDistribution.C <= 2
&& gradeDistribution.D <= 3
&& ...)
return 'B';
//Keep adding for each case and return as soon as you find the grade.
}
Now, the class GradeDistribution, whose variable we have used above can be created which will hold count of each grade:
public class GradeDistribution
{
public int A; //Count for Grade A
public int B; //Count for Grade B
public int C; //Count for Grade C
public int D; //Count for Grade D
}
The above code is an example of introducing a class for an entity that does not exist in real world.
Next, GetIndividualCount() can be written as:
private static GradeDistribution GetIndividualCount(int partA, int partB, int partC)
{
var gradeDistribution = new GradeDistribution();
/*
Calculate and assign values to gradeDistribution.A, gradeDistribution.B...
*/
return gradeDistribution;
}

Project Euler 10: simple code is not giving the desired result, need help understanding why

I'm solving Project Euler problems for kicks, I'm currently at number 10.
First of all: I know there are other solutions, I'm currently writing another method using the sieve of Eratosthenes. What I'd like your help with is understanding why this code does not work.
This is my code (the problems involves finding the sum of every prime under 2 million). The prime-checking method seems to work fine, but the result is way less than it should be.
class Euler10
{
public static void Main()
{
long sum = 0; // Was originally an int. Thanks Soner Gönül!
for(int i = 1; i < 2000000; i++)
{
if (CheckIfPrime(i) == true)
sum += i;
}
System.Console.WriteLine(sum);
System.Console.Read();
}
static bool CheckIfPrime(int number)
{
if (number <= 1)
return false;
if (number == 2)
return true;
if (number % 2 == 0)
return false;
for (int i = 3; i*i < number; i += 2)
{
if ((number % i) == 0)
return false;
}
return true;
}
}
The number I get is 1,308,111,344, which is two orders of magnitude lower than it should be. The code is so simple I am baffled by this error.
EDIT: making sum a long solved the digit problem, thanks everyone! Now, though, I get 143042032112 as an answer: the i*i in CheckIfPrime() isn't always right.
Using the sqrt() function and adding one (to compensate for the int cast) gives the correct result. Here's the correct CheckIfPrime() function:
bool CheckIfPrime(int number)
{
if (number <= 1)
return false;
if (number == 2)
return true;
if (number % 2 == 0)
return false;
int max = 1 + (int)System.Math.Sqrt(number);
for (int i = 3; i < max; i += 2)
{
if ((number % i) == 0)
return false;
}
return true;
}
EDIT 2: Will Ness helped me optimize the code further (calculating number's square root and comparing it to i is slower than elevating i^2 and then comparing it to number): the problem with the original method is that it didn't take into consideration edge cases in which number is the exact square of i, thus sometimes returning true instead of false. The correct code for CheckIfPrime(), then, is:
bool CheckIfPrime(int number)
{
if (number <= 1)
return false;
if (number == 2)
return true;
if (number % 2 == 0)
return false;
for (int i = 3; i*i <= number; i += 2)
{
if ((number % i) == 0)
return false;
}
return true;
}
Thanks again people!
Your code does not work because it tries using a 32-bit int to hold a number that exceeds the highest value in a 32-bit variable. The answer to the problem is 142,913,828,922, which needs 38 bits.
Changing the data type of sum to long should fix this problem.
Using long should help.http://msdn.microsoft.com/en-us/library/ctetwysk.aspx
Gives you a 64 bit integer where as int is only 32 bits.
You are using int for sum variable which is 32-bit but you are try to assign it more than Int32.Maximum which is 2,147,483,647.
But your result is 143,042,032,112 which needs more bits than 32 for storing it.
Set its type as long which stores 64 bit.
long sum = 0;
Here a working DEMO.
for (... i=3 ; i*i < number; i+=2 ) is wrong. It should be
for (... i=3 ; i*i <= number; i+=2 )
...
both i and number must be of the same type of course; this will almost never give you an overflow, since you start from 3 (unless number is very big, close to the upper limit of the type's range).
The comparison should be inclusive to catch cases where number is a square of a prime.
Your algorithm is not the Sieve of Eratosthenes; the modulo operator gives it away. Your algorithm is trial division by odd numbers. Here is a function using the Sieve of Eratosthenes:
function sumPrimes(n)
sum := 0
sieve := makeArray(2..n, True)
for p from 2 to n step 1
if sieve[p]
sum := sum + p
for i from p * p to n step p
sieve[i] := False
return sum
Calling sumPrimes(2000000) gives the answer, which I won't write down out of respect for Project Euler. That function runs in time O(n log log n), which is much better than the O(n^2) of your original program. There are better ways to sieve, but that is simple, and easy to get right, and good enough for most purposes, including yours. You should get an answer in less than a second.
I'll leave it to you to translate to C# with appropriate data types.
If you're interested in a somewhat larger version of this problem, I calculated the sum of the first billion primes at my blog: 11138479445180240497.

Categories

Resources