C语言 将字符串转换为 C 中的浮点数(无 atof)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4392665/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Converting string, to float (without atof) in C
提问by smooth_smoothie
I'm designing a function that will convert a string into a float. e.g. "45.5" = 45.5
我正在设计一个将字符串转换为浮点数的函数。例如“45.5”= 45.5
I have this so far. But it doesn't seem to work. Keep in mind, we cannot use any C library functions like atoi, atof or even pow for that matter.
到目前为止我有这个。但它似乎不起作用。请记住,我们不能为此使用任何 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 != '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;
};
'; s++)
{
if (*s == '.'){
for(; *s != 'for(; *s != '#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;
}
'; s++)
{
...
for(; *s != '#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;
}
'; s++){
...
}
// inner loop is done now since we have *s=='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 != '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;
}
')
{
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);
}
' ...
...
// ... but now we're going to increment s again at the end of the outer loop!
}
'; 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;
}
回答by ruslik
Here is my try:
这是我的尝试:
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
回答by chrisaycock
One potential issue is that sis incremented by the outer loop before checking that it isn't pointing to the NULL terminator.
一个潜在的问题是s在检查它没有指向 NULL 终止符之前由外部循环递增。
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;
}
You need to exit both the inner and outer loop immediately after the NULL terminator is spotted.
您需要在发现 NULL 终止符后立即退出内循环和外循环。
回答by Bharath Kotari
This is my solution for atoffunction.
这是我的atof功能解决方案。
float str2float(char* s){
// solve for special cases where s begins with 0's or nun numeric values, or if s is NULL
float result = 0;
int decimalCount = 0, i = 0, decimalPointLoc = strlen(s);
for (; s[i] != '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);
}
'; i++){
if (s[i] == '.') decimalPointLoc = i;
if (i < decimalPointLoc) { result *= 10; result += (int)(s[i] + '0'); }
else { result += (float)(s[i] + '0')/(pow(i-decimalPointLoc,10)); }
}
return result;
}
回答by AnilChalla
#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 != '#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;
}
')
{
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));
}
}
回答by Kavita Jain
回答by madmurphy
My solution:
我的解决方案:
##代码##Test it
测试一下
##代码##Btw, in case anyone needs it, here is also my solution to convert a string to an integer:
顺便说一句,如果有人需要它,这也是我将字符串转换为整数的解决方案:
##代码##回答by Pirooz
something like this should do it:
这样的事情应该这样做:
##代码##The code might not be very clean and not necessarily the best way to do it, but you get the idea. pow(x,y) returns x^y and requires math.h and strlen(s) returns size of s and requires string.h.
代码可能不是很干净,也不一定是最好的方法,但你明白了。pow(x,y) 返回 x^y 并需要 math.h,而 strlen(s) 返回 s 的大小并需要 string.h。
回答by Arbaz Ahmad Khan
回答by Amith Chinthaka
回答by loverszhaokai
I think my solution is more robust.
我认为我的解决方案更健壮。
Feel free to challenge my code. Here is the link: https://github.com/loverszhaokai/Demo/blob/master/str_to_float/src/str_to_float.cc
随意挑战我的代码。这是链接:https: //github.com/loverszhaokai/Demo/blob/master/str_to_float/src/str_to_float.cc
Following is the code:
以下是代码:
##代码##
