简体   繁体   中英

Finding sum of x^k from k= 0 to n in O(logn) time

So my question is how to do this in C more specifically. I'm aware that O(logn) usually means that we'll be using recursion by somehow splitting one of the parameters.

What I'm trying to achieve is the sum of k = 0 to n of x n . for example exponent_sum(x, n) would be the parameters in this case.

Then,

exponent_sum(4, 4) would be 4 0 + 4 1 + 4 2 + 4 3 + 4 4 = 341.

I'm not sure where to start. Some hints would be really appreciated.

One way to look at the sum is as a number in base x consisting of all 1s.

For eg, 4 4 + 4 3 + 4 2 + 4 1 + 4 0 is 11111 in base 4.

In any base, a string of 1s is going to be equal to 1 followed by a string of the same number of 0s, minus 1, divided by the base minus 1.

For eg:

  • in base 10: (1000 - 1) / 9 = 999 / 9 = 111
  • in base 16: (0x10000 - 1) / 0xF = 0xFFFF / 0xF = 0x1111
  • in base 8: (0100 - 1) / 7 = 077 / 7 = 011

etc

So put these together and we can generalize that

exponent_sum(x, n) = (x (n + 1) - 1) / (x - 1)

For example, exponent_sum(4, 4) = (4 5 - 1) / 3 = 1023 / 3 = 341

So the big O complexity for it will be the same as for computing x n

Let me add another proof for the sake of completeness:

s = 1 + x 1 + x 2 + ... + x n

Then

xs = x(1 + x 1 + x 2 + ... + x n ) = x 1 + x 2 + ... + x n + x n+1 = s - 1 + x n+1

Solving for s

(x - 1)s = x n+1 - 1,

s = (x n+1 - 1)/(x - 1)

Another way to see the solution is like this: suppose the sum is S written as

S = 1 + x + x^2 + ... + x^k

Then if we multiply both sides of it by x we get

S*x = x * (1 + x + x^2 + ... + x^k)
    = x + x^2 + ... + x^k + x^(k+1)

then add 1 to both sides

S*x + 1 = 1 + x + x^2 + ... + x^k + x^(k+1)
        = (1 + x + x^2 + ... + x^k) + x^(k+1)
        = S + x^(k+1)

which means

S*x - S = x^(k+1) - 1
S*(x - 1) = x^(k+1) - 1

so

S = (x^(k+1) - 1) / (x - 1)

Use the theory Of geometric progression. where

sum = (first-term(pow(common-ratio,number-of-terms)-1))/(common-ratio-1);
here first-term is obviously 1;
Common-ratio= number itself;
number-of-terms=number+1;

But common-ratio should be greater than 1; For

Common-ratio=1;
Sum=number*number-of-terms.

You can evaluate the sum directly, without using the geometric progression formula. This has the advantage that no division is required (which is necessary if, for example, you want to adapt the code to return the result modulo some large number).

Letting S(k) to be the sum x^0 + ... + x^{k-1}, it satisfies these recurrence relations:

S(1)    = 1
S(2n)   = S(n) * (1 + x^n)
S(2n+1) = S(n) * (1 + x^n) + x^{2n}

Using these, the only difficulty is arranging to keep a running value of xp to use as x^n. Otherwise the algorithm is very similar to a bottom-up implementation of exponentiation by squaring.

#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>

int64_t exponent_sum(int64_t x, int64_t k) {
    int64_t r = 0, xp = 1;
    for (int i = 63; i >= 0; i--) {
        r *= 1 + xp;
        xp *= xp;
        if (((k + 1) >> i) & 1) {
            r += xp;
            xp *= x;
        }
    }
    return r;
}

int main(int argc, char *argv[]) {
    for (int k = 0; k < 10; k++) {
        printf("4^0 + 4^1 + ... + 4^%d = %" PRId64 "\n", k, exponent_sum(4, k));
    }
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM