5

I'm trying to work out how to write the following:

total = (value * 0.95 ^ 0) + (value * 0.95 ^ 1) + (value * 0.95 ^ 2) ...

or:

x = (y * z ^ 0) + (y * z ^ 1) + (y * z ^ 2) + (y * z ^ 3) ...

This expresses how to calculate x for 4 iterations, but how can I express this to work with a variable number of iterations? Obviously I could create a loop and add the values together, but I'd really like to find a single equation that solves this.

I'm using c++ but I guess this isn't really a language specific problem (sorry I literally don't know where else to ask this question!).

Any ideas?

Thanks, Chris.

ChrisIzatt
  • 53
  • 4
  • use loop to do this – apple apple Nov 17 '16 at 14:17
  • what do you mean with "single equation" ? I mean the equation you wrote is also not complete, but has some `...` in the end and if you think about it, the `...` just stands for "repeat the steps for some index where the index goes from some number to some larger number (for sure not infinity)" and thats a loop. Why dont you want to write a loop? A recursive function would be an alternative – 463035818_is_not_an_ai Nov 17 '16 at 14:18
  • 2
    BTW, a tiny bit of calculus enables you to compute the sum of all integral powers of 0.95; this is not C++ but some basic math. Read about [power series](https://en.wikipedia.org/wiki/Power_series). Ask someone who knows a little bit of math (he does not need to be able to program) – Basile Starynkevitch Nov 17 '16 at 14:23
  • 2
    Why don't you want to use a loop? I think it's useless for programming purposes to look for something complicated when a loop is enough. If you're looking for a formula, this is more a mathematical question than a programming question. – Donald Duck Nov 17 '16 at 14:34
  • Thanks for the replies. I felt that there could be a more elegant way to express this rather than using a loop (as molbdnilo has shown). @Basile Unfortunately the math guy is sick today! – ChrisIzatt Nov 17 '16 at 14:53
  • The `^` operator in C++ isn't a power operator but an exclusive or operator ([see here](https://msdn.microsoft.com/en-us/library/3akey979.aspx)). To do powers in C++, use `std::pow(x, y)` (this function is in `#include `). – Donald Duck Nov 18 '16 at 17:15

8 Answers8

9

There is no need for a loop here, you "just" need to employ some maths.

Note that you can rewrite that as

y * (z0 + z1 + ... + zn)

Now, the series

z0 + z1 + ... + zn

sums to

(z(n+1) - 1) / (z - 1)

so your equation would be

x = y * (z(n+1) - 1) / (z - 1)

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • Perfect! I just needed to add y to that to get the result I was after! Thanks a million! – ChrisIzatt Nov 17 '16 at 14:46
  • I am not an expert in math, but shouldn't the exponent be (n+1) instead of just n? Take a look at wolfram alpha: http://www.wolframalpha.com/input/?i=sum+z%5En+n%3D0+to+m – Andreas H. Nov 21 '16 at 09:28
  • @AndreasH. Indeed it should. I mistakenly took the sum from 1 to n. (When you're over 10k rep, you start getting upvotes for wrong answers ;-) – molbdnilo Nov 21 '16 at 09:41
5

Equation-wise solving, this is a geometric series and can therefore be calculated with

double geometric_series(double y, double z, int N) {
  return y * (std::pow(z, N) - 1.0) / (z - 1.0);
}

but the same result can be obtained with some fun C++ metaprogramming: if you know the number of iterations in advanced and you're allowed to use C++17 features and fold expressions you could do as follows

template<std::size_t... N> 
double calculate_x(double y, double z, std::index_sequence<N...>) { // [0;N[
 auto f = [](double y_p, double z_p, double exp) {
   return y_p * std::pow(z_p, exp);
 };
 return (f(y, z, N) + ...);
}

template <std::size_t N>
auto calculate_x(double y, double z) {
  return calculate_x(y, z, std::make_index_sequence<N>{}); 
}

Alternatively this can also be done with pre-C++17 templates

template <int N>
double calculate_x(double y, double z) {
  return calculate_x<N-1>(y, z) + (y * std::pow(z, N - 1));
}

template <>
double calculate_x<0>(double, double) {
  return 0;
}

Otherwise a simpler solution would be to just use a loop

double calculate_x_simple(double y, double z, int N) {
  double ret = 0.0;
  for (int i = 0 ; i < N ; ++i)
    ret += y * std::pow(z, i);
  return ret;
}

Driver for the code above

int main() {

   // x = (y * z ^ 0) + (y * z ^ 1) + (y * z ^ 2) + (y * z ^ 3)
   double y = 42.0;
   double z = 44.5;
   std::cout << (calculate_x<3>(y, z) == calculate_x_simple(y, z, 3)); // 1

}
Marco A.
  • 43,032
  • 26
  • 132
  • 246
3

If a loop would be the only option:

double x = 0;
int n = 5;
for(int exponent = 0; exponent <= n; ++exponent)
  x += y*pow(z, exponent);
Andreas H.
  • 1,757
  • 12
  • 24
3

As you mentioned, it seems reasonable to use a loop. But if you know the amount of iterations at compile time, you could use templates like this:

template <int n>
double foo(double y, double z)
{
    return foo<n-1>(y, z) + y * std::pow(z, n);
}

template <>
double foo<-1>(double, double)
{
    return 0;
}

With just a little bit of optimisation this will unfold to a single equation.

Example:

#include <iostream>
#include <cmath>

template <int n>
double foo(double y, double z)
{
    return foo<n-1>(y, z) + y * std::pow(z, n);
}

template <>
double foo<-1>(double, double)
{
    return 0;
}


int main()
{
    std::cout << foo<2>(2,3) << std::endl;
}

Output: 26

Jonas
  • 6,915
  • 8
  • 35
  • 53
2

you can just use math.pow function with a for loop

#include <stdio.h>
#include <math.h>

int main(void) {
    int i;
    int n = 5;
    double y = 0.5;
    double z = 0.3;
    double answer = 0;
    for (i = 0  ; i < n ; i++)
        answer += y * pow(z,i);

    printf("%f", answer);
    return 0;
}
cokceken
  • 2,068
  • 11
  • 22
2

Using n as the number of iterations,

#include <cmath>
double foo(double y, double z, int n)
{
   double x =0;
   for(int i = 0 ; i<n; ++i){
      x+=y*std::pow(z,i);
   }
   return x;
}

Where std::pow is the power function.

Jean-Emmanuel
  • 688
  • 8
  • 18
2

It can be expressed as a sum from n=0 to m. It can be expressed in a single formula, according to wolframalpha.

Honza Dejdar
  • 947
  • 7
  • 19
  • Thanks for the link - looks beyond me though! I think I'm going to need to invest some time in math / physics! – ChrisIzatt Nov 17 '16 at 14:48
2

Don't know if this fulfills your purpose, but you can use recursion(which in real terms is a loop only :) )

int x = evaluate(y, z, count);


int evaluate(y,z, count)
{
   if (count <= 0)
    return 0;

   return (evaluate(y, z, count-1) + y*z^count);
}
Dharmendra
  • 384
  • 1
  • 5
  • 22