Reputation: 1343
I'm designing a function that will convert a string into a float. e.g. "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.
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;
}
Upvotes: 9
Views: 47977
Reputation: 1
#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;
}
Upvotes: -1
Reputation: 1821
My solution:
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;
}
Test it
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
Btw, in case anyone needs it, here is also my solution to convert a string to an integer:
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;
}
Upvotes: 0
Reputation: 90
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);
}
Upvotes: 0
Reputation: 43
#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;
}
Upvotes: 0
Reputation: 107
This is my solution for atof
function.
#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;
}
Upvotes: 1
Reputation: 127
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
Following is the code:
#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;
}
Upvotes: 0
Reputation: 1051
#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));
}
}
Upvotes: 0
Reputation: 1
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);
}
Upvotes: 0
Reputation: 1278
something like this should do it:
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] != '\0'; 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;
}
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.
Upvotes: 0
Reputation: 14880
Here is my try:
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;
};
Upvotes: 22
Reputation: 37930
One potential issue is that s
is incremented by the outer loop before checking that it isn't pointing to the NULL terminator.
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!
}
You need to exit both the inner and outer loop immediately after the NULL terminator is spotted.
Upvotes: 3