C# - Same Calculation Slower Using Int vs Long? - c#

I've run into something really strange while working my way through some practice problems using dotnetfiddle. I have a program that applies a mathematical sequence (different calculations each step depending on whether the current step is even or odd):
using System;
public class Program
{
public static void Main()
{
int ceiling = 1000000;
int maxMoves = 0;
int maxStart = 0;
int testNumber;
for(int i = 1; i <= ceiling; i++){
testNumber = i;
int moves = 1;
while(testNumber != 1){
if(testNumber % 2 == 0){
testNumber = testNumber / 2;
moves++;
} else {
testNumber = (3 * testNumber) + 1;
moves++;
}
}
if(moves > maxMoves){
maxMoves = moves;
maxStart = i;
}
}
Console.WriteLine(maxStart);
Console.WriteLine(maxMoves);
}
}
As written, the execution time limit gets exceeded. However, if I change the declaration of test number to a long instead of an int, the program runs:
int maxMoves = 0;
int maxStart = 0;
**long** testNumber;
Why would making this change, which requires recasting i from an int to a long each increment of the for loop (at testNumber = i), be faster than leaving this as an int? Is performing the mathematical operations faster on a long value?

The reason seems to be an overflow. If you run that code enclosed in a
checked
{
// your code
}
you get an OverflowException when running with testNumber as int.
The reason is that eventually 3*testNumber+1 exceeds the boundary of an int. In an unchecked context this does not throw an exception, but leads to negative values for testNumber.
At this point your sequence (I think it's Collatz, right?) does not work anymore and the calculation takes (probably infinitly) longer, because you never reach 1 (or at least it takes you a whole lot more iterations to reach 1).

Related

Dividing 2 integer without using / operator using c#. Can anyone convert this to for loop [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Can I ask for this question to be deleted? To help me recover my account. Thank you
int[] numbers = { 200, 100, 50, 3, 1 };
int count = int.Parse(txtNumber.Text);
double number = 0;
double number1 = 0;
double number2 = 0;
double number3 = 0;
double number4 = 0;
if (count == 0)
{
MessageBox.Show("Can't Divide 0");
return;
}
while (count >= numbers[0])
{
count = count - numbers[0];
number++;
}
txt200.Text = number.ToString();
label1.Text = count.ToString();
while (decimal.Parse(label1.Text) >= numbers[1])
{
label1.Text = (int.Parse(label1.Text) - numbers[1]).ToString();
number1++;
}
txt100.Text = number1.ToString();
Can somebody help me to vote this for deletion??
You can do it with an empty for loop, where all the operations occur in the loop's condition and the iterator:
int result = 1;
for (int numCopy = numerator; numCopy > denominator; numCopy -= denominator, result++);
Here's a sample method:
public static int Divide(int numerator, int denominator)
{
int result = 0;
for (; numerator >= denominator; numerator -= denominator, result++) ;
return result;
}
Note that I'm working only with integers here. Converting strings to integers and then back to strings again inside a loop is not very efficient. Now we can convert the Text properties once, pass the integers to our method, and then convert the result once.
Here's a sample usage (using a Console application):
static void Main()
{
int numerator = GetIntFromUser("Please enter the numerator: ");
int denominator = GetIntFromUser("Please enter the denominator: ");
int result = Divide(numerator, denominator);
Console.WriteLine($"{numerator} / {denominator} = {result}");
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
Oh, and these are the helper methods I'm using:
private static int GetIntFromUser(string prompt)
{
int input;
do
{
Console.Write(prompt);
} while (!int.TryParse(Console.ReadLine(), out input));
return input;
}
private static ConsoleKeyInfo GetKeyFromUser(string prompt)
{
Console.Write(prompt);
var key = Console.ReadKey();
Console.WriteLine();
return key;
}
A typical while-loop looks like this:
// Initialize loop variable
int i = 0;
while (i < count) // Test loop condition
{
//TODO: Do some work.
// Increment loop variable
i++;
}
The for-loop allows you to initialize, test and increment the loop variable at one spot
for (int i = 0; i < count; i++) {
//TODO: Do some work.
}
But while-loops seem appropriate here. If you extract the calculation into a function, you can reuse it. This is better than copy-pasting the code to apply it to several inputs.
private static int Divide(int dividend, int divisor)
{
int result = 0;
int remainder = dividend;
while (remainder >= divisor) {
remainder -= divisor;
result++;
}
Console.WriteLine($"{dividend} / {divisor} = {result}, remainder = {remainder}");
return result;
}
Don't assign the label text inside the loop, as the label will only keep the last assignment. Also, labels are not a good place to store numbers.
Convert all the numbers that are in labels and textboxes to integers before you start any calculation.
Do the calculations without referencing any UI controls.
Convert and assign the result of the calculations to labels and textboxes.
Mixing UI stuff and calculations makes the code unnecessarily complicated and difficult to read.
Give speaking names to controls and variables. Nobody knows what a textbox named txt3, a label named label1 or a variable named number2 are supposed to represent. Good names are txtDividend, txtResult or dividend and result for the respective variables.

Current code to generate array filled with unique ints crashes

(this is a library)
The function GetUniqueInt is being called with (5, 5) as the variables.
Currently the code will stall unity to a complete halt, or crash my PC with a memory overflow error.
Does anyone have any ideas as to how I could prevent it from crashing or what is making it crash?
using UnityEngine;
namespace MajorSolution
{
public static class MajorMath
{
public static int[] GetUniqueInt(int intCount, int intLength)
{
int[] returnValue = new int[intCount];
int[] temp = new int[intLength];
for (int a = 0; a < intCount; a++)
{
string create = new string("create".ToCharArray());
switch (create)
{
case "create":
returnValue[a] = GetRandomInt(intCount);
goto case "check";
case "check":
bool alreadyTaken = false;
for (int c = 0; c < returnValue.Length - 1; c++)
{
if (returnValue[a] == returnValue[c])
{
// Already Taken!
alreadyTaken = true;
}
}
if (!alreadyTaken)
{
break;
}
else
{
goto case "create";
}
}
}
Debug.Log(returnValue);
return returnValue;
}
public static int GetRandomInt(int intCount)
{
int[] storage = new int[intCount];
int returnValue = 0;
for (int i = 0; i < intCount; i++)
{
storage[i] = (Mathf.FloorToInt(Random.Range(0, 9)) * (int)Mathf.Pow(10,i));
returnValue += storage[i];
}
return returnValue;
}
}
}
Edit I just realized I did not exactly answer the question of why it is bringing the PC to a halt because you have an infinite loop in the code.
The problem is occurring in the following lines of code, notice what is happening.
case "create":
returnValue[a] = GetRandomInt(intCount);
goto case "check";
In the above block of code you are generating a number and putting it in the returnValue array. Now you jump into your "check" block
case "check":
bool alreadyTaken = false;
for (int c = 0; c < returnValue.Length - 1; c++)
{
if (returnValue[a] == returnValue[c])
{
// Already Taken!
alreadyTaken = true;
}
}
In this block of code you are looping over the entire returnValue array including the value you just inserted in it. Basically you are looping over the array asking if a value that you just put in the array is in the array.
Without knowing exactly what you are trying to do with these methods, I will just make a simple fix suggestion with some minor cleanup
public static int[] GetUniqueInt(int count, int length)
{
var returnValue = new int[count];
var values = new HashSet<int>(); // Used to track what numbers we have generated
for (int i = 0; i < count; ++i)
{
// Generate the number and check to be sure we haven't seen it yet
var number = GetRandomInt(length);
while(values.Contains(number)) // This checks if the number we just generated exists in the HashSet of seen numbers
{
// We get here if the HashSet contains the number. If we have
// seen the number then we need to generate a different one
number = GetRandomInt(length);
}
// When we reach this point, it means that we have generated a new unique number
// Add the number to the return array and also add it to the list of seen numbers
returnValue[a] = number;
values.Add(number); // Adds the number to the HashSet
}
Debug.Log(returnValue);
return returnValue;
}
I did end up removing the using of intLength but from your posted code it was only used to declare a temp array which itself was never used. Based on that, I just removed it entirely.
Based on your comment I updated the fix to use intLength. I made one other minor change. I removed int from the variable names of count and length. Hungarian notation is a lot less common in C# code. Personally, I feel like the code is cleaner and easier to read without the Hungarian notation. The key is to use good variable names that express the intent or make it easier to follow. In this case count is the count (read total number) of numbers you want returned and length is the length of the number. You could consider maybe even renaming that to numberOfDigits to make it clearer that the idea is you are going to create a random number with that number of digits in it.

Optimizing the search for prime numbers

I created a function for finding Prime Numbers, but the process takes a long time and uses a lot of memory. I need to optimize my code by making it more time and memory efficient.
The function is split into two parts:
The 1st part calculates odd numbers, the 2nd part is the isSimple method which searches for odd numbers that are prime.
I made some progress by moving the Math.Sqrt(N) outside of the for loop, but I'm not sure what to do next.
Any suggestions are welcome.
Program:
class Program
{
static void Main(string[] args)
{
//consider odd numbers
for (int i = 10001; i <=90000; i+=2)
{
if (isSimple(i))
{
Console.Write(i.ToString() + "\n");
}
}
}
//The method of finding primes
private static bool isSimple(int N)
{
double koren = Math.Sqrt(N);
// to verify a prime number or not enough to check whether it is //divisible number on numbers before its root
for (int i = 2; i <= koren; i++)
{
if (N % i == 0)
return false;
}
return true;
}
}
You are checking all possible divisors with your for (int i = 2; i <= koren; i++) That wastes time. You can halve the time taken by checking only odd divisors. You know that the given number N is odd, so no even number can be a divisor. Try for (int i = 3; i <= koren; i+=2) instead.

Code sample that shows casting to uint is more efficient than range check

So I am looking at this question and the general consensus is that uint cast version is more efficient than range check with 0. Since the code is also in MS's implementation of List I assume it is a real optimization. However I have failed to produce a code sample that results in better performance for the uint version. I have tried different tests and there is something missing or some other part of my code is dwarfing the time for the checks. My last attempt looks like this:
class TestType
{
public TestType(int size)
{
MaxSize = size;
Random rand = new Random(100);
for (int i = 0; i < MaxIterations; i++)
{
indexes[i] = rand.Next(0, MaxSize);
}
}
public const int MaxIterations = 10000000;
private int MaxSize;
private int[] indexes = new int[MaxIterations];
public void Test()
{
var timer = new Stopwatch();
int inRange = 0;
int outOfRange = 0;
timer.Start();
for (int i = 0; i < MaxIterations; i++)
{
int x = indexes[i];
if (x < 0 || x > MaxSize)
{
throw new Exception();
}
inRange += indexes[x];
}
timer.Stop();
Console.WriteLine("Comparision 1: " + inRange + "/" + outOfRange + ", elapsed: " + timer.ElapsedMilliseconds + "ms");
inRange = 0;
outOfRange = 0;
timer.Reset();
timer.Start();
for (int i = 0; i < MaxIterations; i++)
{
int x = indexes[i];
if ((uint)x > (uint)MaxSize)
{
throw new Exception();
}
inRange += indexes[x];
}
timer.Stop();
Console.WriteLine("Comparision 2: " + inRange + "/" + outOfRange + ", elapsed: " + timer.ElapsedMilliseconds + "ms");
}
}
class Program
{
static void Main()
{
TestType t = new TestType(TestType.MaxIterations);
t.Test();
TestType t2 = new TestType(TestType.MaxIterations);
t2.Test();
TestType t3 = new TestType(TestType.MaxIterations);
t3.Test();
}
}
The code is a bit of a mess because I tried many things to make uint check perform faster like moving the compared variable into a field of a class, generating random index access and so on but in every case the result seems to be the same for both versions. So is this change applicable on modern x86 processors and can someone demonstrate it somehow?
Note that I am not asking for someone to fix my sample or explain what is wrong with it. I just want to see the case where the optimization does work.
if (x < 0 || x > MaxSize)
The comparison is performed by the CMP processor instruction (Compare). You'll want to take a look at Agner Fog's instruction tables document (PDF), it list the cost of instructions. Find your processor back in the list, then locate the CMP instruction.
For mine, Haswell, CMP takes 1 cycle of latency and 0.25 cycles of throughput.
A fractional cost like that could use an explanation, Haswell has 4 integer execution units that can execute instructions at the same time. When a program contains enough integer operations, like CMP, without an interdependency then they can all execute at the same time. In effect making the program 4 times faster. You don't always manage to keep all 4 of them busy at the same time with your code, it is actually pretty rare. But you do keep 2 of them busy in this case. Or in other words, two comparisons take just as long as single one, 1 cycle.
There are other factors at play that make the execution time identical. One thing helps is that the processor can predict the branch very well, it can speculatively execute x > MaxSize in spite of the short-circuit evaluation. And it will in fact end up using the result since the branch is never taken.
And the true bottleneck in this code is the array indexing, accessing memory is one of the slowest thing the processor can do. So the "fast" version of the code isn't faster even though it provides more opportunity to allow the processor to concurrently execute instructions. It isn't much of an opportunity today anyway, a processor has too many execution units to keep busy. Otherwise the feature that makes HyperThreading work. In both cases the processor bogs down at the same rate.
On my machine, I have to write code that occupies more than 4 engines to make it slower. Silly code like this:
if (x < 0 || x > MaxSize || x > 10000000 || x > 20000000 || x > 3000000) {
outOfRange++;
}
else {
inRange++;
}
Using 5 compares, now I can a difference, 61 vs 47 msec. Or in other words, this is a way to count the number of integer engines in the processor. Hehe :)
So this is a micro-optimization that probably used to pay off a decade ago. It doesn't anymore. Scratch it off your list of things to worry about :)
I would suggest attempting code which does not throw an exception when the index is out of range. Exceptions are incredibly expensive and can completely throw off your bench results.
The code below does a timed-average bench for 1,000 iterations of 1,000,000 results.
using System;
using System.Diagnostics;
namespace BenchTest
{
class Program
{
const int LoopCount = 1000000;
const int AverageCount = 1000;
static void Main(string[] args)
{
Console.WriteLine("Starting Benchmark");
RunTest();
Console.WriteLine("Finished Benchmark");
Console.Write("Press any key to exit...");
Console.ReadKey();
}
static void RunTest()
{
int cursorRow = Console.CursorTop; int cursorCol = Console.CursorLeft;
long totalTime1 = 0; long totalTime2 = 0;
long invalidOperationCount1 = 0; long invalidOperationCount2 = 0;
for (int i = 0; i < AverageCount; i++)
{
Console.SetCursorPosition(cursorCol, cursorRow);
Console.WriteLine("Running iteration: {0}/{1}", i + 1, AverageCount);
int[] indexArgs = RandomFill(LoopCount, int.MinValue, int.MaxValue);
int[] sizeArgs = RandomFill(LoopCount, 0, int.MaxValue);
totalTime1 += RunLoop(TestMethod1, indexArgs, sizeArgs, ref invalidOperationCount1);
totalTime2 += RunLoop(TestMethod2, indexArgs, sizeArgs, ref invalidOperationCount2);
}
PrintResult("Test 1", TimeSpan.FromTicks(totalTime1 / AverageCount), invalidOperationCount1);
PrintResult("Test 2", TimeSpan.FromTicks(totalTime2 / AverageCount), invalidOperationCount2);
}
static void PrintResult(string testName, TimeSpan averageTime, long invalidOperationCount)
{
Console.WriteLine(testName);
Console.WriteLine(" Average Time: {0}", averageTime);
Console.WriteLine(" Invalid Operations: {0} ({1})", invalidOperationCount, (invalidOperationCount / (double)(AverageCount * LoopCount)).ToString("P3"));
}
static long RunLoop(Func<int, int, int> testMethod, int[] indexArgs, int[] sizeArgs, ref long invalidOperationCount)
{
Stopwatch sw = new Stopwatch();
Console.Write("Running {0} sub-iterations", LoopCount);
sw.Start();
long startTickCount = sw.ElapsedTicks;
for (int i = 0; i < LoopCount; i++)
{
invalidOperationCount += testMethod(indexArgs[i], sizeArgs[i]);
}
sw.Stop();
long stopTickCount = sw.ElapsedTicks;
long elapsedTickCount = stopTickCount - startTickCount;
Console.WriteLine(" - Time Taken: {0}", new TimeSpan(elapsedTickCount));
return elapsedTickCount;
}
static int[] RandomFill(int size, int minValue, int maxValue)
{
int[] randomArray = new int[size];
Random rng = new Random();
for (int i = 0; i < size; i++)
{
randomArray[i] = rng.Next(minValue, maxValue);
}
return randomArray;
}
static int TestMethod1(int index, int size)
{
return (index < 0 || index >= size) ? 1 : 0;
}
static int TestMethod2(int index, int size)
{
return ((uint)(index) >= (uint)(size)) ? 1 : 0;
}
}
}
You aren't comparing like with like.
The code you were talking about not only saved one branch by using the optimisation, but also 4 bytes of CIL in a small method.
In a small method 4 bytes can be the difference in being inlined and not being inlined.
And if the method calling that method is also written to be small, then that can mean two (or more) method calls are jitted as one piece of inline code.
And maybe some of it is then, because it is inline and available for analysis by the jitter, optimised further again.
The real difference is not between index < 0 || index >= _size and (uint)index >= (uint)_size, but between code that has repeated efforts to minimise the method body size and code that does not. Look for example at how another method is used to throw the exception if necessary, further shaving off a couple of bytes of CIL.
(And no, that's not to say that I think all methods should be written like that, but there certainly can be performance differences when one does).

Stack overflow error in loop function

I'm pretty new to c# and I'm trying to make a function that checks if a certain number is in a list, and I want to run the function for every number between 1-10000.
Currently it looks like this but i'm getting System.StackOverflowException so does anyone know how to do this correctly?
int number = 1;
int maxnumber = 10000;
void LoadFavorites()
{
if (number <= maxnumber)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'"))
{
this.listBox1.Items.Add(number);
}
}
// Increases number by 1 and reruns
number = number + 1;
LoadFavorites(); // problem is probably here
}
You are right. You have a recursive function there that does not have an appropriate stopping condition. Maybe you need a loop that goes from 1 to 100000 instead and there you call the function loadFavorites(). The stackoverflow is caused because you are calling loadFavorites() an infinite number of times, eventually you run out of stack space.
e.g.
for(int i=number; i<maxNumber; i++)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+i+"'"))
{
this.listBox1.Items.Add(i);
}
}
There is no exit point, thus the stack overflow.
You need to create a condition on the recursive call otherwise it will never be able to exit.
Example:
void LoadFavorites()
{
if (number <= maxnumber)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'"))
{
this.listBox1.Items.Add(number);
}
}
// Increases number by 1 and reruns
number = number + 1;
if(number <= maxnumber) // create a condition to call this
LoadFavorites(); // problem is probably here
}
OR a better approach
void LoadFavorites()
{
if (number <= maxnumber)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'"))
{
this.listBox1.Items.Add(number++); // add number to list THEN increment number by one
}
LoadFavorites();
}
}
You should be doing this in a loop, not using recursion. Each time you recurse it's going to add information to the stack and eventually you'll run out of stack space. In this case, you're recursing infinitely. (You're not stopping it from recursing if number > maxnumber).
void LoadFavorites()
{
int number = 1;
int maxnumber = 10000;
while (number <= maxnumber)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'"))
{
this.listBox1.Items.Add(number);
}
number = number + 1;
}
}
(edit: additional comment about "'"+number+"'" removed)
You want to move the part that increases the number to inside the if statement:
int number = 1;
int maxnumber = 10000;
void LoadFavorites()
{
if (number <= maxnumber)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'"))
{
this.listBox1.Items.Add(number);
}
// Increases number by 1 and reruns
number = number + 1;
LoadFavorites(); // problem is probably here
}
}
You are calling LoadFavorites recursively without any rule to end recursion. Just, put it inside you if statement...But why don't you write it like this:
int number = 1;
int maxnumber = 10000;
void LoadFavorites()
{
for(var i = number; i <= maxnumber; i++)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'"))
{
this.listBox1.Items.Add(number);
}
}
}
the problem is when number>100001, your code is still running(incrementing by 1 everytime and not exiting the loop).
so change code to this:
if (number <= maxnumber)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'"))
{
this.listBox1.Items.Add(number);
}
number = number + 1;
LoadFavorites();
}
int number = 1;
int maxnumber = 10000;
void LoadFavorites()
{
if (number <= maxnumber)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'"))
{
this.listBox1.Items.Add(number);
}
}
// Increases number by 1 and reruns
number = number + 1;
LoadFavorites(); //**MOVE THESE:
}
Change to
int number = 1;
int maxnumber = 10000;
void LoadFavorites()
{
if (number <= maxnumber)
{
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'"))
{
this.listBox1.Items.Add(number);
// Increases number by 1 and reruns
number = number + 1;
LoadFavorites(); // problem is probably here
}
}
}
You're calling a function from within a function, which, as you probably know, is recursion. With recursion, however, you have to have an exit condition, which causes the loop to exit.
The stack is the order of function calls in a thread. For example, in Java, you have main() which is your entry point. Calling functions from main() adds to the top of the stack. Once the stack gets to a certain size, your computer can no longer buffer more function calls. It simply drops the main function from the stack, and doesn't know where to return to, so it throws an error. (It throws the error once 'main' is dropped, not once it tries to return).
The reason for the change is that you want to continue only if number is < maxnumber. This sets up a condition for the recursion, after which, the function will exit.
The issue is that whenever you call a function in c++, it takes up some memory (it needs space to store its variables, among other things). This memory is called a stack frame. The memory is automatically returned when the function returns, but if you have a recursive function, none of the stack frames can be released until the final function call happens. In this case, LoadFavorites tries to call itself infinitely, and your computer does not contain an infinite amount of memory.
In C++, the best answer generally is to convert this into a loop - in this case, you want a for loop.
void LoadFavorites() {
int maxnumber = 10000;
int number;
for (number = 1; number <= maxnumber; number++) {
if (Properties.Settings.Default.FavoriteList.Contains("'"+number+"'")) {
this.listBox1.Items.Add(number);
}
}
}
Alternately, you could move the call to LoadFavorites into the if statement so that you don't try to call LoadFavorites an infinite number of times. This could work, but depending on the number times you call LoadFavorites, you could still run into the same error. The error can be avoided with the right compiler optimizations, but it generally is safer and clearer to simply use a loop here.

Categories

Resources