"How to Fix" logic in C# factorial Calculation's [duplicate] - c#

This question already has answers here:
Recursion Factorial terminating due to StackOverflowException
(2 answers)
Closed 3 years ago.
I need to write a factorisation calculator with recursion, for the purpose of learning nLog and how to build custom exceptions.
I have tried a few different implementations in visual studio 2019 CE with "if" and "for" loops but I don't really know what I'm doing.
public static int Factorial(int input)
{
try
{
// create a count for step of recursion
int factorCount = 0;
int sqrt = (int)Math.Ceiling(Math.Sqrt(input));
for (int step=1; step<=sqrt;step++)
{
if(input % step == 0) {
//incress the current step of recursion by one
factorCount++;
Console.WriteLine("Calculator.Factorial:Calculating",step);
}
Console.WriteLine(input);
}
The current code is throwing up a
"Process is terminated due to StackOverflowException." and that it is getting till at lest "Console.WriteLine("Calculator.Factorial:Calculating",step); "
before crashing.

you didn't use recursion in your code at all. recursion means a function call itself within itself. in factorial you for n! you have to calculate (n-1)! till n-1 =1. try this:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static int Fact(int n)
{
if (n <= 1)
return 1;
return n * Fact(n - 1);
}
static int Factorial(int n)
{
if (n <= 1)
return 1;
int result = 1;
for (int i = 2; i <= n; i++)
{
result = result * i;
}
return result;
}
static void Main(string[] args)
{
Console.Write("Enter a Number to find factorial: ");
int n = Convert.ToInt32(Console.ReadLine());
int r = Fact(n);
Console.WriteLine(n.ToString() + "! = " + r.ToString());
Console.Write("Enter a Number to find factorial: ");
n = Convert.ToInt32(Console.ReadLine());
r = Factorial(n);
Console.WriteLine(n.ToString() + "! = " + r.ToString());
}
}
}

Related

C# Find every number divisible by 3, in a string of numbers

this is my first post here, I'm new to C# and I have some problems with my code.
class Program
{
static void Main(string[] args)
{
#region FindAllNumbersDivisibleBy3
Console.Write("Enter a string of numbers: ");
string Nums = Console.ReadLine();
List<long> arr = new List<long>();
for (int i = 0; i < Nums.Length; i++)
{
for(int j = Nums.Length - 1; j >= i; j--)
{
try
{
string substring = Nums.Substring(i, j);
if (Convert.ToInt64(substring) % 3 == 0)
{
arr.Add(Convert.ToInt64(substring));
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Console.WriteLine("The following numbers are divisble by 3: ");
for (int i = 0; i < arr.Count; i++)
{
Console.WriteLine(arr[i]);
}
Console.ReadLine();
#endregion
}
}
The problem is the following: I'm given a series of numbers, probably too big and inefficient to be stored as an integer, so it's recommended to use a string, and you have to find every single number divisible by three. That could be the entire string, or some sub-strings, or just single digit numbers, etc. I get some conversion errors from the catch exception, as well as something else regarding some length parameter and I don't really understand what's the problem. It's also possible that the for loops' arguments have some errors too, but as far as I'm concerned the problems start in the try block.
Sorry if this is a very dumb question, I'm still in high school so I'm not very good at programming yet. Thank you for your help in advance.
This is still vulnerable to overflows, but it would take a very long string indeed to reach that point:
class Program
{
static void Main(string[] args)
{
Console.Write("Enter a string of numbers: ");
string Nums = Console.ReadLine();
Console.WriteLine("The following numbers are divisble by 3: ");
foreach(var result in DivisibleByThree(Nums))
{
Console.WriteLine(result);
}
Console.ReadKey(true);
}
public static IEnumerable<string> DivisibleByThree(string input)
{
for (int i = 0; i < input.Length; i++)
{
for(int j = input.Length; j > i; j--)
{
string segment = input.Substring(i, j-i);
if (SumOfDigits(segment) % 3 == 0)
{
yield return segment;
}
}
}
}
public static int SumOfDigits(string digits)
{
return digits.Where(c => char.IsDigit(c)).Select(c => c-'0').Sum();
}
}
See it work here:
https://dotnetfiddle.net/KacyAD
And since someone suggested recursion, I thought that'd be fun to try. I didn't quite get as far as I wanted (removing both loops and using recursion as the only repetition mechanism), but this does work:
public static IEnumerable<string> DivisibleByThree(string input)
{
if (input.Length > 1)
{
foreach(var item in DivisibleByThree(input.Substring(0, input.Length-1)))
{
yield return item;
}
}
while(input.Length > 0)
{
if ( SumOfDigits(input) % 3 == 0) yield return input;
input = input.Substring(1);
}
}
But that's the boring recursion. From a pure performance standpoint, it still spends a lot of time summing the same sequences of digits. There's a probably a way to use recursion to preserve prior work on each recursive call, and in that way make this run significantly faster.
That is, rather than start with a big string and check progressively smaller segments, start with the small string and with each check add the sum for the just the additional digit:
public static IEnumerable<string> DivisibleByThree(string input)
{
for(int i = input.Length - 1; i>=0; i--)
{
foreach(var item in DivisibleByThreeR(input.Substring(i, input.Length - i), 0, 0, 0)) yield return item;
}
}
public static IEnumerable<string> DivisibleByThreeR(string input, int startPos, int nextPos, int sum)
{
sum += input[nextPos] - '0';
if (sum % 3 == 0) yield return input.Substring(startPos, nextPos - startPos + 1);
if (++nextPos < input.Length)
{
foreach (var item in DivisibleByThreeR(input, startPos, nextPos, sum)) yield return item;
}
}
I'm not sure this is really any faster. I didn't benchmark or test at all beyond getting the right result. In fact, I suspect the iterators will eat up any improvements over the pure-loop version.
There's also probably a way to move the loop in the outer method also into the recursive function thereby optimize even further. But it was a nice exercise.
Here's my final fiddle if anyone else wants to play:
https://dotnetfiddle.net/dGFWNx
Here's a solution close to your code that uses BigInteger (you need .NET5+). This shall eliminate the risk of running into OverflowException. Please note that there can be duplicates in the output (you didn't say if you want to see them).
using System.Numerics;
class Program
{
static void Main(string[] args)
{
#region FindAllNumbersDivisibleBy3
Console.Write("Enter a string of numbers: ");
string Nums = Console.ReadLine();
List<BigInteger> results = new();
for (int i = 0; i < Nums.Length; i++)
{
for (int j = Nums.Length; j >= i; j--)
{
try
{
string substring = Nums.Substring(i, j - i);
if (BigInteger.TryParse(substring, out var bi) && BigInteger.ModPow(bi, 1, 3).IsZero)
{
results.Add(bi);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Console.WriteLine("The following numbers are divisible by 3:");
for (int i = 0; i < results.Count; i++)
{
Console.WriteLine(results[i]);
}
Console.ReadLine();
#endregion
}
}
Something that will work even with numbers other than 3 and 9 would be to implement long division and only keep track of the carry remainder (added a Linq version since it seemed like an appropriate problem for it):
static bool IsDivisibleBy(string input, long divBy = 3)
{
long remainder = 0;
foreach (char c in input)
{
var num = Convert.ToInt64(c);
remainder = ((remainder * 10) + num) % divBy;
}
return remainder == 0;
}
static bool IsDivisibleByLinq(string input, long divBy = 3)
{
return input.Select(c => Convert.ToInt64(c))
.Aggregate(0L, (remainder, num) =>
((remainder * 10) + num) % divBy) == 0;
}

C# perfect numbers exercise

can you help me with the following exercise pls? (it's not homework, just an exercise in the book I'm using.)
"An integer is said to be a perfect number if its factors, including one (but not the number itself), sum to the number. For example, 6 is a perfect number, because 6 = 1 + 2 + 3. Write method Perfect that determines whether parameter value is a perfect number. Use this method in an app that determines and displays all the perfect numbers between 2 and 1000. Display the factors of each perfect number to confirm that the number is indeed perfect."
so here's what i got so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perfect_Numbers2
{
class Program
{
static bool IsItPerfect(int value)
{
int x = 0;
int counter = 0;
bool IsPerfect = false;
List<int> myList = new List<int>();
for (int i = value; i <= value; i++)
{
for (int j = 1; j < value; j++)
{
// if the remainder of i divided by j is zero, then j is a factor of i
if (i%j == 0) {
myList[counter] = j; //add j to the list
counter++;
}
for (int k = 0; k < counter; k++)
{
// add all the numbers in the list together, then
x = myList[k] + myList[k + 1];
}
// test if the sum of the factors equals the number itself (in which case it is a perfect number)
if (x == i) {
IsPerfect = true;
}
}
Console.WriteLine(i);
}
return IsPerfect;
}
static void Main(string[] args)
{
bool IsItAPerfectNum = false;
for (int i = 2; i < 1001; i++)
{
IsItAPerfectNum = IsItPerfect(i);
}
}
}
}
how would you do it? is my code fixable? how would you fix it? thanks!
im getting an error at line myList[counter] = j; (index was out of range) and besides it's not displaying the perfect numbers like it's supposed to....
EDIT = I made some changes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perfect_Numbers2
{
class Program
{
static bool IsItPerfect(int value)
{
int x = 0;
int counter = 0;
bool IsPerfect = false;
List<int> myList = new List<int>();
for (int i = value; i <= value; i++)
{
for (int j = 1; j < i; j++)
{
if (i%j == 0) // if the remainder of i divided by j is zero, then j is a factor of i
{
myList.Add(j); //add j to the list
}
x = myList.Sum();
if (x == i) // test if the sum of the factors equals the number itself (in which case it is a perfect number)
{
IsPerfect = true;
}
}
Console.WriteLine(i);
}
return IsPerfect;
}
static void Main(string[] args)
{
bool IsItAPerfectNum = false;
for (int i = 2; i < 1001; i++)
{
IsItAPerfectNum = IsItPerfect(i);
Console.WriteLine(IsItAPerfectNum);
Console.ReadKey(true);
}
}
}
}
now i can cycle through all the numbers until 1000 and it displays if it's perfect or not (true or false) [which isn't what the exercise called for, but it's a step in the right direction (the exercise says that it should display only the perfect numbers)].
In any case, what's strange is that it says true at number 24, which isn't a perfect number.... http://en.wikipedia.org/wiki/Perfect_numbers#Examples
why is 24 different?
thanks very much
can you help me with the following exercise please?
Yes. Rather than showing you where your error is, I'll teach you how to find your error. Even better, the same technique will lower the chances of you causing the error in the first place.
The key here is to break the problem down into small parts where each small part can be tested independently. You have already started to do this! You have two methods: Main and IsItPerfect. You should have at least three more methods. The methods you should have are:
IsDivisor -- takes two integers, returns true if the first divides the second.
GetAllDivisors -- takes an integer, returns a list of all the divisors
Sum -- takes a list of integers, returns the sum
Your method IsPerfect should be calling GetAllDivisors and Sum and comparing the sum to the original number, and that's all it should be doing. Your method GetAllDivisors should be calling IsDivisor, and so on.
You can't find the bug easily because your method is doing too much. If you're not getting the correct result out and you have four methods instead of one then you can test each method independently to make sure that it works, or fix it if it does not.
Your first for loop will be executed exactly once.
for (int i = value; i <= value; i++)
For example for value = 6
for (int i = 6; i <= 6; i++)
Some help with the 24 issue you are having: 24 is returning true as you are actually checking if it is perfect on every additional factor. So 24 gets flipped to true here:
Factors of 24 | Total so far
1 1
2 3
3 6
4 10
6 16
8 24 <-- returns true
12 36 <-- should be false, but flag is never reset
I have just now completed the same exercise which is from a really great book called visual c# 2012 by Mr Deitel.
The way i started to tackle is, i started off with figuring out how to work out the factorials of numbers and then slowly kept building on from there.
Since you are following the same book, i would suggest you not to use things that are not covered up to that chapters exercise, like list collections which you have used, As this will make the exercise unnecessarily difficult. and negates the learning methodology set out by of the author.
here is my code which i hope can help you in some way.
class Program
{
static int factorTotal = 1;
static void Main(string[] args)
{
int count = 1;
while (count <= 10000)
{
bool isPerfect = IsPerfectNumber(count);
if (isPerfect && (factorTotal >1))
{
Console.WriteLine("Is Perfect: {0}", factorTotal);
}
factorTotal = 1;
count++;
}
} // end main
static bool IsPerfectNumber(int n)
{
int temp;
int counter = 2;
bool IsPerfect = false;
while (counter <= (n - 1))
{
temp = n % counter;
if (temp == 0) // if true than factor found
{
factorTotal = factorTotal + counter;
}
counter++;
}
if ((factorTotal) == n)
IsPerfect = true;
else
IsPerfect = false;
return IsPerfect;
}
}//end class
under the Main method of you console application copy and paste below code.
I explained few things at the end of the code...
=====================================================================
{
Console.WriteLine("perfect numbers/n");
Console.Write("Enter upper limit: ");
int iUpperLimit = int.Parse(Console.ReadLine());
string sNumbers = "";
List<int> lstFactor = new List<int>();
for(int i = 1;i<=iUpperLimit;i++)
{
for(int k = 1;k<i;k++)
{
if (i % k == 0)
{
lstFactor.Add(k); //this collect all factors
}
if (k == i-1)
{
if (lstFactor.Sum() == i) //explain1
{
sNumbers += " " + i;
lstFactor.Clear(); //explain2
break;
}
else
{
lstFactor.Clear(); //explain2
}
}
}
}
Console.WriteLine("\nperfect numbers are: " + sNumbers);
Console.ReadKey();
}
}
=======================================================================
note that i is a number that we test and k is its factors.
explain1 => we add all factors collected and check if they are equal to i (we simply check if i is perfect number)
explain2 => we have to clear our list before we can check if the next number i is a perfect number or not so that factors of the previous number does not interfere with factors of the current number.
int start=1;
int end=50;
for(int a=end ; a > start ;a--)
{
int b=1;
int c=0;
bool x=false;
for(int i=1 ; i < a ;i++)
{
b=a/i;
if(b*i==a)
{
c+=i;
}
if(c==a & i==a/2)
{
x=true;
}
}
if(x==true)
Console.Write("{0} is : {1}",a,x);
}

Use rand5(), to generate rand7() (with the same probability) [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Expand a random range from 1–5 to 1–7
I have seen the question in here: Link
The solution the author provided didn't seem to generate the same probability.
For example, the number 4, out of 10k calls for the function, was returned 1-2 times (when the other numbers, like 2, were returned about 2k times each).
Maybe I understood wrong, or I wrote the algorithm wrong, but here:
static int rand5()
{
return new Random().Next(1, 6);
}
static int rand7()
{
while (true)
{
int num = 5 * (rand5() - 1) + rand5();
if (num < 22) return ((num % 7) + 1);
}
}
static void Main(string[] args)
{
int limit = 10000;
int[] scores = new int[7];
for (int i = 0; i < limit; i++)
{
scores[rand7() - 1]++;
}
foreach (int n in scores)
{
Console.Write(n + " ");
}
Console.WriteLine();
}
Thanks in advance.
You are not generating random numbers in Rand5.
Do it like this:
static Random rand = new Random()
static int rand5()
{
return rand.Next(1, 6);
}

C#, finding the largest prime factor of a number

I am new at programming and I am practicing my C# programming skills. My application is meant to find the largest prime factor of a number entered by the user. But my application is not returning the right answer and I dont really know where the problem is. Can you please help me?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Calcular máximo factor primo de n. De 60 es 5.");
Console.Write("Escriba un numero: ");
long num = Convert.ToInt64(Console.ReadLine());
long mfp = maxfactor(num);
Console.WriteLine("El maximo factor primo es: " + num);
Console.Read();
}
static private long maxfactor (long n)
{
long m=1 ;
bool en= false;
for (long k = n / 2; !en && k > 1; k--)
{
if (n % k == 0 && primo(k))
{
m = k;
en = true;
}
}
return m;
}
static private bool primo(long x)
{
bool sp = true;
for (long i = 2; i <= x / 2; i++)
{
if (x % i == 0)
sp = false;
}
return sp;
}
}
}
It will be much faster to remove the small factors until the residue is prime.
static private long maxfactor (long n)
{
long k = 2;
while (k * k <= n)
{
if (n % k == 0)
{
n /= k;
}
else
{
++k;
}
}
return n;
}
For example, if n = 784, this does 9 modulo operations instead of several hundred. Counting down even with the sqrt limit still would do 21 modulo ops just in maxfactor, and another dozen in primo.
New more optimized version here
Console.WriteLine("El maximo factor primo es: " + mfp);
instead of
Console.WriteLine("El maximo factor primo es: " + num);
you have condition (!en) that makes it iterate only until first prime factor. Also you can reduce bounds from n/2 to sqrt(n)+1
Catalin DICU already answered your question, but you've got some non-idiomatic constructs in your code that you should probably look at refactoring. For example, in your maxfactor method, you don't need the "en" condition, just return the value as soon as you've found it:
static private long maxfactor (long n)
{
for (long k = n / 2; k > 1; k--)
{
if (n % k == 0 && primo(k))
{
return k;
}
}
// no factors found
return 1;
}
Similarly for your primo method, you can just return false as soon as you find a factor.
here's a f# version for this:
let lpf n =
let rec loop n = function
|k when k*k >= n -> n
|k when n % k = 0I -> loop (n/k) k
|k -> loop n (k+1I)
loop n 2I
This runs for less than three seconds.
public static void Main()
{
int prime=1;
long n=600851475143;
for (long i=2;i<=n;i++)
{
while (n%i==0)
n=n/i;
prime++;
}
Console.WriteLine(prime);
Console.WriteLine("Hello World!");
Console.ReadKey();
}

Refactoring Fibonacci Algorithm

I haven't used a statically typed language in many years and have set myself the task of getting up to speed with C#. I'm using my usual trick of following the fifteen exercises here http://www.jobsnake.com/seek/articles/index.cgi?openarticle&8533 as my first task.
I've just finished the second Fibonacci task which didn't take to long and works just fine but in my opinion looks ugly and I'm sure could be achieved in far fewer lines of more elegant code.
I usually like to learn by pair programming with someone who already knows what they're doing, but that option isn't open to me today, so I'm hoping posting here will be the next best thing.
So to all the C# Jedi's out there, if you were going to refactor the code below, what would it look like?
using System;
using System.Collections;
namespace Exercises
{
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("Find all fibinacci numbers between:");
int from = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("And:");
int to = Convert.ToInt32(Console.ReadLine());
Fibonacci fibonacci = new Fibonacci();
fibonacci.PrintArrayList(fibonacci.Between(from, to));
}
}
class Fibonacci
{
public ArrayList Between(int from, int to)
{
int last = 1;
int penultimate = 0;
ArrayList results = new ArrayList();
results.Add(penultimate);
results.Add(last);
while(last<to)
{
int fib = last + penultimate;
penultimate = last;
last = fib;
if (fib>from && fib<to) results.Add(fib.ToString());
}
return results;
}
public void PrintArrayList(ArrayList arrayList)
{
Console.WriteLine("Your Fibonacci sequence:");
Console.Write(arrayList[0]);
for(int i = 1; i<arrayList.Count; i++)
{
Console.Write("," + arrayList[i]);
}
Console.WriteLine("");
}
}
}
Regards,
Chris
As an iterator block:
using System;
using System.Collections.Generic;
using System.Linq;
static class Program {
static IEnumerable<long> Fibonacci() {
long n = 0, m = 1;
yield return 0;
yield return 1;
while (true) {
long tmp = n + m;
n = m;
m = tmp;
yield return m;
}
}
static void Main() {
foreach (long i in Fibonacci().Take(10)) {
Console.WriteLine(i);
}
}
}
This is now fully lazy, and using LINQ's Skip/Take etc allows you to control the start/end easily. For example, for your "between" query:
foreach (long i in Fibonacci().SkipWhile(x=>x < from).TakeWhile(x=>x <= to)) {...}
If you prefer recursion instead of the loop:
public static void Main(string[] args)
{
Func<int, int> fib = null;
fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
int start = 1;
int end = 10;
var numbers = Enumerable.Range(start, end).Select(fib);
foreach (var number in numbers)
{
Console.WriteLine(number);
}
}
I would change the IEnumerable<int> type to IEnumerable<Int64> as it will start to overflow from 50
For those who haven't yielded to Linq-ed in like me, the 'Simple Jack' Version. i'm SO banned out of the Jedi club ;)
static List<int> GetAllFibonacciNumbersUpto(int y)
{
List<int> theFibonacciSeq = new List<int>();
theFibonacciSeq.Add(0); theFibonacciSeq.Add(1);
int F_of_n_minus_2 = 0; int F_of_n_minus_1 = 1;
while (F_of_n_minus_2 <= y)
{
theFibonacciSeq.Add(F_of_n_minus_1 + F_of_n_minus_2);
F_of_n_minus_2 = F_of_n_minus_1;
F_of_n_minus_1 = theFibonacciSeq.Last<int>();
}
return theFibonacciSeq;
}
now that we have that out of the way...
// read in some limits
int x = 0; int y = 6785;
foreach (int iNumber in GetAllFibonacciNumbersUpto(y).FindAll(element => (element >= x) && (element <= y)))
Console.Write(iNumber + ",");
Console.WriteLine();

Categories

Resources