0

I am beginner in programming and I'm learning a c++ language.

I have to create a program, that firstly load a amount of numbers and after this load numbers. I need to obtain a result that adds number one by one if they are not power of 2, else I need to subtract this number.

For example: for 3, result is = -1 - 2 + 3 = 0 (1 and 2 are powers of 2) for 4, result is = -1 - 2 + 3 - 4 = -4

It sounds that it's not problem, but the max value, that program must convert into result is 1 000 000 000. And it must give a result in 3 seconds.

I am pasting my code below. Please, help me make this with ability of converting huge numbers in short time.

#include <iostream>

using namespace std;

int main()
{
    long long amount, number, i = 0, a, b, result = 0;

    cin >> amount;

    while (i < amount) {
        cin >> number;

        if (number < 100000000) {
            a = 1;
            result = 0;
        } else if (100000000 <= number) {
            a = 100000001;
            result = 4999999791564546;
        }

        while (a <= number) {
            b = a;

            while (b % 2 == 0 && b > 1) {
                b = b / 2;
            }

            if (b == 1) {
                result = result - a;
            } else {
                result = result + a;
            }

            a++;
        }

        cout << result << endl;
        i++;
    }
}
Sean Bright
  • 118,630
  • 17
  • 138
  • 146
  • 2
    Welcome to Stack Overflow! If you want help improving working code you should post this on [CodeReview.SE](https://codereview.stackexchange.com/help/how-to-ask). If you do decide to do so please delete the question here. – NathanOliver Oct 10 '19 at 16:14
  • 3
    I'm voting to close this question as off-topic because it is asking for help optimizing working code, and therefore should be posted on [codereview.se] instead, which was designed specifically for that purpose. – Ken White Oct 10 '19 at 16:16
  • 2
    Or at least change title to something what will describe what program does. If this is online problem (like SPOJ, hakerrank, ...), please provide link to the problem description. Your description is a bit fuzzy. – Marek R Oct 10 '19 at 16:17
  • Did you compile with compiler optimizations *enabled* (aka a "release" build)? If not, do that as the first thing. Unoptimized C++ code (debug builds) is often (very) slow (but easy to debug, and what your compiler probably generates by default). To get speed, you need to enable the optimizer. – Jesper Juhl Oct 10 '19 at 16:20
  • Possible duplicate of [What's the simplest way to test whether a number is a power of 2 in C++?](https://stackoverflow.com/questions/108318/whats-the-simplest-way-to-test-whether-a-number-is-a-power-of-2-in-c) – Marek R Oct 10 '19 at 16:35
  • You may be able to get some performance improvement by using `b = b >> 1;` (right shift) instead of `b = b / 2`. A right shift takes less processing power than division. Your compiler may be able to make the optimizations. – Thomas Matthews Oct 10 '19 at 16:35
  • Another optimization is to use `b & 1` instead of `b % 2`. The `b % 2` requires division; the other is a bit test. The bit test is often faster than division. Your compiler may perform this optimization depending on the optimization level. – Thomas Matthews Oct 10 '19 at 16:37
  • 2
    Hint: your values are equal to ` - 2 * `. The first sum is known (see Gauss), the second one is just ` - 1`. Putting it all together and with a dash of GCC intrinsics to optimize the log2, you can calculate each value in a handful of multiplications and additions. – Quentin Oct 10 '19 at 16:45
  • @Quentin yes he provided example of consecutive values, but in description and code sample: values to be sum up are read from stdin, so they are not sequence of consecutive values. – Marek R Oct 11 '19 at 09:18
  • 1
    @MarekR that's for calculating a single value. – Quentin Oct 11 '19 at 09:23
  • @Quentin I added a piece of code using your proposed solution. Thank you. – A M Oct 11 '19 at 13:32

1 Answers1

1

All credits go to Quentin. I developed the same idea, but Quentin mentioned first, so all credits go to him.

In all this competetive programming challenges, where you see big numbers and a time limit, "brute force" or "looping over everything" will most certainly not give the desired result.

A good algorithm is always the better solution.

So looking at the task, we need to add all values except some. That means, the first step to the solution is to add all values and then to subtract the "some unwanted" values (the powers of 2). The intermediate result is a sum of all the "wanted" values.

All unwanted values (the powers of 2) need also to be added.

The final result is the intermediate result minus the sum of the powers of 2. Or, as stated in the task description in obfuscated words: "Sum of all values" - "sum of powers of 2" - "sum of powers of 2".

So, as step 1, we need to calculate the sum of all values. This is a well known algorithm. You can find everywhere. Short illustration for value 6:

123456
654321
------
777777

So, we write in one line the sequence of the values and in the next line the reversed sequence. Last line sums the single digts. And, we will easily see the pattern: n * (n+1) / 2

The sum of the powers of 2 is similar simple. In the binary number system, a power of 2 is a value with exactly one set bit:

 1 = 0001
 2 = 0010
 4 = 0100
 8 = 1000
---------
Sum: 1111

The sum is a value with all bits set. With some simple bit fiddling, we can easily find the solution.

Please see a complete working solution below. Please note: It will be extremely fast and the input value will nearly have no influence on the computing time.

#include <iostream>
#include <algorithm>

constexpr unsigned long MaxSource = 1000000000UL;

int main()
{
    // Get the Base value from the user
    std::cout << "Enter a number (1..1000000000):\n";

    unsigned long sourceNumber {0};
    std::cin >> sourceNumber;

    // Limit input value
    sourceNumber = std::clamp (sourceNumber, 1UL, MaxSource);

    // calculate the sum of all values in the range 1..sourceNumber
    const long long t1 {static_cast<long long>(sourceNumber)};
    const long long t2 {t1+1};
    const long long sum1 { (t1 * t2) >> 1 };

    // Now calculate the sum of all powers of 2
    long long sum2 {0x00000000'FFFFFFFF};
    long long bitTestMask {0x00000000'80000000};

    // find the highest set bit
    while (0 == (t1 & bitTestMask)) {
        bitTestMask = bitTestMask >> 1;
        sum2 = sum2  >> 1;
    }

    std::cout << "Result:  " << sum1 - sum2 - sum2 << "\n";

    return 0;
}

I omitted the the typical competetive programmin multiple test case stuff.

What a pity that nobody will read this . . .

A M
  • 14,694
  • 5
  • 19
  • 44
  • Nice breakdown! For the record, [here](https://wandbox.org/permlink/XufUnDnNjTsVQR5X) is my implementation :) – Quentin Oct 11 '19 at 14:28