C# aggregation function for a non-linear series - c#

I'm given two arrays, one representing a price, the other representing a number of units:
e.g.
decimal[] price = new decimal[] {1.65, 1.6, 1.55, 1.4, 1.3};
long[] quantity = new long[] {5000, 10000, 12000, 20000, 50000};
So the first 5000 units will cost 1.65 each, the next will cost 10000 will cost 1.6 each, and so on...
It's pretty easy to get the average price with an aggregate funct when you know the amount of units you wish to order e.g.Average price for 7000 units = (5000/7000 * 1.65) + (2000/7000 * 1.6), however, I'm having trouble coming up with an algorithm for when the total unit amount is the unknown variable, and we are given the target average price.
E.g. How many units would I have to order so the average unit price = 1.57

If you think geometrically about it, consider a chart showing the total price (ordinate axis) as a function of the total number of items (abscissa) bought. The plot starts in (0, 0) (buying zero costs zero). First we get a straight line segment of slope 1.65 and horizontal width 5000. Then from the end-point of that comes a new segment of slope 1.6 and width 10000. The total plot is continuous and piece-wise straight-lined but with bends where the unit price changes.
Then to solve your problem, find the intersection with the line of equation y == 1.57 * x, i.e. the line starting at (0, 0) and having slope 1.57. For each of the segments (whose two endpoints you know), check if this segment meets y == 1.57 * x, and if it does, there's your solution.
If the numbers in your price array are decreasing, there can be at most one solution (given that 1.57 is strictly less than the first price, price[0]), the plot representing a concave function.
EDIT: I tried to code this geometry in C#. I didn't add checks that price are all positive and decreasing, and that quantity are all positive. You must check that. Here's my code:
decimal[] price = { 1.65m, 1.6m, 1.55m, 1.4m, 1.3m, };
long[] quantity = { 5000, 10000, 12000, 20000, 50000, };
decimal desiredAverage = 1.57m;
int length = price.Length;
if (length != quantity.Length)
throw new InvalidOperationException();
var abscissaValues = new long[length + 1];
var ordinateValues = new decimal[length + 1];
for (int i = 1; i <= length; ++i)
{
for (int j = 0; j < i; ++j)
{
abscissaValues[i] += quantity[j];
ordinateValues[i] += price[j] * quantity[j];
}
} // calculation of plot complete
int segmentNumber = Enumerable.Range(1, length).FirstOrDefault(i => ordinateValues[i] / abscissaValues[i] <= desiredAverage);
if (segmentNumber > 1)
{
decimal x = (ordinateValues[segmentNumber - 1] * abscissaValues[segmentNumber] - abscissaValues[segmentNumber - 1] * ordinateValues[segmentNumber])
/ (desiredAverage * (abscissaValues[segmentNumber] - abscissaValues[segmentNumber - 1]) - (ordinateValues[segmentNumber] - ordinateValues[segmentNumber - 1]));
Console.WriteLine("Found solution x == " + x);
}
else
{
Console.WriteLine("No solution");
}
I don't know if someone can write it more beautifully, but it seems to work. Output is:
Found solution x == 29705.882352941176470588235294

I believe that's because there's no one answer, no one combination of prices which will result in one average, no close form equation. What we may be looking at is a variant of the Knapsack Problem. http://en.wikipedia.org/wiki/Knapsack_problem with a minimization of value instead of maximization.
EDIT: As correctly pointed out below, this is not a variant of the knapsack problem. There is a closed form solution:
If T = total units bought,
1.57 = 1.55 * (12000/T) + 1.6 * ((T-12000)/T). Solve for T.
The starting price block (here 1.55) is the block just below the average price per unit given in the problem (here 1.57).

Related

Multiple iterations of random double numbers tend to get smaller

I am creating a stock trading simulator where the last days's trade price is taken as opening price and simulated through out the current day.
For that I am generating random double numbers that may be somewhere -5% of lastTradePrice and 5% above the lastTradePrice. However after around 240 iterations I see how the produced double number gets smaller and smaller closing to zero.
Random rand = new Random();
Thread.Sleep(rand.Next(0,10));
Random random = new Random();
double lastTradeMinus5p = model.LastTradePrice - model.LastTradePrice * 0.05;
double lastTradePlus5p = model.LastTradePrice + model.LastTradePrice * 0.05;
model.LastTradePrice = random.NextDouble() * (lastTradePlus5p - lastTradeMinus5p) + lastTradeMinus5p;
As you can see I am trying to get random seed by utilising Thread.sleep(). And yet its not truly randomised. Why is there this tendency to always produce smaller numbers?
Update:
The math itself is actually fine, despite the downwards trend as Jon has proven it.
Getting random double numbers between range is also explained here.
The real problem was the seed of Random. I have followed Jon's advice to keep the same Random instance across the thread for all three prices. And this already is producing better results; the price is actually bouncing back upwards. I am still investigating and open to suggestions how to improve this. The link Jon has given provides an excellent article how to produce a random instance per thread.
Btw the whole project is open source if you are interested. (Using WCF, WPF in Browser, PRISM 4.2, .NET 4.5 Stack)
The TransformPrices call is happening here on one separate thread.
This is what happens if I keep the same instance of random:
And this is generated via RandomProvider.GetThreadRandom(); as pointed out in the article:
Firstly, calling Thread.Sleep like this is not a good way of getting a different seed. It would be better to use a single instance of Random per thread. See my article on randomness for some suggested approaches.
However, your code is also inherently biased downwards. Suppose we "randomly" get 0.0 and 1.0 from the random number generator, starting with a price of $100. That will give:
Day 0: $100
Day 1: $95 (-5% = $5)
Day 2: $99.75 (+5% = $4.75)
Now we can equally randomly get 1.0 and 0.0:
Day 0: $100
Day 1: $105 (+5% = $5)
Day 2: $99.75 (-5% = $5.25)
Note how we've got down in both cases, despite this being "fair". If the value increases, that means it can go down further on the next roll of the dice, so to speak... but if the value decreases, it can't bounce back as far.
EDIT: To give an idea of how a "reasonably fair" RNG is still likely to give a decreasing value, here's a little console app:
using System;
class Test
{
static void Main()
{
Random random = new Random();
int under100 = 0;
for (int i = 0; i < 100; i++)
{
double price = 100;
double sum = 0;
for (int j = 0; j < 1000; j++)
{
double lowerBound = price * 0.95;
double upperBound = price * 1.05;
double sample = random.NextDouble();
sum += sample;
price = sample * (upperBound - lowerBound) + lowerBound;
}
Console.WriteLine("Average: {0:f2} Price: {1:f2}", sum / 1000, price);
if (price < 100)
{
under100++;
}
}
Console.WriteLine("Samples with a final price < 100: {0}", under100);
}
}
On my machine, the "average" value is always very close to 0.5 (rarely less then 0.48 or more than 0.52) but the majority of "final prices" are always below 100 - about 65-70% of them.
Quick guess: This is a math-thing, and not really related to the random generator.
When you reduce the trade price by 5%, you get a resulting value that is lower than that which you began with (obviously!).
The problem is that when you then increase the trade price by 5% of that new value, those 5% will be a smaller value than the 5% you reduced by previously, since you started out with a smaller value this time. Get it?
I obviously haven't verified this, but I have strong hunch this is your problem. When you repeat these operations a bunch of times, the effect will get noticeable over time.
Your math should be:
double lastTradeMinus5p = model.LastTradePrice * 0.95;
double lastTradePlus5p = model.LastTradePrice * (1/0.95);
UPDATE: As Dialecticus pointed out, you should probably use some other distribution than this one:
random.NextDouble() * (lastTradePlus5p - lastTradeMinus5p)
Also, your range of 5% seems pretty narrow to me.
I think this is mainly because the random number generator you are using is technically pants.
For better 'randomness' use RNGCryptoServiceProvider to generate the random numbers instead. It's technically a pseudo-random number generated, but the quality of 'randomness' is much higher (suitable for cryptographic purposes).
Taken from here
//The following sample uses the Cryptography class to simulate the roll of a dice.
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
class RNGCSP
{
private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
// Main method.
public static void Main()
{
const int totalRolls = 25000;
int[] results = new int[6];
// Roll the dice 25000 times and display
// the results to the console.
for (int x = 0; x < totalRolls; x++)
{
byte roll = RollDice((byte)results.Length);
results[roll - 1]++;
}
for (int i = 0; i < results.Length; ++i)
{
Console.WriteLine("{0}: {1} ({2:p1})", i + 1, results[i], (double)results[i] / (double)totalRolls);
}
rngCsp.Dispose();
Console.ReadLine();
}
// This method simulates a roll of the dice. The input parameter is the
// number of sides of the dice.
public static byte RollDice(byte numberSides)
{
if (numberSides <= 0)
throw new ArgumentOutOfRangeException("numberSides");
// Create a byte array to hold the random value.
byte[] randomNumber = new byte[1];
do
{
// Fill the array with a random value.
rngCsp.GetBytes(randomNumber);
}
while (!IsFairRoll(randomNumber[0], numberSides));
// Return the random number mod the number
// of sides. The possible values are zero-
// based, so we add one.
return (byte)((randomNumber[0] % numberSides) + 1);
}
private static bool IsFairRoll(byte roll, byte numSides)
{
// There are MaxValue / numSides full sets of numbers that can come up
// in a single byte. For instance, if we have a 6 sided die, there are
// 42 full sets of 1-6 that come up. The 43rd set is incomplete.
int fullSetsOfValues = Byte.MaxValue / numSides;
// If the roll is within this range of fair values, then we let it continue.
// In the 6 sided die case, a roll between 0 and 251 is allowed. (We use
// < rather than <= since the = portion allows through an extra 0 value).
// 252 through 255 would provide an extra 0, 1, 2, 3 so they are not fair
// to use.
return roll < numSides * fullSetsOfValues;
}
}
According to your code, I can derive it in a simpler version as below:
Random rand = new Random();
Thread.Sleep(rand.Next(0,10));
Random random = new Random();
double lastTradeMinus5p = model.LastTradePrice * 0.95; // model.LastTradePrice - model.LastTradePrice * 0.05 => model.LastTradePrice * ( 1 - 0.05 )
double lastTradePlus5p = model.LastTradePrice * 1.05; // model.LastTradePrice + model.LastTradePrice * 0.05 => model.LastTradePrice * ( 1 + 0.05 )
model.LastTradePrice = model.LastTradePrice * ( random.NextDouble() * 0.1 + 0.95 ) // lastTradePlus5p - lastTradeMinus5p => ( model.LastTradePrice * 1.05 ) - ( model.LastTradePrice * 0.95 ) => model.LastTradePrice * ( 1.05 - 0.95)
So you are taking model.LastTradePrice times a fractional number(between 0 to 1) times 0.1 which will always decrease more to zero, but increase less to 1 !
The litle fraction positive part comes because of the + 0.95 part with the zero-tending random.NextDouble() * 0.1

Identify large differences within a sorted list

Lets say i have a list of doubles:
0.0015
0.0016
0.0017
0.0019
0.0021
0.0022
0.0029
0.0030
0.0033
0.0036
And there's obviously a large difference in 0.0022 and 0.0029 compared to the rest, but is there a way i can make my C# program to be able to notice this difference within a sorted list W/O using a static threshold value. Because these data that i receive, the difference might not always be 0.0007 difference. So i would prefer if my program is able to be 'smart' enough to identify these 'large' differences and separate this list into multiple lists.
if i have understood your question correctly here goes. you may need to fill in a few gaps but you will get the drift with the below example:
List<double> doubleList = new List<double>{
0.0015,
0.0016,
0.0017,
0.0019,
0.0021,
0.0022,
0.0029,
0.0030,
0.0033,
0.0036
};
double averageDistance = 0.0;
double totals = 0.0;
double distance = 0.0;
for (int x = 0; x < (doubleList.Count - 1); x++)
{
distance = doubleList[x] - doubleList[x + 1];
totals += Math.Abs(distance);
}
averageDistance = totals / doubleList.Count;
// check to see if any distance between numbers is more than the average in the list
for (int x = 0; x < (doubleList.Count - 1); x++)
{
distance = doubleList[x] - doubleList[x + 1];
if (distance > averageDistance)
{
// this is where you have a gap that you want to do some split (etc)
}
}
Calculate the mean average (http://en.wikipedia.org/wiki/Arithmetic_mean) and the standard deviation (http://en.wikipedia.org/wiki/Standard_deviation). Use these to determine the values that fall outside of 'n' standard deviations.
Another approach would be to calculate all the differences between consecutive values, sort these (descending) and assume the top 'm' % of these difference values represent the largest changes.

Time to Temperature Calculation

This might not be the correct place for this, so apologies in advance if it isn't.
My situation - I need to come up with a simple formula/method of giving it an hour E.g. 13, 15, 01 etc, and based on that number, the method will return the 'approx' temperature for that particular time.
This is very approximate and it will not use weather data or anything like that, it will just take the hour of the day and return a value between say -6 deg C > 35 deg C. (very extreme weather, but you get the idea.)
This is the sort of examples I would like to know how to do:
Just as a note, I COULD use an ugly array of 24 items, each referencing the temp for that hour, but this needs to be float based - e.g. 19.76 should return 9.25 deg...
Another note: I don't want a complete solution - I'm a confident programmer in various languages, but the maths have really stumped me on this. I've tried various methods on paper using TimeToPeak (the peak hour being 1pm or around there) but to no avail. Any help would be appreciated at this point.
EDIT
Following your comment, here is a function that provides a sinusoidal distribution with various useful optional parameters.
private static double SinDistribution(
double value,
double lowToHighMeanPoint = 0.0,
double length = 10.0,
double low = -1.0,
double high = 1.0)
{
var amplitude = (high - low) / 2;
var mean = low + amplitude;
return mean + (amplitude * Math.Sin(
(((value - lowToHighMeanPoint) % length) / length) * 2 * Math.PI));
}
You could use it like this, to get the results you desired.
for (double i = 0.0; i < 24.0; i++)
{
Console.WriteLine("{0}: {1}", i, SinDistribution(i, 6.5, 24.0, -6.0, 35.0));
}
This obviously discounts environmental factors and assumes the day is an equinox but I think it answers the question.
So,
double EstimatedTemperature(double hour, double[] distribution)
{
var low = Math.Floor(hour);
var lowIndex = (int)low;
var highIndex = (int)Math.Ceiling(hour);
if (highIndex > distribution.Count - 1)
{
highIndex = 0;
}
if (lowIndex < 0)
{
lowIndex = distribution.Count - 1;
}
var lowValue = distribution.ElementAt(lowIndex);
var highValue = distribution.ElementAt(highIndex);
return lowValue + ((hour - low) * (highValue - lowValue));
}
assuming a rather simplistic linear transition between each point in the distibution. You'll get erroneous results if the hour is mapped to elements that are not present in the distribution.
For arbitrary data points, I would go with one of the other linear interpolation solutions that have been provided.
However, this particular set of data is generated by a triangle wave:
temp = 45*Math.Abs(2*((t-1)/24-Math.Floor((t-1)/24+.5)))-10;
The data in your table is linear up and down from a peak at hour 13 and a minimum at hour 1. If that is the type of model that you want then this is really easy to put into a formulaic solution. You would just simply perform linear interpolation between the two extremes of the temperature based upon the hour value. You would have two data points:
(xmin, ymin) as (hour-min, temp-min)
(xmax, ymax) as (hour-max, temp-max)
You would have two equations of the form:
The two equations would use the (x0, y0) and (x1, y1) values as the above two data points but apply them the opposite assignment (ie peak would be (x0, y0) on one and (x1, y1) in the other equation.
You would then select which equation to use based upon the hour value, insert the X value as the hour and compute as Y for the temperature value.
You will want to offset the X values used in the equations so that you take care of the offset between when Hour 0 and where the minimum temperature peak happens.
Here is an example of how you could do this using a simple set of values in the function, if you wish, add these as parameters;
public double GetTemp(double hour)
{
int min = 1;
int max = min + 12;
double lowest = -10;
double highest = 35;
double change = 3.75;
return (hour > max) ? ((max - hour) * change) + highest : (hour < min) ? ((min - hour)*change) + lowest : ((hour - max) * change) + highest;
}
I have tested this according to your example and it is working with 19.75 = 9.6875.
There is no check to see whether the value entered is within 0-24, but that you can probably manage yourself :)
You can use simple 2 point linear approximation. Try somthing like this:
function double hourTemp(double hour)
{
idx1 = round(hour);
idx2 = idx1 + 1;
return (data[idx2] - data[idx1]) * (hour - idx1) + data[idx1];
}
Or use 3,5 or more points to get polynom cofficients with Ordinary Least Squares method.
Your sample data similar to the sin function so you can make sin function approximation.

C# 2 Array Split Amount Question

My question is i have a certain money amount, lets say 552.
I wish to split that in its coins/bills => So the result would for example be 1x 500 1x 50 1x 2
I have made 2 arrays for this:
double[] CoinValue = {500, 200, 100, 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01};
uint[] CoinAmount = new uint[CoinValue.Length];
My problem is how exactly do i "tell" the array the value for 500 should be 1 in the countAmount array.=> 1. So if i have 1000 the array CoinAmount array would know it would need to hold 2 as value(2x500 = 1000).
So my end result would be something like this, giving the amount of coin/bills:
1 x 500
1 x 50
1 x 2
.......
Thanks in advance.
Don't use doubles if you want exact answers. Use either decimals or integer arithmetic (by converting to cents).
I'm not going to provide full source code as this looks like homework or a learning exercise, so instead I'll just give a few hints.
To find out how many notes of a certain denomination you need, use division:
int number = (int)(total / sizeOfBill);
Start with the largest bills and work downwards to the smallest to get a small number of notes/coins, otherwise you could end up with thousands of cent coins instead of a few bills.
Not an answer: a harder version of the problem for you to consider.
The coinage system you describe has a nice property that when you repeatedly "take out" the largest denomination from the remaining total, you end up with the solution that has the smallest number of bills/coins. FYI, an algorithm which operates by repeatedly choosing the largest thing is called a "greedy algorithm"; in this case, the greedy algorithm give an optimal result, if you're optimizing for the smallest number of bills/coins.
Can you solve the problem for a coinage system where the coins are:
1 crown = 60 pence ("pence" is the plural of "penny")
1 half-crown = 30 pence
1 florin = 24 pence
1 shilling = 12 pence
1 tanner = 6 pence
The greedy algorithm for making change now does not work if you are optimizing for the smallest number of coins. For example, 48 pence by the greedy algorithm goes
take out a half-crown, leaving 18 pence
take out a shilling, leaving 6 pence
take out a tanner, leaving nothing
Three coins. But obviously 48 pence is two florins, which is only two coins.
Can you come up with an algorithm that handles this coinage system and gives the least number of coins possible for every problem?
(Note that the pre-decimal British coinage system is suitable for neither decimal nor double arithmetic; do it all in integers!)
PLEASE use decimal for this; double is rarely suitable for money types:
double value = 0.3;
value -= 0.1;
value -= 0.1;
value -= 0.1;
Console.WriteLine(value); //**not** zero
Anyway, a very crude approach (also assumes that the coins are sorted descending and that all values are non-negative) is below. It gets trickier if you don't have coins for the lowest values (i.e. you have 0.5M and 0.2M but no 0.1M and need to issue 0.8M - since this needs 4x0.2M, not 0.5M+0.2M+(damn))
decimal value = 10023.23M;
decimal[] CoinValue = { 500, 200, 100, 50, 20, 10, 5, 2, 1, 0.5M, 0.2M, 0.1M, 0.05M, 0.02M, 0.01M };
int[] counts = new int[CoinValue.Length];
for (int i = 0; i < CoinValue.Length; i++) {
decimal v = CoinValue[i];
while (value >= v) {
counts[i]++;
value -= v;
}
}
for (int i = 0; i < CoinValue.Length; i++) {
if (counts[i] > 0) {
Console.WriteLine(CoinValue[i] + "\t" + counts[i]);
}
}
Console.WriteLine("Untendered: " + value);
Given your array ... also works with decimals of course.
double[] CoinValue = { 500, 200, 100, 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01 };
uint[] result = new uint[CoinValue.Length];
double ammount = 552.5;
double remaining = ammount;
for (int i = 0; i < CoinValue.Length; ++i) {
result[i] = (uint) (remaining / CoinValue[i]);
if (result[i] > 0)
remaining = remaining % CoinValue[i];
}

How do I calculate PI in C#?

How can I calculate the value of PI using C#?
I was thinking it would be through a recursive function, if so, what would it look like and are there any math equations to back it up?
I'm not too fussy about performance, mainly how to go about it from a learning point of view.
If you want recursion:
PI = 2 * (1 + 1/3 * (1 + 2/5 * (1 + 3/7 * (...))))
This would become, after some rewriting:
PI = 2 * F(1);
with F(i):
double F (int i) {
return 1 + i / (2.0 * i + 1) * F(i + 1);
}
Isaac Newton (you may have heard of him before ;) ) came up with this trick.
Note that I left out the end condition, to keep it simple. In real life, you kind of need one.
How about using:
double pi = Math.PI;
If you want better precision than that, you will need to use an algorithmic system and the Decimal type.
If you take a close look into this really good guide:
Patterns for Parallel Programming: Understanding and Applying Parallel Patterns with the .NET Framework 4
You'll find at Page 70 this cute implementation (with minor changes from my side):
static decimal ParallelPartitionerPi(int steps)
{
decimal sum = 0.0;
decimal step = 1.0 / (decimal)steps;
object obj = new object();
Parallel.ForEach(
Partitioner.Create(0, steps),
() => 0.0,
(range, state, partial) =>
{
for (int i = range.Item1; i < range.Item2; i++)
{
decimal x = (i - 0.5) * step;
partial += 4.0 / (1.0 + x * x);
}
return partial;
},
partial => { lock (obj) sum += partial; });
return step * sum;
}
There are a couple of really, really old tricks I'm surprised to not see here.
atan(1) == PI/4, so an old chestnut when a trustworthy arc-tangent function is
present is 4*atan(1).
A very cute, fixed-ratio estimate that makes the old Western 22/7 look like dirt
is 355/113, which is good to several decimal places (at least three or four, I think).
In some cases, this is even good enough for integer arithmetic: multiply by 355 then divide by 113.
355/113 is also easy to commit to memory (for some people anyway): count one, one, three, three, five, five and remember that you're naming the digits in the denominator and numerator (if you forget which triplet goes on top, a microsecond's thought is usually going to straighten it out).
Note that 22/7 gives you: 3.14285714, which is wrong at the thousandths.
355/113 gives you 3.14159292 which isn't wrong until the ten-millionths.
Acc. to /usr/include/math.h on my box, M_PI is #define'd as:
3.14159265358979323846
which is probably good out as far as it goes.
The lesson you get from estimating PI is that there are lots of ways of doing it,
none will ever be perfect, and you have to sort them out by intended use.
355/113 is an old Chinese estimate, and I believe it pre-dates 22/7 by many years. It was taught me by a physics professor when I was an undergrad.
Good overview of different algorithms:
Computing pi;
Gauss-Legendre-Salamin.
I'm not sure about the complexity claimed for the Gauss-Legendre-Salamin algorithm in the first link (I'd say O(N log^2(N) log(log(N)))).
I do encourage you to try it, though, the convergence is really fast.
Also, I'm not really sure about why trying to convert a quite simple procedural algorithm into a recursive one?
Note that if you are interested in performance, then working at a bounded precision (typically, requiring a 'double', 'float',... output) does not really make sense, as the obvious answer in such a case is just to hardcode the value.
What is PI? The circumference of a circle divided by its diameter.
In computer graphics you can plot/draw a circle with its centre at 0,0 from a initial point x,y, the next point x',y' can be found using a simple formula:
x' = x + y / h : y' = y - x' / h
h is usually a power of 2 so that the divide can be done easily with a shift (or subtracting from the exponent on a double). h also wants to be the radius r of your circle. An easy start point would be x = r, y = 0, and then to count c the number of steps until x <= 0 to plot a quater of a circle. PI is 4 * c / r or PI is 4 * c / h
Recursion to any great depth, is usually impractical for a commercial program, but tail recursion allows an algorithm to be expressed recursively, while implemented as a loop. Recursive search algorithms can sometimes be implemented using a queue rather than the process's stack, the search has to backtrack from a deadend and take another path - these backtrack points can be put in a queue, and multiple processes can un-queue the points and try other paths.
Calculate like this:
x = 1 - 1/3 + 1/5 - 1/7 + 1/9 (... etc as far as possible.)
PI = x * 4
You have got Pi !!!
This is the simplest method I know of.
The value of PI slowly converges to the actual value of Pi (3.141592165......). If you iterate more times, the better.
Here's a nice approach (from the main Wikipedia entry on pi); it converges much faster than the simple formula discussed above, and is quite amenable to a recursive solution if your intent is to pursue recursion as a learning exercise. (Assuming that you're after the learning experience, I'm not giving any actual code.)
The underlying formula is the same as above, but this approach averages the partial sums to accelerate the convergence.
Define a two parameter function, pie(h, w), such that:
pie(0,1) = 4/1
pie(0,2) = 4/1 - 4/3
pie(0,3) = 4/1 - 4/3 + 4/5
pie(0,4) = 4/1 - 4/3 + 4/5 - 4/7
... and so on
So your first opportunity to explore recursion is to code that "horizontal" computation as the "width" parameter increases (for "height" of zero).
Then add the second dimension with this formula:
pie(h, w) = (pie(h-1,w) + pie(h-1,w+1)) / 2
which is used, of course, only for values of h greater than zero.
The nice thing about this algorithm is that you can easily mock it up with a spreadsheet to check your code as you explore the results produced by progressively larger parameters. By the time you compute pie(10,10), you'll have an approximate value for pi that's good enough for most engineering purposes.
Enumerable.Range(0, 100000000).Aggregate(0d, (tot, next) => tot += Math.Pow(-1d, next)/(2*next + 1)*4)
using System;
namespace Strings
{
class Program
{
static void Main(string[] args)
{
/* decimal pie = 1;
decimal e = -1;
*/
var stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start(); //added this nice stopwatch start routine
//leibniz formula in C# - code written completely by Todd Mandell 2014
/*
for (decimal f = (e += 2); f < 1000001; f++)
{
e += 2;
pie -= 1 / e;
e += 2;
pie += 1 / e;
Console.WriteLine(pie * 4);
}
decimal finalDisplayString = (pie * 4);
Console.WriteLine("pie = {0}", finalDisplayString);
Console.WriteLine("Accuracy resulting from approximately {0} steps", e/4);
*/
// Nilakantha formula - code written completely by Todd Mandell 2014
// π = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) + 4/(10*11*12) - (4/(12*13*14) etc
decimal pie = 0;
decimal a = 2;
decimal b = 3;
decimal c = 4;
decimal e = 1;
for (decimal f = (e += 1); f < 100000; f++)
// Increase f where "f < 100000" to increase number of steps
{
pie += 4 / (a * b * c);
a += 2;
b += 2;
c += 2;
pie -= 4 / (a * b * c);
a += 2;
b += 2;
c += 2;
e += 1;
}
decimal finalDisplayString = (pie + 3);
Console.WriteLine("pie = {0}", finalDisplayString);
Console.WriteLine("Accuracy resulting from {0} steps", e);
stopwatch.Stop();
TimeSpan ts = stopwatch.Elapsed;
Console.WriteLine("Calc Time {0}", ts);
Console.ReadLine();
}
}
}
public static string PiNumberFinder(int digitNumber)
{
string piNumber = "3,";
int dividedBy = 11080585;
int divisor = 78256779;
int result;
for (int i = 0; i < digitNumber; i++)
{
if (dividedBy < divisor)
dividedBy *= 10;
result = dividedBy / divisor;
string resultString = result.ToString();
piNumber += resultString;
dividedBy = dividedBy - divisor * result;
}
return piNumber;
}
In any production scenario, I would compel you to look up the value, to the desired number of decimal points, and store it as a 'const' somewhere your classes can get to it.
(unless you're writing scientific 'Pi' specific software...)
Regarding...
... how to go about it from a learning point of view.
Are you trying to learning to program scientific methods? or to produce production software? I hope the community sees this as a valid question and not a nitpick.
In either case, I think writing your own Pi is a solved problem. Dmitry showed the 'Math.PI' constant already. Attack another problem in the same space! Go for generic Newton approximations or something slick.
#Thomas Kammeyer:
Note that Atan(1.0) is quite often hardcoded, so 4*Atan(1.0) is not really an 'algorithm' if you're calling a library Atan function (an quite a few already suggested indeed proceed by replacing Atan(x) by a series (or infinite product) for it, then evaluating it at x=1.
Also, there are very few cases where you'd need pi at more precision than a few tens of bits (which can be easily hardcoded!). I've worked on applications in mathematics where, to compute some (quite complicated) mathematical objects (which were polynomial with integer coefficients), I had to do arithmetic on real and complex numbers (including computing pi) with a precision of up to a few million bits... but this is not very frequent 'in real life' :)
You can look up the following example code.
I like this paper, which explains how to calculate π based on a Taylor series expansion for Arctangent.
The paper starts with the simple assumption that
Atan(1) = π/4 radians
Atan(x) can be iteratively estimated with the Taylor series
atan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9...
The paper points out why this is not particularly efficient and goes on to make a number of logical refinements in the technique. They also provide a sample program that computes π to a few thousand digits, complete with source code, including the infinite-precision math routines required.
The following link shows how to calculate the pi constant based on its definition as an integral, that can be written as a limit of a summation, it's very interesting:
https://sites.google.com/site/rcorcs/posts/calculatingthepiconstant
The file "Pi as an integral" explains this method used in this post.
First, note that C# can use the Math.PI field of the .NET framework:
https://msdn.microsoft.com/en-us/library/system.math.pi(v=vs.110).aspx
The nice feature here is that it's a full-precision double that you can either use, or compare with computed results. The tabs at that URL have similar constants for C++, F# and Visual Basic.
To calculate more places, you can write your own extended-precision code. One that is quick to code and reasonably fast and easy to program is:
Pi = 4 * [4 * arctan (1/5) - arctan (1/239)]
This formula and many others, including some that converge at amazingly fast rates, such as 50 digits per term, are at Wolfram:
Wolfram Pi Formulas
PI (π) can be calculated by using infinite series. Here are two examples:
Gregory-Leibniz Series:
π/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...
C# method :
public static decimal GregoryLeibnizGetPI(int n)
{
decimal sum = 0;
decimal temp = 0;
for (int i = 0; i < n; i++)
{
temp = 4m / (1 + 2 * i);
sum += i % 2 == 0 ? temp : -temp;
}
return sum;
}
Nilakantha Series:
π = 3 + 4 / (2x3x4) - 4 / (4x5x6) + 4 / (6x7x8) - 4 / (8x9x10) + ...
C# method:
public static decimal NilakanthaGetPI(int n)
{
decimal sum = 0;
decimal temp = 0;
decimal a = 2, b = 3, c = 4;
for (int i = 0; i < n; i++)
{
temp = 4 / (a * b * c);
sum += i % 2 == 0 ? temp : -temp;
a += 2; b += 2; c += 2;
}
return 3 + sum;
}
The input parameter n for both functions represents the number of iteration.
The Nilakantha Series in comparison with Gregory-Leibniz Series converges more quickly. The methods can be tested with the following code:
static void Main(string[] args)
{
const decimal pi = 3.1415926535897932384626433832m;
Console.WriteLine($"PI = {pi}");
//Nilakantha Series
int iterationsN = 100;
decimal nilakanthaPI = NilakanthaGetPI(iterationsN);
decimal CalcErrorNilakantha = pi - nilakanthaPI;
Console.WriteLine($"\nNilakantha Series -> PI = {nilakanthaPI}");
Console.WriteLine($"Calculation error = {CalcErrorNilakantha}");
int numDecNilakantha = pi.ToString().Zip(nilakanthaPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
Console.WriteLine($"Number of correct decimals = {numDecNilakantha}");
Console.WriteLine($"Number of iterations = {iterationsN}");
//Gregory-Leibniz Series
int iterationsGL = 1000000;
decimal GregoryLeibnizPI = GregoryLeibnizGetPI(iterationsGL);
decimal CalcErrorGregoryLeibniz = pi - GregoryLeibnizPI;
Console.WriteLine($"\nGregory-Leibniz Series -> PI = {GregoryLeibnizPI}");
Console.WriteLine($"Calculation error = {CalcErrorGregoryLeibniz}");
int numDecGregoryLeibniz = pi.ToString().Zip(GregoryLeibnizPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
Console.WriteLine($"Number of correct decimals = {numDecGregoryLeibniz}");
Console.WriteLine($"Number of iterations = {iterationsGL}");
Console.ReadKey();
}
The following output shows that Nilakantha Series returns six correct decimals of PI with one hundred iterations whereas Gregory-Leibniz Series returns five correct decimals of PI with one million iterations:
My code can be tested >> here
Here is a nice way:
Calculate a series of 1/x^2 for x from 1 to what ever you want- the bigger number- the better pie result. Multiply the result by 6 and to sqrt().
Here is the code in c# (main only):
static void Main(string[] args)
{
double counter = 0;
for (double i = 1; i < 1000000; i++)
{
counter = counter + (1 / (Math.Pow(i, 2)));
}
counter = counter * 6;
counter = Math.Sqrt(counter);
Console.WriteLine(counter);
}
public double PI = 22.0 / 7.0;

Categories