I'm writing a graphics program in C# and I couldn't figure out a good way to run a for loop between two values, where either one may be larger or smaller than the other.
To demonstrate, the following code works perfectly when X2>X1:
for (int x = X1; x<=X2; x++) {
//code
}
However, it fails when X2<X1. What I want to happen in this situation is that the loop starts at X1 and goes backwards until X2.
I since I'm doing a graphics program, I can't simply swap X1 and X2 when X2<X1, as this would mean swapping their associated Y values, which could produce the same problem just for Y values. The loop must always start at X1, it's the direction(+/-) that needs to change, not the order of values.
I've thought of a few solutions however they all have flaws, it's worth noting that X1 will never equal X2.
#1: Replicate loop
if (X2<X1) {
for (int x = X1; x>=X2; x--) {/*code*/}
} else {
for (int x = X1; x<=X2; x++) {/*code*/}
}
Unsuitable because of replicated code, especially if the "//code" section is particularly long
#2: Lots of ternaries
for (int x = X1; x!=X2+(X2<X1?-1:1); x+=(X2<X1?-1:1)) {/*code*/}
While this code works and is concise, it's readability is terrible. Also I've seen in various places that using "not equal to" for your loop constraint is bad practice source
#3: Use a while loop
int x = X1;
while(true) {
//code
if (X2<X1) {
x--;
if (x<X2) break;
} else {
x++;
if (x>X2) break;
}
}
This solution seems very long and convoluted to perform such a simple task, in addition, use of "while(true)" is also bad practice source
I think the most readable option is to simple create/extract method from the repeating code (the first proposed version):
void ComputeRenderedStuff(int x)
{
// do your computations for x
}
if (X2<X1)
for (int x = X1; x>=X2; x--)
ComputeRenderedStuff(x);
else
for (int x = X1; x<=X2; x++)
ComputeRenderedStuff(x);
A simple solution would be to use one variable for the loop itself, and another variable for the steps:
int length = Math.Abs(x1-x2);
for(int i=0; i <= length; i++)
{
// step will go either from x1 to x2 or from x2 to x1.
int step = (x1 < x2) ? x1 + i : x2 + (length-i);
}
Of course, you can wrap the entire loop in a method, so you wouldn't have to repeat the code:
void ForLoopUnknownDirection(int start, int stop, Action<int> action)
{
int length = Math.Abs(start-stop);
for(int i=0; i <= length; i++)
{
int step = (start < stop) ? start + i : stop + (length-i);
action(step);
}
}
This way you can do whatever you want between the numbers while only writing the loop code once.
See a live demo on rextester
Simply use Math.Min() and Math.Max() to choose lower and upper boundaries.
Something like this:
int MinX = Math.Min(X1, X2);
int MaxX = Math.Max(X1, X2);
for (int x = MinX; x <= MaxX; x++) {
//code
}
Maybe extract a method like this
private static IEnumerable<int> Step(int start, int end)
{
if (start < end)
{
for (int x = start; x <= end; x++)
yield return x;
}
else
{
for (int x = start; x >= end; x--)
yield return x;
}
}
Then you can do
foreach (int x in Step(X1, X2))
{
/*code*/
}
Use a directional increment ( d in the code below )
var d = (x1 > x2) ? -1 : 1;
var i = x1;
while (i != x2)
{
//
// insert your code here
//
i = i + d;
}
Am I purdy? ๐
Why so complicated?
for (int n = 0; n < Count; n++)
{
int Index = (ascending ? n : Count - 1- n);
}
I am working on a problem from CodeChef where I need to calculate the factorial of n numbers.
The user inputs a number which determines how many ints to perform a factorial calculation on and then inputs the numbers to calculate.
My problem is with the multiplication itself. For example if I have an int == 5 then the result will be 20 (it will calculate n by the last factorial only, not by all of them)
Here is where the problem exists:
for(int x = 0; x < _numbersToProcess.Length; x++) {// Loop throuigh Array by index
for (int y = 1; y < _numbersToProcess[x]; y++) {// Y is equal to less than index x
_result[x] = _numbersToProcess[x] * y;// Multiply x by y then add to array
}
}
The outer loop defines how many calculations to perform.
The inner loop calulates the factorials by iterating through each index of _numberToProcess and multiplying it by every number less than the number to be calculated on.
The problem is that the factorial calculation overwrites itself,
for example:
factorial of 5 result: 20 but it should be 120 (it overwrites itself until it reaches the last multiplier)
So I tried the following:
_result[x] = _numbersToProcess[x] *= y;
This is obviously the same as _numbersToProcess[x] = _numbersToProcess[x] * y;
But this gives a completley different result:
If we again input 5 then this will result in the output of -1899959296.
I know I can easily copy and paste from other submissions but I want to know why my method does not result in the correct output.
Here is the method in its entirety:
int _numbers = int.Parse(Console.ReadLine());// Get number of ints to calculate
int[] _numbersToProcess = new int[_numbers];// Array of inputs
int[] _result = new int[_numbers];
int i = 0;
while(i < _numbersToProcess.Length) {
_numbersToProcess[i] = int.Parse(Console.ReadLine());
i++;
}
for(int x = 0; x < _numbersToProcess.Length; x++) {// Loop throuigh Array by index
for (int y = 1; y < _numbersToProcess[x]; y++) {// Y is equal to less than index x
_result[x] = _numbersToProcess[x] *= y;// Multiply x by y then add to array
}
}
for (int n = 0; n < _result.Length; n++) {// Y is equal to less than index x
Console.WriteLine(_result[n]);// Write to console
}
Console.ReadLine();
int _numbers = int.Parse(Console.ReadLine());// Get number of ints to calculate
int[] _numbersToProcess = new int[_numbers];// Array of inputs
int[] _result = new int[_numbers];
int i = 0;
while(i < _numbersToProcess.Length) {
_numbersToProcess[i] = int.Parse(Console.ReadLine());
i++;
}
for (int x = 0; x < _numbersToProcess.Length; x++)
{// Loop throuigh Array by index
int fact = 1;
for (int y = 1; y <= _numbersToProcess[x]; y++)
{// Y is equal to less than index x
fact = fact*y;
}
_result[x] = fact;
}
for (int n = 0; n < _result.Length; n++) {// Y is equal to less than index x
Console.WriteLine(_result[n]);// Write to console
}
Console.ReadLine();
Problem is with your inner for loop. here, you are always, overriding result array.
i.e for y=5;
inner for loop executes for 5 times.
iteration -1 :
y=1,
_numbersToProcess[5]=5
_result[x]=5
iteration -2 :
y=2,
_numbersToProcess[5]=10
_result[x]=10
iteration -3 :
y=3,
_numbersToProcess[5]=30
_result[x]=30
.
.
.
.
.
thus it goes for 12 iteration as your _numbertoprocess[5] is changing and stops once it reaches less than 0 i.e -1899959296.
iteration 12:
_numbertoprocess[5] = -1899959296.
i.e you are changing numbertoprocess everytime in your inner for loop.
you can verify it by adding
Console.WriteLine(y);
Console.WriteLine(_numbersToProcess[x]);
Console.WriteLine(_result[x]);
in your inner for loop.
for (int y = 1; y < _numbersToProcess[x]; y++) {// Y is equal to less than index x
_result[x] = _numbersToProcess[x] *= y;// Multiply x by y then add to array
}
In loop condition y < _numberToProcess[x];. It compare between y and _numberToProcess[x] array value
I think you should edit loop condition to y < x
Be lucky.
Here i'm using a recursive function factorial
/* Factorial function*/
int factorial (int n)
{
return (n*factorial(n-1))
}
int _numbers = int.Parse(Console.ReadLine());// Get number of ints to calculate
int[] _numbersToProcess = new int[_numbers];// Array of inputs
int[] _result = new int[_numbers];
int i = 0;
while(i < _numbersToProcess.Length) {
_numbersToProcess[i] = int.Parse(Console.ReadLine());
i++;
}
for(int x = 0; x < _numbersToProcess.Length; x++) {// Loop throuigh Array by index
_result[x] = factorial(_result[x])// Multiply x by y then add to array
}
}
for (int n = 0; n < _result.Length; n++) {// Y is equal to less than index x
Console.WriteLine(_result[n]);// Write to console
}
Console.ReadLine();
#include <stdio.h>
int main()
{
int c, n, fact = 1;
printf("Enter a number to calculate it's factorial\n");
scanf("%d", &n);
for (c = 1; c <= n; c++)
fact = fact * c;
printf("Factorial of %d = %d\n", n, fact);
return 0;
}
Check this out maybe it will help...
#include <stdio.h>
#include <stdlib.h>
long f(int n) {
if (n==0) return 1;
else return n * f(n-1);
}
int main(int argc, char *argv[]) {
long *factorials;
int *inputs;
int n;
printf("Enter number n = ");
scanf("%d", &n);
factorials = (long *) malloc(n*sizeof(long));
inputs = (int *) malloc(n*sizeof(int));
for (int i = 0; i < n; i++) {
long k;
printf("Enter %d number = ", i + 1);
scanf("%ld", &k);
inputs[i] = k;
factorials[i] = f(k);
}
for (int i = 0; i < n; i++) {
printf("Factorial for %d = %ld\n", inputs[i], factorials[i]);
}
return 0;
}
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.
How might I go about calculating PI in C# to a certain number of decimal places?
I want to be able to pass a number into a method and get back PI calculated to that number of decimal places.
public decimal CalculatePi(int places)
{
// magic
return pi;
}
Console.WriteLine(CalculatePi(5)); // Would print 3.14159
Console.WriteLine(CalculatePi(10)); // Would print 3.1415926535
etc...
I don't care about the speed of the program. I just want it to be as simple and easy to understand as it can be. Thanks in advance for the help.
First, assuming you want some arbitrary number of digits of pi, and we do not want to be confined with the precision of any of the various floating point numbers out there, let us define a Pi function as a string rather than any number type.
One of the coolest algorithms I found while searching for this technique is the Stanley Rabinowitz and Stan Wagon - Spigot Algorithm. It requires no floating point math, and is mostly an iterative method. It does require some memory for storing integer arrays in the intermediate calculations.
Without taking the time to streamline or clean the code here is an implementation of the algorithm (note the result does not add the decimal point).
Please be sure to cite the algorithm and this site if you intend to use this code for anything other than personal use.
C# Code
public static string CalculatePi(int digits)
{
digits++;
uint[] x = new uint[digits*10/3+2];
uint[] r = new uint[digits*10/3+2];
uint[] pi = new uint[digits];
for (int j = 0; j < x.Length; j++)
x[j] = 20;
for (int i = 0; i < digits; i++)
{
uint carry = 0;
for (int j = 0; j < x.Length; j++)
{
uint num = (uint)(x.Length - j - 1);
uint dem = num * 2 + 1;
x[j] += carry;
uint q = x[j] / dem;
r[j] = x[j] % dem;
carry = q * num;
}
pi[i] = (x[x.Length-1] / 10);
r[x.Length - 1] = x[x.Length - 1] % 10; ;
for (int j = 0; j < x.Length; j++)
x[j] = r[j] * 10;
}
var result = "";
uint c = 0;
for(int i = pi.Length - 1; i >=0; i--)
{
pi[i] += c;
c = pi[i] / 10;
result = (pi[i] % 10).ToString() + result;
}
return result;
}
Update
I finally got around to fixing the "carry error" that happens after 35 digits. Page 6 of the linked document, in fact, specifically talks about what is going on here. I have tested the final version good to 1000 digits.
Math.Round(Math.PI, places)
If you need more precision you will have trouble using the double data type as it supports a certain max. precision (which is provided by Math.PI).
After much searching I found this little snippet:
public static class BigMath
{
// digits = number of digits to calculate;
// iterations = accuracy (higher the number the more accurate it will be and the longer it will take.)
public static BigInteger GetPi(int digits, int iterations)
{
return 16 * ArcTan1OverX(5, digits).ElementAt(iterations)
- 4 * ArcTan1OverX(239, digits).ElementAt(iterations);
}
//arctan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9 - ...
public static IEnumerable<BigInteger> ArcTan1OverX(int x, int digits)
{
var mag = BigInteger.Pow(10, digits);
var sum = BigInteger.Zero;
bool sign = true;
for (int i = 1; true; i += 2)
{
var cur = mag / (BigInteger.Pow(x, i) * i);
if (sign)
{
sum += cur;
}
else
{
sum -= cur;
}
yield return sum;
sign = !sign;
}
}
}
It is working like a charm so far. You just have to add the System.Numerics library from the GAC to resolve the BigInteger type.
Same algorithm as nicholas but uses yield for lazy evaluation
static public IEnumerable<uint> Pi()
{
uint[] x = new uint[short.MaxValue];
uint[] r = new uint[short.MaxValue];
for (int j = 0; j < short.MaxValue; j++)
x[j] = 20;
for (int i = 0; i < short.MaxValue; i++)
{
uint carry = 0;
for (int j = 0; j < x.Length; j++)
{
uint num = (uint)(x.Length - j - 1);
uint dem = num * 2 + 1;
x[j] += carry;
uint q = x[j] / dem;
r[j] = x[j] % dem;
carry = q * num;
}
yield return (x[x.Length - 1] / 10);
r[x.Length - 1] = x[x.Length - 1] % 10; ;
for (int j = 0; j < x.Length; j++)
{
x[j] = r[j] * 10;
}
}
}
I used short.MaxValue as the upper bound for the number of places but that is because my machine is low on virtual memory. A better machine should be able to accommodate up to int.MaxValue.
The function can be called like so:
class Program
{
static void Main(string[] args)
{
foreach (uint digit in Calculator.Pi().Take(100))
{
Console.WriteLine(digit);
}
Console.Read();
}
}
If you are satisfied with the number of digits provided by the native math library, then it is simple; just round to the desired number of digits. If you need more digits (dozens, or hundreds, or thousands), you need a spigot algorithm that spits out the digits one at a time. Jeremy Gibbons gives an algorithm which I implement twice at my blog, where you will find code in Scheme, C, Python, Haskell, Perl and Forth (but not C#, sorry).
The easiest way is to store a large number of digits pi in a String constant. Then whenever you need n digits of precision, you just take a substring from 0 to n+2.