2010-07-21 4 views
2

Compte tenu de log (a) et log (b), journal de retour (a + b)Quels sont les avantages du code C suivant?

double log_sum(double log_a, double log_b){ 
    double v; 
    if(log_a < log_b){ 
     v=log_b+log(1+exp(log_a-log_b)); 
    } 
    else{ 
     v=log_a+log(1+exp(log_b-log_a)); 
    } 
    return v; 
} 

Je veux savoir quels sont les avantages de la fonction ci-dessus?

+5

Compile probablement. C'est un avantage. –

+0

Que voulez-vous dire exactement? Voulez-vous dire quel est l'avantage de la déclaration «if»? –

+6

-1 pour être énormément vague. – JWWalker

Répondre

7

L'alternative primaire (force brute) ressemble à:

v = log(exp(log_a) + exp(log_b)); 

qui a trois évaluations de la fonction transcendantale.

Le calcul montré utilise seulement deux fonctions transcendantes - et devrait être plus rapide.

Il peut également être plus stable numériquement.

0

Je suppose que vous demandez pourquoi cette fonction est mieux que de calculer directement log(a+b) en rétablissant a et b, en les sommant et calcul log():

log(exp(log_a) + exp(log_b)) 

Dans ce cas, vous devez calculer l'exposant deux fois, et dans la fonction vous demandez à propos de l'exposant est calculé une seule fois. Puisque l'exposant de calcul prend relativement beaucoup de temps, il pourrait être plus rapide.

2

Si vous voulez dire par opposition à log(exp(log_a) + exp(log_b)), alors l'avantage est assez clair; la façon dont vous mentionnez seulement doit calculer un log et un exp, alors que ce chemin doit calculer deux exps. C'est beaucoup plus coûteux qu'une addition/soustraction/si un test supplémentaire.

2

Pas vraiment une réponse, mais un indice possible.

Les nombres conservés sous forme logarithmique peuvent être multipliés ou divisés en ajoutant ou en soustrayant simplement les nombres. Par exemple, exp(log(a) + log(b)) est identique à a * b. Ou, en utilisant a = 41, b = 101, ce serait exp(3.71357 + 4.61512), qui est exp(8.32869), ou 4140.98930. Évidemment, la précision joue un rôle, et j'ai tronqué les chiffres à 5 chiffres. 41 * 101 est 4141.

Je n'ai pas traité votre exemple de code, et je ne comprends pas non plus pourquoi votre code fait les choses comme il le fait, mais j'espère que ce qui précède vous aidera à le reconstituer.

EDIT: J'ai exécuté quelques nombres à travers votre exemple de code. Si a = 41 et b = 101, et log_a = 3.71357 et log_b = 4.61512, alors votre code d'exemple calcule 4.95582, et exp(4.95582) est égal à 142.0. La façon "la plus simple" d'obtenir ce même résultat est log(exp(log_a) + exp(log_b)), mais comme d'autres l'ont souligné, cette méthode implique trois fonctions transcendantes coûteuses, alors que votre exemple de code n'en nécessite que deux (plus une comparaison triviale).

0

D'autres ont posté de bonnes réponses pour savoir pourquoi faire cela du tout. Je me pose des questions sur la partie if/else. Peu importe si log_a ou log_b est plus grand, les deux expressions pour v doivent être équivalentes à log(a+b). Dans chaque cas 0 < exp(...) <= 1, et log(1+exp(...)) est un petit nombre positif. Pour une raison quelconque, je ne sais pas que cela doit être bon.

5

Les ordinateurs et les journaux ne s'entendent pas toujours. Comme cela a été évoqué par d'autres, la précision devient un réel problème.This blog post explique en grande partie ce phénomène. L'article parle de fonctions de bibliothèque apparemment inutiles, et pourquoi elles sont très pratiques.

La fonction log1p calcule log (1 + x). À quel point cela pourrait-il être difficile à mettre en œuvre?

Il existe toutes sortes de règles folles et de transformations que vous pouvez utiliser lorsque vous traitez des journaux/exponentielles. Ce que je devine, c'est que l'auteur a utilisé certaines de ces règles soit pour rendre le calcul plus précis, plus efficace, ou les deux.

+0

+1, c'est un bon lien. John D. Cook a également écrit de bons articles sur www.codeproject.com. –

0

Si vous demandez à propos de l'if/else, c'est pour éviter la perte de précision. Toutes les opérations arithmétiques sur les nombres à virgule flottante (sauf pour la multiplication par des puissances de 2 et certains cas d'addition/soustraction de nombres du même exposant) détruisent l'information, et un bon code à virgule flottante choisira la méthode avec la moindre perte de précision.

3

D'autres ont déjà mentionné la perte de précision potentielle, mais dans ce cas, le problème est vraiment déborde. Essayez ceci:

double log_a = 100; 
double log_b = 1000; 
printf("%f\n", log_b+log(1+exp(log_a-log_b))); 
printf("%f\n", log_a+log(1+exp(log_b-log_a))); 

Sur une plate-forme typique, le premier imprimera « inf » tandis que le second imprimera « 1000,000000 ».

+0

Oui, cela a du sens. –

Questions connexes