Maybe I didn't understood how to use those two types: BigInteger/BigRational, but generally speaking I want to implement those two equations:
This is my data: n=235, K = 40 and this small p (which actually is called rho) is 5. In the beginning the problem was with the Power function: the results were very very very big - so that is why I used the BigInteger library. But then I realize that there will be a division made and the result will be a number of type double - so I changed to BigRational library.
Here is my code:
static void Main(string[] args)
{
var k = 40;
var n = 235;
var p = 5;
// the P(n) equation
BigRational pnNumerator = BigRational.Pow(p, n);
BigRational pnDenominator = BigRational.Pow(k, (n - k)) * Factorial(k);
// the P(0) equation
//---the right side of "+" sign in Denominator
BigRational pk = BigRational.Pow(p, k);
BigRational factorialK = Factorial(k);
BigRational lastPart = (BigRational.Subtract(1, (double)BigRational.Divide(p, k)));
BigRational factorialAndLastPart = BigRational.Multiply(factorialK, lastPart);
BigRational fullRightSide = BigRational.Divide(pk, factorialAndLastPart);
//---the left side of "+" sign in Denominator
BigRational series = Series(k, p, n);
BigRational p0Denominator = series + fullRightSide;
BigRational p0Result = BigRational.Divide(1, p0Denominator);
BigRational pNResult = BigRational.Divide((pnNumerator * p0Result), pnDenominator);
Console.WriteLine(pNResult);
Console.ReadKey();
}
static BigRational Series(int k, int p, int n)
{
BigRational series = new BigRational(0.0);
var fin = k - 1;
for (int i = 0; i < fin; i++)
{
var power = BigRational.Pow(p, i);
var factorialN = Factorial(n);
var sum = BigRational.Divide(power, factorialN);
series += sum;
}
return series;
}
static BigRational Factorial(int k)
{
if (k <= 1)
return 1;
else return BigRational.Multiply(k, Factorial(k - 1));
}
The main problem is that it does not return any "normal" value like for example 0.3 or 0.03. The result which is printed to the console is a very long number (like 1200 digits in it)...
Can someone please take a look at my code and help me fix the problem and be able to solve this equations by the code. Thank you
Console.WriteLine(pNResult); calls BigRational.ToString() under-the-hood, which prints the number in the form numerator/denominator.
It's easy to miss the / in the output given how large the numerator and denominator both are in this case.
BigRational supports conversions to decimal and to double. The result is too small to fit in a decimal in this case though. Converting to a double, gives the result 7.89682541396914E-177.
If you need better precision, you'll need a custom conversion to a decimal-format string, like the one in this Stackoverflow answer.
Using that custom conversion routine to get the result to 1000 decimal places -
Console.WriteLine(pNResult.ToDecimalString(1000));
- gives the result as:
0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000078968254139691306770128897137459492828971170349380336740935269651539684650525033676003134593283361305530675112470528408219177025044254116462798561450442318290046626248451723040397770263675109107145461310779641705093156106311143727608208629473359566457461384474633112850335950017209558136575135801388668687571284492241030561019606955986265585636660304889792027894460104216176719717671500843399685686146432982358441225578366059001576682388503227237202077881334695352338638383337717103303153521108812750644260562351186866587629456292506971252525125976755540274041651740194108430555751648707933592643410475214924394223640168857340953563111097979394441303100701008120008166339365089771585037880235325673143152814510586536335380671360865230428857049658368242543653234599817430185879648427434216378356518036776477170130227628307039
To check that your calculation code is operating correctly, you can add unit-tests for the different functions (Factorial, Series and the computation of P itself).
An approach that is practical here is to calculate the results by hand for certain small values of k, n and p and check that your functions compute the same results.
If you're using Visual Studio, you can use this MSDN page as a starting point for creating a unit-test project. Note that the functions under test must be visible to the unit-test project, and your unit-test project will need to have a reference added to your existing project where you're doing the computation, as explained in the link.
Starting with Factorial, which is the easiest to check, you could add a test like this:
[TestClass]
public class UnitTestComputation
{
[TestMethod]
public void TestFactorial()
{
Assert.AreEqual(1, Program.Factorial(0));
Assert.AreEqual(1, Program.Factorial(1));
Assert.AreEqual(2, Program.Factorial(2));
Assert.AreEqual(6, Program.Factorial(3));
Assert.AreEqual(24, Program.Factorial(4));
}
}
The code in your question passes that test.
You can then add a test method for your Series function:
[TestMethod]
public void TestSeries()
{
int k = 1;
int p = 1;
BigRational expected = 1;
Assert.AreEqual(expected, Program.Series(k, p));
k = 2;
p = 1;
expected += 1;
Assert.AreEqual(expected, Program.Series(k, p));
k = 3;
p = 1;
expected += (BigRational)1 / (BigRational)2;
Assert.AreEqual(expected, Program.Series(k, p));
k = 1;
p = 2;
expected = 1;
Assert.AreEqual(expected, Program.Series(k, p));
k = 2;
p = 2;
expected += 2;
Assert.AreEqual(expected, Program.Series(k, p));
}
This showed up some problems in your code:
n shouldn't actually be a parameter to this function, because in this context n isn't the parameter to function P, but actually just the "index-of-summation". n's local value in this function is represented by your i variable.
This then means that your Factorial(n) call needs to change to Factorial(i)
The loop is also off-by-one, because the Sigma notation for the summation is inclusive of the number at the top of the Sigma, so you should have <= fin (or you could also have written this simply as < k).
This is the updated Series function:
// CHANGED: Removed n as parameter (n just the index of summation here)
public static BigRational Series(int k, int p)
{
BigRational series = new BigRational(0.0);
var fin = k - 1;
// CHANGED: Should be <= fin (i.e. <= k-1, or < k) because it's inclusive counting
for (int i = 0; i <= fin; i++)
{
var power = BigRational.Pow(p, i);
// CHANGED: was Factorial(n), should be factorial of n value in this part of the sequence being summed.
var factorialN = Factorial(i);
var sum = BigRational.Divide(power, factorialN);
series += sum;
}
return series;
}
To test the P(n) calculation you can move that out into its own function to test (I've called it ComputeP here):
[TestMethod]
public void TestP()
{
int n = 1;
int k = 2;
int p = 1;
// P(0) = 1 / (2 + 1/(2*(1 - 1/2))) = 1/3
// P(1) = (1/(1/2 * 2)) * P(0) = P(0) = 1/3
BigRational expected = 1;
expected /= 3;
Assert.AreEqual(expected, Program.ComputeP(k, n, p));
n = 2;
k = 2;
p = 1;
// P(2) = (1/(1*2)) * P(0) = 1/6
expected = 1;
expected /= 6;
Assert.AreEqual(expected, Program.ComputeP(k, n, p));
}
This showed up a problem with calculating P(n) - you had a cast to double in there which shouldn't have been present (the result is inaccurate then - you need to keep all the intermediate results in BigRational). There's no need for the cast, so just removing it fixes this problem.
Here is the updated ComputeP function:
public static BigRational ComputeP(int k, int n, int p)
{
// the P(n) equation
BigRational pnNumerator = BigRational.Pow(p, n);
BigRational pnDenominator = BigRational.Pow(k, (n - k)) * Factorial(k);
// the P(0) equation
//---the right side of "+" sign in Denominator
BigRational pk = BigRational.Pow(p, k);
BigRational factorialK = Factorial(k);
// CHANGED: Don't cast to double here (loses precision)
BigRational lastPart = (BigRational.Subtract(1, BigRational.Divide(p, k)));
BigRational factorialAndLastPart = BigRational.Multiply(factorialK, lastPart);
BigRational fullRightSide = BigRational.Divide(pk, factorialAndLastPart);
//---the left side of "+" sign in Denominator
BigRational series = Series(k, p);
BigRational p0Denominator = series + fullRightSide;
BigRational p0Result = BigRational.Divide(1, p0Denominator);
BigRational pNResult = BigRational.Divide((pnNumerator * p0Result), pnDenominator);
return pNResult;
}
For avoidance of confusion, here is the whole updated calculation program:
using System;
using System.Numerics;
using System.Text;
using Numerics;
public class Program
{
public static BigRational ComputeP(int k, int n, int p)
{
// the P(n) equation
BigRational pnNumerator = BigRational.Pow(p, n);
BigRational pnDenominator = BigRational.Pow(k, (n - k)) * Factorial(k);
// the P(0) equation
//---the right side of "+" sign in Denominator
BigRational pk = BigRational.Pow(p, k);
BigRational factorialK = Factorial(k);
// CHANGED: Don't cast to double here (loses precision)
BigRational lastPart = (BigRational.Subtract(1, BigRational.Divide(p, k)));
BigRational factorialAndLastPart = BigRational.Multiply(factorialK, lastPart);
BigRational fullRightSide = BigRational.Divide(pk, factorialAndLastPart);
//---the left side of "+" sign in Denominator
BigRational series = Series(k, p);
BigRational p0Denominator = series + fullRightSide;
BigRational p0Result = BigRational.Divide(1, p0Denominator);
BigRational pNResult = BigRational.Divide((pnNumerator * p0Result), pnDenominator);
return pNResult;
}
// CHANGED: Removed n as parameter (n just the index of summation here)
public static BigRational Series(int k, int p)
{
BigRational series = new BigRational(0.0);
var fin = k - 1;
// CHANGED: Should be <= fin (i.e. <= k-1, or < k) because it's inclusive counting
for (int i = 0; i <= fin; i++)
{
var power = BigRational.Pow(p, i);
// CHANGED: was Factorial(n), should be factorial of n value in this part of the sequence being summed.
var factorialN = Factorial(i);
var sum = BigRational.Divide(power, factorialN);
series += sum;
}
return series;
}
public static BigRational Factorial(int k)
{
if (k <= 1)
return 1;
else return BigRational.Multiply(k, Factorial(k - 1));
}
static void Main(string[] args)
{
var k = 40;
var n = 235;
var p = 5;
var result = ComputeP(k, n, p);
Console.WriteLine(result.ToDecimalString(1000));
Console.ReadKey();
}
}
// From https://stackoverflow.com/a/10359412/4486839
public static class BigRationalExtensions
{
public static string ToDecimalString(this BigRational r, int precision)
{
var fraction = r.GetFractionPart();
// Case where the rational number is a whole number
if (fraction.Numerator == 0 && fraction.Denominator == 1)
{
return r.GetWholePart() + ".0";
}
var adjustedNumerator = (fraction.Numerator
* BigInteger.Pow(10, precision));
var decimalPlaces = adjustedNumerator / fraction.Denominator;
// Case where precision wasn't large enough.
if (decimalPlaces == 0)
{
return "0.0";
}
// Give it the capacity for around what we should need for
// the whole part and total precision
// (this is kinda sloppy, but does the trick)
var sb = new StringBuilder(precision + r.ToString().Length);
bool noMoreTrailingZeros = false;
for (int i = precision; i > 0; i--)
{
if (!noMoreTrailingZeros)
{
if ((decimalPlaces % 10) == 0)
{
decimalPlaces = decimalPlaces / 10;
continue;
}
noMoreTrailingZeros = true;
}
// Add the right most decimal to the string
sb.Insert(0, decimalPlaces % 10);
decimalPlaces = decimalPlaces / 10;
}
// Insert the whole part and decimal
sb.Insert(0, ".");
sb.Insert(0, r.GetWholePart());
return sb.ToString();
}
}
And here is the whole unit-test program:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Numerics;
[TestClass]
public class UnitTestComputation
{
[TestMethod]
public void TestFactorial()
{
Assert.AreEqual(1, Program.Factorial(0));
Assert.AreEqual(1, Program.Factorial(1));
Assert.AreEqual(2, Program.Factorial(2));
Assert.AreEqual(6, Program.Factorial(3));
Assert.AreEqual(24, Program.Factorial(4));
}
[TestMethod]
public void TestSeries()
{
int k = 1;
int p = 1;
BigRational expected = 1;
Assert.AreEqual(expected, Program.Series(k, p));
k = 2;
p = 1;
expected += 1;
Assert.AreEqual(expected, Program.Series(k, p));
k = 3;
p = 1;
expected += (BigRational)1 / (BigRational)2;
Assert.AreEqual(expected, Program.Series(k, p));
k = 1;
p = 2;
expected = 1;
Assert.AreEqual(expected, Program.Series(k, p));
k = 2;
p = 2;
expected += 2;
Assert.AreEqual(expected, Program.Series(k, p));
}
[TestMethod]
public void TestP()
{
int n = 1;
int k = 2;
int p = 1;
// P(0) = 1 / (2 + 1/(2*(1 - 1/2))) = 1/3
// P(1) = (1/(1/2 * 2)) * P(0) = P(0) = 1/3
BigRational expected = 1;
expected /= 3;
Assert.AreEqual(expected, Program.ComputeP(k, n, p));
n = 2;
k = 2;
p = 1;
// P(2) = (1/(1*2)) * P(0) = 1/6
expected = 1;
expected /= 6;
Assert.AreEqual(expected, Program.ComputeP(k, n, p));
}
}
Incidentally, the P(n) result with the updated program for your input values for n, p and k is now:
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000593109980769066916025972569398424267669807629726200017375290861590898269902277869938365969961320969473356001666906480007119114830921839913623591124192047955091318951831902550404167336054683697071654765071519020060437129398945035521954738463786221029427589397688847246112810536958194364039693387170592425527136243952416704526069736811587380688876091926255908361275575249492845970903676492429684929779402600032481018886875698972533534890841796034626337674846620462046294537488580901129338625628349474358946962065227890599744775562637784553656488649841148591533557896418988044457914999854241038974478576578909626765823565817758792682480009619613438867365912697996527957775248350987801430141776875171808382272960426476953742528769626555642957093028553993908356226007570404005591174451216846471710162760343
NOTE: You should add to the unit-tests with more results you've checked by hand, and also check any of my working here in interpreting the algebra as code to ensure this is correct.
Related
Calculate the following sum
1!/1 + 2!/(1+1/2) + 3!/(1+1/2+1/3) + ... + n!/ (1+1/2+1/3+...+1/n), where n > 0.
public static double GetSumSix(int n)
{
double i, result = 0.0;
static double factorial(double n)
{
double res = 1;
for (double i = 2; i <= n; i++)
res *= i;
return res;
}
for (i = 1.0; i <= n; i++)
{
result += factorial(i) / (1.0 / i);
}
return result;
}
Help me please , I don't understand why is my solution not working?
Your denominator logic is incorrect. You could create another function to work out what '1/1+1/2+...+1/n' is and use that in the denominator? right now your code will work out 1+2!*2+3!*3+...
You could actually use something similar to your factorial method
static double GetDenominator(double n)
{
double res = 1;
for (double i = 2; i <= n; i++)
//insert code here
return res;
}
The Lemon's answer is correct, you're not accumulating the denominator of the sequence so what you were calculating was:
f(n) = 1!/1 + 2!/(1/2) + 3!/(1/3) + ... n!/(1/n)
Since both the numerator and denominator of each term are algorithmically linked to the values in the prior term you can simply update them each pass through the loop. This is (slightly) faster and fairly easy to read.
public static double GetSumSix(int n)
{
double factorial = 1;
double denominator = 1;
double accum = 1;
for (int i = 2; i <= n; i++)
{
factorial *= i;
denominator += 1.0d/i;
accum += factorial / denominator;
}
return accum;
}
Your logic is not correct as per your question , also your code won't execute as you have a function inside your GetSumSix function. I have put some helping points in below code so you will understand how the logic works.
using System;
public class Program
{
public static void Main()
{
var Calculate = GetSumSix(3);
Console.WriteLine("The Answer is " + Calculate);
}
public static double GetSumSix(int n)
{
int i;
double result = 0.0;
int factorial = 1;
string calculatedFormula = String.Empty;
string FinalFormat = String.Empty;
//Find n!
for(int x=n;x>=1;x--)
{
factorial *= x;
}
// Find Denominator (1+1/2+1/3+…+1/n)
for (i = 1.0; i <= n; i++)
{
result += GetDenominator(i, ref calculatedFormula);
FinalFormat += calculatedFormula;
}
result = factorial/result;
Console.WriteLine("Calculated Formula is:"+ factorial +"/(" + FinalFormat +")When N is :" + n);
return result;
}
public static double GetDenominator(double n, ref string cal)
{
if (n == 1)
{
cal += n + "+ ";
return 1;
}
else
{
cal = "1/" + n + "+ ";
return 1 / n;
}
}
}
Thanks.
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'm getting x,y,z values from gyro-sensor. Each variable is being sent 10 values per second. In 3 seconds I have;
x=[30values]
y=[30values]
z=[30values]
Some of the values are too different from the others cause of noise. With laplace transform I need to get the most frequent value from my array.
I need to filter the array with Laplace Transform equation. I need to build the equation in C#. How can I implement the array with the equation?
Since this kind of filter (Laplace) is very specialized to certain area of Engineering and needs a person who has good understanding on both the programming language (in this case is C#) and the filter itself, I would recommend you to use such source, rather than code the filter by yourself.
Here is the snippet of the source code:
class Laplace
{
const int DefaultStehfest = 14;
public delegate double FunctionDelegate(double t);
static double[] V; // Stehfest coefficients
static double ln2; // log of 2
public static void InitStehfest(int N)
{
ln2 = Math.Log(2.0);
int N2 = N / 2;
int NV = 2 * N2;
V = new double[NV];
int sign = 1;
if ((N2 % 2) != 0)
sign = -1;
for (int i = 0; i < NV; i++)
{
int kmin = (i + 2) / 2;
int kmax = i + 1;
if (kmax > N2)
kmax = N2;
V[i] = 0;
sign = -sign;
for (int k = kmin; k <= kmax; k++)
{
V[i] = V[i] + (Math.Pow(k, N2) / Factorial(k)) * (Factorial(2 * k)
/ Factorial(2 * k - i - 1)) / Factorial(N2 - k)
/ Factorial(k - 1) / Factorial(i + 1 - k);
}
V[i] = sign * V[i];
}
}
public static double InverseTransform(FunctionDelegate f, double t)
{
double ln2t = ln2 / t;
double x = 0;
double y = 0;
for (int i = 0; i < V.Length; i++)
{
x += ln2t;
y += V[i] * f(x);
}
return ln2t * y;
}
public static double Factorial(int N)
{
double x = 1;
if (N > 1)
{
for (int i = 2; i <= N; i++)
x = i * x;
}
return x;
}
}
coded by Mr. Walt Fair Jr. in CodeProject.
I want to ask how I can reorder the digits in an Int32 so they result in the biggest possible number.
Here is an example which visualizes what I am trying to do:
2927466 -> 9766422
12492771 -> 97742211
I want to perform the ordering of the digits without using the System.Linq namespace and without converting the integer into a string value.
This is what I got so far:
public static int ReorderInt32Digits(int v)
{
int n = Math.Abs(v);
int l = ((int)Math.Log10(n > 0 ? n : 1)) + 1;
int[] d = new int[l];
for (int i = 0; i < l; i++)
{
d[(l - i) - 1] = n % 10;
n /= 10;
}
if (v < 0)
d[0] *= -1;
Array.Sort(d);
Array.Reverse(d);
int h = 0;
for (int i = 0; i < d.Length; i++)
{
int index = d.Length - i - 1;
h += ((int)Math.Pow(10, index)) * d[i];
}
return h;
}
This algorithm works flawlessly but I think it is not very efficient.
I would like to know if there is a way to do the same thing more efficiently and how I could improve my algorithm.
You can use this code:
var digit = 2927466;
String.Join("", digit.ToString().ToCharArray().OrderBy(x => x));
Or
var res = String.Join("", digit.ToString().ToCharArray().OrderByDescending(x => x) );
Not that my answer may or may not be more "efficient", but when I read your code you calculated how many digits there are in your number so you can determine how large to make your array, and then you calculated how to turn your array back into a sorted integer.
It would seem to me that you would want to write your own code that did the sorting part without using built in functionality, which is what my sample does. Plus, I've added the ability to sort in ascending or descending order, which is easy to add in your code too.
UPDATED
The original algorithm sorted the digits, now it sorts the digits so that the end result is the largest or smallest depending on the second parameter passed in. However, when dealing with a negative number the second parameter is treated as opposite.
using System;
public class Program
{
public static void Main()
{
int number1 = 2927466;
int number2 = 12492771;
int number3 = -39284925;
Console.WriteLine(OrderDigits(number1, false));
Console.WriteLine(OrderDigits(number2, true));
Console.WriteLine(OrderDigits(number3, false));
}
private static int OrderDigits(int number, bool asc)
{
// Extract each digit into an array
int[] digits = new int[(int)Math.Floor(Math.Log10(Math.Abs(number)) + 1)];
for (int i = 0; i < digits.Length; i++)
{
digits[i] = number % 10;
number /= 10;
}
// Order the digits
for (int i = 0; i < digits.Length; i++)
{
for (int j = i + 1; j < digits.Length; j++)
{
if ((!asc && digits[j] > digits[i]) ||
(asc && digits[j] < digits[i]))
{
int temp = digits[i];
digits[i] = digits[j];
digits[j] = temp;
}
}
}
// Turn the array of digits back into an integer
int result = 0;
for (int i = digits.Length - 1; i >= 0; i--)
{
result += digits[i] * (int)Math.Pow(10, digits.Length - 1 - i);
}
return result;
}
}
Results:
9766422
11224779
-22345899
See working example here... https://dotnetfiddle.net/RWA4XV
public static int ReorderInt32Digits(int v)
{
var nums = Math.Abs(v).ToString().ToCharArray();
Array.Sort(nums);
bool neg = (v < 0);
if(!neg)
{
Array.Reverse(nums);
}
return int.Parse(new string(nums)) * (neg ? -1 : 1);
}
This code fragment below extracts the digits from variable v. You can modify it to store the digits in an array and sort/reverse.
int v = 2345;
while (v > 0) {
int digit = v % 10;
v = v / 10;
Console.WriteLine(digit);
}
You can use similar logic to reconstruct the number from (sorted) digits: Multiply by 10 and add next digit.
I'm posting this second answer because I think I got the most efficient algorithm of all (thanks for the help Atul) :)
void Main()
{
Console.WriteLine (ReorderInt32Digits2(2927466));
Console.WriteLine (ReorderInt32Digits2(12492771));
Console.WriteLine (ReorderInt32Digits2(-1024));
}
public static int ReorderInt32Digits2(int v)
{
bool neg = (v < 0);
int mult = neg ? -1 : 1;
int result = 0;
var counts = GetDigitCounts(v);
for (int i = 0; i < 10; i++)
{
int idx = neg ? 9 - i : i;
for (int j = 0; j < counts[idx]; j++)
{
result += idx * mult;
mult *= 10;
}
}
return result;
}
// From Atul Sikaria's answer
public static int[] GetDigitCounts(int n)
{
int v = Math.Abs(n);
var result = new int[10];
while (v > 0) {
int digit = v % 10;
v = v / 10;
result[digit]++;
}
return result;
}
I am trying to analyse some data using a C# app and need to calculate trend lines. I am aware that there are multiple types of trend line but for now I am trying to calculate exponential growth; I am going to be using it to predict future values. The equation I have been working off is
x(t) = x(0) * ((1+r)^t)
And this is the code that I have written to try and replicate the graph:
public void ExponentialBestFit(List<DateTime> xvalues, List<double> yvalues)
{
//Find the first value of y (The start value) and the first value of x (The start date)
xzero = Convert.ToDouble(xvalues[0].ToOADate());
yzero = yvalues[0];
if (yzero == 0)
yzero += 0.1;
//For every value of x (exluding the 1st value) find the r value
//
// | y | Where t = the time sinse the start time (time period)
//Equation for r = t root|-------| - 1 Where y = the current y value
// | y[0] | Where y[0] = the first y value #IMPROVMENT - Average 1st y value in range
//
double r = 0;
//c is a count of how many r values are added; it is not equal to the count of all the values
int c = 0;
for (int i = 1; i < xvalues.Count; i++)
{
r += Math.Pow(yvalues[i]/yzero, 1/(Convert.ToDouble(xvalues[i].ToOADate()) - xzero)) - 1;
c++;
}
r = r / c;
}
The data I am passing in is over a period of time however the increments in which the time increases are not the same. When I created a chart in excel they use a different formula
x(t) = x(0)*(e^kt)
I think however I have no idea where the k value is being generated from. The two lists that I am passing in are Date and Value and each row in each list corresponds to the same row in the other list. The question is - Is there a better way of creating the equation and variables and are the variables I am getting the most accurate it can be for my data?
This is the c# version of the javascript provided.
// Calculate Exponential Trendline / Growth
IEnumerable<double> Growth(IList<double> knownY, IList<double> knownX, IList<double> newX, bool useConst)
{
// Credits: Ilmari Karonen
// Default values for optional parameters:
if (knownY == null) return null;
if (knownX == null)
{
knownX = new List<double>();
for (var i = 0; i<=knownY.Count; i++)
knownX.Add(i);
}
if (newX == null)
{
newX = new List<double>();
for (var i = 0; i <= knownY.Count; i++)
newX.Add(i);
}
int n = knownY.Count;
double avg_x = 0.0;
double avg_y = 0.0;
double avg_xy = 0.0;
double avg_xx = 0.0;
double beta = 0.0;
double alpha = 0.0;
for (var i = 0; i < n; i++)
{
var x = knownX[i];
var y = Math.Log(knownY[i]);
avg_x += x;
avg_y += y;
avg_xy += x * y;
avg_xx += x * x;
}
avg_x /= n;
avg_y /= n;
avg_xy /= n;
avg_xx /= n;
// Compute linear regression coefficients:
if (useConst)
{
beta = (avg_xy - avg_x * avg_y) / (avg_xx - avg_x * avg_x);
alpha = avg_y - beta * avg_x;
}
else
{
beta = avg_xy / avg_xx;
alpha = 0.0;
}
// Compute and return result array:
return newX.Select(t => Math.Exp(alpha + beta*t)).ToList();
}
The following JavaScript code should help. I used it to implement Excel's GROWTH function. It's written in JavaScript, but porting it to C# should be very easy. Please note that most of it was written by someone else (credits in the code).
function GROWTH(known_y, known_x, new_x, use_const) {
// Credits: Ilmari Karonen
// Default values for optional parameters:
if (typeof(known_x) == 'undefined') {
known_x = [];
for (var i = 1; i <= known_y.length; i++) known_x.push(i);
}
if (typeof(new_x) == 'undefined') {
new_x = [];
for (var i = 1; i <= known_y.length; i++) new_x.push(i);
}
if (typeof(use_const) == 'undefined') use_const = true;
// Calculate sums over the data:
var n = known_y.length;
var avg_x = 0;
var avg_y = 0;
var avg_xy = 0;
var avg_xx = 0;
for (var i = 0; i < n; i++) {
var x = known_x[i];
var y = Math.log(known_y[i]);
avg_x += x;
avg_y += y;
avg_xy += x*y;
avg_xx += x*x;
}
avg_x /= n;
avg_y /= n;
avg_xy /= n;
avg_xx /= n;
// Compute linear regression coefficients:
if (use_const) {
var beta = (avg_xy - avg_x*avg_y) / (avg_xx - avg_x*avg_x);
var alpha = avg_y - beta*avg_x;
} else {
var beta = avg_xy / avg_xx;
var alpha = 0;
}
// Compute and return result array:
var new_y = [];
for (var i = 0; i < new_x.length; i++) {
new_y.push(Math.exp(alpha + beta * new_x[i]));
}
return new_y;
}
Since x(t)=x(0)*e^{kt}, we can take logarithms to get ln x(t)=ln x(0) + kt. This means that to find ln x(0) and k, you can find the least squares fit for the data {(t,ln x(t))}. This will tell you that ln x(t) = b + at, so that k=a and x(0)=e^b.