Since H = 1 + ½ +1/3 + ¼ + ... + 1 / N, make an algorithm to calculate H, where N is entered by the user

5

The program is only printing 1, it's as if it does not store the value of the variable h, can anyone help? Here is the code:

public class MainUmSobreH {
public static void main(String[] args) {
    double h = 0;
    int n = 4;
    for(int i=1; i<=n; i++) {

        h = h + 1/i;

        System.out.println(h);
    }
}
}
    
asked by anonymous 22.03.2018 / 21:34

3 answers

5

Need to convert double when adding / dividing:

public class MainUmSobreH {
    public static void main(String[] args) {
      double h = 0;
      int n = 4;
      for(int i=1; i<=n; i++) {

        h = h + (double)1/i;

        System.out.println(h);
    }
}

This should work correctly.

    
22.03.2018 / 21:42
5

Floating-point numbers are mythological beasts of wandering behavior. Or at least they are so if you do not know how to tame them before using them.

Using floating points, I can add 3 numbers in an order and get a result different than adding those same numbers in another order:

a + b + c =?= c + a + b

I briefly discuss the subject in some answers:

  • in this one , I have to make a sum f(n)*b for several values of n ; one of the strategies I did not put the b in evidence, then the sum was sum = f(1)*b + f(2)*b + f(3)*b , with 3 multiplications and 2 sums, in the other alternative I only multiply at the end of the sum sum = b*(f(1) + f(2) + f(3)) with 2 sums and 1 multiplication; and, no, they are not equivalent sums when taking into account the precision of the floating point
  • in this other answer , I used this fact of loss of precision as a stop condition in an infinite sum, including I show that there are cases where you add a + y == a, y != 0 , therefore (a + y) + y == a , but that there can be a + (y + y) > a

So what would be the way to try to ensure as much accuracy as possible in the sum? Adding from the least significant value to the most significant! Basically change the order of for proposed by @Paulo R. F. Amorim . It is also possible to do this in recursion proposed by @Marcos Andrade with a little more caution.

Solution with iteration

double sum = 0d;
int n = 4
for (int i = n; i >= 1; i--) {
    sum += 1d/i;
}

I am using the notation indicating that the number is a double as proposed by @Isac . Another alternative would be to 1.0/i , which forces the number to be interpreted as double of any sort.

Recursive solution 1

The idea here is to have an interface function that calls the recursive function itself. Let's pass in the recursive function the sum accumulated until then, so we can be adding the smallest elements first to then add the most significant element.

This strategy somewhat resembles some solutions used in when you do not want anyone browsing the database to know that the list to be passed as a third non-intuitive argument must be an empty list.

public static double somaInverso(int n) {
    return somaInversoPrivado(n, 0.0);
}

private static double somaInversoPrivado(int n, double acumulado) {
  if (n == 1) {
    return 1.0 + acumulado;
  }
  return somaInversoPrivado(n-1, 1.0/n + acumulado);
}

Note that here I left the somaInversoPrivado method as a private method to the class that does these calculations. It is an auxiliary function whose API should not be exposed.

Recursive solution 2

Here things happen similarly to each other, but instead of sending the cumulative sum, I send in which step in the recursion I am. I have to stop when I'm at the n step. The idea is that the result of step i is 1.0/i + sum(i+1, n) , this ensures that in the last recursive step the smallest value is returned, which will then be summed with the second smaller value and so on.

public static double somaInverso(int n) {
    return somaInversoPrivado(1, n);
}

private static double somaInversoPrivado(int i, int n) {
  if (n == i) {
    return 1.0/i;
  }
  return 1.0/i + somaInversoPrivado(i + 1, n);
}
    
23.03.2018 / 04:56
4

This algorithm is also a classic example of recursion. I find it interesting to leave here as an alternative way to end the example.

Simplifying the algorithm (without checking for exceptions etc):

package recursividade;

public class Progressao {

    public static void main(String[] args) {
        double inicial = 0;
        int limite = 4;
        double resultado = inicial + CalcularProgressao(limite);
        System.out.println(resultado);
    }

    public static double CalcularProgressao(int limite) {
        if (limite == 1) {
            return 1.0;
        }
        else {
            return 1.0/limite + CalcularProgressao(limite-1);
        }
    }
}

It is important to mention that return uses 1.0 instead of 1, since it is necessary to return a Double.

    
22.03.2018 / 23:03