Max Float Fraction - c

Platform: Linux 3.2.0 (Debian 7.0)
Compiler: GCC 4.7.2 (Debian 4.7.2-5)
I am trying to convert character strings into floats. I am aware that there are already functions that do this. I am only doing this for practice. My function works well with simple numbers like 123.123, 1234, -678.8. But when I try to convert the string .99999999 into a float I end up with 1. Which is obviously a problem. I do not know if this is because .99999999 cannot be expressed by a float or if I am doing something incorrectly. The question I am asking is how can I calculate the maximum fraction that a float can express. How do I, for lack of a better term, know when a float is about to overflow?
Here is what I have so far.
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
int cstrtof(const char *cstr, float *f);
int cstrtof(const char *cstr, float *f)
{
unsigned short int i = 0;
unsigned short int bool_fraction = 0;
float tmp_f = 0;
if(cstr[0] == '\000') return -1;
else if(cstr[0] == '-') i = 1;
for(; cstr[i] != '\000'; i++)
{
printf("tmp_f = %f\n", tmp_f);
if(cstr[i] >= '0' && cstr[i] <= '9')
{
if(tmp_f > (FLT_MAX - (cstr[i] - '0')) / 10) return -2;
else tmp_f = tmp_f * 10 + (cstr[i] - '0');
}
else if(cstr[i] == '.') bool_fraction = i+1;
else return i+1;
}
printf("tmp_f = %f\nbool_fraction = %i\n", tmp_f, bool_fraction);
if(bool_fraction)
{
for(bool_fraction--; bool_fraction < i-1; bool_fraction++, tmp_f /= 10)
{
printf("tmp_f = %f\n", tmp_f);
}
}
printf("tmp_f = %f\nbool_fraction = %i\n", tmp_f, bool_fraction);
if(cstr[0] == '-') *f = tmp_f*-1;
else *f = tmp_f;
return 0;
}
int main(int argc, char *argv[])
{
float f = 0;
int return_value = 0;
return_value = cstrtof(argv[1], &f);
if(return_value == 0)
{
printf("f = %.11f\n", f);
}
else if(return_value == -1)
{
printf("ERROR Empty String\n");
}
else if(return_value == -2)
{
printf("ERROR Data Type Overflow\n");
}
else
{
printf("ERROR Invalid character '%c'\n", argv[1][return_value-1]);
}
return 0;
}
Also cstrtof() is based on the following function.
int cstrtoslli(const char *cstr, signed long long int *slli)
{
unsigned short int i = 0;
signed long long int tmp_slli = 0;
if(cstr[0] == '\000') return -1;
else if(cstr[0] == '-') i = 1;
else if(cstr[0] == '0') return -2;
for(; cstr[i] != '\000'; i++)
{
if(cstr[i] >= '0' && cstr[i] <= '9')
{
//LLONG_MAX is defined in limits.h
if(tmp_slli > (LLONG_MAX - (cstr[i] - '0')) / 10) return -3;
else tmp_slli = tmp_slli * 10 + (cstr[i] - '0');
}
else return i+1;
}
if(cstr[0] == '-') *slli = tmp_slli*-1;
else *slli = tmp_slli;
return 0;
}

The largest representable float value less than 1 is returned by nexttowardf(1, -INFINITY).
This will generally have a different fraction part than, for example, the largest representable float value less than 2, which is nexttowardf(2, -INFINITY). This is because numbers of different magnitudes generally have different numbers of bits available for the fraction part (because some of the bits are used for the integer part). Large numbers have zero bits for the fraction part.
When float is an IEEE-754 32-bit binary floating-point value, which is common in modern implementations, the largest float below 1 is 0.999999940395355224609375. When the routines that convert decimal numerals to float are good quality and the rounding mode is to-nearest (the common default), then the point where numbers switch from rounding to 0.999999940395355224609375 to rounding to 1 is halfway between those two values (and the exact midpoint will round to 1).
Properly converting decimal numerals to binary floating-point is complicated. It is a solved problem and there are academic papers about it, but you should generally rely on existing library code, if it is doing the job properly. Doing it correctly yourself will require a significant investment of time.

The question I am asking is how can I calculate the maximum fraction that a float can express. How do I, for lack of a better term, know when a float is about to overflow?
You are looking for:
#include <math.h>
… nextafterf(1.0f, 0.0f) …
But you should familiarize yourself with C99's hexadecimal notation for floats, and then you can write the constant directly : 0x1.fffffep-1.

Related

How can I check if the result of a division is an integer in C?

I need to check if the result of a mathematical division is an integer or not.
For example, 8 / 2 = 4
is ok.
but 5 / 2 = 2.5
shouldn't be ok.
I've tried the following:
bool isPrime(int num)
{
/* Checks all the numbers before the given input. If the result of
dividing
the input by one of those numbers is an int, then the input is not a
prime number. */
int i, check;
double result;
for (i=2; i<num; i++) {
result = (double) num / i;
check = (int) result;
if (isdigit(check))
return false;
}
return true;
}
I'm having nightmares about isdigit and how to insert the parameter in the right way. I know it requires an int, but I have a double, so I can't really put those pieces together.
It seems like you're trying to do something like this:
result = (double) num / i;
check = (int) result;
if(check == result) {
...
Logically, this is correct. But it will not work in practice because floats does not have infinite precision.
The proper way to check divisibility is using the modulo operator:
if(num % i == 0) {
// Code to run if num / i is an integer
You want to test if an integer division has no remainder: use the modulo operator % that computes the remainder. The isdigit() function has a different purpose: it tests whether a byte read by getc() is a digit ('0' to '9') or not.
Here is a modified version:
bool isPrime(int num) {
/* Checks all the numbers before the given input. If the result of
dividing the input by one of those numbers is integer, then the
input is not a prime number. */
int i;
for (i = 2; i < num; i++) {
if (num % i == 0)
return false;
}
return true;
}
Note that it would be much quicker for prime numbers to stop the search when i * i > num:
bool isPrime(int num) {
/* Checks all the numbers before the given input. If the result of
dividing the input by one of those numbers is integer, then the
input is not a prime number. */
int i;
for (i = 2; i * i <= num; i++) {
if (num % i == 0)
return false;
}
return true;
}
I don´t understand the logic of your function. But maybe this help you. Compare the result of the % modulo operation by the result of the division with the floored version of the division´s result, to 0. If it equals 0, return true;, if not return false;.
At long long int res_floored = res; happens an implicit conversion from double to long long int - The value gets floored, f.e. 4.7 to 4. No explicit cast is needed.
Before that, we have to check if the floored double value of the result of the division is capable to be hold in an long long int. Therefore, I compare res to the macros LONG_MAX and LONG_INT, header limits.h, which represent the maximum and minimum integral values a long int can hold. If it doens´t fit we return -1; as error.
int div_result_in_int (double dividend, double divisor);
{
double res = dividend / divisor;
if (res > LONG_MAX || res < LONG_MIN)
{
return -1;
}
long long int res_floored = res;
if (res % res_floored == 0)
{
return true;
}
else
{
return false;
}
}
I use double for both parameters, because the division of two floating-point values can result in an integral value.
#include <stdio.h>
#include <limits.h>
#define true 1
#define false 0
int div_result_in_int (double dividend, double divisor)
{
double res = dividend / divisor;
if (res > LONG_MAX || res < LONG_MIN)
{
return -1;
}
long long int res_floored = res;
if (res == res_floored)
{
return true;
}
else
{
return false;
}
}
int main(void)
{
printf("%d\n", div_result_in_int(8,4));
printf("%d\n", div_result_in_int(9,5));
printf("%d\n", div_result_in_int(3,1));
printf("%d\n", div_result_in_int(97,14));
printf("%d\n", div_result_in_int(2,0.5));
}
Output:
1
0
1
0
1

Detect and prevent overflow for unsigned long in C

I have some lines in my code to check whether the resulting value overflows (by comparing it to it's previous iteration), and therefore if the input value is too large. This works for some values, but not for values whose increment is so large that it not only overflows, but overflows so much that the resulting value is larger than the previous iteration. For example, it triggers for 18446744073709551616 (MAX_ULONG + 1), but not for 184467440737095516150 (MAX_ULONG * 10). How can I address this issue? The code is as follows:
unsigned long result = 0;
unsigned long overflowCheck = 0;
int power = 0;
for (int i = (strlen(input) - 1); i >= 0; i--) {
if ((input[i] > ('0' - 1)) && (input[i] < ('9' + 1))) {
result += (input[i] - '0') * (unsigned long)pow(iBase, power++);
} else {
printf("Invalid input string.");
valid = 0;
return -1;
}
if (result < overflowCheck) {
printf("Input value too large.");
valid = 0;
return -1;
}
overflowCheck = result;
}
return result;
There are multiple problems in your code:
you should not use pow to perform integer arithmetics: type double may have less value bits than type unsigned long (for example on 64-bit linux, double has 53 value bits and unsigned long has 64). It is simpler to multiply the current value by iBase and add the digit value for each new digit parsed.
it is easier to detect potential overflow before multiplying or adding the values.
Here is a modified version:
#include <errno.h>
#include <limits.h>
unsigned long atoul(const char *input, unsigned int iBase) {
if (iBase < 2 || iBase > 36) {
errno = EINVAL;
return 0;
}
unsigned long result = 0;
unsigned long maxval = ULONG_MAX / iBase;
int maxdigit = ULONG_MAX % iBase;
for (;;) {
int c = *input++;
int digit;
if (c >= '0' && c <= '9') {
digit = c - '0';
} else
if (c >= 'A' && c <= 'Z') {
digit = c - 'A' + 10;
} else
if (c >= 'a' && c <= 'z') {
digit = c - 'a' + 10;
} else {
break;
}
if (digit >= iBase)
break;
if (result > maxval || (result == maxval && digit > maxdigit) {
/* overflow detected */
errno = ERANGE;
return ULONG_MAX;
}
result = result * iBase + digit;
}
return result;
}
Suppose you want to check if x + y overflows where x and y are both unsigned long. The naive approach would be to do this:
if (ULONG_MAX < x + y)
But this will always be false because of overflow. Instead, you would do this:
if (ULONG_MAX - x < y)
This check is algebraically the same as the first attempt but avoids issues of overflow. You can do a similar check in your case:
if ((input[i] > ('0' - 1)) && (input[i] < ('9' + 1))) {
int digit = input[i] - '0';
if (ULONG_MAX / 10 < result) {
printf("overflow");
return -1;
}
result *= 10;
if (ULONG_MAX - digit < result) {
printf("overflow");
return -1;
}
result += digit;
} else {
printf("Invalid input string.");
valid = 0;
return -1;
}
result < 0 will always return false since result is unsigned (and can never be less than 0. One way to check for overflow is to make sure pow() (as a double) is within the bounds for long. However, the real solution here is to not use pow() and keep everything as integers. If you work starting with the most significant digit, you can multiply result by the base (16 in this case) and add the new digit each time. This works because 1234 = base*(base*(base*(0 + 1) + 2) + 3) + 4
Some (incomplete) code would be:
int input_len = strlen(input);
for (int i = 0; i < input_len; i++) {
// After finding out which digit group input[i] is in:
result = result * iBase + (input[i] - '0');
}
Since result will only change by a factor of 16 at most, you can check for overflow by comparing with the previous result every iteration:
unsigned long previous = result;
// Add in the next digit
if (result < previous) {
// Overflow
}

Concatenating binary numbers

I am trying to code a program that will take a floating point number in base 10 and convert its fractional part in base 2. In the following code, I am intending to call my converting function into a printf, and format the output; the issue I have lies in my fra_binary() where I can't figure out the best way to return an integer made of the result of the conversion at each turn respectively (concatenation). Here is what I have done now (the code is not optimized because I am still working on it) :
#include <stdio.h>
#include <math.h>
int fra_binary(double fract) ;
int main()
{
long double n ;
double fract, deci ;
printf("base 10 :\n") ;
scanf("%Lf", &n) ;
fract = modf(n, &deci) ;
int d = deci ;
printf("base 2: %d.%d\n", d, fra_binary(fract)) ;
return(0) ;
}
int fra_binary(double F)
{
double fl ;
double decimal ;
int array[30] ;
for (int i = 0 ; i < 30 ; i++) {
fl = F * 2 ;
F = modf(fl, &decimal) ;
array[i] = decimal ;
if (F == 0) break ;
}
return array[0] ;
}
Obviously this returns partly the desired output, because I would need the whole array concatenated as one int or char to display the series of 1 and 0s I need. So at each turn, I want to use the decimal part of the number I work on as the binary number to concatenate (1 + 0 = 10 and not 1). How would I go about it?
Hope this makes sense!
return array[0] ; is only the first value of int array[30] set in fra_binary(). Code discards all but the first calculation of the loop for (int i = 0 ; i < 30 ; i++).
convert its fractional part in base 2
OP's loop idea is a good starting point. Yet int array[30] is insufficient to encode the fractional portion of all double into a "binary".
can't figure out the best way to return an integer
Returning an int will be insufficient. Instead consider using a string - or manage an integer array in a likewise fashion.
Use defines from <float.h> to drive the buffer requirements.
#include <stdio.h>
#include <math.h>
#include <float.h>
char *fra_binary(char *dest, double x) {
_Static_assert(FLT_RADIX == 2, "Unexpected FP base");
double deci;
double fract = modf(x, &deci);
fract = fabs(fract);
char *s = dest;
do {
double d;
fract = modf(fract * 2.0, &d);
*s++ = "01"[(int) d];
} while (fract);
*s = '\0';
// For debug
printf("%*.*g --> %.0f and .", DBL_DECIMAL_DIG + 8, DBL_DECIMAL_DIG, x,
deci);
return dest;
}
int main(void) {
// Perhaps 53 - -1021 + 1
char fraction_string[DBL_MANT_DIG - DBL_MIN_EXP + 1];
puts(fra_binary(fraction_string, -0.0));
puts(fra_binary(fraction_string, 1.0));
puts(fra_binary(fraction_string, asin(-1))); // machine pi
puts(fra_binary(fraction_string, -0.1));
puts(fra_binary(fraction_string, DBL_MAX));
puts(fra_binary(fraction_string, DBL_MIN));
puts(fra_binary(fraction_string, DBL_TRUE_MIN));
}
Output
-0 --> -0 and .0
1 --> 1 and .0
3.1415926535897931 --> 3 and .001001000011111101101010100010001000010110100011
-0.10000000000000001 --> -0 and .0001100110011001100110011001100110011001100110011001101
1.7976931348623157e+308 --> 179769313486231570814527423731704356798070600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 and .0
2.2250738585072014e-308 --> 0 and .00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
4.9406564584124654e-324 --> 0 and .000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
Also unclear why input is long double, yet processing is with double. Recommend using just one FP type.
Note that your algorithm finds out the binary representation of the fraction most significant bit first.
One way to convert the fractional part to a binary string, would be to supply the function with a string and a string length, and have the function fill it with up to that many binary digits:
/* This function returns the number of chars needed in dst
to describe the fractional part of value in binary,
not including the trailing NUL ('\0').
Returns zero in case of an error (non-finite value).
*/
size_t fractional_bits(char *dst, size_t len, double value)
{
double fraction, integral;
size_t i = 0;
if (!isfinite(value))
return 0;
if (value > 0.0)
fraction = modf(value, &integral);
else
if (value < 0.0)
fraction = modf(-value, &integral);
else {
/* Zero fraction. */
if (len > 1) {
dst[0] = '0';
dst[1] = '\0';
} else
if (len > 0)
dst[0] = '\0';
/* One binary digit was needed for exact representation. */
return 1;
}
while (fraction > 0.0) {
fraction = fraction * 2.0;
if (fraction >= 1.0) {
fraction = fraction - 1.0;
if (i < len)
dst[i] = '1';
} else
if (i < len)
dst[i] = '0';
i++;
}
if (i < len)
dst[i] = '\0';
else
if (len > 0)
dst[len - 1] = '\0';
return i;
}
The above function works very much like snprintf(), except it takes only the double whose fractional bits are to be stored as a string of binary digits (0 or 1). and returns 0 in case of an error (non-finite double value).
Another option is to use an unsigned integer type to hold the bits. For example, if your code is intended to work on architectures where double is an IEEE-754 Binary64 type or similar, the mantissa has up to 53 bits of precision, and an uint64_t would suffice.
Here is an example of that:
uint64_t fractional_bits(const double val, size_t bits)
{
double fraction, integral;
uint64_t result = 0;
if (bits < 1 || bits > 64) {
errno = EINVAL;
return 0;
}
if (!isfinite(val)) {
errno = EDOM;
return 0;
}
if (val > 0.0)
fraction = modf(val, &integral);
else
if (val < 0.0)
fraction = modf(-val, &integral);
else {
errno = 0;
return 0;
}
while (bits-->0) {
result = result << 1;
fraction = fraction * 2.0;
if (fraction >= 1.0) {
fraction = fraction - 1.0;
result = result + 1;
}
}
errno = 0;
return result;
}
The return value is the binary representation of the fractional part: [i]fractional_part[/i] ≈ [i]result[/i] / 2[sup][i]bits[/i][/sup], where [i]bits[/i] is between 1 and 64, inclusive.
In order for the caller to detect an error, the function clears errno to zero if no error occurred. If an error does occur, the function returns zero with errno set to EDOM if the value is not finite, or to EINVAL if bits is less than 1 or greater than 64.
You can combine the two approaches, if you implement an arbitrary-size unsigned integer type, or a bitmap type.

atoi implementation in C

I can't understand the following atoi implementation code, specifically this line:
k = (k << 3) + (k << 1) + (*p) - '0';
Here is the code:
int my_atoi(char *p) {
int k = 0;
while (*p) {
k = (k << 3) + (k << 1) + (*p) - '0';
p++;
}
return k;
}
Can someone explain it to me ?
Another question: what should be the algorithm of atof implementation ?
<< is bit shift, (k<<3)+(k<<1) is k*10, written by someone who thought he was more clever than a compiler (well, he was wrong...)
(*p) - '0' is subtracting the value of character 0 from the character pointed by p, effectively converting the character to a number.
I hope you can figure out the rest... just remember how the decimal system works.
Here is a specification for the standard function atoi. Sorry for not quoting the standard, but this will work just as fine (from: http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/ )
The function first discards as many whitespace characters (as in
isspace) as necessary until the first non-whitespace character is
found. Then, starting from this character, takes an optional initial
plus or minus sign followed by as many base-10 digits as possible, and
interprets them as a numerical value.
The string can contain additional characters after those that form the
integral number, which are ignored and have no effect on the behavior
of this function.
If the first sequence of non-whitespace characters in str is not a
valid integral number, or if no such sequence exists because either
str is empty or it contains only whitespace characters, no conversion
is performed and zero is returned.
k = (k << 3) + (k << 1);
means
k = k * 2³ + k * 2¹ = k * 8 + k * 2 = k * 10
Does that help?
The *p - '0' term adds the value of the next digit; this works because C requires that the digit characters have consecutive values, so that '1' == '0' + 1, '2' == '0' + 2, etc.
As for your second question (atof), that should be its own question, and it's the subject for a thesis, not something simple to answer...
#include <stdio.h>
#include <errno.h>
#include <limits.h>
double atof(const char *string);
int debug=1;
int main(int argc, char **argv)
{
char *str1="3.14159",*str2="3",*str3="0.707106",*str4="-5.2";
double f1,f2,f3,f4;
if (debug) printf("convert %s, %s, %s, %s\n",str1,str2,str3,str4);
f1=atof(str1);
f2=atof(str2);
f3=atof(str3);
f4=atof(str4);
if (debug) printf("converted values=%f, %f, %f, %f\n",f1,f2,f3,f4);
if (argc > 1)
{
printf("string %s is floating point %f\n",argv[1],atof(argv[1]));
}
}
double atof(const char *string)
{
double result=0.0;
double multiplier=1;
double divisor=1.0;
int integer_portion=0;
if (!string) return result;
integer_portion=atoi(string);
result = (double)integer_portion;
if (debug) printf("so far %s looks like %f\n",string,result);
/* capture whether string is negative, don't use "result" as it could be 0 */
if (*string == '-')
{
result *= -1; /* won't care if it was 0 in integer portion */
multiplier = -1;
}
while (*string && (*string != '.'))
{
string++;
}
if (debug) printf("fractional part=%s\n",string);
// if we haven't hit end of string, go past the decimal point
if (*string)
{
string++;
if (debug) printf("first char after decimal=%c\n",*string);
}
while (*string)
{
if (*string < '0' || *string > '9') return result;
divisor *= 10.0;
result += (double)(*string - '0')/divisor;
if (debug) printf("result so far=%f\n",result);
string++;
}
return result*multiplier;
}
Interestingly, the man page for atoi doesn't indicate setting of errno so if you're talking any number > (2^31)-1, you're out of luck and similarly for numbers less than -2^31 (assuming 32-bit int). You'll get back an answer but it won't be what you want. Here's one that could take a range of -((2^31)-1) to (2^31)-1, and return INT_MIN (-(2^31)) if in error. errno could then be checked to see if it overflowed.
#include <stdio.h>
#include <errno.h> /* for errno */
#include <limits.h> /* for INT_MIN */
#include <string.h> /* for strerror */
extern int errno;
int debug=0;
int atoi(const char *c)
{
int previous_result=0, result=0;
int multiplier=1;
if (debug) printf("converting %s to integer\n",c?c:"");
if (c && *c == '-')
{
multiplier = -1;
c++;
}
else
{
multiplier = 1;
}
if (debug) printf("multiplier = %d\n",multiplier);
while (*c)
{
if (*c < '0' || *c > '9')
{
return result * multiplier;
}
result *= 10;
if (result < previous_result)
{
if (debug) printf("number overflowed - return INT_MIN, errno=%d\n",errno);
errno = EOVERFLOW;
return(INT_MIN);
}
else
{
previous_result *= 10;
}
if (debug) printf("%c\n",*c);
result += *c - '0';
if (result < previous_result)
{
if (debug) printf("number overflowed - return MIN_INT\n");
errno = EOVERFLOW;
return(INT_MIN);
}
else
{
previous_result += *c - '0';
}
c++;
}
return(result * multiplier);
}
int main(int argc,char **argv)
{
int result;
printf("INT_MIN=%d will be output when number too high or too low, and errno set\n",INT_MIN);
printf("string=%s, int=%d\n","563",atoi("563"));
printf("string=%s, int=%d\n","-563",atoi("-563"));
printf("string=%s, int=%d\n","-5a3",atoi("-5a3"));
if (argc > 1)
{
result=atoi(argv[1]);
printf("atoi(%s)=%d %s",argv[1],result,(result==INT_MIN)?", errno=":"",errno,strerror(errno));
if (errno) printf("%d - %s\n",errno,strerror(errno));
else printf("\n");
}
return(errno);
}
Here is my implementation(tested successfully with cases containing and starting with letters, +, - and zero's).
I tried to reverse-engineer atoi function in Visual Studio. If the input string only contained numerical characters, it could be implemented in one loop. but it gets complicated because you should take care of -,+ and letters.
int atoi(char *s)
{
int c=1, a=0, sign, start, end, base=1;
//Determine if the number is negative or positive
if (s[0] == '-')
sign = -1;
else if (s[0] <= '9' && s[0] >= '0')
sign = 1;
else if (s[0] == '+')
sign = 2;
//No further processing if it starts with a letter
else
return 0;
//Scanning the string to find the position of the last consecutive number
while (s[c] != '\n' && s[c] <= '9' && s[c] >= '0')
c++;
//Index of the last consecutive number from beginning
start = c - 1;
//Based on sign, index of the 1st number is set
if (sign==-1)
end = 1;
else if (sign==1)
end = 0;
//When it starts with +, it is actually positive but with a different index
//for the 1st number
else
{
end = 1;
sign = 1;
}
//This the main loop of algorithm which generates the absolute value of the
//number from consecutive numerical characters.
for (int i = start; i >=end ; i--)
{
a += (s[i]-'0') * base;
base *= 10;
}
//The correct sign of generated absolute value is applied
return sign*a;
}
about atoi() hint code from here:
and based on the atoi(), my implementation of atof():
[have same limitation of original code, doesn't check length, etc]
double atof(const char* s)
{
double value_h = 0;
double value_l = 0;
double sign = 1;
if (*s == '+' || *s == '-')
{
if (*s == '-') sign = -1;
++s;
}
while (*s >= 0x30 && *s <= 0x39)
{
value_h *= 10;
value_h += (double)(*s - 0x30);
++s;
}
// 0x2E == '.'
if (*s == 0x2E)
{
double divider = 1;
++s;
while (*s >= 0x30 && *s <= 0x39)
{
divider *= 10;
value_l *= 10;
value_l += (double)(*s - 0x30);
++s;
}
return (value_h + value_l/divider) * sign;
}
else
{
return value_h * sign;
}
}

getfloat returning 23.7999

#define MAXBUF 1000
int buf[MAXBUF];
int buffered = 0;
int bufp = 0;
int getch()
{
if(bufp > 0) {
if(!--bufp)
buffered = 0;
return buf[bufp];
}
else {
buffered = 0;
return getchar();
}
}
void ungetch(int c)
{
buf[bufp++] = c;
buffered = 1;
}
int getfloat(float *pn)
{
int c, sign, sawsign;
float power = 1.0;
while(isspace(c=getch()))
;
if(!isdigit(c) && c!= '+' && c!= '-' && c != '.') {
ungetch(c);
return 0;
}
sign = (c == '-') ? -1 : 1;
if(sawsign = (c == '-' || c == '+'))
c = getch();
if(c != '.' && !isdigit(c)) {
ungetch(c);
if(sawsign)
ungetch((sign == -1) ? '-' : '+');
return 0;
}
for(*pn = 0.0; isdigit(c); c = getch())
*pn = 10.0 * *pn + (float)(c - '0');
if(c == '.')
while(isdigit(c = getch())) {
*pn = 10.0 * *pn + (float)(c - '0');
power *= 10.0;
}
*pn *= sign;
*pn /= power;
ungetch(c);
return c;
}
It always returns 23.7999 when i enter 23.8, and i have no idea why. Can anybody tell me why?
Numbers are represented in base 2, and base-2 floating-point values cannot represent every base-10 decimal value exactly. What you enter as 23.8 gets converted into its closest equivalent base-2 value, which is not exactly 23.8. When you print this approximate value out, it gets printed as 23.7999.
You are also using float, which is the smallest floating-point type, and has only 24 bits of precision (roughly 7 decimal digits). If you switch to double, the amount of bits of precision more than doubles from float, so the difference between a decimal value such as 23.8 and its double representation is much smaller. This may allow a printing routine to perform the rounding better so that you see 23.8 with double. However, the actual value in the variable is still not exactly 23.8.
As general advice, unless you have a huge number of floating-point values (making memory usage your primary concern), it is best to use double whenever you need a floating-point type. You don't get rid of all odd behavior but you're going to see less of it than with float.
Because certain floating point numbers are inherently inaccurate.
23.8 can't be represented exactly given the limited accuracy of IEEE 754 floats.

Resources