9
votes

Conversion de la chaîne, à flotter (sans Atof) en C

Je concevons une fonction qui convertira une ficelle en float. par exemple. "45.5" = 45.5

Je l'ai jusqu'à présent. Mais cela ne semble pas fonctionner. Gardez à l'esprit, nous ne pouvons utiliser aucune bibliothèque C de bibliothèque C comme Atoi, ATOF ou même POW pour cette affaire. P>

int str2float( char *s )
{
    int num = 0;
    int dec = 0;
    double i = 1.0;
    int ten = 1;
    /***** ADD YOUR CODE HERE *****/

    for(; *s != '\0'; s++)
    {
        if (*s == '.'){
            for(; *s != '\0'; s++){
                dec = (dec * CONT) + (*s - '0');
                i++;
            }
        }else{
            num = (num * CONT) + (*s - '0');
        }

    }
    for(;i!=0;i--){
        ten *= 10;
    }
    dec = dec / (ten);
    printf("%d", dec);
    num += dec;
    return num;  
}

c

9 commentaires

Je vous suggère de mettre des déclarations Printf () dans chaque étape du calcul, de sorte que vous puissiez voir comment cela progresse. Vous verrez rapidement ce qui se passe mal.


Je me demande pourquoi votre str2float retourne un entier!


Et je vous suggère de passer à travers elle dans le débogueur. Imo c'est encore mieux que printf .


strtod est votre meilleur pari. Vous dites que vous ne pouvez pas utiliser atof , alors ajoutez la tagwork device si je supposais juste :)


N'oubliez pas de gérer des formes de signalisation et exponentielles de pointe; -1.234, +12.34, 1.0E6 Par exemple, il s'agit de formulaires valides traités par les fonctions standard.


Si les devoirs peuvent être effectués au nom des étudiants par REP-HUNTERS SO, quelle valeur est-elle dedans ces jours-ci?


C'est en fait un problème très difficile. Il est facile d'écrire une solution qui fonctionne pour les valeurs proches de 1, mais la gestion extrêmement grande et extrêmement petite est correctement une tâche que des experts ponctuels flottants et des mathématiciens devraient tenter ...


@David Heffernan: Il y a un dicton: plus ils trichent, mieux nous serons payés.


@David, cela ne triche pas. J'avais tenté ce problème pendant plus de 4 heures et je n'allais nulle part. Cela m'a aidé à comprendre le concept et ne me donnez pas seulement la réponse.


11 Réponses :


2
votes

Un problème potentiel est que s code> est incrémenté par la boucle externe avant de vérifier que cela ne pointe pas sur le terminateur NULL.

for(; *s != '\0'; s++)
{
        ...
        for(; *s != '\0'; s++){
        ...
        }
        // inner loop is done now since we have *s=='\0' ...
    ...
    // ... but now we're going to increment s again at the end of the outer loop!
}


0 commentaires

20
votes

Voici mon essai:

float stof(const char* s){
  float rez = 0, fact = 1;
  if (*s == '-'){
    s++;
    fact = -1;
  };
  for (int point_seen = 0; *s; s++){
    if (*s == '.'){
      point_seen = 1; 
      continue;
    };
    int d = *s - '0';
    if (d >= 0 && d <= 9){
      if (point_seen) fact /= 10.0f;
      rez = rez * 10.0f + (float)d;
    };
  };
  return rez * fact;
};


3 commentaires

Merci, ça marche. Je devais faire les endroits décimaux jusqu'à 4 pour qu'il affiche la sortie correcte. Merci encore.


@user quand je l'exécute, la sortie est 24.5 .


Oui tu as raison! Mon erreur, j'avais un VaR temporaire qui était un Int et non un double qui causait la combinaison.



0
votes

Quelque chose comme ça devrait le faire: xxx

Le code pourrait ne pas être très propre et pas nécessairement le meilleur moyen de le faire, mais vous obtenez l'idée. POW (X, Y) retourne x ^ y et nécessite des maths.h et des lants (s) renvoie la taille de s et nécessite string.h.


3 commentaires

désolé je ne peux pas utiliser SHLEN. Aucune fonction de bibliothèque C.


@ user373466: Vous pouvez implémenter votre propre fonction Strlen. C'est une question de 3 lignes .. :)


Ou vous pouvez définir décimalpointLoc initialement à 1000 et sauter SHLEN complètement. EDIT: OOH, il ajoute '0' au lieu de soustraire, alors supposer que cela ne soit pas testé du tout. Les arguments sont également échangés.



0
votes
double Myatof(char str[]){

int len=0, n=0,i=0;
float f=1.0,val=0.0;

//counting length of String
while(str[len])len++;
//cheking for valid string
if(!len)return 0;

//Extracting Integer  part
while(i<len && str[i]!='.')
    n=10*n +(str[i++]-'0');

//checking if only Integer 
if(i==len) return n;
i++;
while(i<len)
{
    f*=0.1;
    val+=f*(str[i++]-'0');
    }
    return(val+n);
}

0 commentaires

0
votes
#define ZERO 48
#define NINE 57
#define MINUS 45
#define DECPNT 46

int strtoint_n(char* str, int n)
{
    int sign = 1;
    int place = 1;
    int ret = 0;

    int i;
    for (i = n-1; i >= 0; i--, place *= 10)
    {
        int c = str[i];
        switch (c)
        {
            case MINUS:
                if (i == 0) sign = -1;
                else return -1;
                break;
            default:
                if (c >= ZERO && c <= NINE) ret += (c - ZERO) * place;
                else return -1;
        }
    }

    return sign * ret;
}

float _float_fraction(char* str, int n)
{
    float place = 0.1f;
    float ret = 0.0f;

    int i;
    for (i = 0; i < n; i++, place /= 10)
    {
        int c = str[i];
        ret += (c - ZERO) * place;
    }
    return ret;
}
float strtoflt(char* str)
{
    int n = 0;
    int sign = 1;
    int d = -1;
    int ret = 0;

    char* temp = str;
    while (*temp != '\0')
    {
        switch (*temp)
        {
            case MINUS:
                if (n == 0) sign = -1;
                else return -1;
                break;
            case DECPNT:
                if (d == -1) d = n;
                else return -1;
                break;
            default:
                if (*temp < ZERO && *temp > NINE) return -1;
        }
        n++;
        temp++;
    }

    if (d == -1)
    {
        return (float)(strtoint_n(str, n));
    }
    else if (d == 0)
    {
        return _float_fraction((str+d+1), (n-d-1));
    }
    else if (sign == -1 && d == 1)
    {
        return (-1)*_float_fraction((str+d+1), (n-d-1));
    }
    else if (sign == -1)
    {
        ret = strtoint_n(str+1, d-1);
        return (-1) * (ret + _float_fraction((str+d+1), (n-d-1)));
    }
    else
    {
        ret = strtoint_n(str, d);
        return ret + _float_fraction((str+d+1), (n-d-1));
    }
}

1 commentaires

Si quelqu'un veut connaître la réponse, il doit accéder à votre blog. De votre blog, vous fournissez un lien vers SkyDrive. De là, vous devez télécharger un fichier zip et l'extraire pour obtenir la solution. N'est-ce pas un peu trop compliqué? Inclure la source dans votre réponse !! Notez que Les réponses de liaison uniquement sont découragées, les réponses doivent donc être le point final d'une recherche pour une solution (contre une autre halte de références, qui tendent à devenir obsolète au fil du temps). Veuillez envisager d'ajouter un synopsis autonome ici, en gardant le lien comme référence.



0
votes

Je pense que ma solution est plus robuste.

N'hésitez pas à contester mon code. Voici le lien: https://github.com/loverszhaokai/demo/blob/master /str_to_float/src/str_to_float.cc

Suivant est le code: xxx


1 commentaires

C'est une mauvaise idée d'accumuler le résultat en double, car chaque fois que vous ajoutez décimal + = (* str - '0') * déc_num , il existe une nouvelle erreur de contournement ajoutée (et des flotteurs binaires sont vraiment pauvres à représenter des pouvoirs négatifs de dix). Si vous conservez des entiers, vous ne diviserez qu'une seule fois et que le résultat sera dans une ULP de la valeur réelle. De plus, STRUP () peut échouer et il s'agit d'une overcilleuse juste à cause de l'espace alimentaire - pourquoi pas seulement garder les pointeurs de début et de fin? Enfin, ".123" est parfaitement valide. En fait, j'ai utilisé cela formant beaucoup à un moment donné.



1
votes

Ceci est ma solution pour Atof code> fonction.

#include<stdio.h>
float my_a2f(char *);

main() {
  char ch[20];
  float i;
  printf("\n enter the number as a string\n");
  scanf("%[^\n]", ch);
  i = my_a2f(ch);
  printf(" string =%s , float =%g \n", ch, i);
}

float my_a2f(char *p) {
  // here i took another two   variables for counting the number of digits in mantissa
  int i, num = 0, num2 = 0, pnt_seen = 0, x = 0, y = 1; 
  float f1, f2, f3;
  for (i = 0; p[i]; i++)
    if (p[i] == '.') {
      pnt_seen = i;
      break;
    }
  for (i = 0; p[i]; i++) {
    if (i < pnt_seen) num = num * 10 + (p[i] - 48);
    else if (i == pnt_seen) continue;
    else {
      num2 = num2 * 10 + (p[i] - 48);
      ++x;
    }
  }
  // it takes 10 if it has 1 digit ,100 if it has 2 digits in mantissa
  for (i = 1; i <= x; i++) 
    y = y * 10;
  f2 = num2 / (float) y;
  f3 = num + f2;
  return f3;
}


3 commentaires

L'exemple de OP "45.5" est proposé avec "float = 45.15" ici. Suggérer une critique.


Merci Chux, oui, si nous comptons le nombre de chiffres en num2 et divisez-le en fonction de cela. Ensuite, cela fonctionnera dans la plupart des cas, je mettrai à jour ma réponse. S'il vous plaît vérifier si cela fonctionne.


Mieux vaut utiliser float num, num2, y pour éviter le débordement. Mieux vaut utiliser '0' que 48 . F1 non utilisé.



0
votes
#include<stdio.h>
#include<string.h>
float myAtoF(char *);
//int myAtoI(char);
void main(int argc,char **argv)
{
float res;
char str[10];
if(argc<2)
{
    printf("Supply a floating point Data\n");
    return;
}
printf("argv[1] = %s\n",argv[1]);
//  strcpy(str,argv[1]);
//  printf("str = %s\n",str);
    res=myAtoF(argv[1]);
    printf("Res = %f\n",res);
   }
float myAtoF(char *str)
{
    printf("str = %s\n",str);
    int i,sum,total,index;
    float res;
    if(!strchr(str,'.'))
    {
        printf("Supply only real Data\n");
        return ;
    }
    i=0;
    while(str[i])
    {
        if(!str[i]>='0'&&str[i]<='9')
        {
            printf("Wrong Data Supplied\n");
            return;    

        }
        if(str[i]=='.')
        { 
            index=i;
            i++;
            continue;

        }
        total=str[i]-48;
        if(i==0)
        {
            sum=total;
            i++;
            continue;
        }
        sum=sum*10+total;
        i++;
    }
    printf("Integer Data : %d\n",sum);
    index=(strlen(str)-1)-index;
    printf("index : %d\n",index);
    res=sum;
    for(i=1;i<=index;i++)
    {
        res=(float)res/10;
    }
    return res;
}

0 commentaires

0
votes
double atof(char* num)
 {
     if (!num || !*num)
         return 0; 
     double integerPart = 0;
     double fractionPart = 0;
     int divisorForFraction = 1;
     int sign = 1;
     bool inFraction = false;
     /*Take care of +/- sign*/
     if (*num == '-')
     {
         ++num;
         sign = -1;
     }
     else if (*num == '+')
     {
         ++num;
     }
     while (*num != '\0')
     {
         if (*num >= '0' && *num <= '9')
         {
             if (inFraction)
             {
                 /*See how are we converting a character to integer*/
                 fractionPart = fractionPart*10 + (*num - '0');
                 divisorForFraction *= 10;
             }
             else
             {
                 integerPart = integerPart*10 + (*num - '0');
             }
         }
         else if (*num == '.')
         {
             if (inFraction)
                 return sign * (integerPart + fractionPart/divisorForFraction);
             else
                 inFraction = true;
         }
         else
         {
             return sign * (integerPart + fractionPart/divisorForFraction);
         }
         ++num;
     }
     return sign * (integerPart + fractionPart/divisorForFraction);
 }

1 commentaires

Tandis que cet extrait de code peut résoudre la question, y compris une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondez à la question des lecteurs à l'avenir, et ces personnes pourraient ne pas connaître les raisons de votre suggestion de code.



0
votes

ma solution: strong> xxx pré>

Testez-le strong> p>

int str2int (const char *str) {
  unsigned char abc;
  int ret = 0;
  for (abc = 1; abc & 1; str++) {
    abc  =  *str == '-' ?
              (abc & 6 ? abc & 6 : (abc & 23) | 20)
            : *str == '+' ?
              (abc & 6 ? abc & 6 : (abc & 7) | 4)
            : *str > 47 && *str < 58 ?
              abc | 10
            : !(abc & 2) && (*str == ' ' || *str == '\t') ?
               (abc & 23) | 1
            :
              abc & 22;
    if (abc & 8) {
      ret = ret * 10 + *str - 48;
    }
  }
  return abc & 16 ? -ret : ret;
}


5 commentaires

Qu'avez-vous gagné en abusant de l'opérateur ternaire? Les plus profonds vont bien, mais les extérieurs sont inutiles et prennent plus de temps à raison de l'équivalent si / sinon chaîne.


L'opérateur ternaire n'est qu'une autre façon d'obtenir le même résultat, avec la même performance et avec une meilleure clarté du code (de cette manière, vous savez que les conditions sont toutes concentrées sur l'attribution d'une valeur à la variable abc , avec un si / ele instruction Vous devez lire tout le bloc pour être sûr de celui-ci). Qu'est-ce que j'aurais gagné sans elle?


Je suppose que nous avons juste différentes idées sur la lisibilité, alors ... Cela ressemble à une personne qui a été écrite par quelqu'un qui vient d'apprendre à utiliser l'opérateur ternaire: p


Eh bien ... Mon code utilise un bitmask, et sans commentaire qui explique comment les drapeaux sont structurés, le code ci-dessus ne peut jamais être vraiment "lisible", je pense, indépendamment de vous écrire le si / sinon chaîne.


Vrai. (Commentaire Rembourrage)



-1
votes
#include <stdio.h>
#include <math.h>
#include<string.h>


double myatof(char *num);
int main(void)
{
    double res;char str[15];

    printf("enter a number in the form of a  string:\n");
    gets(str);
    res=myatof(str);
    printf("Float representation of above number  is %f\n",res);
    return 0;
}

double myatof(char *str)
{
    int i=0;int len1,len2,j;
    float num=0.0;float num1=0.0; float num2=0.0;

    do
    {
        if((str[i++]=='.'))
        {
            len1=i-1;len2=-((strlen(str)-1)-(i-1));

            for(int p=0,q=(len1-1);p<len1,q>=0;p++,q--)
            {
                num1+=((str[p]-'0')*pow(10,q));
            }
            for(int r=len1+1,s=-1;r<strlen(str),s>=len2;r++,s--)
            {
                num2+=((str[r]-'0')*pow(10,s));
            }
        }
    }while(str[i]!='\0');

    num=num1+num2;
    printf("%f\t",num1);
    printf("%f\t",num2);
    return num;
}

1 commentaires

Le code ci-dessus ne fonctionnera pas pour -ve (négatif) numéros