2017-07-23 2 views
-1

J'ai une variable, Npart qui est int et initialisée à 64. Ci-dessous mon code (test.c):lldb et le code C donnent des résultats différents pour pow()

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

int Npart, N; 

int main(){ 

Npart = 64; 

N = (int) (pow(Npart/1., (1.0/3.0))); 
printf("%d %d\n",Npart, N); 

return 0; 
}; 

qui imprime 64 3, probablement en raison de problèmes de précision numérique. Je compile comme suit:

gcc -g3 test.c -o test.x 

Si j'essaie de débogage à l'aide lldb, j'essaie de calculer la valeur et l'imprimer dans l'invite de commande, ce qui suit se produit:

$ lldb ./test.x 
(lldb) target create "./test.x" 
Current executable set to './test.x' (x86_64). 
(lldb) breakpoint set --file test.c --line 1 
Breakpoint 1: where = test.x`main + 44 at test.c:8, address = 0x0000000100000f0c 
(lldb) r 
Process 20532 launched: './test.x' (x86_64) 
Process 20532 stopped 
* thread #1: tid = 0x5279e0, 0x0000000100000f0c test.x`main + 44 at test.c:8, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 
frame #0: 0x0000000100000f0c test.x`main + 44 at test.c:8 
    5  
    6 int main(){ 
    7  
-> 8 Npart = 64; 
    9  
    10 N = (int) (pow(Npart/1., (1.0/3.0))); 
    11 printf("%d %d\n",Npart, N); 
(lldb) n 
Process 20532 stopped 
* thread #1: tid = 0x5279e0, 0x0000000100000f12 test.x`main + 50 at test.c:10, queue = 'com.apple.main-thread', stop reason = step over 
frame #0: 0x0000000100000f12 test.x`main + 50 at test.c:10 
    7  
    8 Npart = 64; 
    9  
-> 10 N = (int) (pow(Npart/1., (1.0/3.0))); 
    11 printf("%d %d\n",Npart, N); 
    12 
    13 return 0; 
(lldb) n 
Process 20532 stopped 
* thread #1: tid = 0x5279e0, 0x0000000100000f4a test.x`main + 106 at test.c:11, queue = 'com.apple.main-thread', stop reason = step over 
    frame #0: 0x0000000100000f4a test.x`main + 106 at test.c:11 
    8 Npart = 64; 
    9  
    10 N = (int) (pow(Npart/1., (1.0/3.0))); 
-> 11 printf("%d %d\n",Npart, N); 
    12 
    13 return 0; 
    14 }; 
(lldb) print Npart 
(int) $0 = 64 
(lldb) print (int)(pow(Npart/1.,(1.0/3.0))) 
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available. 
(int) $1 = 0 
(lldb) print (int)(pow(64,1.0/3.0)) 
(int) $2 = 0 

Pourquoi lldb donner des résultats différents?

Modifier: Clarifié la question et fourni un exemple vérifiable minimal.

+0

questions visant à obtenir l'aide de débogage (« pourquoi pas ce code fonctionne? ») Doit comprendre le comportement souhaité, un problème spécifique ou une erreur et le code le plus court nécessaire pour le reproduire dans la question elle-même. Les questions sans énoncé de problème clair ne sont pas utiles aux autres lecteurs. Voir: Comment créer un exemple minimal, complet et vérifiable. – Olaf

+0

@Olaf Veuillez voir la question mise à jour.Merci d'avoir pris le temps d'expliquer la raison de la downvote. – sodiumnitrate

+0

Tout d'abord, vous êtes revêtement de sol 'n' qui serait la chose la moins saine à faire (utiliser round/nearbyint/rint/peu importe) –

Répondre

3

Votre code calcule la racine cubique de 64, qui devrait être 4.

Le code C convertit la valeur de retour à un nombre entier par plancher il. Le pow est généralement implémenté dans une sorte de polynôme de Taylor ou similaire - ceci tend à être inexact numériquement. Le résultat sur votre ordinateur semble être un peu moins de 4,0, qui, lorsqu'il est jeté à int est tronquée - la solution serait d'utiliser par exemple lround premier lieu:

N = lround(pow(Npart/1., (1.0/3.0))); 

Quant au lldb , la clé est le texte:

error: 'pow' has unknown return type; cast the call to its declared return type 

-à-dire qu'il ne sait pas le type de retour - ainsi le prototype - de la fonction. pow est déclarée comme

double pow(double x, double y); 

mais étant donné que le seul indice que lldb a sur le type de retour est la distribution que vous avez fourni, lldb pense que le prototype est

int pow(int x, double y); 

et qui conduira dans un comportement non défini - en pratique, lldb pense que la valeur de retour doit être le int du registre EAX, par conséquent 0 a été imprimé, mais la valeur de retour réelle était dans un certain registre à virgule flottante/SIMD. De même, puisque les types des arguments ne sont pas connus non plus, vous ne devez pas passer dans un int.

donc je suppose que vous obtenez la valeur appropriée dans le débogueur avec

print (double)(pow(64.0, 1.0/3.0)) 
+1

Pour réduire la taille des informations de débogage, la plupart des compilateurs n'émettent que des prototypes de fonctions dans les informations de débogage pour le dylib qui définit la fonction. Vous n'avez pas d'informations de débogage pour libC, donc lldb ne connaîtra pas la signature de pow, comme Antti le signale à juste titre. Mais si vous êtes sur macOS, vous pouvez lancer la commande: 'expr -l objc - @import Darwin' qui va permettre à lldb de construire le module Darwin - y compris toutes les définitions standard de la bibliothèque C, et le charger dans l'analyseur d'expression. Cela fournira à lldb les prototypes pour toutes les fonctions C standard, et vous pourrez les appeler sans lancer. –

+0

@JimIngham pourrait valoir une réponse séparée! Je ne suis pas un utilisateur Mac: / –