Преобразование строки, чтобы плавать (без atof) в C - PullRequest
9 голосов
/ 09 декабря 2010

Я разрабатываю функцию, которая преобразует строку в число с плавающей точкой. например "45,5" = 45,5

Пока у меня есть это. Но это не похоже на работу. Имейте в виду, что мы не можем использовать никакие функции библиотеки C, такие как atoi, atof или даже pow в этом отношении.

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;  
}

Ответы [ 11 ]

15 голосов
/ 09 декабря 2010

Вот моя попытка:

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;
};
2 голосов
/ 09 декабря 2010

Одна потенциальная проблема заключается в том, что s увеличивается внешним циклом перед проверкой того, что он не указывает на нулевой терминатор.

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!
}

Вам необходимо выйти как из внутреннего, так и из внешнего цикла сразу же после обнаружения терминатора NULL.

1 голос
/ 09 августа 2016

Это мое решение для функции atof.

#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;
}
0 голосов
/ 12 марта 2018
#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;
}
0 голосов
/ 02 октября 2017

Мое решение:

float str2float (const char * str) {
  unsigned char abc;
  float ret = 0, fac = 1;
  for (abc = 9; abc & 1; str++) {
    abc  =  *str == '-' ?
              (abc & 6 ? abc & 14 : (abc & 47) | 36)
            : *str == '+' ?
              (abc & 6 ? abc & 14 : (abc & 15) | 4)
            : *str > 47 && *str < 58 ?
              abc | 18
            : (abc & 8) && *str == '.' ?
              (abc & 39) | 2
            : !(abc & 2) && (*str == ' ' || *str == '\t') ?
              (abc & 47) | 1
            :
              abc & 46;
    if (abc & 16) {
      ret = abc & 8 ? *str - 48 + ret * 10 : (*str - 48) / (fac *= 10) + ret;
    }
  }
  return abc & 32 ? -ret : ret;
}

Проверьте это

printf("%f\n", str2float("234.3432435543")); // 234.343246
printf("%f\n", str2float("+234.3432435543")); // 234.343246
printf("%f\n", str2float("-234.3432435543")); // -234.343246
printf("%f\n", str2float("   +  234.3432435543")); // 234.343246
printf("%f\n", str2float(".5")); // 0.500000
printf("%f\n", str2float("- .5")); // -0.500000

Кстати, в случае, если это кому-нибудь понадобится, вот мое решение для преобразования строки в целое число :

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;
}
0 голосов
/ 11 января 2017
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);
 }
0 голосов
/ 07 сентября 2016
#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 голосов
/ 10 сентября 2015

Я думаю, что мое решение является более надежным.

Не стесняйтесь оспаривать мой код.Вот ссылка: https://github.com/loverszhaokai/Demo/blob/master/str_to_float/src/str_to_float.cc

Ниже приведен код:

#include <climits>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

int last_err_code = 0;
// last_err_code = 0 when there is no error
//
// last_err_code = 1 when there is invalid characters, the valid characters
//                   are 0~9, '.', '+-'
//
// last_err_code = 2 when there is no integer before '.' or there is no integer
//                   after '.'
//                   e.g. ".123", "123.", "."
//
// last_err_code = 3 when there is more than one '.'
//                   e.g. "123..456", "123.4.56"
//
// last_err_code = 4 when the integer is bigger than FLOAT_MAX
//                   e.g. "1111111111111111111111111111111111111.23"
//

// Clear the left and right whitespace
// e.g. "  123 456  " -> "123 456"
char *trim(char *str)
{
    while (*str == ' ' || *str == '\t')
        str++;

    char *start = str;

    if (!(*str))
        return str;

    char *end = str;

    while (*str) {
        if (*str != ' ' && *str != '\t')
            end = str;
        str++;
    }

    *(end + 1) = 0;

    return start;
}

// String to Float
float str_to_float(const char *pstr)
{
    char *pstr_copy, *str;
    // The sign of float, set -1 when the first character is '-'
    int sign = 1;
    // The value of integers
    long long integer = 0;
    // The value of decimals
    double decimal = 0;
    // The multiple of next decimal
    double dec_num = 0.1;
    // Has found dot '.'
    bool has_dot = 0;
    // Has integer
    bool has_integer = 0;

    if (pstr == NULL)
        return 0;

    pstr_copy = strdup(pstr);
    str = trim(pstr_copy);

    if (!(*str)) {
        // "   "
        return 0;
    }

    if (*str == '+' || *str == '-') {
        if (*str == '-')
            sign = -1;
        str++;
    }

    while (*str) {

        if (*str >= '0' && *str <= '9') {

            if (!has_dot) {
                // "123"
                if (!has_integer)
                    has_integer = 1;

                integer *= 10;
                integer += *str - '0';

                if (integer > (long long)INT_MAX) {
                    // e.g. "111111111111111111111111111111111.22"
                    last_err_code = 4;
                    return 0;
                }

            } else if (!has_integer) {
                // ".123"
                last_err_code = 2;
                return 0;
            } else {
                // "123.456"
                if (dec_num < (double)1e-10) {
                    // There are too many decimals, ignore the following decimals
                } else {
                    decimal += (*str - '0') * dec_num;
                    dec_num *= 0.1;
                }
            }

        } else if (*str == '.') {

            if (has_dot) {
                // e.g. "123...456"
                last_err_code = 3;
                return 0;
            }
            has_dot = 1;

        } else {
            // e.g. "123fgh?.456"
            last_err_code = 1;
            return 0;
        }

        str++;
    }

    if (has_dot && (!has_integer || dec_num == 0.1)) {
        // e.g. ".123" or "123." or "."
        last_err_code = 2;
        return 0;
    }

    free(pstr_copy);

    float ret = (float) integer + (float)decimal;
    return ret * sign;
}

int main()
{
    const struct TestCase {
        const char *str;
        const float ret;
        int last_err_code;
    } test_cases[] = {
        // last_err_code != 0
        { "abc", 0, 1 },
        { "123+.456", 0, 1 },
        { "++123.456", 0, 1 },

        { ".", 0, 2 },
        { ".123", 0, 2 },
        { "123.", 0, 2 },

        { "123..456", 0, 3 },
        { "123.4.56", 0, 3 },

        // Case #8:
        { "1111111111111111111111111111111.456", 0, 4 },

        // last_err_code == 0
        { "", 0, 0 },
        { "123.456", 123.456, 0 },
        // There are too many decimals
        { "1.12345678901234567890", 1.12345678, 0 },
    };

    int errors = 0;

    for (int iii = 0; iii < sizeof(test_cases) / sizeof(TestCase); iii++) {
        const TestCase &tc = test_cases[iii];
        // Clear last_err_code
        last_err_code = 0;
        const float actual_ret = str_to_float(tc.str);

        if (tc.ret != actual_ret || last_err_code != tc.last_err_code) {

            errors++;

            cout << "Case #" << iii << ": FAILED" <<  endl;
            cout << "\tExpected ret=" << tc.ret << endl;
            cout << "\tAcutal   ret=" << actual_ret << endl;
            cout << "\tExpected last_err_code=" << tc.last_err_code << endl;
            cout << "\tAcutal   last_err_code=" << last_err_code << endl;
        }
    }

    if (errors == 0)
        cout << "All test passed!" << endl;
    else
        cout << "There are " << errors << " cases failed." << endl;

    return 0;
}
0 голосов
/ 12 сентября 2013
#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));
    }
}
0 голосов
/ 25 марта 2013
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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...