2015-10-03 1 views
1

J'utilise le livre "think java" et je suis bloqué sur l'exercice 7.6. Le but ici est d'écrire une fonction qui peut trouver . Il vous donne un conseils de couple:comment créer une fonction Exp (-x^2)?

Une façon d'évaluer est d'utiliser l'extension de la série infinie:

En d'autres termes, nous devons ajouter une série de termes où les ième terme est égal à

Voici le code que j'ai trouvé, mais il est horriblement faux (comparé à Math.exp) pour autre chose qu'une puissance de 1. Je ne comprends pas pourquoi, autant que je peux dire que le code est correct avec la formule du livre. Je ne suis pas sûr que ce soit plus une question mathématique ou quelque chose en rapport avec la taille d'un nombre double et int, mais j'essaie simplement de comprendre pourquoi cela ne fonctionne pas.

public static void main(String[] args) { 
     System.out.println("Find exp(-x^2)"); 
     double x = inDouble("Enter x: "); 
     System.out.println("myexp(" + -x*x + ") = " + gauss(x, 20)); 
     System.out.println("Math.exp(" + -x*x + ") = " + Math.exp(-x*x)); 
    } 

    public static double gauss(double x, int n) { 
     x = -x*x; 
     System.out.println(x); 
     double exp = 1; 
     double prevnum = 1; 
     int prevdenom = 1; 
     int i = 1; 
     while (i < n) { 
     exp = exp + (prevnum*x)/(prevdenom*i); 
     prevnum = prevnum*x; 
     prevdenom = prevdenom*i; 
     i++; 
     } 
     return exp; 
    } // I can't figure out why this is so inacurate, as far as I can tell the math is accurate to what the book says the formula is 

    public static double inDouble(String string) { 
     Scanner in = new Scanner (System.in); 
     System.out.print(string); 
     return in.nextDouble(); 
    } 
+3

Les entiers de Java n'ont que 32 bits, alors que votre 'prevdenom' veut atteindre 19 !, un nombre de 57 bits. Voyez ce qui arrive quand vous faites 'prevdenom' un double au lieu d'un int. –

+0

Merci! Ça a bien marché! Je suppose que cela a du sens alors que ça ne fonctionnait pas comme un nombre entier parce que le nombre était trop grand. –

+0

Etes-vous autorisé à utiliser machineEpsilon pour les doubles? –

Répondre

1

Je suis sur le point d'ajouter au commentaire sur votre question. Je fais cela parce que j'ai l'impression d'avoir une implémentation légèrement meilleure.

Votre approche

Votre approche est d'avoir la fonction accepte deux arguments, où le second argument est le nombre d'itérations. Ce n'est pas mal, mais comme @JamesKPolk a fait remarquer, vous pourriez avoir à faire des recherches manuelles pour un int (ou long) qui ne sera pas déborder

Mon approche

Mon approche utiliserait quelque chose appelé la machine epsilon pour un type de données. La machine epsilon est le plus petit nombre de ce type (dans votre cas, double) qui est représentable comme ce nombre. Il existe algorithm pour déterminer ce qu'est cette machine epsilon, si vous n'êtes pas "autorisé" à accéder à la machine epsilon dans la classe Double.

Il y a les mathématiques derrière ceci:

La représentation de la série pour votre fonction est series representation of e^(-x^2) Puisqu'il est série en alternance, le terme d'erreur est la valeur absolue du premier terme que vous choisissez de ne pas inclure (je laisse la preuve à toi). Cela signifie que nous pouvons avoir une implémentation basée sur des erreurs qui n'utilise pas les itérations! La meilleure partie est que vous pourriez l'implémenter pour des flottants, et des types de données qui sont "plus" que doubles! Je présente ainsi:

public static double gauss(double x) 
{ 
    x = -x*x; 
    double exp = 0, error = 1, numerator = 1, denominator = 1; 
    double machineEpsilon = 1.0; 
    // calculate machineEpsilon 
    while ((1.0 + 0.5 * machineEpsilon) != 1.0) 
     machineEpsilon = 0.5 * machineEpsilon; 
    int n = 0; // 
    // while the error is large enough to be representable in terms of the current data type 
    while ((error >= machineEpsilon) || (-error <= -machineEpsilon)) 
    { 
     exp += error; 
     // calculate the numerator (it is 1 if we just start, but -x times its past value otherwise) 
     numerator = ((n == 0) ? 1 : -numerator * x); 
     // calculate the denominator (denominator gets multiplied by n) 
     denominator *= (n++); 
     // calculate error 
     error = numerator/denominator; 
    } 
    return exp; 
} 

Faites-moi savoir comment cela fonctionne!

+0

Merci, cela fonctionne! Il m'a fallu du temps pour le comprendre mais ça fait des sens –