n-th Root Algorithm - c#

What is the fastest way to calculate the n-th root of a number?
I'm aware of the Try and Fail method, but I need a faster algorithm.

The canonical way to do this is Newton's Method. In case you don't know, the derivative of xn is nxn-1. This will come in handy. 1 is a good first guess. You want to apply it to the function a - xn
IIRC, it's superconvergent on functions of the form a - xn, but either way, it's quite fast. Also, IIRC, the warning in the wiki about it failing to converge would apply to more complex functions that have properties that the 'nice' functions you are interested in lack.

Not the fastest, but it works. Substitute your chosen type:
private static decimal NthRoot(decimal baseValue, int N)
{
if (N == 1)
return baseValue;
decimal deltaX;
decimal x = 0.1M;
do
{
deltaX = (baseValue / Pow(x, N - 1) - x) / N;
x = x + deltaX;
} while (Math.Abs(deltaX) > 0);
return x;
}
private static decimal Pow(decimal baseValue, int N)
{
for (int i = 0; i < N - 1; i++)
baseValue *= baseValue;
return baseValue;
}

Are you referring to the nth root algorithm ? This is not a try-and-fail method, but an iterative algorithm which is repeated until the required precision is reached.

Related

calculations for a very large number

I have a function which calculates the factorial and combinations as follows.
int faktorial(int n)
{
if( (n == 0)||(n == 1))
{
return (1);
}
else
{
return (n * faktorial(n-1));
}
}
int Kombinasi(int x, int y)
{
int n = faktorial(x);
int k = (faktorial(x - y)) * (faktorial(y));
int hasil = n / k;
return (hasil);
}
But there is a problem that in calculating the factorial.
Suppose I want to count combination with x = 1000 and y = 4. The function of the combination of the existing call factorial function. but the factorial function is not able to count them. How to solve this problem ?. Sorry my english is very bad. thanks.
BigInteger works and is pretty fast at 1000!.
BigInteger faktorial(BigInteger n)
{
if ((n == 0) || (n == 1))
{
return (1);
}
else
{
return (n * faktorial(n - 1));
}
}
BigInteger Kombinasi(BigInteger x, BigInteger y)
{
BigInteger n = faktorial(x);
BigInteger k = (faktorial(x - y)) * (faktorial(y));
BigInteger hasil = n / k;
return (hasil);
}
Answer:
402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Note, however, that it appears to overflow the stack above around 8889!.
First, to answer your question - you can handle bigger values (up to 2^64 - 1) if you use
ulong c;
Second, a little help - that won't help you with the exercise. Even unsigned long won't be able to handle such large values. However, note that instead, to get (n choose k), you can simply calculate (n * (n - 1) * .... * (n - k + 1)) / k!, Which deals with much smaller values.
Since it looks like what you really want to do is compute a binomial coefficient, an alternative to using BigInteger is to take advantage of some of the numerical properties of factorials. So rather than computing factorials directly (which can be large), you can instead do this:
long Kombinasi(long x, long y)
{
if( y == 0 ) return 1;
return ( x * Kombinasi( x - 1, y - 1 ) ) / y;
}
You could also use this algorithm in combination with BigInteger if you need even larger values:
BigInteger Binomial( BigInteger n, BigInteger k )
{
if( k <= 0 ) return 1;
return ( n * Binomial( n - 1, k - 1 ) ) / k;
}
This will be much more efficient than computing the factorials and dividing since it takes advantage of the fact that most of the factorial terms cancel out. It will also perform fewer multiplications, especially if k is small.
As suggested by other members We can use BitInteger for big numbers.
I dont know whether it is useful or not, but I want to explain one point here.
So lets say We have a signed int which has big value(int.Max) and If you try to add some positive integer value (10), It wont give you System.OverflowException. It simply give you negative value. So If you want to raise exception in such cases. You can use checked keyword. if the expression produces a value that is outside the range of the destination type. If the expression contains one or more non-constant values, the compiler does not detect the overflow. Overflow checking can be enabled by use of the checked keyword. So when you try something like I mentioned above, It will throw exception and you can handle it accordingly.
checked in C#

'Grokkable' algorithm to understand exponentiation where the exponent is floating point

To clarify first:
2^3 = 8. That's equivalent to 2*2*2. Easy.
2^4 = 16. That's equivalent to 2*2*2*2. Also easy.
2^3.5 = 11.313708... Er, that's not so easy to grok.
Want I want is a simple algorithm which most clearly shows how 2^3.5 = 11.313708. It should preferably not use any functions apart from the basic addition, subtract, multiply, or divide operators.
The code certainly doesn't have to be fast, nor does it necessarily need to be short (though that would help). Don't worry, it can be approximate to a given user-specified accuracy (which should also be part of the algorithm). I'm hoping there will be a binary chop/search type thing going on, as that's pretty simple to grok.
So far I've found this, but the top answer is far from simple to understand on a conceptual level.
The more answers the merrier, so I can try to understand different ways of attacking the problem.
My language preference for the answer would be C#/C/C++/Java, or pseudocode for all I care.
Ok, let's implement pow(x, y) using only binary searches, addition and multiplication.
Driving y below 1
First, take this out of the way:
pow(x, y) == pow(x*x, y/2)
pow(x, y) == 1/pow(x, -y)
This is important to handle negative exponents and drive y below 1, where things start getting interesting. This reduces the problem to finding pow(x, y) where 0<y<1.
Implementing sqrt
In this answer I assume you know how to perform sqrt. I know sqrt(x) = x^(1/2), but it is easy to implement it just using a binary search to find y = sqrt(x) using y*y=x search function, e.g.:
#define EPS 1e-8
double sqrt2(double x) {
double a = 0, b = x>1 ? x : 1;
while(abs(a-b) > EPS) {
double y = (a+b)/2;
if (y*y > x) b = y; else a = y;
}
return a;
}
Finding the answer
The rationale is that every number below 1 can be approximated as a sum of fractions 1/2^x:
0.875 = 1/2 + 1/4 + 1/8
0.333333... = 1/4 + 1/16 + 1/64 + 1/256 + ...
If you find those fractions, you actually find that:
x^0.875 = x^(1/2+1/4+1/8) = x^(1/2) * x^(1/4) * x^(1/8)
That ultimately leads to
sqrt(x) * sqrt(sqrt(x)) * sqrt(sqrt(sqrt(x)))
So, implementation (in C++)
#define EPS 1e-8
double pow2(double x, double y){
if (x < 0 and abs(round(y)-y) < EPS) {
return pow2(-x, y) * ((int)round(y)%2==1 ? -1 : 1);
} else if (y < 0) {
return 1/pow2(x, -y);
} else if(y > 1) {
return pow2(x * x, y / 2);
} else {
double fraction = 1;
double result = 1;
while(y > EPS) {
if (y >= fraction) {
y -= fraction;
result *= x;
}
fraction /= 2;
x = sqrt2(x);
}
return result;
}
}
Deriving ideas from the other excellent posts, I came up with my own implementation. The answer is based on the idea that base^(exponent*accuracy) = answer^accuracy. Given that we know the base, exponent and accuracy variables beforehand, we can perform a search (binary chop or whatever) so that the equation can be balanced by finding answer. We want the exponent in both sides of the equation to be an integer (otherwise we're back to square one), so we can make accuracy any size we like, and then round it to the nearest integer afterwards.
I've given two ways of doing it. The first is very slow, and will often produce extremely high numbers which won't work with most languages. On the other hand, it doesn't use log, and is simpler conceptually.
public double powSimple(double a, double b)
{
int accuracy = 10;
bool negExponent = b < 0;
b = Math.Abs(b);
bool ansMoreThanA = (a>1 && b>1) || (a<1 && b<1); // Example 0.5^2=0.25 so answer is lower than A.
double accuracy2 = 1.0 + 1.0 / accuracy;
double total = a;
for (int i = 1; i < accuracy* b; i++) total = total*a;
double t = a;
while (true) {
double t2 = t;
for(int i = 1; i < accuracy; i++) t2 = t2 * t; // Not even a binary search. We just hunt forwards by a certain increment
if((ansMoreThanA && t2 > total) || (!ansMoreThanA && t2 < total)) break;
if (ansMoreThanA) t *= accuracy2; else t /= accuracy2;
}
if (negExponent) t = 1 / t;
return t;
}
This one below is a little more involved as it uses log(). But it is much quicker and doesn't suffer from the super-high number problems as above.
public double powSimple2(double a, double b)
{
int accuracy = 1000000;
bool negExponent= b<0;
b = Math.Abs(b);
double accuracy2 = 1.0 + 1.0 / accuracy;
bool ansMoreThanA = (a>1 && b>1) || (a<1 && b<1); // Example 0.5^2=0.25 so answer is lower than A.
double total = Math.Log(a) * accuracy * b;
double t = a;
while (true) {
double t2 = Math.Log(t) * accuracy;
if ((ansMoreThanA && t2 > total) || (!ansMoreThanA && t2 < total)) break;
if (ansMoreThanA) t *= accuracy2; else t /= accuracy2;
}
if (negExponent) t = 1 / t;
return t;
}
You can verify that 2^3.5 = 11.313708 very easily: check that 11.313708^2 = (2^3.5)^2 = 2^7 = 128
I think the easiest way to understand the computation you would actually do for this would be to refresh your understanding of logarithms - one starting point would be http://en.wikipedia.org/wiki/Logarithm#Exponentiation.
If you really want to compute non-integer powers with minimal technology one way to do that would be to express them as fractions with denominator a power of two and then take lots of square roots. E.g. x^3.75 = x^3 * x^(1/2) * x^(1/4) then x^(1/2) = sqrt(x), x^(1/4) = sqrt(sqrt(x)) and so on.
Here is another approach, based on the idea of verifying a guess. Given y, you want to find x such that x^(a/b) = y, where a and b are integers. This equation implies that x^a = y^b. You can calculate y^b, since you know both numbers. You know a, so you can - as you originally suspected - use binary chop or perhaps some numerically more efficient algorithm to solve x^a = y^b for x by simply guessing x, computing x^a for this guess, comparing it with y^b, and then iteratively improving the guess.
Example: suppose we wish to find 2^0.878 by this method. Then set a = 439, b = 500, so we wish to find 2^(439/500). If we set x=2^(439/500) we have x^500 = 2^439, so compute 2^439 and (by binary chop or otherwise) find x such that x^500 = 2^439.
Most of it comes down to being able to invert the power operation.
In other words, the basic idea is that (for example) N2 should be basically the "opposite" of N1/2 so that if you do something like:
M = N2
L = M1/2
Then the result you get in L should be the same as the original value in N (ignoring any rounding and such).
Mathematically, that means that N1/2 is the same as sqrt(N), N1/3 is the cube root of N, and so on.
The next step after that would be something like N3/2. This is pretty much the same idea: the denominator is a root, and the numerator is a power, so N3/2 is the square root of the cube of N (or the cube of the square root of N--works out the same).
With decimals, we're just expressing a fraction in a slightly different form, so something like N3.14 can be viewed as N314/100--the hundredth root of N raised to the power 314.
As far as how you compute these: there are quite a few different ways, depending heavily on the compromise you prefer between complexity (chip area, if you're implementing it in hardware) and speed. The obvious way is to use a logarithm: AB = Log-1(Log(A)*B).
For a more restricted set of inputs, such as just finding the square root of N, you can often do better than that extremely general method though. For example, the binary reducing method is quite fast--implemented in software, it's still about the same speed as Intel's FSQRT instruction.
As stated in the comments, its not clear if you want a mathematical description of how fractional powers work, or an algorithm to calculate fractional powers.
I will assume the latter.
For almost all functions (like y = 2^x) there is a means of approximating the function using a thing called the Taylor Series http://en.wikipedia.org/wiki/Taylor_series. This approximates any reasonably behaved function as a polynomial, and polynomials can be calculated using only multiplication, division, addition and subtraction (all of which the CPU can do directly). If you calculate the Taylor series for y = 2^x and plug in x = 3.5 you will get 11.313...
This almost certainly not how exponentiation is actually done on your computer. There are many algorithms which run faster for different inputs. For example, if you calculate 2^3.5 using the Taylor series, then you would have to look at many terms to calculate it with any accuracy. However, the Taylor series will converge much faster for x = 0.5 than for x = 3.5. So one obvious improvement is to calculate 2^3.5 as 2^3 * 2^0.5, as 2^3 is easy to calculate directly. Modern exponentiation algorithms will use many, many tricks to speed up processing - but the principle is still much the same, approximate the exponentiation function as some infinite sum, and calculate as many terms as you need to get the accuracy that is required.

Dividing two Ulong integers outputs wrong result

I am writing a program for Catalan number. So here is the formula for that:
I decided to use the middle part of the formula, because the other parts are too abstract for my knowledge (maybe I slept too much in math classes).
Actually my program works fine for n = 0;,n = 5;, n = 10; But if I enter n = 15; - here comes the boom - the output is 2 when it should be 9694845.
So here is my child:
using System;
namespace _8_Numbers_of_Catalan
{
class CatalanNumbers
{
static void Main()
{
Console.Write("n: ");
int n = int.Parse(Console.ReadLine());
Console.WriteLine("Catalan({0})", n);
//calculating the Catan number from the formula
// Catan(n) = [(2*n)!]/[(n+1)! * n!]
Console.WriteLine((factorial(2 * n)) / (factorial(n + 1) * factorial(n)));
}//finding the factorial
private static ulong factorial(int n)
{
ulong fact = 1;
for (int i = 1; i <= n; i++)
{
fact *= (ulong)i;
}
return fact;
}
}
}
Thank you in advance for understanding me if there is something obviously wrong. I am new in programming.
That is because you are performing calculation of these using integer variables that can contain at most 64 bits.
Your call to factorial(15 * 2) is 30! which would result in a value of
265,252,859,812,191,058,636,308,480,000,000
Much more than fits in a 64 bit integer variable:
18,446,744,073,709,551,615 (0xFFFFFFFFFFFFFFFF).
The options you have are to use a System.Numerics.BigInteger type (slow) or a double (up to a maximum value of 1.7976931348623157E+308). Which means you will loose some precision, that may or may not be relevant.
Another option you have is to use an algorithm to approximate the value of large factorials using an asymptotic approximation such as the Schönhage–Strassen algorithm used by Mathematica.
You may also want to check out some existing online resources for calculation of big factorials in .NET
As a last but not least option (and I have not thoroughly checked) it seems likely to me that specific algorithms exists that allow you to calculate (or approximate to a sufficient accuracy and precision) a Catalan number.
you should use a System.Numerics.BigInteger for this. (add System.Numerics as reference in your project).
private static BigInteger factorial(int n)
{
BigInteger fact = 1;
for (int i = 1; i <= n; i++)
{
fact *= i;
}
return fact;
}
// output: 9694845

Binary Search versus LINQ select statement

I have a list of floating point data in which I want to find the index just below a passed value. A simplified example:
double[] x= {1.0, 1.4, 2.3, 5.6, 7.8};
double[] y= {3.4, 8.2, 5.3, 8.1, 0.5};
int lowerIndex = BinaryIndexSearch(x, 2.0); // should return 1
The intent is that an interpolation will then be performed with x and y using lowerIndex and lowerIndex+1.
The binary index search algorithm looks like
int BinaryIndexSearch(double[] x, double value)
{
int upper = x.Length - 1;
int lower = 0;
int pivot;
do
{
pivot = (upper + lower) / 2;
if (value >= x[pivot])
{
lower = pivot + 1;
}
else
{
upper = pivot - 1;
}
}
while (value < x[pivot] || value >= x[pivot + 1]);
return pivot;
}
Is there a more efficient way to do this with LINQ? Would it typically be faster? The comparison operation at the end of the do..while loop is the "hottest" line of code my program.
LINQ will not be more efficient than a binary search.
However, you are re-inventing the existing Array.BinarySearch method.
If the element is not found, Array.BinarySearch will return the bitwise complement (~ operator) of the location where it ought to be.
Linq is written over IEnumerable. It is not meant for performance. As a general rule of thumb all algorithms that have intimate knowledge of the data structure used will be faster than a generic solution (like LINQ is).

Nth root of small number return an unexpected result in C#

When I try to take the N th root of a small number using C# I get a wrong number.
For example, when I try to take the third root of 1.07, I get 1, which is clearly not true.
Here is the exact code I am using to get the third root.
MessageBox.Show(Math.Pow(1.07,(1/3)).toString());
How do I solve this problem?
I would guess that this is a floating point arithmetic issue, but I don't know how to handle it.
C# is treating the 1 and the 3 as integers, you need to do the following:
Math.Pow(1.07,(1d/3d))
or
Math.Pow(1.07,(1.0/3.0))
It is actually interesting because the implicit widening conversion makes you make a mistake.
I'm pretty sure the "exact code" you give doesn't compile.
MessageBox.Show(Math.Pow(1.07,(1/3).toString()));
The call to toString is at the wrong nesting level, needs to be ToString, and (1/3) is integer division, which is probably the real problem you're having. (1/3) is 0 and anything to the zeroth power is 1. You need to use (1.0/3.0) or (1d/3d) or ...
First things first: if that's the exact code you're using, there's likely something wrong with your compiler :-)
MessageBox.Show(Math.Pow(1.07,(1/3).toString()));
will evaluate (1/3).toString() first then try and raise 1.07 to the power of that string.
I think you mean:
MessageBox.Show(Math.Pow(1.07,(1/3)).ToString());
As to the problem, (1/3) is being treated as an integer division returning 0 and n0 is 1 for all values of n.
You need to force it to a floating point division with something like 1.0/3.0.
This may help in case you have a real nth root precision problem, but my experiance is that the builtin Math.Pow(double, int) is more precise:
private static decimal NthRoot(decimal baseValue, int N)
{
if (N == 1)
return baseValue;
decimal deltaX;
decimal x = 1M;
do
{
deltaX = (baseValue / Pow(x, N - 1) - x) / N;
x = x + deltaX;
} while (Math.Abs(deltaX) > 0);
return x;
}
private static decimal Pow(decimal a, int b)
{
if (b == 0) return 1;
if (a == 0) return 0;
if (b == 1) return a;
if (b % 2 == 0)
return Pow(a * a, b / 2);
else if (b % 2 == 1)
return a * Pow(a * a, b / 2);
return 0;
}

Categories

Resources