Does the compiler optimize away if statements inside loop - c#

I'm going through another programmers code and see the following function (and several variations, are called inside a massive loop and in the critical path) and I'm wondering if the c# compiler is smart enough to optimize it:
public double SomeFunction(double p_lower, double p_upper) {
double result = 0.0;
int low = (int)Math.Ceiling(p_lower);
int high = (int)Math.Ceiling(p_upper);
for( int i = low; i <= high; ++i){
double dbl_low;
double dbl_high;
if (i == low && i == high) {
dbl_low = p_lower; // corrected from low in original post
dbl_high = p_upper; // corrected from high original post
} else if (i == low) {
dbl_low = p_lower;
dbl_high = i;
} else if (i == high) {
dbl_low = i - 1;
dbl_high = p_upper;
} else {
dbl_low = i - 1;
dbl_high = i;
}
if (dbl_low != dbl_high) {
result += f(dbl_low,dbl_high);
}
}
return result;
}
What this function does is clear, the range from p_lower to p_upper is split up three parts:
Fraction up to the first integer, steps of 1 until the last integer, fraction from last integer to p_upper and call a function on those intervals.
The first condition is the edge case where the both lower and upper are within the same unit interval (correction from original)
My instinct (from when I learned to program and compilers were horrible) would be to rewrite the code as this:
public double SomeFunction2(double p_lower, double p_upper) {
if(p_upper < p_lower){
return 0.0;
}
double result = 0.0;
double low = Math.Ceiling(p_lower);
double high = Math.Ceiling(p_upper);
/// edge case
if (Math.Abs(low - high) < 0.00001) {
return Math.Abs(p_upper-p_lower)< 0.00001? 0.0 : f(p_lower, p_upper);
}
/// first fraction
result += Math.Abs(low - p_lower)< 0.00001? 0.0 : f(p_lower, low);
/// whole intervals
for( double i = low + 1.0; i < high; ++i){ // < instead of <=
result += f(i-1.0, i);
}
/// add last fraction and return
return result + f(high - 1.0, p_upper);
}
This way, there is not a whole cascade of conditional statements that is evaluated every loop, the first of which will always be false after the first, the second will always be true except for the final one. In fact there is no conditional in the loop, since the last condition has been incorporated in the loop range.
The loop counter is a double which should not be an issue since the range for low and high is 0.0 ... 120.0 all of which are exact as a double.
Am I wasting my time and does the compiler handle all this and is all I gain some readability?

I changed your second function a bit to improve readability:
using System;
using System.Diagnostics;
class Program
{
static void Main()
{
Stopwatch sw = new Stopwatch();
const int COUNT = 10000000;
double[] lowers = new double[COUNT];
double[] uppers = new double[COUNT];
double[] result = new double[COUNT];
double[] result2 = new double[COUNT];
Random random = new Random();
for (int i = 0; i < COUNT; i++)
{
lowers[i] = Math.Round(random.NextDouble() * 60.0, 2);
uppers[i] = lowers[i] + Math.Round(random.NextDouble() * 40.0,2);
}
sw.Start();
for (int i = 0; i < COUNT; i++)
{
result[i] = SomeFunction(lowers[i], uppers[i]);
}
sw.Stop();
Console.WriteLine("Elapsed Time for SomeFunction is {0} ms", sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
for (int i = 0; i < COUNT; i++)
{
result2[i] = SomeFunction2(lowers[i], uppers[i]);
}
sw.Stop();
Console.WriteLine("Elapsed Time for SomeFunction2 is {0} ms", sw.ElapsedMilliseconds);
for (int i = 0; i < COUNT; i++)
{
if (result[i] != result2[i])
{
Console.WriteLine("i: {0}",i);
}
}
}
public static double SomeFunction(double p_lower, double p_upper) {
double result = 0.0;
int low = (int)Math.Ceiling(p_lower);
int high = (int)Math.Ceiling(p_upper);
for(int i = low; i <= high; ++i){
double dbl_low;
double dbl_high;
if (i == low && i == high) {
dbl_low = p_lower;
dbl_high = p_upper;
} else if (i == low) {
dbl_low = p_lower;
dbl_high = i;
} else if (i == high) {
dbl_low = i - 1;
dbl_high = p_upper;
} else {
dbl_low = i - 1;
dbl_high = i;
}
if (dbl_low != dbl_high) {
result += f(dbl_low,dbl_high);
}
}
return result;
}
public static double SomeFunction2(double p_lower, double p_upper) {
double result = 0.0;
if (p_upper <= p_lower) {
return result;
}
double low = Math.Ceiling(p_lower);
double high = Math.Ceiling(p_upper);
/// edge case
if (high == low) {
return f(p_lower, p_upper);
}
/// first fraction
if (low > p_lower) {
result += f(p_lower, low);
}
/// whole intervals
for (int i = (int)low + 1; i < high; ++i){
result += f(i-1.0, i);
}
/// add last fraction and return
return result + f(high - 1.0, p_upper);
}
// Simple function f(a,b) for test purpose
public static double f(double a, double b)
{
return a + b;
}
}
Running this several times gave me:
3680 ms / 1863 ms -> 49%
2362 ms / 1441 ms -> 39%
3175 ms / 2030 ms -> 36%
2956 ms / 1531 ms -> 48%
So it stays quite close in terms of performance

The answer is that the latest MS c# compiler does not optimize this code fully.
I added large arrays of random numbers to Rafalon's program as a crude benchmark.
With this simple addition function the time difference is ~1950ms for SomeFunction and ~1160ms for Somefunction2. A 40% reduction in execution time by simply moving conditionals out of the loop.
Thanks to the people pointing out the error in transcribing the original functions and pointing out there were errors/I had misunderstood part of the original function I managed to get a new function that passes all our unit tests.
using System;
using System.Diagnostics;
class Program
{
static void Main()
{
Stopwatch sw = new Stopwatch();
const int COUNT = 10000000;
double[] lowers = new double[COUNT];
double[] uppers = new double[COUNT];
double[] result = new double[COUNT];
double[] result2 = new double[COUNT];
double sumerror = 0.0;
Random random = new Random();
for (int i = 0; i < COUNT; i++)
{
lowers[i] = Math.Round(random.NextDouble() * 60.0, 2);
uppers[i] = lowers[i] + Math.Round(random.NextDouble() * 40.0,2);
}
sw.Start();
for (int i = 0; i < COUNT; i++)
{
result[i] = SomeFunction(lowers[i], uppers[i]);
}
sw.Stop();
Console.WriteLine("Elapsed Time for SomeFunction is {0} ms", sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
for (int i = 0; i < COUNT; i++)
{
result2[i] = SomeFunction2(lowers[i], uppers[i]);
}
sw.Stop();
Console.WriteLine("Elapsed Time for SomeFunction2 is {0} ms", sw.ElapsedMilliseconds);
for (int i = 0; i < COUNT; i++)
{
sumerror += (result[i] - result2[i]);
if (Math.Abs(result[i] - result2[i])> 0.0001)
{
Console.WriteLine("i: {0}",i);
}
}
Console.WriteLine(sumerror); // should be zero, and we now use the results so no optimizing everything away.
}
public static double SomeFunction(double p_lower, double p_upper) {
double result = 0.0;
int low = (int)Math.Ceiling(p_lower);
int high = (int)Math.Ceiling(p_upper);
for(int i = low; i <= high; ++i){
double dbl_low;
double dbl_high;
if (i == low && i == high) {
dbl_low = p_lower;
dbl_high = p_upper;
} else if (i == low) {
dbl_low = p_lower;
dbl_high = i;
} else if (i == high) {
dbl_low = i - 1;
dbl_high = p_upper;
} else {
dbl_low = i - 1;
dbl_high = i;
}
if (dbl_low != dbl_high) {
result += f(dbl_low,dbl_high);
}
}
return result;
}
public static double SomeFunction2(double p_lower, double p_upper) {
double result = 0.0;
double low = Math.Ceiling(p_lower);
double high = Math.Ceiling(p_upper);
/// edge case
if (Math.Abs(high - low) < 0.00001) {
return Math.Abs(p_upper-p_lower)< 0.00001? 0.0 : f(p_lower, p_upper);
}
/// first fraction
result += Math.Abs(low - p_lower)< 0.00001? 0.0 : f(p_lower, low);
/// whole intervals
for( int i = (int)low + 1; i < high; ++i){
result += f(i-1.0, i);
}
/// add last fraction and return
return result + f(high - 1.0, p_upper);
}
// Simple function f(a,b) for test purpose
public static double f(double a, double b)
{
return a + b;
}
}

Related

Calculate the sequence : n!/ (1+1/2+1/3+...+1/n)

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.

How to return a value from Cudafy c# GPU calculation?

My Issue
Hey, so I'm making this simple calculation to find the sum of sins between 0 and 100 degrees(as I use it as a benchmark for my systems), the calculation isn't the problem my issue is that I am new to Cudafy and I am unsure on how to properly pass in and return values so that it can be printed off here is my code:
Code
public const int N = 33 * 1024;
public const int threadsPerBlock = 256;
public const int blocksPerGrid = 32;
public static void Main()
{
Stopwatch watch = new Stopwatch();
watch.Start();
string Text = "";
int iterations = 1000000;
CudafyModule km = CudafyTranslator.Cudafy();
GPGPU gpu = CudafyHost.GetDevice(CudafyModes.Target, CudafyModes.DeviceId);
gpu.LoadModule(km);
double[] dev_Value = gpu.Allocate<double>();
gpu.Launch(blocksPerGrid, threadsPerBlock).SumOfSines(iterations,dev_Value);
double Value;
gpu.CopyFromDevice(dev_Value, out Value);
watch.Stop();
Text = watch.Elapsed.TotalSeconds.ToString();
Console.WriteLine("The process took a total of: " + Text + " Seconds");
Console.WriteLine(Value);
Console.Read();
gpu.FreeAll();
}
[Cudafy]
public static void SumOfSines(GThread thread,int iterations,double [] Value)
{
double total = new double();
double degAsRad = Math.PI / 180.0;
for (int i = 0; i < iterations; i++)
{
total = 0.0;
for (int z = 1; z < 101; z++)
{
double angle = (double)z * degAsRad;
total += Math.Sin(angle);
}
}
Value[0] = total;
}
The value that I am trying to extract from the CUDAfy part is the total and then print it off aswell as printing the time for the benchmarking. If anyone could post advice it would be very much appreciated (also any suggestions for making rid of any useless lines or unefficient pieces would also be good).
Doesn't matter I found the answer but I'll post it here:
public const int N = 33 * 1024;
public const int threadsPerBlock = 256;
public const int blocksPerGrid = 32;
public static void Main()
{
Stopwatch watch = new Stopwatch();
watch.Start();
CudafyModule km = CudafyTranslator.Cudafy();
GPGPU gpu = CudafyHost.GetDevice(CudafyModes.Target, CudafyModes.DeviceId);
gpu.LoadModule(km);
string Text = "";
int iterations = 1000000;
double Value;
double[] dev_Value = gpu.Allocate<double>(iterations * sizeof(double));
gpu.Launch(blocksPerGrid, threadsPerBlock).SumOfSines(iterations, dev_Value);
gpu.CopyFromDevice(dev_Value, out Value);
watch.Stop();
Text = watch.Elapsed.TotalSeconds.ToString();
Console.WriteLine("The process took a total of: " + Text + " Seconds");
Console.WriteLine(Value);
Console.Read();
gpu.FreeAll();
}
[Cudafy]
public static void SumOfSines(GThread thread, int _iterations, double[] Value)
{
int threadID = thread.threadIdx.x + thread.blockIdx.x * thread.blockDim.x;
int numThreads = thread.blockDim.x * thread.gridDim.x;
if (threadID < _iterations){
for (int i = threadID; i < _iterations; i += numThreads)
{
double _degAsRad = Math.PI / 180;
Value[i] = 0.0;
for (int a = 0; a < 100; a++)
{
double angle = (double)a * _degAsRad;
Value[i] += Math.Sin(angle);
}
}
}
}
-Jack

Format a number based on a required number of decimal places *and* sig figs

Our scientific application allows the user to configure the number of significant figures and decimal places to use when displaying numeric values. The formatting is currently being done with this code:-
var sigFigFormatted = valueToConvert.ToString("G" + numberOfSigFigs);
var theFullyFormattedValue = Convert.ToDouble(sigFigFormatted)
.ToString("F" + numberOfDecimalPlaces);
I don't like all this conversion to/from strings, and can't help thinking there must be a more efficient solution?
Look at accepted answer for this question.
I've ported code from the accepted answer to C# and made some tests.
Code:
using System;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication1
{
public static class NumericExtensions
{
public static double RoundToSignificantFigures(this double num, int n)
{
if (num == 0)
{
return 0;
}
double magnitude = Math.Pow(10, n - (int)Math.Ceiling(Math.Log10(Math.Abs(num))));
double shifted = Math.Round(num * magnitude);
return shifted / magnitude;
}
public static double RoundToSignificantFiguresWithConvert(this double num, int n)
{
var sigFigFormatted = num.ToString("G" + n.ToString());
return Convert.ToDouble(sigFigFormatted);
}
}
class Program
{
static string[] Test1(double[] numbers, int numberOfSigFigs, int numberOfDecimalPlaces)
{
var result = new string[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
result[i] = numbers[i].RoundToSignificantFigures(numberOfSigFigs).ToString("F" + numberOfDecimalPlaces.ToString());
}
return result;
}
static string[] Test2(double[] numbers, int numberOfSigFigs, int numberOfDecimalPlaces)
{
var result = new string[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
result[i] = numbers[i].RoundToSignificantFiguresWithConvert(numberOfSigFigs).ToString("F" + numberOfDecimalPlaces.ToString());
}
return result;
}
static void Main(string[] args)
{
// create an array or random numbers
var rng = new Random();
var numbers = new double[100000];
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = 10000000000000000000D * (rng.NextDouble() - 0.5D);
}
const int numberOfSigFigs = 3;
const int numberOfDecimalPlaces = 3;
// make first run without time measurement
Test1(numbers, numberOfSigFigs, numberOfDecimalPlaces);
Test2(numbers, numberOfSigFigs, numberOfDecimalPlaces);
const int numberOfIterations = 100;
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < numberOfIterations; i++)
{
Test1(numbers, numberOfSigFigs, numberOfDecimalPlaces);
}
sw.Stop();
Console.WriteLine("Test1 elapsed {0} ms", sw.ElapsedMilliseconds.ToString());
sw.Restart();
for (int i = 0; i < numberOfIterations; i++)
{
Test2(numbers, numberOfSigFigs, numberOfDecimalPlaces);
}
sw.Stop();
Console.WriteLine("Test2 elapsed {0} ms", sw.ElapsedMilliseconds.ToString());
Console.ReadKey();
}
}
}
Results:
Test1 elapsed 7259 ms
Test2 elapsed 12918 ms
So NumericExtensions.RoundToSignificantFigures shows more efficient way of formating numbers.

0-1 Knapsack algorithm

Is the following 0-1 Knapsack problem solvable:
'float' positive values and
'float' weights (can be positive or negative)
'float' capacity of the knapsack > 0
I have on average < 10 items, so I'm thinking of using a brute force implementation. However, I was wondering if there is a better way of doing it.
This is a relatively simple binary program.
I'd suggest brute force with pruning. If at any time you exceed the allowable weight, you don't need to try combinations of additional items, you can discard the whole tree.
Oh wait, you have negative weights? Include all negative weights always, then proceed as above for the positive weights. Or do the negative weight items also have negative value?
Include all negative weight items with positive value. Exclude all items with positive weight and negative value.
For negative weight items with negative value, subtract their weight (increasing the knapsack capavity) and use a pseudo-item which represents not taking that item. The pseudo-item will have positive weight and value. Proceed by brute force with pruning.
class Knapsack
{
double bestValue;
bool[] bestItems;
double[] itemValues;
double[] itemWeights;
double weightLimit;
void SolveRecursive( bool[] chosen, int depth, double currentWeight, double currentValue, double remainingValue )
{
if (currentWeight > weightLimit) return;
if (currentValue + remainingValue < bestValue) return;
if (depth == chosen.Length) {
bestValue = currentValue;
System.Array.Copy(chosen, bestItems, chosen.Length);
return;
}
remainingValue -= itemValues[depth];
chosen[depth] = false;
SolveRecursive(chosen, depth+1, currentWeight, currentValue, remainingValue);
chosen[depth] = true;
currentWeight += itemWeights[depth];
currentValue += itemValues[depth];
SolveRecursive(chosen, depth+1, currentWeight, currentValue, remainingValue);
}
public bool[] Solve()
{
var chosen = new bool[itemWeights.Length];
bestItems = new bool[itemWeights.Length];
bestValue = 0.0;
double totalValue = 0.0;
foreach (var v in itemValues) totalValue += v;
SolveRecursive(chosen, 0, 0.0, 0.0, totalValue);
return bestItems;
}
}
Yeah, brute force it. This is an NP-Complete problem, but that shouldn't matter because you will have less than 10 items. Brute forcing won't be problematic.
var size = 10;
var capacity = 0;
var permutations = 1024;
var repeat = 10000;
// Generate items
float[] items = new float[size];
float[] weights = new float[size];
Random rand = new Random();
for (int i = 0; i < size; i++)
{
items[i] = (float)rand.NextDouble();
weights[i] = (float)rand.NextDouble();
if (rand.Next(2) == 1)
{
weights[i] *= -1;
}
}
// solution
int bestPosition= -1;
Stopwatch sw = new Stopwatch();
sw.Start();
// for perf testing
//for (int r = 0; r < repeat; r++)
{
var bestValue = 0d;
// solve
for (int i = 0; i < permutations; i++)
{
var total = 0d;
var weight = 0d;
for (int j = 0; j < size; j++)
{
if (((i >> j) & 1) == 1)
{
total += items[j];
weight += weights[j];
}
}
if (weight <= capacity && total > bestValue)
{
bestPosition = i;
bestValue = total;
}
}
}
sw.Stop();
sw.Elapsed.ToString();
If you can only have positive values then every item with a negative weight must go in.
Then I guess you could calculate Value/Weight Ratio, and brute force the remaining combinations based on that order, once you get one that fits you can skip the rest.
The problem may be that the grading and sorting is actually more expensive than just doing all the calculations.
There will obviously be a different breakeven point based on the size and distribution of the set.
public class KnapSackSolver {
public static void main(String[] args) {
int N = Integer.parseInt(args[0]); // number of items
int W = Integer.parseInt(args[1]); // maximum weight of knapsack
int[] profit = new int[N + 1];
int[] weight = new int[N + 1];
// generate random instance, items 1..N
for (int n = 1; n <= N; n++) {
profit[n] = (int) (Math.random() * 1000);
weight[n] = (int) (Math.random() * W);
}
// opt[n][w] = max profit of packing items 1..n with weight limit w
// sol[n][w] = does opt solution to pack items 1..n with weight limit w
// include item n?
int[][] opt = new int[N + 1][W + 1];
boolean[][] sol = new boolean[N + 1][W + 1];
for (int n = 1; n <= N; n++) {
for (int w = 1; w <= W; w++) {
// don't take item n
int option1 = opt[n - 1][w];
// take item n
int option2 = Integer.MIN_VALUE;
if (weight[n] <= w)
option2 = profit[n] + opt[n - 1][w - weight[n]];
// select better of two options
opt[n][w] = Math.max(option1, option2);
sol[n][w] = (option2 > option1);
}
}
// determine which items to take
boolean[] take = new boolean[N + 1];
for (int n = N, w = W; n > 0; n--) {
if (sol[n][w]) {
take[n] = true;
w = w - weight[n];
} else {
take[n] = false;
}
}
// print results
System.out.println("item" + "\t" + "profit" + "\t" + "weight" + "\t"
+ "take");
for (int n = 1; n <= N; n++) {
System.out.println(n + "\t" + profit[n] + "\t" + weight[n] + "\t"
+ take[n]);
}
}
}
import java.util.*;
class Main{
static int max(inta,int b)
{
if(a>b)
return a;
else
return b;
}
public static void main(String args[])
{
int n,i,cap,j,t=2,w;
Scanner sc=new Scanner(System.in);
System.out.println("Enter the number of values ");
n=sc.nextInt();
int solution[]=new int[n];
System.out.println("Enter the capacity of the knapsack :- ");
cap=sc.nextInt();
int v[]=new int[n+1];
int wt[]=new int[n+1];
System.out.println("Enter the values ");
for(i=1;i<=n;i++)
{
v[i]=sc.nextInt();
}
System.out.println("Enter the weights ");
for(i=1;i<=n;i++)
{
wt[i]=sc.nextInt();
}
int knapsack[][]=new int[n+2][cap+1];
for(i=1;i<n+2;i++)
{
for(j=1;j<n+1;j++)
{
knapsack[i][j]=0;
}
}
/*for(i=1;i<n+2;i++)
{
for(j=wt[1]+1;j<cap+2;j++)
{
knapsack[i][j]=v[1];
}
}*/
int k;
for(i=1;i<n+1;i++)
{
for(j=1;j<cap+1;j++)
{
/*if(i==1||j==1)
{
knapsack[i][j]=0;
}*/
if(wt[i]>j)
{
knapsack[i][j]=knapsack[i-1][j];
}
else
{
knapsack[i][j]=max(knapsack[i-1][j],v[i]+knapsack[i-1][j-wt[i]]);
}
}
}
//for displaying the knapsack
for(i=0;i<n+1;i++)
{
for(j=0;j<cap+1;j++)
{
System.out.print(knapsack[i][j]+" ");
}
System.out.print("\n");
}
w=cap;k=n-1;
j=cap;
for(i=n;i>0;i--)
{
if(knapsack[i][j]!=knapsack[i-1][j])
{
j=w-wt[i];
w=j;
solution[k]=1;
System.out.println("k="+k);
k--;
}
else
{
solution[k]=0;
k--;
}
}
System.out.println("Solution for given knapsack is :- ");
for(i=0;i<n;i++)
{
System.out.print(solution[i]+", ");
}
System.out.print(" => "+knapsack[n][cap]);
}
}
This can be solved using Dynamic Programming. Below code can help you solve the 0/1 Knapsack problem using Dynamic Programming.
internal class knapsackProblem
{
private int[] weight;
private int[] profit;
private int capacity;
private int itemCount;
private int[,] data;
internal void GetMaxProfit()
{
ItemDetails();
data = new int[itemCount, capacity + 1];
for (int i = 1; i < itemCount; i++)
{
for (int j = 1; j < capacity + 1; j++)
{
int q = j - weight[i] >= 0 ? data[i - 1, j - weight[i]] + profit[i] : 0;
if (data[i - 1, j] > q)
{
data[i, j] = data[i - 1, j];
}
else
{
data[i, j] = q;
}
}
}
Console.WriteLine($"\nMax profit can be made : {data[itemCount-1, capacity]}");
IncludedItems();
}
private void ItemDetails()
{
Console.Write("\nEnter the count of items to be inserted : ");
itemCount = Convert.ToInt32(Console.ReadLine()) + 1;
Console.WriteLine();
weight = new int[itemCount];
profit = new int[itemCount];
for (int i = 1; i < itemCount; i++)
{
Console.Write($"Enter weight of item {i} : ");
weight[i] = Convert.ToInt32(Console.ReadLine());
Console.Write($"Enter the profit on the item {i} : ");
profit[i] = Convert.ToInt32(Console.ReadLine());
Console.WriteLine();
}
Console.Write("\nEnter the capacity of the knapsack : ");
capacity = Convert.ToInt32(Console.ReadLine());
}
private void IncludedItems()
{
int i = itemCount - 1;
int j = capacity;
while(i > 0)
{
if(data[i, j] == data[i - 1, j])
{
Console.WriteLine($"Item {i} : Not included");
i--;
}
else
{
Console.WriteLine($"Item {i} : Included");
j = j - weight[i];
i--;
}
}
}
}

How can I calculate a factorial in C# using a library call?

I need to calculate the factorial of numbers up to around 100! in order to determine if a series of coin flip-style data is random, as per this Wikipedia entry on Bayesian probability. As you can see there, the necessary formula involves 3 factorial calculations (but, interestingly, two of those factorial calculations are calculated along the way to the third).
I saw this question here, but I'd think that integer is going to get blown out pretty quickly. I could also make a function that is more intelligent about the factorial calculation (ie, if I have 11!/(7!3!), as per the wiki example, I could go to (11*10*9*8)/3!), but that smacks of premature optimization to me, in the sense that I want it to work, but I don't care about speed (yet).
So what's a good C# library I can call to calculate the factorial in order to get that probability? I'm not interested in all the awesomeness that can go into factorial calculation, I just want the result in a way that I can manipulate it. There does not appear to be a factorial function in the Math namespace, hence the question.
You could try Math.NET - I haven't used that library, but they do list Factorial and Logarithmic Factorial.
There has been a previous question on a similar topic. Someone there linked the Fast Factorial Functions web site, which includes some explanations of efficient algorithms and even C# source code.
Do you want to calculate factorials, or binomial coefficients?
It sounds like you want to calculate binomial coefficients - especially as you mention 11!/(7!3!).
There may be a library that can do this for you, but as a (presumably) programmer visiting stack overflow there's no reason not to write one yourself. It's not too complicated.
To avoid memory overflow, don't evaluate the result until all common factors are removed.
This algorithm still needs to be improved, but you have the basis for a good algorithm here. The denominator values need to be split into their prime factors for the best result. As it stands, this will run for n = 50 quite quickly.
float CalculateBinomial(int n, int k)
{
var numerator = new List<int>();
var denominator = new List<int>();
var denominatorOld = new List<int>();
// again ignore the k! common terms
for (int i = k + 1; i <= n; i++)
numerator.Add(i);
for (int i = 1; i <= (n - k); i++)
{
denominator.AddRange(SplitIntoPrimeFactors(i));
}
// remove all common factors
int remainder;
for (int i = 0; i < numerator.Count(); i++)
{
for (int j = 0; j < denominator.Count()
&& numerator[i] >= denominator[j]; j++)
{
if (denominator[j] > 1)
{
int result = Math.DivRem(numerator[i], denominator[j], out remainder);
if (remainder == 0)
{
numerator[i] = result;
denominator[j] = 1;
}
}
}
}
float denominatorResult = 1;
float numeratorResult = 1;
denominator.RemoveAll(x => x == 1);
numerator.RemoveAll(x => x == 1);
denominator.ForEach(d => denominatorResult = denominatorResult * d);
numerator.ForEach(num => numeratorResult = numeratorResult * num);
return numeratorResult / denominatorResult;
}
static List<int> Primes = new List<int>() { 2, 3, 5, 7, 11, 13, 17, 19,
23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 };
List<int> SplitIntoPrimeFactors(int x)
{
var results = new List<int>();
int remainder = 0;
int i = 0;
while (!Primes.Contains(x) && x != 1)
{
int result = Math.DivRem(x, Primes[i], out remainder);
if (remainder == 0)
{
results.Add(Primes[i]);
x = result;
i = 0;
}
else
{
i++;
}
}
results.Add(x);
return results;
}
I can estimate n = 110, k = 50 (returns 6x10^31) but cannot run n = 120, k = 50.
The following can calculate the factorial of 5000 in 1 second.
public class Number
{
#region Fields
private static long _valueDivision = 1000000000;
private static int _valueDivisionDigitCount = 9;
private static string _formatZeros = "000000000";
List<long> _value;
#endregion
#region Properties
public int ValueCount { get { return _value.Count; } }
public long ValueAsLong
{
get
{
return long.Parse(ToString());
}
set { SetValue(value.ToString()); }
}
#endregion
#region Constructors
public Number()
{
_value = new List<long>();
}
public Number(long value)
: this()
{
SetValue(value.ToString());
}
public Number(string value)
: this()
{
SetValue(value);
}
private Number(List<long> list)
{
_value = list;
}
#endregion
#region Public Methods
public void SetValue(string value)
{
_value.Clear();
bool finished = false;
while (!finished)
{
if (value.Length > _valueDivisionDigitCount)
{
_value.Add(long.Parse(value.Substring(value.Length - _valueDivisionDigitCount)));
value = value.Remove(value.Length - _valueDivisionDigitCount, _valueDivisionDigitCount);
}
else
{
_value.Add(long.Parse(value));
finished = true;
}
}
}
#endregion
#region Static Methods
public static Number operator +(Number c1, Number c2)
{
return Add(c1, c2);
}
public static Number operator *(Number c1, Number c2)
{
return Mul(c1, c2);
}
private static Number Add(Number value1, Number value2)
{
Number result = new Number();
int count = Math.Max(value1._value.Count, value2._value.Count);
long reminder = 0;
long firstValue, secondValue;
for (int i = 0; i < count; i++)
{
firstValue = 0;
secondValue = 0;
if (value1._value.Count > i)
{
firstValue = value1._value[i];
}
if (value2._value.Count > i)
{
secondValue = value2._value[i];
}
reminder += firstValue + secondValue;
result._value.Add(reminder % _valueDivision);
reminder /= _valueDivision;
}
while (reminder > 0)
{
result._value.Add(reminder % _valueDivision);
reminder /= _valueDivision;
}
return result;
}
private static Number Mul(Number value1, Number value2)
{
List<List<long>> values = new List<List<long>>();
for (int i = 0; i < value2._value.Count; i++)
{
values.Add(new List<long>());
long lastremain = 0;
for (int j = 0; j < value1._value.Count; j++)
{
values[i].Add(((value1._value[j] * value2._value[i] + lastremain) % _valueDivision));
lastremain = ((value1._value[j] * value2._value[i] + lastremain) / _valueDivision);
//result.Add(();
}
while (lastremain > 0)
{
values[i].Add((lastremain % _valueDivision));
lastremain /= _valueDivision;
}
}
List<long> result = new List<long>();
for (int i = 0; i < values.Count; i++)
{
for (int j = 0; j < i; j++)
{
values[i].Insert(0, 0);
}
}
int count = values.Select(list => list.Count).Max();
int index = 0;
long lastRemain = 0;
while (count > 0)
{
for (int i = 0; i < values.Count; i++)
{
if (values[i].Count > index)
lastRemain += values[i][index];
}
result.Add((lastRemain % _valueDivision));
lastRemain /= _valueDivision;
count -= 1;
index += 1;
}
while (lastRemain > 0)
{
result.Add((lastRemain % _valueDivision));
lastRemain /= _valueDivision;
}
return new Number(result);
}
#endregion
#region Overriden Methods Of Object
public override string ToString()
{
string result = string.Empty;
for (int i = 0; i < _value.Count; i++)
{
result = _value[i].ToString(_formatZeros) + result;
}
return result.TrimStart('0');
}
#endregion
}
class Program
{
static void Main(string[] args)
{
Number number1 = new Number(5000);
DateTime dateTime = DateTime.Now;
string s = Factorial(number1).ToString();
TimeSpan timeSpan = DateTime.Now - dateTime;
long sum = s.Select(c => (long) (c - '0')).Sum();
}
static Number Factorial(Number value)
{
if( value.ValueCount==1 && value.ValueAsLong==2)
{
return value;
}
return Factorial(new Number(value.ValueAsLong - 1)) * value;
}
}
using System;
//calculating factorial with recursion
namespace ConsoleApplication2
{
class Program
{
long fun(long a)
{
if (a <= 1)
{
return 1;}
else
{
long c = a * fun(a - 1);
return c;
}}
static void Main(string[] args)
{
Console.WriteLine("enter the number");
long num = Convert.ToInt64(Console.ReadLine());
Console.WriteLine(new Program().fun(num));
Console.ReadLine();
}
}
}
hello everybody according to this solution i have my own solution where i calculate factorial of array 1D elements. the code is `int[] array = new int[5]
{
4,3,4,3,8
};
int fac = 1;
int[] facs = new int[array.Length+1];
for (int i = 0; i < array.Length; i++)
{
for (int j = array[i]; j > 0; j--)
{
fac *= j;
}
facs[i] = fac;
textBox1.Text += facs[i].ToString() + " ";
fac = 1;
}`
copy and paste the code above ^ in the button , it solves factorial of elements of array 1D. best regards.

Categories