Cálculo de fatoriais de números muito grandes!

Olá a todos!

Criei uma aplicação que calcula o fatorial de um inteiro x a partir do método:

[code]public class Fatorial
{
public int fatorial(int x)
{
if (x == 0)
return 1;
else
return x * fatorial(x - 1);
}

}
[/code]

A aplicação também avalia o valor da expressão e = 1 + 1/1! + 1/2! + 1/3! … (n termos), onde n é dado pelo usuário. Abaixo apresentamos o código:

[code]import java.util.Scanner;

/**
*

  • @author Tales R. T. Carneiro
    */
    public class FatorialTeste
    {

    /**

    • @param args the command line arguments
      */
      public static void main(String[] args)
      {
      // TODO code application logic here

      /**

      • Local variables
        */
        int x;
        int result;
        int n;
        int count;
        double e;

      /**

      • Asks for an integer
      • and reads it
        */
        Scanner input = new Scanner(System.in);

      System.out.print("Entre com um inteiro positivo: ");
      x = input.nextInt();

      /**

      • Calculates the fatorial of an integer
      • and prints the result on the screen
        */
        Fatorial f = new Fatorial();
        result = f.fatorial(x);
        System.out.printf(“O fatorial de %d é: %d”, x, result);

      /**

      • Calculates the value of the expression:
      • e = 1 + 1 / 1! + 1 / 2! + 1 / 3! … (n terms)
        */
        System.out.print("Entre com um inteiro n > 0: ");
        n = input.nextInt();

      if (n == 1)
      e = 1;
      else
      {
      count = 1;
      e = 1;
      while (count < n)
      {
      e = e + 1 / (double) f.fatorial(count);
      count++;
      }
      }

      System.out.printf(“e = %.8f”, e);
      }
      }

[/code]

Acontece que quando calculo um fatorial de um inteiro muito grande o valor avaliado pelo java é zero. Ao mesmo tempo quando n muito grande temos e = infinito quando na verdade a série deveria convergir. Ou seja, quando utilizamos números muito elevados o programa produz resultados errados. Por que isso acontece?

[quote=talesc]Olá a todos!

Criei uma aplicação que calcula o fatorial de um inteiro x a partir do método:

[code]public class Fatorial
{
public int fatorial(int x)
{
if (x == 0)
return 1;
else
return x * fatorial(x - 1);
}

}
[/code]

A aplicação também avalia o valor da expressão e = 1 + 1/1! + 1/2! + 1/3! … (n termos), onde n é dado pelo usuário. Abaixo apresentamos o código:

[code]import java.util.Scanner;

/**
*

  • @author Tales R. T. Carneiro
    */
    public class FatorialTeste
    {

    /**

    • @param args the command line arguments
      */
      public static void main(String[] args)
      {
      // TODO code application logic here

      /**

      • Local variables
        */
        int x;
        int result;
        int n;
        int count;
        double e;

      /**

      • Asks for an integer
      • and reads it
        */
        Scanner input = new Scanner(System.in);

      System.out.print("Entre com um inteiro positivo: ");
      x = input.nextInt();

      /**

      • Calculates the fatorial of an integer
      • and prints the result on the screen
        */
        Fatorial f = new Fatorial();
        result = f.fatorial(x);
        System.out.printf(“O fatorial de %d é: %d”, x, result);

      /**

      • Calculates the value of the expression:
      • e = 1 + 1 / 1! + 1 / 2! + 1 / 3! … (n terms)
        */
        System.out.print("Entre com um inteiro n > 0: ");
        n = input.nextInt();

      if (n == 1)
      e = 1;
      else
      {
      count = 1;
      e = 1;
      while (count < n)
      {
      e = e + 1 / (double) f.fatorial(count);
      count++;
      }
      }

      System.out.printf(“e = %.8f”, e);
      }
      }

[/code]

Acontece que quando calculo um fatorial de um inteiro muito grande o valor avaliado pelo java é zero. Ao mesmo tempo quando n muito grande temos e = infinito quando na verdade a série deveria convergir. Ou seja, quando utilizamos números muito elevados o programa produz resultados errados. Por que isso acontece?[/quote]

talesc, eu acho que este tópico aqui te ajuda, valeu!

Ajudou sim! Mas eu queria manter uma classe Fatorial em separado, em outra classe fora daquela com o método main.

não entendi. pq acha que não dá pra fazer isso que quer se utilizar big integer?

Aqui dou duas formas de calcular o número e.
Uma delas é somar os elementos do maior para o menor (ou seja, 1/0! + 1/1! + 1/2! …)
A outra, que é a mais exata, é somar os elementos do menor para o maior (ou seja, 1/24! + 1/23! + 1/22! … + 1/2! + 1/1! + 1/0!)
Tanto na primeira quanto na segunda eu uso a fórmula padrão, mas o cálculo do fatorial é implícito, não explícito. Isso economiza um bocadinho de tempo, já que não preciso ficar recalculando o fatorial para cada termo da expressão que calcula e.

class CalculoE {
    public double calcularE () {
        double soma = 0.0;
        double fator = 1.0;
        for (int n = 1; n <= 24; ++n) {
            soma += fator;
            fator /= n;
        }
        return soma;
    }

    public double calcularE_metodo2() {
        double[] fatores = new double [25];
        double soma = 0.0;
        double fator = 1.0;
        for (int n = 1; n <= 24; ++n) { 
            fatores[n] = 1.0 / fator;
            fator *= n;
        }
        for (int n = 24; n >= 1; n--) {
            soma += fatores [n];
        }
        return soma;
    }


    public static void main (String[] args) {
        CalculoE c = new CalculoE();

        // Valor esperado: 2,7182818284590452353602874713527...
        // Valor impresso: 2.7182818284590455 - note que o último dígito é 5, não 2 (diferença: +3)
        System.out.println (c.calcularE());
        // Valor impresso: 2.7182818284590450 - note que o último dígito é 0, não 2 (diferença: -2) 
        System.out.println (c.calcularE_metodo2());
    }
}

[quote=entanglement]Aqui dou duas formas de calcular o número e.
Uma delas é somar os elementos do maior para o menor (ou seja, 1/0! + 1/1! + 1/2! …)
A outra, que é a mais exata, é somar os elementos do menor para o maior (ou seja, 1/24! + 1/23! + 1/22! … + 1/2! + 1/1! + 1/0!)
Tanto na primeira quanto na segunda eu uso a fórmula padrão, mas o cálculo do fatorial é implícito, não explícito. Isso economiza um bocadinho de tempo, já que não preciso ficar recalculando o fatorial para cada termo da expressão que calcula e.

[code]
class CalculoE {
public double calcularE () {
double soma = 0.0;
double fator = 1.0;
for (int n = 1; n <= 24; ++n) {
soma += fator;
fator /= n;
}
return soma;
}

public double calcularE_metodo2() {
    double[] fatores = new double [25];
    double soma = 0.0;
    double fator = 1.0;
    for (int n = 1; n <= 24; ++n) { 
        fatores[n] = 1.0 / fator;
        fator *= n;
    }
    for (int n = 24; n >= 1; n--) {
        soma += fatores [n];
    }
    return soma;
}


public static void main (String[] args) {
    CalculoE c = new CalculoE();

    // Valor esperado: 2,7182818284590452353602874713527...
    // Valor impresso: 2.7182818284590455 - note que o último dígito é 5, não 2 (diferença: +3)
    System.out.println (c.calcularE());
    // Valor impresso: 2.7182818284590450 - note que o último dígito é 0, não 2 (diferença: -2) 
    System.out.println (c.calcularE_metodo2());
}

}
[/code][/quote]

muito legal!

O estudo das séries de Taylor e MacLaurin são fundamentais para desenvolvimento de programas que trabalham com calculo pesado.

vc viu se essa é a formula conhecida que converge mais rápido?

Com as informações que deram, já dá pra resolver o problema, mas acho que ainda não dá pra entender muito bem porque esse erro ocorre. Se quiser entender porque números muito grandes podem resultar em valores negativos e números muito pequenos podem resultar em zero, recomendo dar uma pesquisada sobre overflow e underflow.

Do jeito que ele calculou o fatorial (acumulando os resultados em um int, e retornando um int) vai dar problemas mesmo.

É que quando o resultado de uma multiplicação de dois ints excede o valor de um int, o resultado é indefinido (pode ser negativo, positivo, zero etc.).

Se a pessoa que fez esse cálculo que “diverge” visse que o valor do fatorial, para n > 12, dá resultados errados do jeito que ele escreveu, veria que na verdade o cálculo é que está sendo feito indevidamente.

A série de Taylor para o cálculo de “e” é muito estável e não “diverge” de forma alguma.

[quote=Luiz Augusto Prado][quote=entanglement]Aqui dou duas formas de calcular o número e.
Uma delas é somar os elementos do maior para o menor (ou seja, 1/0! + 1/1! + 1/2! …)
A outra, que é a mais exata, é somar os elementos do menor para o maior (ou seja, 1/24! + 1/23! + 1/22! … + 1/2! + 1/1! + 1/0!)
Tanto na primeira quanto na segunda eu uso a fórmula padrão, mas o cálculo do fatorial é implícito, não explícito. Isso economiza um bocadinho de tempo, já que não preciso ficar recalculando o fatorial para cada termo da expressão que calcula e.

[code]
class CalculoE {
public double calcularE () {
double soma = 0.0;
double fator = 1.0;
for (int n = 1; n <= 24; ++n) {
soma += fator;
fator /= n;
}
return soma;
}

public double calcularE_metodo2() {
    double[] fatores = new double [25];
    double soma = 0.0;
    double fator = 1.0;
    for (int n = 1; n <= 24; ++n) { 
        fatores[n] = 1.0 / fator;
        fator *= n;
    }
    for (int n = 24; n >= 1; n--) {
        soma += fatores [n];
    }
    return soma;
}


public static void main (String[] args) {
    CalculoE c = new CalculoE();

    // Valor esperado: 2,7182818284590452353602874713527...
    // Valor impresso: 2.7182818284590455 - note que o último dígito é 5, não 2 (diferença: +3)
    System.out.println (c.calcularE());
    // Valor impresso: 2.7182818284590450 - note que o último dígito é 0, não 2 (diferença: -2) 
    System.out.println (c.calcularE_metodo2());
}

}
[/code][/quote]

muito legal!

O estudo das séries de Taylor e MacLaurin são fundamentais para desenvolvimento de programas que trabalham com calculo pesado.

vc viu se essa é a formula conhecida que converge mais rápido?

[/quote]

Show mesmo entanglement! Como o regis_hideki já disse, com essas informações já dá para resolver tranquilo!

vi o tópico sobre matemática e resolvi falar de meu problema sobre fatoração e equação de 1 e 2 grau, está no meu site, com link para download em 4shared.com o site é www.raghy.net23.net está no link JAVA, o programa é o matemática java.

Aliás também coube aqui no anexo, envio para apreciação…
está em andamento (sempre está em andamento) , mas funciona tudo até então.

[quote=raghy]vi o tópico sobre matemática e resolvi falar de meu problema sobre fatoração e equação de 1 e 2 grau, está no meu site, com link para download em 4shared.com o site é www.raghy.net23.net está no link JAVA, o programa é o matemática java.

Aliás também coube aqui no anexo, envio para apreciação…
está em andamento (sempre está em andamento) , mas funciona tudo até então.[/quote]

Show também raghy, valeu!

Experimenta dar uma olhada nos livros abaixo
mas somente nos capítulos que tratam do assunto:

Java Use a Cabeça
Jaca Como Programar

Não sou muito fã de matemática mas tive
uma boa base vendo os capítulos que falam
sobre tamanho de tipos e comparação entre tipos,
estouro/derramamento, dentre outra coisas.

Abraço.