2017-05-07 6 views
0

J'ai un problème avec certaines fonctions intégrées pour C. Fondamentalement, ce que j'essaie de créer est mon propre calculateur oscillateur colpitts qui prend les entrées suivantes dans l'ordre des arguments: valeur Inductor, Valeur du condensateur, valeur du second condensateur.strtoll et division ne retournent pas les nombres corrects

Les entrées peuvent se terminer par F, ou H et peuvent également avoir un préfixe p, m, n et u pour représenter pico, milli, nano et micro. La sortie sera également formatée si le nombre est trop grand et qu'un suffixe lui sera ajouté.

Le problème que j'ai avec mon programme après avoir inséré les instructions de débogage printf est que la conversion de nombre n'est pas correcte.

J'ai utilisé les arguments de test comme suit dans cet ordre:

1p 2pF 3F 

Ceci est ma sortie initiale:

DEBUG Init proc: 1p      
DEBUG post proc: 0.000000    
DEBUG Init proc: 2p      
DEBUG post proc: 0.000000    
DEBUG Init proc: 3      
DEBUG post proc: 3.000000 

Mais les lignes post DEBUG proc sont mal à l'exception du dernier.

Je voulais voir:

DEBUG Init proc: 1p      
DEBUG post proc: 0.000000000001    
DEBUG Init proc: 2p      
DEBUG post proc: 0.000000000002    
DEBUG Init proc: 3      
DEBUG post proc: 3.000000 

Voici mon code:

#include <stdio.h> 
#include <math.h> 
#include <stdlib.h> 
int main(int argc,char* argv[]){ 
    if (argc < 4){ 
printf("Need 3 args: L, C1, C2. %d supplied\n",argc-1);return -1; 
    } 
    long double nums[4],f;long isnum; 
    int n=0; 
    for (n=1;n<4;n++){ 
//process each arg 
char *p=argv[n];while(*p != '\0'){p++;};p--; 
//strip last character if it's F, f, H, or h 
if (*p=='F' || *p=='f' || *p=='H' || *p=='h'){*p='\0';p--;} 
printf("DEBUG Init proc: %s\n",argv[n]); 
switch (*p){ 
    case '0': //do nothing if new last character is a number 
    break; 
    case 'p': //convert picounit to unit 
    *p='\0'; 
    nums[n]=strtoll(argv[n],NULL,10)/1000000000000ULL; 
    break; 
    case 'n': //convert nanounit to unit 
    *p='\0'; 
    nums[n]=strtoll(argv[n],NULL,10)/1000000000ULL; 
    break; 
    case 'u'://convert microunit to unit 
    *p='\0'; 
    nums[n]=strtoll(argv[n],NULL,10)/1000000ULL; 
    break; 
    case 'm'://convert milliunit to unit 
    *p='\0'; 
    nums[n]=strtoll(argv[n],NULL,10)/1000ULL; 
    break; 
    default: //do nothing if new last character is a number from 1 to 9 or print error if it isn't u,m,n or p. 
    isnum=strtol(p,NULL,10); 
    if (isnum < 1 || isnum > 9 || isnum=='\0'){ 
    printf("Number %d is in bad format. Use suffix of either: uH mH nH pH uF mF nF pF\n",n); 
    return -1; 
    } 
    nums[n]=strtoll(argv[n],NULL,10); 
} 
printf("DEBUG post proc: %Lf\n",nums[n]); 
    } 
    printf("Input values: %Lf,%Lf,%Lf\n",nums[1],nums[2],nums[3]); 
    //calculate frequency 
    f=1/(2*3.14159)*sqrt(nums[1]*((nums[2]*nums[3])/(nums[2]+nums[3]))); 
    char suf=' '; //prepare suffix to display frequency in user friendly format 
    if (f > 1000000){f=f/1000000;suf='M';} //convert to Mhz if f > 1000000 
    if (suf=='\0' && f > 1000){f=f/1000;suf='K';} 
    printf("Frequency = %Lf %c hz\n",f,suf); 
    return 0; 
} 

Comme je n'ai un processeur 32 bits pour travailler avec, je sens que mes réponses à ce sont limitées. Que puis-je faire pour corriger ce problème?

+1

Vous effectuez une division entière, d'où le résultat, par ex. 'strtoll (argv [n], NULL, 10)/1000000000000ULL' est (probable) 0 (un int); convertissant cela en double, il restera 0. Divisez par 1000000000000.0 à la place pour forcer la division en virgule flottante. – Evert

+0

Ok, j'ai ajouté .0 à tous les grands nombres et ça n'aide pas. – Mike

+0

Votre code accédera hors des limites si un argument de juste 'F' est donné –

Répondre

2

Tout d'abord - comme mentionné par Evert - vous faites des divisions entières. Écrire nums[n]=strtoll(argv[n],NULL,10)/(1000000000000.0); ou nums[n]=((double)strtoll(argv[n],NULL,10))/1000000000000ULL devrait résoudre ce sujet.

Une fois que vos numéros sont corrects, la sortie est probablement arrondie à la 6e place décimale:

C99 §7.19.6.1 La fonction fprintf, f, F

Un argument double représentant une le nombre à virgule flottante est converti en notation décimale dans le style [−]ddd.ddd, où le nombre de chiffres après le caractère décimal est égal à la spécification de précision. Si la précision est manquante, elle est prise comme 6; ...

Ecrivez printf("DEBUG post proc: %1.15Lf\n",nums[n]) et vous devriez voir les autres.

+0

Cette partie 1,15 fonctionne bien pour moi. – Mike

+1

Dans le cas d'un nombre aussi petit, l'utilisation du formateur 'e' est probablement plus appropriée. – Evert

+0

Tous les deux 'nums [n] = strtoll (argv [n], NULL, 10)/(1000000000000.0); ni nums [n] = ((double) strtoll (argv [n], NULL, 10))/1000000000000ULL ont une courte venue. Le quotient peut être calculé en utilisant le calcul «double», mais le résultat est stocké dans un «long double». Suggérer 'nums [n] = strtoll (argv [n], NULL, 10)/1.0e12L'; – chux