1

I need to know how to convert a user input, which is a string, to a double. like if he writes in the string "23.45", it converts into double 23.45 (without any library functions).

I already got this code for integer, but don't know how to continue with double:

#include <stdio.h>

void main()
{
    char input[100];
    printf("Type a String which will be converted to an Integer: ");
    scanf("%s", input);

    int number = 0;
    int i = 0;

    if (input[i] >= 48 && input[i] <= 57)
    {
        while (input[i] >= '0' && input[i] <= '9')
        {
            number = number * 10;
            number = number + input[i] - '0';
            i++;
        }
        printf("string %s -> number %d \n", input, number);
    }
    else
    {
        printf("Enter a number! \n");
    }
}
9
  • 1
    Why did you use the ascii value in the if and the char literals in the while? Commented Jan 18, 2016 at 15:24
  • Change your code to handle the decimal point. Other than that you're largely there. Best of luck. Commented Jan 18, 2016 at 15:30
  • 1
    Does code need to handle 1) exponents 2) overflow 3) underflow 4) Infinities 5) Not-a-numbers 5) -0.0 6) what precision level? Voting to close as too broad. Commented Jan 18, 2016 at 15:33
  • 2
    @DeathToxic:This is the second time I see you asking how to do something "without any library functions". Is this homework? A job assignment? (Either way somebody is wasting your time.) Is this an attempt to learn how the standard library works? Commented Jan 18, 2016 at 15:40
  • 1
    @BobJarvis: So int main() { puts( "23.45" ); } would satisfy, as it passes the stated test case? ;-) Commented Jan 18, 2016 at 15:43

4 Answers 4

1

There's probably no reason why you'd roll out your own version of this, as strtod in stdlib.h already covers all manner of formats.

Here's a version which covers signed numbers as input and has some hints of where more suitable error handling could be placed:

#include <stdbool.h>

static void halt_and_catch_fire (void);

double strtod_homebrewn (const char* str)
{
  double result = 0;

  // handle signs:  
  bool is_negative = false;
  if(*str == '-')
  {
    is_negative = true;
    str++;
  }
  else if(*str == '+')
  {
    str++;
  }

  // handle the dot position:
  bool is_dot_found = false;
  double multiplier = 0.1;

  // the actual conversion:
  for(const char* s=str; *s!='\0'; s++)
  {
    if(*s >= '0' && *s <= '9') // ctype.h isdigit() would be preferred here
    {
      if(is_dot_found)
      {
        result += (*s - '0') * multiplier;
        multiplier /= 10;
      }
      else
      {
        result *= 10;
        result += *s - '0';
      }
    }
    else if(*s == '.')
    {
      if(is_dot_found) // two dots?
      {
        halt_and_catch_fire(); // replace this with error handling
      }

      is_dot_found = true;
    }
    else if(*s != '\0') // all cases tested, some weird unknown character found
    {
      halt_and_catch_fire(); // replace this with error handling
    }
  }


  if(is_negative)
  {
    result = -result;
  }

  return result;
}

static void halt_and_catch_fire (void)
{
  halt_and_catch_fire();
}
Sign up to request clarification or add additional context in comments.

2 Comments

Similar issues as commented here
@chux Yup... to write a fully functional strtod you'd need quite a bit more effort than the above. It also handles different base than decimal etc.
0
#include <stdio.h>

void main()
{
    char input[100];
    printf("Type a String which will be converted to a double: ");
    scanf("%s", input);

    double number = 0.0;
    double divider = 1.0;
    int inFraction = 0;
    int i = 0;

    if (input[i] >= 48 && input[i] <= 57)
    {
        inFraction = 0;
        while ((input[i] >= '0' && input[i] <= '9') || input[i] == '.')
        {
            if (input[i] == '.')
            {
                i++;
                inFraction = 1;
                continue;
            }

            number = number * 10.0;
            number = number + input[i] - '0';
            i++;

            if (inFraction) divider *= 10.0;
        }

        number /= divider;

        printf("string %s -> number %g \n", input, number);
    }
    else
    {
        printf("Enter a number! \n");
    }
}

1 Comment

Note: Not too bad, yet reports 0.0 for very small input that overflow divider. Unnecessarily loses some precision with strings with many digits like "1152921504606846976" (2**60)
0

Edit: As clux pointed out, this fails when the fraction starts with zeroes. Bummer. Anyway, perhaps someone conceives a simple fix? I can only think of adding a "readzeroes()" function and let that run after the dot.

You already have a function to read an int. Simply use that. Pseudo code:

float read_float()
{
    float f = read_int()
    if(next is dot) skipdot else return f;
    float frac = read_int() 
    while (frac>1) frac /= 10
    return f+frac;
}

1 Comment

Nice idea using read_int(), but fails when frac was made by input like ".000123".
0

Edit: only use this approach for small number of digits after the decimal point. Read the comments to know why it would fail for a large number of digits.

Since you mentioned without using any library functions, you could do something like this.

float number;
int decimal = 0;
int decimal_found =10;
while(input[i]!='\0')
{
    if((input[i] <='0' || input[i] >='9')&&input[i]!='.' )
    break;

    if(input[i] == '.')
    decimal = 1;

    if(decimal == 1)
    {
        number = number + (input[i] - '0')/decimal_found;
        decimal_found = decimal_found*10;
    }
    else
    {
        number =  number *10;
        number = number + input[i] - '0';
    }
    i++;
}

Simply check a decimal variable to know when decimal has been reached, then use and if else to have separate conditions for the number variable

10 Comments

This code fails for an input like 23asdadada.45, apart from that the check of decimal == true is unnecessary, and bools for C are not standard.
This works on numbers with few enough decimal places, but the technique of adding an appropriate number of tenths, then an appropriate number of hundredths, thousandths, and so on is likely to lead to inaccuracy, I believe.
There are techniques to avoid that. A primary technique is to collect the tailing digits as an integer (count the digits, including the leading zeros; they matter in this context), then divide the accumulated integer by the appropriate power of ten. However, even that is not perfect. There are whole articles and probably even books on the subject — full treatment is very long.
@fpg1503: True. The current standard is C11; we should be assuming C11, not just C99. The only problem is the severely retrograde Microsoft compiler which only partially supports some of C99 and/or C11 in the most recent versions. But, in the absence of information to the contrary, assuming C11 is reasonable, and at least C99 is perfectly reasonable, and your statement that "there is no bool in C" is erroneous — there is bool in standard C (and has been for a decade and a half and some time to spare).
@fpg1503: And I'm stating that your headline assertion is incorrect (bool is a part of C). If your comment had said "not part of C90" or "not supported by Microsoft C" or some other such qualification, I wouldn't have needed to say anything. As it is, your headline information is wrong and linking to somewhere that qualifies your information into being right isn't helpful. OK; (more than) enough said. Let's leave the topic alone from here on, but be careful how you present assertions about what is, or is not, in the C standard.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.