Infinite Series: While loop ends in infinity - c#

I want to compute a series, but i don't get my do..while loop correct.
The user makes in input x, which then is summed up as following:
sum = sum + x / 2 ^ n, where n is the running variable.
This has to be looped, until the sum <= 0.00001.
Then the program will notify the user about the value of the sum and how big the running variable is.
My code so far:
public static int n = 0;
static void Main(string[] args)
{
double x, sum = 0, e = 0.00001;
Console.Write("input x: ");
x = Convert.ToDouble(Console.ReadLine());
do
{
sum = sum + x / Math.Pow(2,n);
n++;
} while (sum >= e);
Console.WriteLine ("Sum = " + sum + ", " + n + " count");
}
But my code results in an infinite loop. Do you have any ideas, how i could achieve it?

You're looping until the sum is very small; you should loop until the increment is very small:
var delta = e;
do
{
delta = x / Math.Pow(2,n);
sum = sum + delta;
n++;
} while (delta >= e);

Related

Capped sum that needs to stop before the limit

I have been trying to make a program that you input a number and i keeps asking for numbers untill their sum has reached the number and displays how many numbers it took. the problem i'm facing is that if the last number makes it over the input number it still counts it while it should stop.
static void Main(string[] args)
{
int sumLimit = Convert.ToInt32(Console.ReadLine());
int sum = 0;
int count = 0;`
while (sum < sumLimit)
{
int number = Convert.ToInt32(Console.ReadLine());
sum += number;
count++;
}
Console.WriteLine(sum + " " + count);
Console.ReadLine();
}
Here's one option to fix it, depending on your expected result you can let the count start at -1 or 0:
int sumLimit = Convert.ToInt32(Console.ReadLine());
int sum = 0;
int count = -1;
int number = 0;
while (sum + number < sumLimit)
{
sum += number;
count++;
number = Convert.ToInt32(Console.ReadLine());
}
Console.WriteLine(sum + " " + count);
Console.ReadLine();

Issues with looping code and do-while loops (c#)

static double calculateTotals(double a)
{
double transfee = a * .01;
double total = a + transfee;
return total;
}
static void Main(string[] args)
{
Console.WriteLine("How many dontations to process?");
int donations = Convert.ToInt16(Console.ReadLine());
int[] count = new int[] { donations + 1 };
int ct = 1;
int i = -1;
do
{
Console.WriteLine("Enter name: ");
string name = Console.ReadLine();
Console.WriteLine("Enter donation amount: ");
double amount = Convert.ToDouble(Console.ReadLine());
double transfee = amount * .01;
i++;
ct = count[i += 1];
Console.WriteLine(name + "\t" + amount + "\t" + transfee);
} while (i < donations);
Console.WriteLine("TOTALS:" + "\t" + calculateTotals(amount) + "\t" + transfee);
Console.ReadLine();
}
}
Hello. I am a beginner at coding, so I apologize if this is a poor attempt.
I am trying to make an app that records the amount donated by an individual, calculates a transaction fee, and outputs the results for each person. At the end, I am creating a final row of output that will state the total donations and the total transaction fees.
I am currently unsure how to properly implement the array into my loop, and am unsure if the loop is optimized in general.
Again, I am a beginner. I apologize for such code, but I'd love some clarification on these things.
Thank you!
First, your array declaration syntax is wrong. See this link.
So it should be int[] count = new int[donations+1];
Second, you need to declare and instantiate your amount and transfee variables outside of your loop.
double transfee = 0.0F;
double amount = 0.0F;
do
{
...
amount = Convert.ToDouble(Console.ReadLine());
transfee = amount * .01;
...
} while (i < donations);
This should be enough information to get you going again. Since you're learning, I don't think anyone would really unfold an answer for you that does the job you're trying to figure out :)
Your code :
int i = -1;
do
{
...
i++;
ct = count[i += 1];
...
} while (i < donations);
You are actually increase i two times, then get values from count[i] assign to ct variable
See this sample :
int[] count = new int[3];
count[0] = 0;
count[1] = 1;
count[2] = 2;
int i = -1;
do
{
i++;
int x = count[i += 1];
Console.WriteLine(x);
} while (i < 3);
It will cause IndexOutOfRangeException
Explain :
First Loop :
i++; // i increased 1, so i = 0
int x = count[i += 1]; // i increased 1, so i = 1, then get count[1] assign to x, x is 1
Second loop:
i++; // i increased 1, so i = 2
int x = count[i += 1]; // i increased 1, so i = 3, then get count[3] assign to x
count[3] cause IndexOutOfRangeException
Something like count[i += 1] will make your code more difficult to maintain, in my opinion, you should avoid it if possible, try to write it explicity as you can

c# (beginner) how to make a short version of this "if" code? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I just learned how to use if and tried to do a simple calculator. but the code is way too long and i want to add more options to it, can i make it any shorter using any other method?
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("How many numbers do you wish to calculate? ");
string HowMany = Console.ReadLine();
if (HowMany == "2") {
Console.Write("Enter #1: ");
int x = int.Parse(Console.ReadLine());
Console.Write("Enter #2: ");
int y = int.Parse(Console.ReadLine());
int sum = x + y; int sub = x - y; int mult = x * y; int div = x / y;
Console.WriteLine("The Result : Sum = " + sum + " Sub = " + sub + " Mult = " + mult + " Div = " + div); }
else if (HowMany == "3") {
Console.Write("Enter #1: ");
int x = int.Parse(Console.ReadLine());
Console.Write("Enter #2: ");
int y = int.Parse(Console.ReadLine());
Console.Write("Enter #3: ");
int z = int.Parse(Console.ReadLine());
int sum = x + y + z; int sub = x - y - z; int mult = x * y * z; int div = x / y / z;
Console.WriteLine("The Result : Sum = " + sum + " Sub = " + sub + " Mult = " + mult + " Div = " + div); }
else if (HowMany == "4")
{
Console.Write("Enter #1: ");
int x = int.Parse(Console.ReadLine());
Console.Write("Enter #2: ");
int y = int.Parse(Console.ReadLine());
Console.Write("Enter #3: ");
int z = int.Parse(Console.ReadLine());
Console.Write("Enter #4: ");
int w = int.Parse(Console.ReadLine());
int sum = x + y + z + w; int sub = x - y - z - w; int mult = x * y * z * w; int div = x / y / z / w;
Console.WriteLine("The Result : Sum = " + sum + " Sub = " + sub + " Mult = " + mult + " Div = " + div);
}
Console.ReadKey();
}
}
}
This does just the sum. I'll leave handling the other calculations to you.
int sum = 0;
for(int i = 1;i<=HowMany;i++)
{
Console.Write("Enter #{0}: ", i);
int input = int.Parse(Console.ReadLine());
sum += input;
}
Console.WriteLine("The Result : Sum = {0}", sum);
using System.IO;
using System;
class Program {
static void Main() {
Console.WriteLine("How many numbers do you wish to calculate? ");
string HowMany = Console.ReadLine();
int[] nums = new int[int.Parse(HowMany)];
int sum = 0, sub = 0, mult = 1, div = 1;
for (int i = 0; i < int.Parse(HowMany); i++) {
Console.Write("Enter #" + (i + 1) + ": ");
nums[i] = int.Parse(Console.ReadLine());
sum += nums[i];
sub -= nums[i];
mult *= nums[i];
div /= nums[i];
}
Console.WriteLine("The Result : Sum = " + sum + " Sub = " + sub + " Mult = " + mult + " Div = " + div);
Console.ReadKey();
}
}
You can just use a loop, and keep a rolling total of the values. Also, I changed div to be a double, because integer division is really boring - it's nice to see the decimal value:
I also made it so the user can only enter an integer greater than zero for the quantity of numbers they want to calculate.
And finally, they can only enter a non-zero integer for the number, because a zero input means we have to do some check for that during division, the multiplication value will always be zero, and it does nothing to the addition and subtraction totals.
Console.Write("How many numbers do you wish to calculate? ");
int count;
while (!int.TryParse(Console.ReadLine(), out count) || count < 1)
{
Console.Write("Error: enter a positive, whole number: ");
}
int input, sum = 0, sub = 0, mult = 0;
double div = 0;
for (int i = 1; i <= count; i++)
{
Console.Write($"Enter #{i}: ");
// Don't allow user to enter 0. It does nothing to the addition or subtraction
// values, will make the multiplication value zero, and cannot be use for division
while (!int.TryParse(Console.ReadLine(), out input) || input == 0)
{
Console.Write("Error: enter a non-zero whole number: ");
}
if (i == 1)
{
// On the first input, we just store the number
sum = sub = mult = input;
div = input;
}
else
{
sum += input;
sub -= input;
mult *= input;
div /= input;
}
}
Console.WriteLine("The Result : Sum = " + sum + " Sub = " +
sub + " Mult = " + mult + " Div = " + div);
Console.ReadKey();

Get sum of each digit below n as long

This is the code I have but it's to slow, any way to do it faster..
the number range I'm hitting is 123456789 but I can't get it below 15 seconds, and I need it to get below 5 seconds..
long num = 0;
for (long i = 0; i <= n; i++)
{
num = num + GetSumOfDigits(i);
}
static long GetSumOfDigits(long n)
{
long num2 = 0;
long num3 = n;
long r = 0;
while (num3 != 0)
{
r = num3 % 10;
num3 = num3 / 10;
num2 = num2 + r;
}
return num2;
}
sum =(n(n+1))/2 is not giving me the results I need, not calculating properly..
For N = 12 the sum is 1+2+3+4+5+6+7+8+9+(1+0)+(1+1)+(1+2)= 51.
I need to do this with a formula instead of a loop..
I've got about 15 tests to run through each under 6 seconds..
with parallel I got one test from 15seconds to 4-8 seconds..
Just to show you the test I'm doing this is the hard one..
[Test]
public void When123456789_Then4366712385()
{
Assert.AreEqual(4366712385, TwistedSum.Solution(123456789));
}
On my computer I can run all the tests under 5 seconds..
Look at the photo..
With DineMartine Answer I got these results:
Your algorithm complexity is N log(N). I have found a better algorithm with complexity log(N). The idea is to iterate on the number of digits which is :
log10(n) = ln(n)/ln(10) = O(log(n)).
The demonstration of this algorithm involves a lot of combinatorial calculus. So I choose not to write it here.
Here is the code :
public static long Resolve(long input)
{
var n = (long)Math.Log10(input);
var tenPow = (long)Math.Pow(10, n);
var rest = input;
var result = 0L;
for (; n > 0; n--)
{
var dn = rest / tenPow;
rest = rest - dn * tenPow;
tenPow = tenPow / 10;
result += dn * (rest + 1) + dn * 45 * n * tenPow + dn * (dn-1) * tenPow * 5 ;
}
result += rest * (rest + 1) / 2;
return result;
}
Now you would solve the problem in a fraction of second.
The idea is to write the input as a list of digit :
Assuming the solution is given by a function f, we are looking for g a recursive expression of f over n :
Actually g can be written as follow :
If you find h, the problem would be practically solved.
A little bit convoluted but gets the time down to practicaly zero:
private static long getSumOfSumOfDigitsBelow(long num)
{
if (num == 0)
return 0;
// 1 -> 1 ; 12 -> 10; 123 -> 100; 321 -> 100, ...
int pow10 = (int)Math.Pow(10, Math.Floor(Math.Log10(num)));
long firstDigit = num / pow10;
long sum = 0;
var sum999 = getSumOfSumOfDigitsBelow(pow10 - 1);
var sumRest = getSumOfSumOfDigitsBelow(num % pow10);
sum += (firstDigit - 1)*(firstDigit - 0)/2*pow10 + firstDigit*sum999;
sum += firstDigit*(num%pow10 + 1) + sumRest;
return sum;
}
getSumOfSumOfDigitsBelow(123456789) -> 4366712385 (80us)
getSumOfSumOfDigitsBelow(9223372036854775807) -> 6885105964130132360 (500us - unverified)
The trick is to avoid to compute the same answer again and again. e.g. 33:
your approach:
sum = 1+2+3+4+5+6+7+8+9+(1+0)+(1+1)+(1+2)+ ... +(3+2)+(3+3)
my approach:
sum = 10*(0 + (1+2+3+4+5+6+7+8+9)) +
10*(1 + (1+2+3+4+5+6+7+8+9)) +
10*(2 + (1+2+3+4+5+6+7+8+9)) +
3*(3 + (1 + 2 + 3))
The (1+2+3+4+5+6+7+8+9)-part have to be calculated only once. The loop of 0..firstDigit-1 can be avoided by the n(n-1)/2-trick. I hope this makes sense.
The complexity is O(2^N) with N counting the number of digits. This looks very bad but is fast enough for your threshold of 5s even for long-max. It may be possible to transform this algorithm in something running in O(n) by calling getSumOfSumOfDigitsBelow() only once but it would look much more complex.
First step of optimization: look at your algorithm ;)
Comming back to this problem after the answer of DineMartine :
To further optimize the algorithm, the sum999-part can be replaced by an explicit formula. Lets take some number 9999...9=10^k-1 into the code and replace accordingly:
sum(10^k-1) = (9 - 1)*(9 - 0)/2*pow10 + 9*sum999 + 9*(num%pow10 + 1) + sumRest
sum(10^k-1) = 36*pow10 + 9*sum999 + 9*(num%pow10 + 1) + sumRest
sum999 and sumRest are the same for the numbers of type 10^k:
sum(10^k-1) = 36*pow10 + 10*sum(10^(k-1)-1) + 9*(num%pow10 + 1)
sum(10^k-1) = 36*pow10 + 10*sum(10^(k-1)-1) + 9*((10^k-1)%pow10 + 1)
sum(10^k-1) = 36*pow10 + 10*sum(10^(k-1)-1) + 9*pow10
sum(10^k-1) = 45*pow10 + 10*sum(10^(k-1)-1)
We have a definition of sum(10^k-1) and know sum(9)=45. And we get:
sum(10^k-1) = 45*k*10^k
The updated code:
private static long getSumOfSumOfDigitsBelow(long num)
{
if (num == 0)
return 0;
long N = (int) Math.Floor(Math.Log10(num));
int pow10 = (int)Math.Pow(10, N);
long firstDigit = num / pow10;
long sum = (firstDigit - 1)*firstDigit/2*pow10
+ firstDigit* 45 * N * pow10 / 10
+ firstDigit*(num%pow10 + 1)
+ getSumOfSumOfDigitsBelow(num % pow10);
return sum;
}
This is the same algorithm as the one from DineMartine but expressed in a recursive fashion (I've compared both implementations and yes I'm sure it is ;) ). The runtime goes down to practically zero and the time complexity is O(N) counting the number of digits or O(long(N)) taking the value.
If you have multiple processors (or cores) in your system, you can speed it up quite a lot by doing the calculations in parallel.
The following code demonstrates (it's a compilable console app).
The output when I try it on my system (4 cores with hyperthreading) is as follows for a release build:
x86 version:
Serial took: 00:00:14.6890714
Parallel took: 00:00:03.5324480
Linq took: 00:00:04.4480217
Fast Parallel took: 00:00:01.6371894
x64 version:
Serial took: 00:00:05.1424354
Parallel took: 00:00:00.9860272
Linq took: 00:00:02.6912356
Fast Parallel took: 00:00:00.4154711
Note that the parallel version is around 4 times faster. Also note that the x64 version is MUCH faster (due to the use of long in the calculations).
The code uses Parallel.ForEach along with a Partitioner to split the range of number into sensible regions for the number of processors available. It also uses Interlocked.Add() to quickly add the numbers with efficient locking.
I've also added another method where you need to pre-calculate the sums for the numbers between 0 and 1000. You should only need to pre-calculate the sums once for each run of the program. See FastGetSumOfDigits().
Using FastGetSumOfDigits() more than doubles the previous fastest time on my PC. You can increase the value of SUMS_SIZE to a larger multiple of 10 to increase the speed still further, at the expense of space. Increasing it to 10000 on my PC decreased the time to ~0.3s
(The sums array only needs to be a short array, to save space. It doesn't need a larger type.)
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
internal class Program
{
public static void Main()
{
long n = 123456789;
Stopwatch sw = Stopwatch.StartNew();
long num = 0;
for (long i = 0; i <= n; i++)
num = num + GetSumOfDigits(i);
Console.WriteLine("Serial took: " + sw.Elapsed);
Console.WriteLine(num);
sw.Restart();
num = 0;
var rangePartitioner = Partitioner.Create(0, n + 1);
Parallel.ForEach(rangePartitioner, (range, loopState) =>
{
long subtotal = 0;
for (long i = range.Item1; i < range.Item2; i++)
subtotal += GetSumOfDigits(i);
Interlocked.Add(ref num, subtotal);
});
Console.WriteLine("Parallel took: " + sw.Elapsed);
Console.WriteLine(num);
sw.Restart();
num = Enumerable.Range(1, 123456789).AsParallel().Select(i => GetSumOfDigits(i)).Sum();
Console.WriteLine("Linq took: " + sw.Elapsed);
Console.WriteLine(num);
sw.Restart();
initSums();
num = 0;
Parallel.ForEach(rangePartitioner, (range, loopState) =>
{
long subtotal = 0;
for (long i = range.Item1; i < range.Item2; i++)
subtotal += FastGetSumOfDigits(i);
Interlocked.Add(ref num, subtotal);
});
Console.WriteLine("Fast Parallel took: " + sw.Elapsed);
Console.WriteLine(num);
}
private static void initSums()
{
for (int i = 0; i < SUMS_SIZE; ++i)
sums[i] = (short)GetSumOfDigits(i);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long GetSumOfDigits(long n)
{
long sum = 0;
while (n != 0)
{
sum += n%10;
n /= 10;
}
return sum;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static long FastGetSumOfDigits(long n)
{
long sum = 0;
while (n != 0)
{
sum += sums[n % SUMS_SIZE];
n /= SUMS_SIZE;
}
return sum;
}
static short[] sums = new short[SUMS_SIZE];
private const int SUMS_SIZE = 1000;
}
}
To increase performance you could calculate the sum starting from the highest number.
Let r=n%10 + 1. Calculate the sum for the last r numbers.
Then we note that if n ends with a 9, then the total sum can be calculated as 10 * sum(n/10) + (n+1)/10 * 45. The first term is the sum of all digits but the last, and the second term is the sum of the last digit.
The function to calculate the total sum becomes:
static long GetSumDigitFrom1toN(long n)
{
long num2 = 0;
long i;
long r = n%10 + 1;
if (n <= 0)
{
return 0;
}
for (i = 0; i < r; i++)
{
num2 += GetSumOfDigits(n - i);
}
// The magic number 45 is the sum of 1 to 9.
return num2 + 10 * GetSumDigitFrom1toN(n/10 - 1) + (n/10) * 45;
}
Test run:
GetSumDigitFrom1toN(12L): 51
GetSumDigitFrom1toN(123456789L): 4366712385
The time complexity is O(log n).
Sum of digits for 0..99999999 is 10000000 * 8 * (0 + 1 + 2 + ... + 9).
Then calculating the rest (100000000..123456789) using the loop might be fast enough.
For N = 12:
Sum of digits for 0..9 is 1 * 1 * 45. Then use your loop for 10, 11, 12.
For N = 123:
Sum of digits for 0..99 is 10 * 2 * 45. Then use your loop for 100..123.
You see the pattern?
A different approach you can try:
Convert the number to a string, then to a Char array
Sum the ASCII codes for all the chars, minus the code for 0
Example code:
long num = 123456789;
var numChars = num.ToString().ToCharArray();
var zeroCode = Convert.ToByte('0');
var sum = numChars.Sum(ch => Convert.ToByte(ch) - zeroCode);

Adding the sum of all the random numbers in a random number generator

Hi, I am trying to add the sum of the random numbers in my random number gen to get the average of the random numbers that were generated also to display them in a message box. I can not do arrays. Here is what I have so far:
class Program
{
static double average = 0;
static double sum = 0;
static void Main(string[] args)
{
Random number = new Random();
int min = int.MaxValue, max = int.MinValue;
string result = "\tn \n";
for (int counter = 0; counter < 100; counter++)
{
int n = number.Next(0, 1000);
// Console.WriteLine(n);
if (n < min)
min = n;
if (n > max)
max = n;
}
sum = sum + (number.Next()) ;
average = sum / 100;
int range = min - (min + 1);
result += " \t"
+ min
+ " \t"
+ max
+ " \t"
+ average
+ " \t"
+ sum
+ " \t"
+ range;
MessageBox.Show(result, "Min = {0}, Max = {1}, Range = {2}");
}
I would like a hint to solve this problem not a list of code that is just given to me. Thank you.
You'll want to put this inside of the for loop:
sum = sum + n;
(or sum += n;)
Then after the loop, the average will be the sum divided by 100.
Also you can take out the min and max part, unless that is needed for something else.

Categories

Resources