Time Complexity for Power Function in C - c

For the Power function below, time limit has exceeded.
I can see other solutions to this problem here, but wanted to know why time limit exceeds with my implementation.
double Power(double x, int n)
{
if (n == 0) return 1;
if (x == 0) return 0;
double result = x;
int temp = n;
if (temp < 0)
{
temp = temp * -1;
}
for (int i = 1; i < temp; i++)
{
result *= x;
}
if (n < 0)
{
result = 1 / result;
}
return result;
}

Your algorithm is very slow for large values of n. You're doing n multiplications to get the power, so this is O(n) complexity.
p = x*x*x*...*x
\---------/
n times
You can speed up the calculation by grouping the values. For example you could calculate the square of x and then multiply that value n/2 times with itself (Note that you may need a single x in the end if n is odd).
x2 = x*x
p = x2*x2*...*x2 (*x)
\----------/
n/2 times
With this you only needed (n+1)/2+1 multiplications, which is O(n/2) and twice as fast in the limit of large n.
As you might guess, you can even further group the values and reuse those grouped powers, which leads to a O(log(n)) time complexity as #dbush pointed out in the comment to your question:
double Power(double x, int n) {
double result = 1.0;
double group;
if ( x == 0.0 ) {
return 0.0;
}
if ( n < 0 ) {
n = -n;
group = 1.0/x;
} else {
group = x;
}
while ( n > 0 ) {
if ( n % 2 ) {
result *= group;
}
n = n/2;
group *= group;
}
return result;
}
This algorithm keeps squaring the value of the group and multiply that group value to the result if needed.
Note There is a constant time O(1) implementation of the power function (e.g. the pow from math.h). This makes use of the fact that doubles only have a limited precision. The power can be written as
pow(x,n) = exp(n*log(x))
and the exponential exp as well as the natural logarithm log can be calulated in constant time (see my answer to this question for example). For small integer values of n, the above algorithm is faster though.

Related

Calculate binomial coefficient in binary

Is there a fast algorithm for calculating binomial coefficients and leaving the results binary. For example, (10 choose 8) = 101101. I do not need to convert my results to base 10, instead I want to store my results as binary strings. I was asking this question before reinventing the wheel.
I found the most efficient way. It's performing a prime factorization of the binomial coefficient, then converting to binary. I've added really fast code for finding the prime factorization of a binomial coefficient. It's called Kummer's theorem and you can use this online calculator to verify your results. The factorization algorithm is from this Jstor paper. This is a Haskell version if you're into that kind of stuff. Note you need to first generate a list of primes on your own. Then test individual primes. Also, the fundamental theorem of arithmetic is at work.
//Note primeNumber is always less than n
//Inputs n,k,primeNumber
//Output: e (the exponent of prime number)
//Note: 0 means primeNumber is not a factor of this binomial coefficient
//Example: (n=10,k=3,primeNumber=3), e = 1
//So if you had a list of primes 2,3,5 then for each you get e=3,e=1,e=1. (10,3) = 2^3 *3^1 * 5 ^1
int BinomialFactorization(int n, int k, int primeNumber)
{
int a = 0;
int b = 0;
int exponent = 0;
int r = 0;
//Finds smaller value between n and n-k since (n choose k) == (n choose n-k)
//Algorithm only works when k < n/2
if(k > (n/2))
{
k = n - k;
}
//Speeds up according to paper
if(primeNumber > n - k)
{
return 1;
}
//Speeds up according to paper
if(primeNumber > n/2)
{
printf("%d", 0);
return 0;
}
if(primeNumber * primeNumber > n)
{
if(n % primeNumber < k % primeNumber)
{
return 1;
}
else
{ //Saw this on online calculator
return 0;
}
}
//Changing base algorithm
while(n > 0)
{
a = n % primeNumber;
n = n / primeNumber;
b = k % primeNumber + r;
k = k / primeNumber;
if(a < b)
{
exponent = exponent + 1;
r = 1;
}
else
{
r = 0;
}
}
return exponent;
}

What should I change so that my arctan(x) approximation can display x=1 and x=-1 properly?

One of my C assignments was it to write an approximation of arctan(x) in the language C. The equation which I should base it on is
arctan(x)=\sum {k=0}^{\infty }(-1)^{k} \tfrac{x^{2k+1}}{2k+1}
In addition x is only defined as -1<=x<=1.
Here is my code.
#include <stdio.h>
#include <math.h>
double main(void) {
double x=1;
double k;
double sum;
double sum_old;
int count;
double pw(double y, double n) {
double i;
double number = 1;
for (i = 0; i < n; i++) {
number *= y;
}
return(number);
}
double fc (double y) {
double i;
double number = 1;
for (i = 1; i <= y; i++){
number *= i;
}
return(number);
}
if(x >= (-1) && x <= 1) {
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
printf("My result is: %.17lf\n",sum);
printf("atan(%f) is: %.17f\n", x, atan(x));
printf("My result minus atan(x) = %.17lf\n", sum - atan(x));
} else {
printf("x is not defined. Please choose an x in the intervall [-1, 1]\n");
}
return 0;
}
It seemingly works fine with every value, except value 1 and -1. If x=1, then the output ends with:
...
7207 || 0.78543285189457468
7208 || 0.78536
Whereas the output should look more like this. In this case x=0.5.
25 || 0.46364760900080587
26 || 0.46364760900080587
My result is: 0.46364760900080587
atan(0.500000) is: 0.46364760900080609
My result minus atan(x) atan(x) = -0.00000000000000022
How can I improve my code so that it can run with x=1 and x=-1.
Thanks in advance.
PS: I use my own created pw() function instead of pow(), because I wanted to bybass the restriction of not using pow() as we didn't had that in our lectures yet.
PPS: I'd appreciate any advice as to how to improve my code.
In each iteration, you add (-1)k • x2k+1 / (2k+1), and you stop when there is no change to the sum.
If this were calculated with ideal arithmetic (exact, infinitely precise arithmetic), it would never stop for non-zero x, since you are always changing the sum. When calculating with fixed-precision arithmetic, it stops when the term is so small it does not change the sum because of the limited precision.
When |x| is less than one by any significant amount, this comes quickly because x2k+1 gets smaller. When |x| is one, the term becomes just 1 / (2k+1), which gets smaller very slowly. Not until k is around 253 would the sum stop changing.
You might consider changing your stopping condition to be when sum has not changed from sum_old very much rather than when it has not changed at all.
if(x >= (-1) && x <= 1) {
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
Comparing doubles can be tricky. The conventional way to compare doubles is to test within epsilon. There should be an epsilon value defined somewhere, but for your purposes how many digits are enough to approximate? If you only need like 3 or 4 digits you can instead have
#define EPSILON 0.0001 //make this however precise you need to approximate.
if(x >= (-1) && x <= 1) {
for(k=0; fabs(sum - sum_old) > EPSILON; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
If the issue is that -1,1 iterate too many times either reduce the precision or increase the step per iteration. I am not sure that is what you're asking though, please clarify.
I think the cause of this is for a mathematical reason rather than a programming one.
Away from the little mistakes and adjustments that you should do to your code, putting x = 1 in the infinite series of arctan, is a boundary condition:
In this series, we add a negative value to a positive value then a negative value. This means the sum will be increasing, decreasing, increasing, ... and this will make some difference each iteration. This difference will be smaller until the preciseness of double won't catch it, so the program will stop and give us the value.
But in the sum equation. When we set z = 1 and n goes from 0 to ∞, this will make this term (-1^n) equal to 1 in one time and -1 in the next iteration. Also,
the value of the z-term will be one and the denominator value when n approaches infinity will = ∞ .
So the sum several iterations will be like +1/∞ -1/∞ +1/∞ -1/∞ ... (where ∞ here represents a big number). That way the series will not reach a specific number. This is because z = 1 is a boundary in this equation. And that is causing infinite iterations in your solution without reaching a number.
If you need to calculate arctan(1) I think you should use this formula:
All formulas are from this Wikipedia article.
Here is some modifications that make your code more compact and has less errors:
#include <stdio.h>
#include <math.h>
#define x 0.5 //here x is much easier to change
double pw(double, double); //declaration of the function should be done
int main() { //the default return type of main is int.
double k;
double sum = 0 ; //you should initiate your variables.
double sum_old = 1 ; //=1 only to pass the for condition first time.
//you don't need to define counter here
if(x < -1 || x > 1){
printf("x is not defined. Please choose an x in the interval [-1, 1]\n");
return 0;
}
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
printf("%.0f || %.17lf\n", k, sum);
}
printf("My result is: %.17lf\n",sum);
printf("atan(%f) is: %.17f\n", x, atan(x));
printf("My result minus atan(x) = %.17lf\n", sum - atan(x));
return 0;
}
double pw(double y, double n) { //functions should be declared out of the main function
double i;
double number = 1;
for (i = 0; i < n; i++) {
number *= y;
}
return(number);
}
double fc (double y) {
double i;
double number = 1;
for (i = 1; i <= y; i++){
number *= i;
}
return(number);
}

For loop with unsigned int

I have a logical problem in my code, maybe it is caused by overflowing but I can't solve this on my own, so I would be thankful if anyone can help me.
In the following piece of code, I have implemented the function taylor_log(), which can count "n" iterations of taylor polynomial. In the void function I am looking for number of iterations (*limit) which is enough to count a logarithm with desired accuracy compared to log function from .
The thing is that sometimes UINT_MAX is not enough iterations to get the desired accuracy and at this point I want to let the user know that the number of needed iterations is higher than UINT_MAX. But my code don't work, for example for x = 1e+280, eps = 623. It just counts, counts and never give result.
TaylorPolynomial
double taylor_log(double x, unsigned int n){
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; i <= n; i++)
{
f_sum *= (x - 1) / x;
sum += f_sum / i;
}
return sum;
}
void guessIt(double x, double eps, unsigned int *limit){
*limit = 10;
double real_log = log(x);
double t_log = taylor_log(x, *limit);
while(myabs(real_log - t_log) > eps)
{
if (*limit == UINT_MAX)
{
*limit = 0;
break;
}
if (*limit >= UINT_MAX/2)
{
*limit = UINT_MAX;
t_log = taylor_log(x, *limit);
}
else
{
*limit = (*limit) *2;
t_log = taylor_log(x, *limit);
}
}
}
EDIT: Ok guys, thanks for your reactions so far. I have changed my code to this:
if (*limit == UINT_MAX-1)
{
*limit = 0;
break;
}
if (*limit >= UINT_MAX/2)
{
*limit = UINT_MAX-1;
t_log = taylor_log(x, *limit);
}
but it still doesn't work correctly, I have set printf to the beggining of taylor_log() function to see the value of "n" and its (..., 671088640, 1342177280, 2684354560, 5, 4, 3, 2, 2, 1, 2013265920, ...). Don't understand it..
This code below assigns the limit to UINT_MAX
if (*limit >= UINT_MAX/2)
{
*limit = UINT_MAX;
t_log = taylor_log(x, *limit);
}
And your for loop is defined like this:
for (unsigned int i = 1; i <= n; i++)
i will ALWAYS be less than or equal to UINT_MAX because there is never going to be a value of i that is greater than UINT_MAX. Because that's the largest value i could ever be. So there is certainly overflow and your loop exit condition is never met. i rolls over to zero and the process repeats indefinitely.
You should change your loop condition to i < n or change your limit to UINT_MAX - 1.
[Edit]
OP coded correctly but must insure a limited range (0.5 < x < 2.0 ?)
Below is a code version that self determines when to stop. Iteration count goes high near x near 0.5 and 2.0. The iteration count needed goes into the millions. Such the alternative coded far below.
double taylor_logA(double x) {
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; ; i++) {
f_sum *= (x - 1) / x;
double sum_before = sum;
sum += f_sum / i;
if (sum_before == sum) {
printf("%d\n", i);
break;
}
}
return sum;
}
Wrongalternative implementation of the series: Ref
Sample alternative - it converges faster.
double taylor_log2(double x, unsigned int n) {
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; i <= n; i++) {
f_sum *= (x - 1) / 1; // / 1 (or remove)
if (i & 1) sum += f_sum / i;
else sum -= f_sum / i; // subtract even terms
}
return sum;
}
A reasonable number of terms will converge as needed.
Alternatively, continue until terms are too small (maybe 50 or so)
double taylor_log3(double x) {
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; ; i++) {
double sum_before = sum;
f_sum *= x - 1;
if (i & 1) sum += f_sum / i;
else sum -= f_sum / i;
if (sum_before == sum) {
printf("%d\n", i);
break;
}
}
return sum;
}
Other improvements possible. example see More efficient series
First, using std::numeric_limits<unsigned int>::max() will make your code more c++-ish than c-ish. Second, you can use the integral type unsigned long long and std::numeric_limits<unsigned long long>::max() for the limit, which is pretty mush the limit for an integral type. If you want a higher limit, you may use long double. floating points also allows you to use infinity with std::numeric_limits<double>::infinity() note that infinity work with double, float and long double.
If neither of these types provide you the precision you need, look at boost::multiprecision
First of all, the Taylor series for the logarithm function only converges for values of 0 < x < 2, so it's quite possible that the eps precision is never hit.
Secondly, are you sure that it loops forever, instead of hitting the *limit >= UINT_MAX/2 after a very long time?
OP is using the series well outside its usable range of 0.5 x < 2.0 with calls like taylor_log(1e280, n)
Even within the range, x values near the limits of 0.5 and 2.0 converge very slowly needing millions+ of iterations. A precise log() will not result. Best to use the 2x range about 1.0.
Create a wrapper function to call the original function in its sweet range of sqrt(2)/2 < x < sqrt(2). Converges, worst case, with about 40 iterations.
#define SQRT_0_5 0.70710678118654752440084436210485
#define LN2 0.69314718055994530941723212145818
// Valid over the range (0...DBL_MAX]
double taylor_logB(double x, unsigned int n) {
int expo;
double signif = frexp(x, &expo);
if (signif < SQRT_0_5) {
signif *= 2;
expo--;
}
double y = taylor_log(signif,n);
y += expo*LN2;
return y;
}

GNU Scientific Library, Power function efficiency

I was going through GSL library. I am pasting the function they used for finding the power of a double number.
double gsl_pow_int(double x, int n)
{
double value = 1.0;
if(n < 0) {
x = 1.0/x;
n = -n;
}
/* repeated squaring method
* returns 0.0^0 = 1.0, so continuous in x
*/
do {
if(n & 1) value *= x; /* for n odd */
n >>= 1;
x *= x;
} while (n);
return value;
}
But wouldn't it be more efficient if they use?
double gsl_pow_int(double x, int n)
{
double value = 1.0;
if(n < 0) {
x = 1.0/x;
n = -n;
}
/* repeated squaring method
* returns 0.0^0 = 1.0, so continuous in x
*/
do{
if(--n)value*=x;
}while(n);
return value;
}
Your code doesn't even properly handle negative powers! How can you claim that your code is optimised.
Also,next,just decreasing space from your program doesn't make your
code more-optimised.Their code has got more readability and more
proper indentation than yours!!! Their code is proper for negative
powers too and much more optimised!
Also,next, bitwise logical operations like & and right shifting >> is considered more efficient than multiplying as what you have done.

Calculate Factorial within a single "for" loop to calculate sum of series

It took me a while conceptual to grasp how to code a loop that would calculate a given series in which a factorial was used.
I coded it--then my teacher told us we had to use a single for loop. I can't seem to grasp how to do something like this. It doesn't make sense how you'd keep the running total of the products across several numbers.
Here is my code; which includes a nested for loop. I really appreciate any and all help.
int main() {
/*init variables*/
int N; //number of terms
float NUMER, DENOM = 1;
float FRAC, sum = 0, x;
/*asks user for value of N*/
printf("Input number of terms: ");
scanf("%i", &N);
/*asks user for value of x*/
printf("Input value of x: ");
scanf("%f", &x);
for (int n = 0; n <= N; n++) {
NUMER = (pow(x, n)); //calculates numerator
for (int fac = 1; fac <= n; fac++) { //calculates factorial using for loop
DENOM = n * fac;
}
if (DENOM <= 0)
printf("\n\nError, dividing by zero.\n\n"); //this is for debugging purposes; disregard
FRAC = NUMER / DENOM; //calculates fraction
sum += FRAC; //running sum of series
}
printf("\nSum of the series is %.1f\n\n", sum); //prints sum of series
return 0;
You want DENOM = n!, so you can just start with DENOM = 1
and update the value inside the loop:
DENOM = 1;
for (int n = 0; n <= N; n++) {
NUMER = (pow(x, n)); //calculates numerator
FRAC = NUMER / DENOM; //calculates fraction
sum += FRAC; //running sum of series
DENOM *= n+1;
}
Instead of computing x^n and n! each time through the outer loop, you can initialize
the quotient to 1.0 before the outer loop, then on each pass through the outer loop,
multiply by x/n to get the next term in the series. This will avoid the need
to call pow(x,n), and use an inner loop to calculate the factorial, each pass through
the outer loop.
If you think about what you would do if calculating a factorial by hand, I think you can figure out how to code this pretty easily.
Lets say you are trying to calculate 11!. Well, you would start at 11, and them multiply by 10. Now you have 110. Now multiply by 9. You have 990. Now multiply by 8...
As you can see, the 11, 10, 9, 8... series is what your for loop is going to be. Just keep your 'current answer' in a variable and keep multiplying it by the number provided by your for loop.
That seems...complicated. Terseness is or can be your friend :D
I don't think it needs to be much more complicated than:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char* argv[] )
{
double limit = 10 ; // how far do we want to go?
double x = 2 ; // some value for X
double xn = 1 ; // by definition, for all X, X^0 is 1
double nf = 1 ; // by convention, 0! is 1
double value = 0 ;
double sum = 0 ;
double n = 0 ;
while ( n < limit )
{
value = xn / nf ; // compute the next element of the series
sum += value ; // add that to the accumulator
xn *= x ; // compute the *next* value for X^n
nf *= (++n) ; // compute the *next* value for N!
}
return 0;
}
You get a more stable answer working the loop in reverse. Many infinite sums numerically come out better summing the smallest terms together first.
f(x,n) = x^0/0! + x^1/1! + x^2/2! + ... + x^n/n!
Let the sum be S(x,n) = x/n
Let the sum of the 2 last terms be S(x,n-1) = x/(n-1) + x/(n-1)*S(x,n)
Let the sum of the 3 last terms be S(x,n-2) = x/(n-2) + x/(n-2)*S(x,n-1)
...
Let the sum of the N last terms be S(x,1) = x/(1) + x/(1)*S(x,1)
double e(double x, unsigned n) {
double sum = 0.0;
while (n > 0) {
sum = x*(1 + sum)/n;
n--;
}
sum += 1.0; // The zero term
return sum;
}
Notice that even if n is large like 1000, and the mathematical answer < DBL_MAX, this loop does not run into floating point overflow so easily.
[edit] But if code must be done in a forward loop, the below calculates each term not as separate products that may overflow, but a unified computation.
double e_forward(double x, unsigned n) {
double sum = 1.0;
double term = 1.0;
for (unsigned i = 1; i <= n; i++) {
term *= x / i;
sum += term;
}
return sum;
}

Resources