3
\$\begingroup\$

Given a real number a and a natural n, calculate the sum 1 + a + a² + … + aⁿ, without using the formula for the sum of a geometric progression. The running time of the program must be proportional to n.

My solution:

#include <iostream>
using namespace std;

int main()
{
    int s = 1, i, n, m;
    double a;
    cin >> a >> n;
    while (n <= 0)
    {
        cin >> n;
    }
    m = a;
    for (i = 1; i <= n; i++)
    {
        s += m;
        m *= a;
    }
    cout << s << endl;
    return 0;
}

Input data:
Enter 2 numbers - a and n.

Output:
The sum of powers of a: \$\sum_{i=0}^n a^i\$

\$\endgroup\$
5
  • 3
    \$\begingroup\$ If you're experiencing problems, post on StackOverflow. On CodeReview, please include functional code with example inputs and outputs. \$\endgroup\$
    – T145
    Oct 29 at 22:27
  • \$\begingroup\$ Code Review is for working code. Also check variable types. \$\endgroup\$ Oct 30 at 6:57
  • \$\begingroup\$ @Pavlo - what do you think is non-working? This certainly produces the correct output for small numbers. \$\endgroup\$ Oct 30 at 8:31
  • 1
    \$\begingroup\$ @TobySpeight Only for integers, and according to the problem it should work for real numbers. \$\endgroup\$
    – G. Sliepen
    Oct 30 at 10:27
  • 2
    \$\begingroup\$ @G.Sliepen, I didn't test non-integers until I was already most of the way through answering - not sure whether to keep this one open, as it's likely that Jim also tested only with integers and so was unaware of the bug. \$\endgroup\$ Oct 30 at 10:37
3
\$\begingroup\$

Avoid using namespace std;. Although it's unlikely to be a problem in a small program such as this, you're better off developing the good habit of using properly qualified names, only bringing in specific identifiers where necessary, not whole namespaces (excepting namespaces such as std::literals which are designed for it).

We don't need to declare all our variables at the beginning of the function. It's generally better to keep variables' scope to a minimum - e.g. for (int i = 1; …).

When dealing with user input, remember that any invalid input will prevent conversion. The easy way to test for that is to check whether the stream is "bad" after the conversion:

std::cin >> a >> n;
if (!std::cin) {
    std::cerr << "Invalid input values";
    return 1;
}

This next code seems to be asking for valid input, but there's no prompting for a user to understand what's going on:

while (n <= 0)
{
    cin >> n;
}

I don't see why 0 shouldn't be allowed for n. It certainly seems reasonable that we should output 1 in that case. And since negative numbers don't make sense, perhaps n should be an unsigned type?

m = a;
    s += m;

a is a double, but here we're truncating to int. That's probably not what we want (and will give the wrong output for fractional or large values).

Instead of introducing the index variable i that we don't use within the body of the loop, we could use n itself for the index variable, using while and --n.

Avoid std::endl. If you really need to flush after writing \n, it's probably better to use std::flush so it's obviously intentional.

We can use the standard macros EXIT_FAILURE and EXIT_SUCCESS (defined in <cstdlib>) for our return value.


Modified code

Taking the above improvements into account:

#include <cstdlib>
#include <iostream>

int main()
{
    double a;
    unsigned n;
    std::cin >> a >> n;
    if (!std::cin) {
        std::cerr << "Invalid input values";
        return EXIT_FAILURE;
    }

    double s = 1.0;
    double m = 1.0;

    while (n-- > 0) {
        m *= a;
        s += m;
    }

    std::cout << s << '\n';
    return EXIT_SUCCESS;
}

Note

We could have combined the loop body as s += m *= a; - but I think the two separate statements are clearer to readers.

\$\endgroup\$
2
  • \$\begingroup\$ s += m *= a - "Clearer to readers" and would the compiler generate the same output anyway? So there is really zero benefit (other than understanding it can be done and may be useful in other situations?) \$\endgroup\$
    – Greedo
    Oct 30 at 10:10
  • 2
    \$\begingroup\$ Yes, the final binary should be the same (try it over on Compiler Explorer if you're really interested). I only mentioned it to make the point that "clever" code isn't necessarily better than "simple" code. \$\endgroup\$ Oct 30 at 10:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.