Is there a more efficient way, without a loop for example, to find a the end value for n
for a specific x
?
Yes.
#include <stdio.h>
// Finding the sum of 2^x and all powers of 8 less than 2^x
int main(void) {
const int x = 13 - 1; // OP's `x` is off by 1.
unsigned power2 = 1u << x;
unsigned sum_power8 = 011111111111;
sum_power8 &= power2 - 1;
unsigned n = power2 + sum_power8;
printf("%u\n", n);
}
Ouptut
4681
Thought I'd try @Reinderien simplification.
#include <stdio.h>
#include <inttypes.h>
void foo(int x) {
int n;
for (int c = 0, p = 0; p < x; ++p) {
n = c + (1 << p);
if (p % 3 == 0)
c = n;
}
printf("%2d %12d %o\n", x, n, n);
}
void foo2(int x) {
const uint64_t full = 01111111111111111111111;
const uint64_t n = full & ((1llu << x) - 1);
printf("%2d %12" PRIu64 " %" PRIo64 "\n", x, n, n);
}
int main() {
for (int x = 0; x <= 13; x++) {
foo(x);
}
for (int x = 0; x <= 13; x++) {
foo2(x);
}
}
Yet came up with different results than OP's.
0 10 12
1 1 1
2 3 3
3 5 5
4 9 11
5 25 31
6 41 51
7 73 111
8 201 311
9 329 511
10 585 1111
11 1609 3111
12 2633 5111
13 4681 11111
0 0 0
1 1 1
2 1 1
3 1 1
4 9 11
5 9 11
6 9 11
7 73 111
8 73 111
9 73 111
10 585 1111
11 585 1111
12 585 1111
13 4681 11111
Something is amiss.
int n;
should be int n = 0;
in case loop never iterates. Even if the function is planned to be call only with x >= 1
, good coding practice to avoid troubles of using uninitialized objects.
Candidate fix:
void foo3(int x) {
int n = 0;
int p = (x-1)/3*3;
const uint64_t full = 01111111111111111111111;
n = (int) (full & ((1llu << p) - 1));
int c = n;
// This portion likely can be further simplified.
for (; p < x; p ++) { // Loop 0,1,2 times
n = c + (1 << p);
if (p % 3 == 0)
c = n;
}
printf("%2d %12d %o\n", x, n, n);
}
Output
0 0 0
1 1 1
2 3 3
3 5 5
4 9 11
5 25 31
6 41 51
7 73 111
8 201 311
9 329 511
10 585 1111
11 1609 3111
12 2633 5111
13 4681 11111
[Edit]
Instead of starting with OP's code, consider the goal:
sum of 2^x and all powers of 8 less than 2^x
A direct encoding of that is
void foo4(unsigned x) {
unsigned long long power2 = 1uLL << x;
unsigned long long sum_power8 = 0;
for (unsigned long long power8 = 1; power8 < power2; power8 *= 8) {
sum_power8 += power8;
}
unsigned long long n = power2 + sum_power8;
printf("%2u %12llu %llo\n", x, n, n);
}
With output:
0 1 1
1 3 3
2 5 5
3 9 11
4 25 31
5 41 51
6 73 111
7 201 311
...
This also shows that OP's x
is off-by-one. With x=1
, foo(x)
is 3, not 1.
Simplified code:
void foo5(unsigned x) {
unsigned long long power2 = 1uLL << x;
unsigned long long sum_power8 = 01111111111111111111111;
sum_power8 &= power2 - 1;
unsigned long long n = power2 + sum_power8;
printf("%2u %12llu %llo\n", x, n, n);
}
Pedantically, unsigned long long sum_power8 = 01111111111111111111111;
should be reworked to handle unsigned long long
wider than 64-bit such as
// https://stackoverflow.com/a/4589384/2410359
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
unsigned long long sum_power8 = (ULLONG_MAX/7 >> (IMAX_BITS(ULLONG_MAX)%3))*8 + 1;
c
is tracking the sum of all powers of 8 less thanx
. But you're asking forn
. And you call this a function (ofx
?) but it doesn't take any arguments. \$\endgroup\$x
variable is the input, and the output is stored inn
. Themain
function is just the entry point of a C program. \$\endgroup\$