Related
Is there an algorithm for calculating a factorial without using System.Numerics library? We receive an int number and we need to return factorial of this number as string(if n = 30, we should return "265252859812191058636308480000000", if n = 70, we should return "11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000" ect. Numbers are very big)
I tried to find out, did anyone already write an article about that, but I didn't find anything.
It suffices to implement multiplication of a large number as a string by a small integer.
Illustration: 12! = 11! x 12 is obtained by multiplying every digit by 12 and summing (with shifts):
39916800
36
108
108
12
72
96
0
0
---------
479001600
A lazy solution. It is possible to evaluate the factorial with just BigNum addition, replacing the multiplications by successive additions. (For n!, we will perform 1+2+3+...n-1 additions. This is acceptable for moderate n.)
The computation uses two pre-allocated string (arrays of char), which are initially filled with null bytes (Writeline skips them). When adding from right to left, we stop when we meet a null.
int n = 20;
// Factorial and temporary string; 100! fits in 158 digits
const int N = 158;
char[] f = new char[N], t = new char[N];
f[N - 1] = '1'; // 1!
// Product up to n by successive additions
for (int i = 2; i <= n; i++)
{
// t= f
f.CopyTo(t, 0);
for (int j = 0; j < i - 1; j++)
{
// f+= t, repeated i-1 times
int c = 0; // Carry
for (int k = N - 1; k >= 0; k--)
{
if (t[k] == 0 && c == 0) break; // Significant part exhausted
int d = Math.Max(0, t[k] - '0') + Math.Max(0, f[k] - '0') + c;
c= d / 10; d = d % 10; f[k] = (char)(d + '0'); // Next carry/digit
}
}
Console.WriteLine(f);
}
Output:
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000
2432902008176640000
static string FindFactorial(int n)
{
int[] result = new int[500000];
result[0] = 1;
int resultSize = 1;
for (int x = 2; x <= n; x++)
resultSize = Multiply(x, result, resultSize);
string factorial = "";
for (int i = resultSize - 1; i >= 0; i--)
factorial += result[i].ToString();
return factorial;
}
static int Multiply(int x, int[] result, int resultSize)
{
int carry = 0;
for (int i = 0; i < resultSize; i++)
{
int product = result[i] * x + carry;
result[i] = product % 10;
carry = product / 10;
}
while (carry != 0)
{
result[resultSize] = carry % 10;
carry /= 10;
resultSize++;
}
return resultSize;
}
This will work
I need to display odds to win with ten decimals if I play with just one variant, for six five and four numbers. For example I need to have this 0.0000000715 but I have this 0.0027829314 if I introduce 49,6,I. What is the problem?How can I make it work? I am a beginner and I don't know how i can obtain this 0.0000000715.
class Program
{
static void Main(string[] args)
{
int n = Convert.ToInt32(Console.ReadLine());
int k = Convert.ToInt32(Console.ReadLine());
string category = Console.ReadLine();
switch (category)
{
case "I":
calculate(n,k);
break;
case "II":
calculate(n, k);
break;
case "III":
calculate(n, k);
break;
}
}
static void calculate(int n, int k)
{
int nk = n - k;
decimal count = prod(1, nk) / prod(k + 1, n);
decimal r = prod(1, k) / prod(n - k + 1, n);
decimal sum = count * r;
Console.WriteLine(Math.Round(r,10));
}
static decimal prod(int x, int y)
{
decimal prod = 0;
for(int i = x; i <= y; i++)
{
prod = x * y;
}
return prod;
}
}
The general solution would be bc(6,n)*bc(49-6,6-n)/bc(49, 6), where n is, 4, 5 or 6 and bc is the binomial coefficient.
Btw.: double should be enough for 10 decimal places, there is no need to use decimal.
using System;
public class Program
{
//bonomial coefficient
static double bc(double n, double k)
{
if (k == 0 || k == n)
return 1;
return bc(n - 1, k - 1) + bc(n - 1, k);
}
public static void Main()
{
for(int n = 4; n <=6; ++n){
Console.WriteLine(bc(6,n)*bc(49-6,6-n)/bc(49, 6));
}
}
}
I am not sur what function you were using.
The chances of winning all 6 numbers is 1 in 13,983,816
The actual calculation is this:
49C6 = 49!/(43! x 6!) = 13983816
So the probability to win is 1 / 13,983,816 = 0.0000000715
Your prod function should look like:
static decimal prod(int x, int y)
{
decimal prod = 1;
for(int i = x; i <= y; i++)
{
prod = prod * i;
}
return prod;
}
As jjj mentioned, you overwrite "prod" everytime, but you need to add it
I want to generate 100 random numbers between 1 and 10. But the average of those 100 random numbers should be 7. How can I do that? I am doing as follows:
//generating random number
Random random = new Random();
int value = random.Next(1,10);
And storing each value in an array. If the average of 100 items in the array is not 7 then I need to get another 100 random numbers. Can anyone suggest a better way of doing this?
public int RandomNumberThatAveragesToSeven()
{
//Chosen by fair dice roll
//Guaranteed to be random
return 7;
}
Without additional parameters, this above algorithm satisfies each and every requirement.
Return must be between 1 and 10
Average of multiple calls must tend to 7 as n tends to inf.
EDIT Since there was so much controversy on this answer...I added this answer...which is definitely random.
public List<int> ProduceRandom100NumbersWithAverageOfSeven()
{
var rand = new Random();
var seed = rand.Next();
if(seed > 0.5)
{
return new List(Enumerable.Concat(
Enumerable.Repeat(6, 50),
Enumerable.Repeat(8, 50)));
}
else
{
return new List(Enumerable.Concat(
Enumerable.Repeat(8, 50),
Enumerable.Repeat(6, 50)));
}
}
Initialize A[0], ..., A[99] to 1.
Initialize I = {0, 1, ..., 99}.
Repeat steps 4-6 600 times.
Pick random i uniformly from I.
Increment A[i].
If A[i] == 10, then remove i from I.
This will guarantee sum(A) is 700 and thus avg(A) is 7.
Note however that this does not give a uniform distribution over all such arrays of 100 integers in {1, ..., 10} such that they sum to 700. To devise an algorithm for uniformly sampling would be a much more challenging exercise.
Something like this might do it:
public static void Main(string[] args)
{
var randomList = new List<int>();
var random = new Random();
var avg = 0;
while (avg != 7)
{
randomList = new List<int>();
GenerateList(randomList, random);
avg = (int) randomList.Average();
}
for (var i = 0; i < randomList.Count; i++)
{
Console.WriteLine(string.Format("Index: {0}, Number: {1}", i, randomList.ElementAt(i)));
}
}
private static void GenerateList(List<int> refList, Random random)
{
for (var i = 0; i < 100; i++)
{
refList.Add(random.Next(1, 10));
}
}
My 2 cents
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Stopwatch watch = Stopwatch.StartNew();
int count = 100;
Double min = 0;
Double max = 10;
Double target = 7;
Double tolerance = 0.00000001;
Double minAverage = target - tolerance;
Double maxAverage = target + tolerance;
Random r = new Random();
List<Double> numbers = new List<double>();
Double sum = 0;
for (int i = 0; i < count; i++)
{
Double d = RangedDouble(min, max, r);
numbers.Add(d);
sum += d;
}
int Adjustments = 0;
while((sum / count < minAverage || (sum / count) > maxAverage))
{
while ((sum / count) < minAverage)
{
Double oldDbl = numbers.First(d => d < minAverage);
Double newDbl = oldDbl + RangedDouble(minAverage - oldDbl, 10 - oldDbl, r);
numbers.Remove(oldDbl);
sum -= oldDbl;
numbers.Add(newDbl);
sum += newDbl;
Adjustments++;
}
while ((sum / count) > maxAverage)
{
Double oldDbl = numbers.First(d => d > maxAverage);
Double newDbl = oldDbl - RangedDouble(oldDbl - maxAverage, oldDbl, r);
numbers.Remove(oldDbl);
sum -= oldDbl;
numbers.Add(newDbl);
sum += newDbl;
Adjustments++;
}
}
watch.Stop();
int x = 0;
while (x < count)
{
Console.WriteLine("{0:F7} {1:F7} {2:F7} {3:F7}", numbers.Skip(x).Take(1).First(), numbers.Skip(x + 1).Take(1).First(), numbers.Skip(x + 2).Take(1).First(), numbers.Skip(x + 3).Take(1).First());
x += 4;
}
Console.WriteLine();
Console.WriteLine(watch.ElapsedMilliseconds);
Console.WriteLine(numbers.Average());
Console.WriteLine(Adjustments);
Console.ReadKey(true);
}
private static double RangedDouble(Double min, Double max, Random r)
{
return (r.NextDouble() * (max - min) + min);
}
}
}
And the output:
8.1510368 7.2103030 7.9909210 9.6693311
8.2275382 7.2839244 8.8634567 7.9751014
7.8643791 7.2262462 9.8914455 9.6875690
8.4396683 8.4308401 7.5380218 8.6147181
8.2760663 7.7399011 7.4312152 9.2115622
9.7850111 9.1061378 9.8672965 9.5610411
7.0415607 8.8446195 9.3562218 8.5279759
7.5227340 9.3572417 9.8927997 9.5880645
9.0908564 7.0918394 9.6213258 8.6528169
9.3803283 9.6869223 1.4006790 3.3310691
7.0719214 2.6370854 9.7558776 8.9180391
3.0486700 5.0082988 8.8624504 5.0497899
0.9692377 7.7140550 9.8495115 6.4933865
4.4939760 9.3187625 5.4353003 6.5405668
9.5693118 5.0339998 6.9644440 4.6902072
0.5241568 9.7748420 0.1406617 8.4731427
9.8064604 6.3113773 0.8628048 9.2417028
8.9148867 9.3111336 3.2424080 9.6710544
4.3794982 5.1687718 9.8207783 0.3283217
9.8321869 2.8093698 7.4377070 4.1130959
5.9840738 9.2560763 3.6691865 2.5498863
7.3242246 7.0179332 5.8906831 9.3340545
0.3735044 7.2442886 0.4409532 9.0749754
9.6716409 8.4097246 2.8069123 7.2970794
2.4964238 8.2826350 9.1115787 3.7373927
1
6.99992266645471
729
edit: changing the code to always result in an average of exactly 7.
This is basically an optimized version of what you were doing already. Instead of generating another 100 numbers, it generates only 10 before doing the check.
using System.Collections.Generic;
using System.Linq;
var r = new Random();
var numbers = new List<int>();
while (numbers.Count < 100)
{
var stack = new Stack<int>();
for (int i = 0; i < 10; i++)
{
stack.Push(r.Next(10));
}
if (stack.Sum() == 70)
{
numbers.AddRange(stack);
}
}
Console.WriteLine(numbers.Average());
OK, it could be tricky to do something like that.
If you need to obtain 100 different numbers and you need that they average will be 7, you'll need them to sum 700.
You'll need to keep track of each number and their total sum. While 700 minus the sum of your obtained so far values is lesser than 10 * the amount of numbers you haven't obtained yet, you can continue obtaining pure random values.
When the moment comes that your obtained values sum is lesser than the values you need to obtain, then you change that last number by a 10, put a 10 in the rest of numbers you need to the end of your list and, on the last number, you get the difference between 700 and the sum of your 99 previous pseudo-random values.
Shuffle your array et voilá, you have a 100 pseudo-random array with numbers from 1 to 10 whose average is 7. Surely it will have more 10s than it'll be desired, but sure you'll be able to fine tune this "algorithm" to make it a bit less 10 prone.
Mmmm, wait a moment, what if you get random values that have an average above 7? You'll need to track also that the sum of your current values is lesser than the numbers you have yet to obtain. If you surpass this value in any moment you'll need to convert your last number to a 1, put a 1 on the rest of your needed values and obtain again your last number as the difference between 700 and your 99 earlier values.
Like the other answers have posted, since we know the length we can get the average by just focusing on the total sum.
I'd solve it recursively. In the base case, we need to generate a list of length 1 which sums to some number s. That's easy: the list just contains s:
rand 1 s = [s]
Now we can solve the recursive case rand n s where n is the desired list length and s is the desired sum. To do this, we'll generate two lists x and y and concatenate them together, subject to the given constraints:
length x + length y = n
sum x + sum y = s
1 * length x <= sum x -- Minimum value is 1
10 * length x >= sum x -- Maximum value is 10
1 * length y <= sum y
10 * length y >= sum y
These equations/inequalities can't be solved yet, so the first thing we do is choose the length of the lists. To keep down the level of recursion we can choose lx = round (n / 2) then set the following:
length x = lx
length y = n - lx = ly
Hence:
sum x + sum y = s
1 * lx <= sum x
10 * lx >= sum x
1 * ly <= sum y
10 * ly >= sum y
We use the first equation to rewrite the inequalities:
1 * lx <= sum x
10 * lx >= sum x
1 * ly <= s - sum x
10 * ly >= s - sum x
We can rearrange the bottom two to make sum x the subject:
sum x + 1 * ly <= s
sum x + 10 * ly >= s
sum x <= s - 1 * ly
sum x >= s - 10 * ly
We know ly and s so these give us definite bounds for sum x, which we combine by taking the largest lower bound and the smallest upper bound:
max (1 * lx) (s - 10 * ly) <= sum x
min (10 * lx) (s - 1 * ly) >= sum x
These bounds make sense: they take into account the cases where every element in x is 1 or 10 and they ensure that the remainder can be handled by sum y. Now we just generate a random number B between these bounds, then set:
sum x = B
sum y = s - B
From that, we can perform our recursion (assuming some random number function randInt):
rand n s = let lx = round (n / 2)
ly = n - lx
lower = max (1 * lx) (s - 10 * ly)
upper = min (10 * lx) (s - 1 * ly)
b = randInt lower upper
in rand lx b ++ rand ly (s - b)
Now your list can be generated by calling:
myList = rand 100 700
I've written this in Haskell for brevity, but it's just arithmetic so should translate to C# easily. Here's a Python version if it helps:
def rand(n, s):
if n == 1:
return [s]
lx = int(n / 2)
ly = n - lx
lower = max(1 * lx, s - 10 * ly)
upper = min(10 * lx, s - 1 * ly)
b = randint(lower, upper)
result = rand(lx, b)
result.extend(rand(ly, s - b))
return result
Please point out any mistakes I've made!
Edit: Although I doubt it's the case for C#, in some languages we could make this simpler and more efficient by using tail-recursion. First we switch to generating one element at a time:
-- Generate one number then recurse
rand 1 s = [s]
rand n s = let ly = n - 1
lower = max 1 (s - 10 * ly)
upper = min 10 (s - 1 * ly)
x = randInt lower upper
in x : rand (n - 1) s
Then we accumulate the result rather than building up unfinished continuations:
rand' xs 1 s = s:xs
rand' xs n s = let ly = n - 1
lower = max 1 (s - 10 * ly)
upper = min 10 (s - 1 * ly)
x = randInt lower upper
in rand' (x:xs) (n-1) s
rand = rand' []
this function is for get fixed average between n Records randomly.
that here in my answer "n" is declared as "count".
https://github.com/amingolmahalle/RandomGenerateDataBetweenTwoNumber
public void ProccessGenerateData(WorkBook workBookData, out List<double> nomreList, out int adjustmentsVal)
{
try
{
nomreList = new List<double>();
adjustmentsVal = 0;
int count = workBookData.NumberStudents;
double min = workBookData.Min;
double max = workBookData.Max;
double target = workBookData.FixedAvg;
double tolerance = workBookData.Tolerance;
double minAverage = Math.Round(target - tolerance, 2);
double maxAverage = Math.Round(target + tolerance, 2);
Random r = new Random(DateTime.Now.Millisecond);
List<double> listNomre = new List<double>();
double sum = 0;
for (int i = 0; i < count; i++)
{
double d = Math.Round(RangedDouble(min, max, r), 2);
listNomre.Add(d);
sum += d;
sum = Math.Round(sum, 2);
}
int adjustments = 0;
while (Math.Round((sum / count), 2) < minAverage || Math.Round((sum / count), 2) > maxAverage)
{
if (Math.Round((sum / count), 2) < minAverage)
{
double oldDbl1 = listNomre.First(d => d < minAverage);
//min<a1+x1<max --> a1 is oldDbl1 , x1 --> Unknown
double newDbl1 = Math.Round(oldDbl1 + RangedDouble(min-oldDbl1, max - oldDbl1, r), 2);
listNomre.Remove(oldDbl1);
sum -= oldDbl1;
sum = Math.Round(sum, 2);
listNomre.Add(newDbl1);
sum += newDbl1;
sum = Math.Round(sum, 2);
adjustments++;
continue;
}
double oldDbl = listNomre.First(d => d > maxAverage);
//min<a1-x1<max --> a1 is oldDbl , x1 --> Unknown
double newDbl = Math.Round(oldDbl - RangedDouble(oldDbl-max, oldDbl - min, r), 2);
listNomre.Remove(oldDbl);
sum -= oldDbl;
sum = Math.Round(sum, 2);
listNomre.Add(newDbl);
sum += newDbl;
sum = Math.Round(sum, 2);
adjustments++;
}
nomreList = listNomre;
adjustmentsVal = adjustments;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
}
private static double RangedDouble(double min, double max, Random r)
{
//Function RangedDouble => Random Number Between 2 Double Numbers
//Random.NextDouble => returns a double between 0 and 1
return Math.Round( r.NextDouble() * (max - min) + min,2);
}
class Program
{
static void Main(string[] args)
{
var rnd = new Random();
var min = 1;
var max = 20;
var avg = 15;
var count = 5000;
var numbers = new List<int>();
for (var i = 0; i < count; i++)
{
var random1 = rnd.Next(min, avg + 1);
var random2 = rnd.Next(avg + 2, max + 1);
var randoms = new List<int>();
randoms.AddRange(Enumerable.Repeat<int>(random2, avg - min));
randoms.AddRange(Enumerable.Repeat<int>(random1, max - avg));
var generatedNumber = randoms[rnd.Next(randoms.Count)];
numbers.Add(generatedNumber);
}
numbers = numbers.OrderBy(x => x).ToList();
var groups = numbers.GroupBy(x => x).OrderByDescending(x => x.Count()).ToList();
groups.ForEach(x => Console.WriteLine($"{x.Key}: {x.Count()}"));
Console.WriteLine($"Average: {numbers.Average(x => x)}");
Console.WriteLine($"Count of numbers: {groups.Count}");
}
}
This method generates a random number sequence then keeps adding/subtracting until we get the correct total (700), so long as the number we are altering is still in the range of 1-10
List<int> randomNumbers = new List<int>();
for (int i = 0; i < 100; i++) {
numbers.Add(r.Next(1, 10));
}
int total = randomNumbers.Sum();
// Now fiddle until we get the correct total (700)
if (total < 700) {
while (total < 700) {
for (int i = 0; i < 100; i++) {
if (numbers[i] < 10) {
numbers[i]++;
total = randomNumbers.Sum();
if (total == 700) break;
}
}
}
}
else if (total > 700) {
while (total > 700) {
for (int i = 99; i >= 0; i--) {
if (numbers[i] > 0) {
numbers[i]--;
total = randomNumbers.Sum();
if (total == 700) break;
}
}
}
}
I'm trying to calculate the product of digits of each number of a sequence of numbers, for example:
21, 22, 23 ... 98, 99 ..
would be:
2, 4, 6 ... 72, 81 ..
To reduce the complexity, I would consider only the [consecutive numbers] in a limited length of digits, such as from 001 to 999 or from 0001 to 9999.
However, when the sequence is large, for example, 1000000000, repeatedly extract the digits and then multiply for every number would be inefficient.
The basic idea is to skip the consecutive zeros we will encounter during the calculation, something like:
using System.Collections.Generic;
using System.Linq;
using System;
// note the digit product is not given with the iteration
// we would need to provide a delegate for the calculation
public static partial class NumericExtensions {
public static void NumberIteration(
this int value, Action<int, int[]> delg, int radix=10) {
var digits=DigitIterator(value, radix).ToArray();
var last=digits.Length-1;
var emptyArray=new int[] { };
var pow=(Func<int, int, int>)((x, y) => (int)Math.Pow(x, 1+y));
var weights=Enumerable.Repeat(radix, last-1).Select(pow).ToArray();
for(int complement=radix-1, i=value, j=i; i>0; i-=1)
if(i>j)
delg(i, emptyArray);
else if(0==digits[0]) {
delg(i, emptyArray);
var k=0;
for(; k<last&&0==digits[k]; k+=1)
;
var y=(digits[k]-=1);
if(last==k||0!=y) {
if(0==y) { // implied last==k
digits=new int[last];
last-=1;
}
for(; k-->0; digits[k]=complement)
;
}
else {
j=i-weights[k-1];
}
}
else {
// receives digits of a number which doesn't contain zeros
delg(i, digits);
digits[0]-=1;
}
delg(0, emptyArray);
}
static IEnumerable<int> DigitIterator(int value, int radix) {
if(-2<radix&&radix<2)
radix=radix<0?-2:2;
for(int remainder; 0!=value; ) {
value=Math.DivRem(value, radix, out remainder);
yield return remainder;
}
}
}
This is only for the enumeration of numbers, to avoid numbers which contain zeros to be calculated in the first place, the digit products are not yet given by the code; but generate the digit products by providing a delegate to perform the calculation will still take time.
How to calculate the digit products of the consecutive numbers efficiently?
EDIT: The "start from anywhere, extended range" version...
This version has a signficantly extended range, and therefore returns an IEnumerable<long> instead of an IEnumerable<int> - multiply enough digits together and you exceed int.MaxValue. It also goes up to 10,000,000,000,000,000 - not quite the full range of long, but pretty big :) You can start anywhere you like, and it will carry on from there to its end.
class DigitProducts
{
private static readonly int[] Prefilled = CreateFirst10000();
private static int[] CreateFirst10000()
{
// Inefficient but simple, and only executed once.
int[] values = new int[10000];
for (int i = 0; i < 10000; i++)
{
int product = 1;
foreach (var digit in i.ToString())
{
product *= digit -'0';
}
values[i] = product;
}
return values;
}
public static IEnumerable<long> GetProducts(long startingPoint)
{
if (startingPoint >= 10000000000000000L || startingPoint < 0)
{
throw new ArgumentOutOfRangeException();
}
int a = (int) (startingPoint / 1000000000000L);
int b = (int) ((startingPoint % 1000000000000L) / 100000000);
int c = (int) ((startingPoint % 100000000) / 10000);
int d = (int) (startingPoint % 10000);
for (; a < 10000; a++)
{
long aMultiplier = a == 0 ? 1 : Prefilled[a];
for (; b < 10000; b++)
{
long bMultiplier = a == 0 && b == 0 ? 1
: a != 0 && b < 1000 ? 0
: Prefilled[b];
for (; c < 10000; c++)
{
long cMultiplier = a == 0 && b == 0 && c == 0 ? 1
: (a != 0 || b != 0) && c < 1000 ? 0
: Prefilled[c];
long abcMultiplier = aMultiplier * bMultiplier * cMultiplier;
for (; d < 10000; d++)
{
long dMultiplier =
(a != 0 || b != 0 || c != 0) && d < 1000 ? 0
: Prefilled[d];
yield return abcMultiplier * dMultiplier;
}
d = 0;
}
c = 0;
}
b = 0;
}
}
}
EDIT: Performance analysis
I haven't looked at the performance in detail, but I believe at this point the bulk of the work is just simply iterating over a billion values. A simple for loop which just returns the value itself takes over 5 seconds on my laptop, and iterating over the digit products only takes a bit over 6 seconds, so I don't think there's much more room for optimization - if you want to go from the start. If you want to (efficiently) start from a different position, more tweaks are required.
Okay, here's an attempt which uses an iterator block to yield the results, and precomputes the first thousand results to make things a bit quicker.
I've tested it up to about 150 million, and it's correct so far. It only goes returns the first billion results - if you needed more than that, you could add another block at the end...
static IEnumerable<int> GetProductDigitsFast()
{
// First generate the first 1000 values to cache them.
int[] productPerThousand = new int[1000];
// Up to 9
for (int x = 0; x < 10; x++)
{
productPerThousand[x] = x;
yield return x;
}
// Up to 99
for (int y = 1; y < 10; y++)
{
for (int x = 0; x < 10; x++)
{
productPerThousand[y * 10 + x] = x * y;
yield return x * y;
}
}
// Up to 999
for (int x = 1; x < 10; x++)
{
for (int y = 0; y < 10; y++)
{
for (int z = 0; z < 10; z++)
{
int result = x * y * z;
productPerThousand[x * 100 + y * 10 + z] = x * y * z;
yield return result;
}
}
}
// Now use the cached values for the rest
for (int x = 0; x < 1000; x++)
{
int xMultiplier = x == 0 ? 1 : productPerThousand[x];
for (int y = 0; y < 1000; y++)
{
// We've already yielded the first thousand
if (x == 0 && y == 0)
{
continue;
}
// If x is non-zero and y is less than 100, we've
// definitely got a 0, so the result is 0. Otherwise,
// we just use the productPerThousand.
int yMultiplier = x == 0 || y >= 100 ? productPerThousand[y]
: 0;
int xy = xMultiplier * yMultiplier;
for (int z = 0; z < 1000; z++)
{
if (z < 100)
{
yield return 0;
}
else
{
yield return xy * productPerThousand[z];
}
}
}
}
}
I've tested this by comparing it with the results of an incredibly naive version:
static IEnumerable<int> GetProductDigitsSlow()
{
for (int i = 0; i < 1000000000; i++)
{
int product = 1;
foreach (var digit in i.ToString())
{
product *= digit -'0';
}
yield return product;
}
}
Hope this idea is of some use... I don't know how it compares to the others shown here in terms of performance.
EDIT: Expanding this slightly, to use simple loops where we know the results will be 0, we end up with fewer conditions to worry about, but for some reason it's actually slightly slower. (This really surprised me.) This code is longer, but possibly a little easier to follow.
static IEnumerable<int> GetProductDigitsFast()
{
// First generate the first 1000 values to cache them.
int[] productPerThousand = new int[1000];
// Up to 9
for (int x = 0; x < 10; x++)
{
productPerThousand[x] = x;
yield return x;
}
// Up to 99
for (int y = 1; y < 10; y++)
{
for (int x = 0; x < 10; x++)
{
productPerThousand[y * 10 + x] = x * y;
yield return x * y;
}
}
// Up to 999
for (int x = 1; x < 10; x++)
{
for (int y = 0; y < 10; y++)
{
for (int z = 0; z < 10; z++)
{
int result = x * y * z;
productPerThousand[x * 100 + y * 10 + z] = x * y * z;
yield return result;
}
}
}
// Use the cached values up to 999,999
for (int x = 1; x < 1000; x++)
{
int xMultiplier = productPerThousand[x];
for (int y = 0; y < 100; y++)
{
yield return 0;
}
for (int y = 100; y < 1000; y++)
{
yield return xMultiplier * y;
}
}
// Now use the cached values for the rest
for (int x = 1; x < 1000; x++)
{
int xMultiplier = productPerThousand[x];
// Within each billion, the first 100,000 values will all have
// a second digit of 0, so we can just yield 0.
for (int y = 0; y < 100 * 1000; y++)
{
yield return 0;
}
for (int y = 100; y < 1000; y++)
{
int yMultiplier = productPerThousand[y];
int xy = xMultiplier * yMultiplier;
// Within each thousand, the first 100 values will all have
// an anti-penulimate digit of 0, so we can just yield 0.
for (int z = 0; z < 100; z++)
{
yield return 0;
}
for (int z = 100; z < 1000; z++)
{
yield return xy * productPerThousand[z];
}
}
}
}
You can do this in a dp-like fashion with the following recursive formula:
n n <= 9
a[n/10] * (n % 10) n >= 10
where a[n] is the result of the multiplication of the digits of n.
This leads to a simple O(n) algorithm: When calculating f(n) assuming you have already calculated f(·) for smaller n, you can just use the result from all digits but the last multiplied with the last digit.
a = range(10)
for i in range(10, 100):
a.append(a[i / 10] * (i % 10))
You can get rid of the expensive multiplication by just adding doing a[n - 1] + a[n / 10] for numbers where the last digit isn't 0.
The key to efficiency is not to enumerate the numbers and extract the digits, but to enumerate digits and generate the numbers.
int[] GenerateDigitProducts( int max )
{
int sweep = 1;
var results = new int[max+1];
for( int i = 1; i <= 9; ++i ) results[i] = i;
// loop invariant: all values up to sweep * 10 are filled in
while (true) {
int prior = results[sweep];
if (prior > 0) {
for( int j = 1; j <= 9; ++j ) {
int k = sweep * 10 + j; // <-- the key, generating number from digits is much faster than decomposing number into digits
if (k > max) return results;
results[k] = prior * j;
// loop invariant: all values up to k are filled in
}
}
++sweep;
}
}
It's up to the caller to ignore the results which are less than min.
Demo: http://ideone.com/rMK7Sh
Here's a low space version using the branch-bound-prune technique:
static void VisitDigitProductsImpl(int min, int max, System.Action<int, int> visitor, int build_n, int build_ndp)
{
if (build_n >= min && build_n <= max) visitor(build_n, build_ndp);
// bound
int build_n_min = build_n;
int build_n_max = build_n;
do {
build_n_min *= 10;
build_n_max *= 10;
build_n_max += 9;
// prune
if (build_n_min > max) return;
} while (build_n_max < min);
int next_n = build_n * 10;
int next_ndp = 0;
// branch
// if you need to visit zeros as well: VisitDigitProductsImpl(min, max, visitor, next_n, next_ndp);
for( int i = 1; i <= 9; ++i ) {
next_n++;
next_ndp += build_ndp;
VisitDigitProductsImpl(min, max, visitor, next_n, next_ndp);
}
}
static void VisitDigitProducts(int min, int max, System.Action<int, int> visitor)
{
for( int i = 1; i <= 9; ++i )
VisitDigitProductsImpl(min, max, visitor, i, i);
}
Demo: http://ideone.com/AIal1L
Calculating a product from the previous one
Because the numbers are consecutive, in most cases you can generate one product from the previous one by inspecting only the units place.
For example:
12345 = 1 * 2 * 3 * 4 * 5 = 120
12346 = 1 * 2 * 3 * 4 * 6 = 144
But once you've calculated the value for 12345, you can calculate 12346 as (120 / 5) * 6.
Clearly this won't work if the previous product was zero. It does work when wrapping over from 9 to 10 because the new last digit is zero, but you could optimise that case anyway (see below).
If you're dealing with lots of digits, this approach adds up to quite a saving even though it involves a division.
Dealing with zeros
As you're looping through values to generate the products, as soon as you encounter a zero you know that the product will be zero.
For example, with four-digit numbers, once you get to 1000 you know that the products up to 1111 will all be zero so there's no need to calculate these.
The ultimate efficiency
Of course, if you're willing or able to generate and cache all the values up front then you can retrieve them in O(1). Further, as it's a one-off cost, the efficiency of the algorithm you use to generate them may be less important in this case.
I end up with very simple code as the following:
Code:
public delegate void R(
R delg, int pow, int rdx=10, int prod=1, int msd=0);
R digitProd=
default(R)!=(digitProd=default(R))?default(R):
(delg, pow, rdx, prod, msd) => {
var x=pow>0?rdx:1;
for(var call=(pow>1?digitProd:delg); x-->0; )
if(msd>0)
call(delg, pow-1, rdx, prod*x, msd);
else
call(delg, pow-1, rdx, x, x);
};
msd is the most significant digit, it's like most significant bit in binary.
The reason I didn't choose to use iterator pattern is it takes more time than the method call. The complete code(with test) is put at the rear of this answer.
Note that the line default(R)!=(digitProd=default(R))?default(R): ... is only for assigment of digitProd, since the delegate cannot be used before it is assigned. We can actually write it as:
Alternative syntax:
var digitProd=default(R);
digitProd=
(delg, pow, rdx, prod, msd) => {
var x=pow>0?rdx:1;
for(var call=(pow>1?digitProd:delg); x-->0; )
if(msd>0)
call(delg, pow-1, rdx, prod*x, msd);
else
call(delg, pow-1, rdx, x, x);
};
The disadvantage of this implementation is that it cannot started from a particular number but the maximum number of full digits.
There're some simple ideas that I solve it:
Recursion
The delegate(Action) R is a recursive delegate definition which is used as tail call recursion, for both the algorithm and the delegate which receives the result of digit product.
And the other ideas below explain for why recursion.
No division
For consecutive numbers, use of the division to extract each digit is considered low efficiency, thus I chose to operate on the digits directly with recursion in a down-count way.
For example, with 3 digits of the number 123, it's one of the 3 digits numbers started from 999:
9 8 7 6 5 4 3 2 [1] 0 -- the first level of recursion
9 8 7 6 5 4 3 [2] 1 0 -- the second level of recursion
9 8 7 6 5 4 [3] 2 1 0 -- the third level of recursion
Don't cache
As we can see that this answer
How to multiply each digit in a number efficiently
suggested to use the mechanism of caching, but for the consecutive numbers, we don't, since it is the cache.
For the numbers 123, 132, 213, 231, 312, 321, the digit products are identical. Thus for a cache, we can reduce the items to store which are only the same digits with different order(permutations), and we can regard them as the same key.
However, sorting the digits also takes time. With a HashSet implemented collection of keys, we pay more storage with more items; even we've reduced the items, we still spend time on equality comparing. There does not seem to be a hash function better than use its value for equality comparing, and which is just the result we are calculating. For example, excepting 0 and 1, there're only 36 combinations in the multiplication table of two digits.
Thus, as long as the calculation is efficient enough, we can consider the algorithm itself is a virtual cache without costing a storage.
Reduce the time on calculation of numbers contain zero(s)
For the digit products of consecutive numbers, we will encounter:
1 zero per 10
10 consecutive zeros per 100
100 consecutive zeros per 1000
and so on. Note that there are still 9 zeros we will encounter with per 10 in per 100. The count of zeros can be calculated with the following code:
static int CountOfZeros(int n, int r=10) {
var powerSeries=n>0?1:0;
for(var i=0; n-->0; ++i) {
var geometricSeries=(1-Pow(r, 1+n))/(1-r);
powerSeries+=geometricSeries*Pow(r-1, 1+i);
}
return powerSeries;
}
For n is the count of digits, r is the radix. The number would be a power series which calculated from a geometric series and plus 1 for the 0.
For example, the numbers of 4 digits, the zeros we will encounter are:
(1)+(((1*9)+11)*9+111)*9 = (1)+(1*9*9*9)+(11*9*9)+(111*9) = 2620
For this implementation, we do not really skip the calculation of numbers contain zero. The reason is the result of a shallow level of recursion is reused with the recursive implementation which are what we can regard as cached. The attempting of multiplication with a single zero can be detected and avoided before it performs, and we can pass a zero to the next level of recursion directly. However, just multiply will not cause much of performance impact.
The complete code:
public static partial class TestClass {
public delegate void R(
R delg, int pow, int rdx=10, int prod=1, int msd=0);
public static void TestMethod() {
var power=9;
var radix=10;
var total=Pow(radix, power);
var value=total;
var count=0;
R doNothing=
(delg, pow, rdx, prod, msd) => {
};
R countOnly=
(delg, pow, rdx, prod, msd) => {
if(prod>0)
count+=1;
};
R printProd=
(delg, pow, rdx, prod, msd) => {
value-=1;
countOnly(delg, pow, rdx, prod, msd);
Console.WriteLine("{0} = {1}", value.ToExpression(), prod);
};
R digitProd=
default(R)!=(digitProd=default(R))?default(R):
(delg, pow, rdx, prod, msd) => {
var x=pow>0?rdx:1;
for(var call=(pow>1?digitProd:delg); x-->0; )
if(msd>0)
call(delg, pow-1, rdx, prod*x, msd);
else
call(delg, pow-1, rdx, x, x);
};
Console.WriteLine("--- start --- ");
var watch=Stopwatch.StartNew();
digitProd(printProd, power);
watch.Stop();
Console.WriteLine(" total numbers: {0}", total);
Console.WriteLine(" zeros: {0}", CountOfZeros(power-1));
if(count>0)
Console.WriteLine(" non-zeros: {0}", count);
var seconds=(decimal)watch.ElapsedMilliseconds/1000;
Console.WriteLine("elapsed seconds: {0}", seconds);
Console.WriteLine("--- end --- ");
}
static int Pow(int x, int y) {
return (int)Math.Pow(x, y);
}
static int CountOfZeros(int n, int r=10) {
var powerSeries=n>0?1:0;
for(var i=0; n-->0; ++i) {
var geometricSeries=(1-Pow(r, 1+n))/(1-r);
powerSeries+=geometricSeries*Pow(r-1, 1+i);
}
return powerSeries;
}
static String ToExpression(this int value) {
return (""+value).Select(x => ""+x).Aggregate((x, y) => x+"*"+y);
}
}
In the code, doNothing, countOnly, printProd are for what to do when we get the result of digit product, we can pass any of them to digitProd which implemented the full algorithm. For example, digitProd(countOnly, power) would only increase count, and the final result would be as same as CountOfZeros returns.
I'd create an array that represent the decimal digits of a number and then increase that number just as you would in real life (i.e. on an overflow increase the more significant digit).
From there I'd use an array of products that can be used as a tiny lookup table.
E.g.
the number 314 would result in the product array: 3, 3, 12
the number 345 would result in the product array: 3, 12, 60
Now if you increase the decimal number you'd only need to recalculate the righter most product by multiplying it with the product to the left. When a second digit is modified you'd only recalculate two products (the second from the right and the outer right product). This way you'll never calculate more than absolutely necessary and you have a very tiny lookup table.
So if you start with the number 321 and increment then:
digits = 3, 2, 1 products = 3, 6, 6
incrementing then changes the outer right digit and therefore only the outer right product is recalculated
digits = 3, 2, 2 products = 3, 6, 12
This goes up until the second digit is incremented:
digits = 3, 3, 0 products = 3, 9, 0 (two products recalculated)
Here is an example to show the idea (not very good code, but just as an example):
using System;
using System.Diagnostics;
namespace Numbers2
{
class Program
{
/// <summary>
/// Maximum of supported digits.
/// </summary>
const int MAXLENGTH = 20;
/// <summary>
/// Contains the number in a decimal format. Index 0 is the righter number.
/// </summary>
private static byte[] digits = new byte[MAXLENGTH];
/// <summary>
/// Contains the products of the numbers. Index 0 is the righther number. The left product is equal to the digit on that position.
/// All products to the right (i.e. with lower index) are the product of the digit at that position multiplied by the product to the left.
/// E.g.
/// 234 will result in the product 2 (=first digit), 6 (=second digit * 2), 24 (=third digit * 6)
/// </summary>
private static long[] products = new long[MAXLENGTH];
/// <summary>
/// The length of the decimal number. Used for optimisation.
/// </summary>
private static int currentLength = 1;
/// <summary>
/// The start value for the calculations. This number will be used to start generated products.
/// </summary>
const long INITIALVALUE = 637926372435;
/// <summary>
/// The number of values to calculate.
/// </summary>
const int NROFVALUES = 10000;
static void Main(string[] args)
{
Console.WriteLine("Started at " + DateTime.Now.ToString("HH:mm:ss.fff"));
// set value and calculate all products
SetValue(INITIALVALUE);
UpdateProducts(currentLength - 1);
for (long i = INITIALVALUE + 1; i <= INITIALVALUE + NROFVALUES; i++)
{
int changedByte = Increase();
Debug.Assert(changedByte >= 0);
// update the current length (only increase because we're incrementing)
if (changedByte >= currentLength) currentLength = changedByte + 1;
// recalculate products that need to be updated
UpdateProducts(changedByte);
//Console.WriteLine(i.ToString() + " = " + products[0].ToString());
}
Console.WriteLine("Done at " + DateTime.Now.ToString("HH:mm:ss.fff"));
Console.ReadLine();
}
/// <summary>
/// Sets the value in the digits array (pretty blunt way but just for testing)
/// </summary>
/// <param name="value"></param>
private static void SetValue(long value)
{
var chars = value.ToString().ToCharArray();
for (int i = 0; i < MAXLENGTH; i++)
{
int charIndex = (chars.Length - 1) - i;
if (charIndex >= 0)
{
digits[i] = Byte.Parse(chars[charIndex].ToString());
currentLength = i + 1;
}
else
{
digits[i] = 0;
}
}
}
/// <summary>
/// Recalculate the products and store in products array
/// </summary>
/// <param name="changedByte">The index of the digit that was changed. All products up to this index will be recalculated. </param>
private static void UpdateProducts(int changedByte)
{
// calculate other products by multiplying the digit with the left product
bool previousProductWasZero = false;
for (int i = changedByte; i >= 0; i--)
{
if (previousProductWasZero)
{
products[i] = 0;
}
else
{
if (i < currentLength - 1)
{
products[i] = (int)digits[i] * products[i + 1];
}
else
{
products[i] = (int)digits[i];
}
if (products[i] == 0)
{
// apply 'zero optimisation'
previousProductWasZero = true;
}
}
}
}
/// <summary>
/// Increases the number and returns the index of the most significant byte that changed.
/// </summary>
/// <returns></returns>
private static int Increase()
{
digits[0]++;
for (int i = 0; i < MAXLENGTH - 1; i++)
{
if (digits[i] == 10)
{
digits[i] = 0;
digits[i + 1]++;
}
else
{
return i;
}
}
if (digits[MAXLENGTH - 1] == 10)
{
digits[MAXLENGTH - 1] = 0;
}
return MAXLENGTH - 1;
}
}
}
This way calculating the product for 1000 numbers in the billion range is nearly as fast as doing that for the numbers 1 to 1000.
By the way, I'm very curious what you're trying to use all this for?
Depending on the length of your numbers and the length of the sequence if would go for some optimization.
As you can limit the maximum size of the number you could iterate over the number itself via an increasing modulus.
Let's say you have the number 42:
var Input = 42;
var Product = 1;
var Result = 0;
// Iteration - step 1:
Result = Input % 10; // = 2
Input -= Result;
Product *= Result;
// Iteration - step 2:
Result = Input % 100 / 10; // = 4
Input -= Result;
Product *= Result;
You can pack this operation into a nice loop which is probably small enough to fit in the processors caches and iterate over the whole number. As you avoid any function calls this is probably also quite fast.
If you want to concern zeros as abort criteria the implementation for this is obviously quite easy.
As Matthew said already: Ultimate performance and efficiency will be gained with a lookup table.
The smaller the range of your sequence numbers is, the faster the lookup table is; because it will be retrieved from the cache and not from slow memory.
What's the fastest and easiest to read implementation of calculating the sum of digits?
I.e. Given the number: 17463 = 1 + 7 + 4 + 6 + 3 = 21
You could do it arithmetically, without using a string:
sum = 0;
while (n != 0) {
sum += n % 10;
n /= 10;
}
I use
int result = 17463.ToString().Sum(c => c - '0');
It uses only 1 line of code.
For integer numbers, Greg Hewgill has most of the answer, but forgets to account for the n < 0. The sum of the digits of -1234 should still be 10, not -10.
n = Math.Abs(n);
sum = 0;
while (n != 0) {
sum += n % 10;
n /= 10;
}
It the number is a floating point number, a different approach should be taken, and chaowman's solution will completely fail when it hits the decimal point.
public static int SumDigits(int value)
{
int sum = 0;
while (value != 0)
{
int rem;
value = Math.DivRem(value, 10, out rem);
sum += rem;
}
return sum;
}
int num = 12346;
int sum = 0;
for (int n = num; n > 0; sum += n % 10, n /= 10) ;
I like the chaowman's response, but would do one change
int result = 17463.ToString().Sum(c => Convert.ToInt32(c));
I'm not even sure the c - '0', syntax would work? (substracting two characters should give a character as a result I think?)
I think it's the most readable version (using of the word sum in combination with the lambda expression showing that you'll do it for every char). But indeed, I don't think it will be the fastest.
I thought I'd just post this for completion's sake:
If you need a recursive sum of digits, e.g: 17463 -> 1 + 7 + 4 + 6 + 3 = 21 -> 2 + 1 = 3
then the best solution would be
int result = input % 9;
return (result == 0 && input > 0) ? 9 : result;
int n = 17463; int sum = 0;
for (int i = n; i > 0; i = i / 10)
{
sum = sum + i % 10;
}
Console.WriteLine(sum);
Console.ReadLine();
I would suggest that the easiest to read implementation would be something like:
public int sum(int number)
{
int ret = 0;
foreach (char c in Math.Abs(number).ToString())
ret += c - '0';
return ret;
}
This works, and is quite easy to read. BTW: Convert.ToInt32('3') gives 51, not 3. Convert.ToInt32('3' - '0') gives 3.
I would assume that the fastest implementation is Greg Hewgill's arithmetric solution.
private static int getDigitSum(int ds)
{
int dssum = 0;
while (ds > 0)
{
dssum += ds % 10;
ds /= 10;
if (dssum > 9)
{
dssum -= 9;
}
}
return dssum;
}
This is to provide the sum of digits between 0-9
public static int SumDigits1(int n)
{
int sum = 0;
int rem;
while (n != 0)
{
n = Math.DivRem(n, 10, out rem);
sum += rem;
}
return sum;
}
public static int SumDigits2(int n)
{
int sum = 0;
int rem;
for (sum = 0; n != 0; sum += rem)
n = Math.DivRem(n, 10, out rem);
return sum;
}
public static int SumDigits3(int n)
{
int sum = 0;
while (n != 0)
{
sum += n % 10;
n /= 10;
}
return sum;
}
Complete code in: https://dotnetfiddle.net/lwKHyA
int j, k = 1234;
for(j=0;j+=k%10,k/=10;);
A while back, I had to find the digit sum of something. I used Muhammad Hasan Khan's code, however it kept returning the right number as a recurring decimal, i.e. when the digit sum was 4, i'd get 4.44444444444444 etc.
Hence I edited it, getting the digit sum correct each time with this code:
double a, n, sumD;
for (n = a; n > 0; sumD += n % 10, n /= 10);
int sumI = (int)Math.Floor(sumD);
where a is the number whose digit sum you want, n is a double used for this process, sumD is the digit sum in double and sumI is the digit sum in integer, so the correct digit sum.
static int SumOfDigits(int num)
{
string stringNum = num.ToString();
int sum = 0;
for (int i = 0; i < stringNum.Length; i++)
{
sum+= int.Parse(Convert.ToString(stringNum[i]));
}
return sum;
}
If one wants to perform specific operations like add odd numbers/even numbers only, add numbers with odd index/even index only, then following code suits best. In this example, I have added odd numbers from the input number.
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Please Input number");
Console.WriteLine(GetSum(Console.ReadLine()));
}
public static int GetSum(string num){
int summ = 0;
for(int i=0; i < num.Length; i++){
int currentNum;
if(int.TryParse(num[i].ToString(),out currentNum)){
if(currentNum % 2 == 1){
summ += currentNum;
}
}
}
return summ;
}
}
The simplest and easiest way would be using loops to find sum of digits.
int sum = 0;
int n = 1234;
while(n > 0)
{
sum += n%10;
n /= 10;
}
#include <stdio.h>
int main (void) {
int sum = 0;
int n;
printf("Enter ir num ");
scanf("%i", &n);
while (n > 0) {
sum += n % 10;
n /= 10;
}
printf("Sum of digits is %i\n", sum);
return 0;
}
Surprised nobody considered the Substring method. Don't know whether its more efficient or not. For anyone who knows how to use this method, its quite intuitive for cases like this.
string number = "17463";
int sum = 0;
String singleDigit = "";
for (int i = 0; i < number.Length; i++)
{
singleDigit = number.Substring(i, 1);
sum = sum + int.Parse(singleDigit);
}
Console.WriteLine(sum);
Console.ReadLine();