I am trying to code a function that converts a double into a string (a sort of dtoa function). I don't want to use any of the standard library that will do all the job for me (itoa is ok, strlen too, because I can code them on my own).
My main idea was to extract the integer part, doing something like this:
/* Let's suppose that str is ok, and d > 0 */
/* Let's also suppose that we don't need to round the result */
/* Let's finally suppose that precision is greater than 0 */
char *dtoa(double d, int precision, char *str)
{
int int_part;
size_t i, len;
char *temp;
int decimals;
if (str == NULL)
return (NULL);
int_part = (int)d;
temp = itoa(int_part);
i = 0;
len = strlen(temp);
while (i < len)
{
str[i] = temp[i];
i++;
}
d -= (double)int_part;
str[i] = '.';
i++;
decimals = 0;
while (decimals < precision)
{
d *= 10;
int_part = (int)d;
str[i] = int_part + '0';
i++;
decimals++;
d -= (double)int_part;
}
return (str);
}
That function doesn't work so bad. I think I am a little bit stupid, because I could extract several decimal numbers instead of extracing them one by one. But, even when I tried this other method, I had a problem.
Actually, when I do this, it works for a lot of double. But, for some of them, I am losing precision. For example, when I try with 1.42, I have 1.4199 as result.
My question is: is there an easy way to solve this problem, or do I need to change all the conversion method? A few years ago, I learned about how the floating point numbers where coded (using the IEE-754 representation) but I would like to avoid me to create a sort of IEE-754 converter.
Thanks for your help!
Edit: This is just an exercice, I'm not going to send a rocket to Mars with this function (the astronauts are grateful).
Edit2: It looks like 1.42 is not a "correct" double. But, in that case, why does this work fine?
printf("Number: %lf\n", 1.42);
Related
I'm looking for a C function like the following that parses a length-terminated char array that expresses a floating point value and returns that value as a float.
float convert_carray_to_float( char const * inchars, int incharslen ) {
...
}
Constraints:
The character at inchars[incharslen] might be a digit or other character that might confuse the commonly used standard conversion routines.
The routine is not allowed to invoke inchars[incharslen] = 0 to create a z terminated string in place and then use the typical library routines. Even patching up the z-overwritten character before returning is not allowed.
Obviously one could copy the char array in to a new writable char array and append a null at the end, but I am hoping to avoid copying. My concern here is performance.
This will be called often so I'd like this to be as efficient as possible. I'd be happy to write my own routine that parses and builds up the float, but if that's the best solution, I'd be interested in the most efficient way to do this in C.
If you think removing constraint 3 really is the way to go to achieve high performance, please explain why and provide a sample that you think will perform better than solutions that maintain constraint 3.
David Gay's implementation, used in the *BSD libcs, can be found here: https://svnweb.freebsd.org/base/head/contrib/gdtoa/ The most important file is strtod.c, but it requires some of the headers and utilities. Modifying that to check the termination every time the string pointer is updated would be a bit of work but not awful.
However, you might afterwards think that the cost of the extra checks is comparable to the cost of copying the string to a temporary buffer of known length, particularly if the strings are short and of a known length, as in your example of a buffer packed with 3-byte undelimited numbers. On most architectures, if the numbers are no more than 8 bytes long and you were careful to ensure that the buffer had a bit of tail room, you could do the copy with a single 8-byte unaligned memory access at very little cost.
Here's a pretty good outline.
Not sure it covers all cases, but it shows most of the flow:
float convert_carray_to_float(char const * inchars, int incharslen)
{
int Sign = +1;
int IntegerPart = 0;
int DecimalPart = 0;
int Denominator = 1;
bool beforeDecimal = true;
if (incharslen == 0)
{
return 0.0f;
}
int i=0;
if (inchars[0] == '-')
{
Sign = -1;
i++;
}
if (inchars[0] == '+')
{
Sign = +1;
i++;
}
for( ; i<incharslen; ++i)
{
if (inchars[i] == '.')
{
beforeDecimal = false;
continue;
}
if (!isdigit(inchars[i]))
{
return 0.0f;
}
if (beforeDecimal)
{
IntegerPart = 10 * IntegerPart + (inchars[i] - '0');
}
else
{
DecimalPart = 10 * DecimalPart + (inchars[i] - '0');
Denominator *= 10;
}
}
return Sign * (IntegerPart + ((float)DecimalPart / Denominator));
}
My apologies if this question was asked already (I'm assuming that since it's a rather simple question and not because I didn't try to find it first!).
What I was trying to do is build a double number one char at a time.
The numbers to the left were easy with the line num = num * 10 + (c - '0'); /*num being the number built so far and c being the char added*/
but then doing something likenum = (double)((int)num) + ( (num%1)*10 + (c - '0') )/decDigits; //decDigits is the number of digits(including the new one) to the right of the decimal point
wouldn't work because apparently you can't use the % operator on a double.
What'd be the right way to achieve the above?
Are you trying to convert a double to a string, or a string to a double? It looks like the latter, and I don’t think you should be using the % operator in that case at all. Starting at 0.1, multiply each digit’s value by what’s appropriate for its place.
It’s easier to explain in C, though:
char c;
double result = 0.0;
/* The part before the decimal place */
while ((c = *s++) && c != '.') {
result = result * 10.0 + (c - '0');
}
/* The part after the decimal place */
if (c == '.') {
double m = 0.1;
s++;
while ((c = *s++)) {
result += m * (c - '0');
m *= 0.1;
}
}
The modulo operator is not defined for floating points. If you are trying to use num%1 to extract the decimal part of num, you should instead try something like this:
double num_dec = num - floor(num);
I've been racking my brain at this problem since yesterday and I was hoping someone could point me in the right direction.
I'm new to C and we must create a program where the user enters a series of linear equations that must be solved with Cramer's rule.
The math is not a problem, however I am not sure how to get the coefficients from an entire equation composed of chars and ints.
The user input should look like a series of linear equations such as:
-3x-3y-1z=6
2x+3y+4z=9
3x+2y+4z=10
This would be simple if we were allowed to only enter the coefficients but sadly the whole equation must be entered. You can assume that there are no spaces in the equation, the order of variables will be the same, and that the equations are valid.
I was thinking about storing the whole equation in an array and searching for each variable (x,y,z) then finding the int before the variable, but I cannot determine a way to convert these found variables into integers.
Any help is greatly appreciated. Thanks in advance.
You can split on x/y/z/= with strtok and then use atoi to transform the char* into int.
Read the man strtok and the man atoi for further information (functions from stdlib).
Your idea will work. I once did that on a very similar project at school, it was a nightmare but it (kinda) worked. You'll need some logic to read more than one number, unless you want to restrict yourself to coefficients lower than two digits. If I remember correctly, I started reading the characters until I found a variable in the expression, then I converted and assigned the value I found to that variable for resolving.
To transform your characters into integers you can use the atoi() function, which receives a string of characters and returns the corresponding integer.
If you're willing to invest extra time, and if you're working under *nix, you may want to dig into regular expression's territory with regex.h. You'll minimize your code, but it won't be easy if you haven't worked with regular expressions before.
//ax+bx+cz=d, -999 <= a,b,c,d <= 999
int a, b, c, d, i ,j;
char A[5], B[5], C[5], D[5], str[22];
char *pntr;
printf("Enter equation: ");
fgets(str, 21, stdin);
pntr = A;
i = j = 0;
while(1){
if(str[i] == 'x'){pntr[j] = '\0'; pntr = B; j = 0; i++; continue;}
else if(str[i] == 'y'){pntr[j] = '\0'; pntr = C; j = 0; i++; continue;}
else if(str[i] == 'z'){pntr[j] = '\0'; pntr = D; j = 0; i += 2; continue;}
else if(str[i] == '\n' || str[i] == '\0'){pntr[j] = '\0'; break;}
pntr[j] = str[i];
i++;
j++;
}
a = atoi(A);
b = atoi(B);
c = atoi(C);
d = atoi(D);
printf("%d %d %d %d \n", a, b, c, d);
valter
So I am getting pretty frustrated with this and feel the only way to figure out exactly what I am doing wrong is to ask you fine people. I am trying to convert a string of characters (contains number values) to hexadecimal. Here is my code (note, I haven't placed the switch for 10-15 to letters yet; I just wanted to make sure I was getting back integer values when I ran this... no luck):
void toHex(char *inString){
char *charVal = inString;
char decVal[100];
for(int i = 0; decVal[i] != '\0'; i++){
decVal[i] = *charVal;
charVal++;
}
char storeMod[100];
int i = 0;
int testVal = atoi(decVal);
for(i; testVal >= 16; i++){
int a = testVal;
testVal = testVal/16;
storeMod[i] = a;
}
int a = 0;
char hexval[100];
hexVal[0] = '0';
hexVal[1] = 'x';
for(int j = i+2; j>=2; j--){
hexVal[j] = storeMod[a];
a++;
}
printf("%s hex valu\n", hexVal);
return;
}
For example, an input of 300 returns ,#
I have also tried:
char hexVal[100];
sprintf(hexVal,"%x",*inString);
strcpy(instring,hexVal);
which returns a hex value of 3fa844e0 for 300 which is obviously wrong as well. Any help is appreciated, I need to do this for octals too so I have to figure this concept out and see what I am doing wrong.
Instead of:
sprintf(hexVal,"%x",*inString);
Use:
sprintf(hexVal, "%x", atoi(inString));
As has been pointed out, you can replace your whole function with:
printf("%lx\n", strtol(inString, NULL, 10));
But, if this is for school or personal gratification, you seem to know the two main steps.
Convert the string to an integer
Encode the integer back into a string of the right base.
For step one, step through the number left-to-right (which is easy in a string) multiplying a running result by 10, and adding the current digit.
For step two, simply run through the number four bits(one hex digit) at a time, inserting that plus '0'. If you've started from the LSB, remember to reverse the string.
In a c programming exercise I am asked to convert an int to char without using the C library.
Any idea how to go about it?
edit: what I mean by int is the built in C/C++ type
Thanks.
Cast it?
char c = (char)i;
Or maybe you meant this?
char c = (char)('0' + i);
I'm sure this isn't what you mean though... I'm guessing you want to create a string (char array)? If so, then you need to convert it one digit at a time starting with the least significant digit. You can do it recursively, in pseudo-code:
function convertToString(i)
if i < 10
return convertDigitToChar(i)
else
return convertDigitToString(i / 10) concat convertDigitToChar(i % 10)
Here / is integer division and % is integer modulo. You also need to handle negative numbers. This can be done by checking first if you have a negative number, calling the function on the aboslute value and adding the minus sign if necessary.
In C for performance you would probably implement this with a loop instead of using recursion, and by directly modifying the contents of a character array instead of concatenating strings.
If you really want a string:
#include <stdio.h>
char *tochar(int i, char *p)
{
if (i / 10 == 0) {
// No more digits.
*p++ = i + '0';
*p = '\0';
return p;
}
p = tochar(i / 10, p);
*p++ = i % 10 + '0';
*p = '\0';
return p;
}
int main()
{
int i = 123456;
char buffer[100];
tochar(i, buffer);
printf("i = %s\n", buffer);
}
For completeness, if the task is to convert int to string as anthares suspects, you can use Mark's second answer to convert each digit of the integer. To get each digit, you have to look into the division and modulo operators.