I have written an atof() implementation in c . I am facing rounding off errors in this implementation . So , putting in a test value of 1236.965 gives a result of 1236.964966 but the library atof() function reurns 1236.965000 . My question is , how to make the user defined atof() implementation more 'correct' ?
Can the library definition of atof() be found somewhere ?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
float str_to_float(char *);
void float_to_str(float,char *);
int main(){
int max_size;
float x;
char *arr;
printf("Enter max size of string : ");
scanf("%d",&max_size);
arr=malloc((max_size+1)*sizeof(char));
scanf("%s",arr);
x=str_to_float(arr);
printf("%f\n%f",x,atof(arr));
return 0;
}
float str_to_float(char *arr){
int i,j,flag;
float val;
char c;
i=0;
j=0;
val=0;
flag=0;
while ((c = *(arr+i))!='\0'){
// if ((c<'0')||(c>'9')) return 0;
if (c!='.'){
val =(val*10)+(c-'0');
if (flag == 1){
--j;
}
}
if (c=='.'){ if (flag == 1) return 0; flag=1;}
++i;
}
val = val*pow(10,j);
return val;
}
Change all your floats to doubles. When I tested it, that gave the same result as the library function atof for your test case.
atof returns double, not float. Remember that it actually is double and not float that is the "normal" floating-point type in C. A floating-point literal, such as 3.14, is of type double, and library functions such as sin, log and (the perhaps deceptively named) atof work with doubles.
It will still not be "precise", though. The closest you can get to 1236.965 as a float is (exactly) 1236.9649658203125, and as a double 1236.964999999999918145476840436458587646484375, which will be rounded to 1236.965000 by printf. No matter how many bits you have in a binary floating-point number, 1236.965 can't be exactly represented, similar to how 1/3 can't be exactly represented with a finite number of decimal digits: 0.3333333333333333...
And also, as seen in the discussion in comments, this is a hard problem, with many possible pitfalls if you want code that will always give the closest value.
I used your code as inspiration to write my own.
What other commenters and answers do not recognize is that the original reason for the question is an embedded situation. In my case the library "atof" pulls in something that does "printf" which pulls in "systemcalls" which I don't have.
So.... here I present a simple (does not implement exponential notation) atof implementation that works in floats, and is suitable for embedding.
My implementation uses way less variables.
float ratof(char *arr)
{
float val = 0;
int afterdot=0;
float scale=1;
int neg = 0;
if (*arr == '-') {
arr++;
neg = 1;
}
while (*arr) {
if (afterdot) {
scale = scale/10;
val = val + (*arr-'0')*scale;
} else {
if (*arr == '.')
afterdot++;
else
val = val * 10.0 + (*arr - '0');
}
arr++;
}
if(neg) return -val;
else return val;
}
how to make the user defined atof() implementation more 'correct' ?
Easy: 1) never overflow intermediate calculation and 2) only round once (at the end).
It is hard to do those 2 steps.
Note: C's atof(), strtof(), etc. also handle exponential notation - in decimal and hex.
Potential roundings
val*10
(val*10)+(c-'0');
pow(10,j)
val*pow(10,j) // This last multiplication is the only tolerable one.
Potential overflow (even though the final answer is within range)
val*10
(val*10)+(c-'0');
pow(10,j)
Using a wider type like double can greatly lessen the occurrence of such problems and achieve OP's "more 'correct'". Yet they still exist.
This is not an easy problem to solved to get the best (correct) floating point result from all string inputs.
Sample approaches to solve.
Avoid overflow: rather than pow(10,j):
val = val*pow(5,j); // rounds, `pow(5,j)` not expected to overflow a finite final result.
val = val*pow(2,j); // Does not round except at extremes
Code should form (ival*10)+(c-'0') using extended integer math in the loop for exactness.
Yet this is just scratching the surface of the many corner cases.
#Eric Postpischil commented on a robust C++ code that handles non-exponential notation string input well. It does initial math using integers and only rounds later in the process. This linked code is not visible unless your rep is 10,000+ as the question was deleted.
Related
#include <stdio.h>
int main(){
int n, v;
printf("Please enter a value from 39 to 59: \n");
scanf("%d", &n);
printf("Please enter a value from 3 to 7: \n");
scanf("%d", &v);
}
When I got those values from user, how can I perform this factorial calculation:
n! / ((n-v)! * v!))
I've tried different data types but apparently none can hold the result.
For example: n = 49, v=6. The result is: 13,983,816, but how can I go about getting it?
You're best bet is to ditch the naive factorial implementations, usually based on recursion, and switch to one that returns the natural log of gamma function.
The gamma function is related to factorial: gamma(n) = (n-1)!
Best of all is natural log of gamma, because you can rewrite that expression like this:
ln(n!/(n-v)!v!) = ln(n!) - ln((n-v)!) - ln(v!)
But
(n-v)! = gamma(n-v+1)
n! = gamma(n+1)
v! = gamma(v+1)
So
ln(n!/(n-v)!v!) = lngamma(n+1) - lngamma(n-v+1) - lngamma(v+1)
You can find an implemenation for lngamma in Numerical Recipes.
lngamma returns a double, so it'll fit even for larger values.
It should go without saying that you'll take exp() of both sides to get the original expression you want back.
#duffymo idea looked like too much fun to ignore: use lgamma() from <math.h>.
Results past maybe x=1e15, start to lose the trailing significant digits.. Still fun to be able to get 1000000.0!.
void factorial_expo(double x, double *significand, double *expo) {
double y = lgamma(x+1);
const static double ln10 = 2.3025850929940456840179914546844;
y /= ln10;
double ipart;
double fpart = modf(y, &ipart);
if (significand) *significand = pow(10.0, fpart);
if (expo) *expo = ipart;
}
void facttest(double x) {
printf("%.1f! = ", x);
double significand, expo;
factorial_expo(x, &significand, &expo);
int digits = expo > 15 ? 15 : expo;
if (digits < 1) digits++;
printf("%.*fe%.0f\n", digits, significand, expo);
}
int main(void) {
facttest(0.0);
facttest(1.0);
facttest(2.0);
facttest(6.0);
facttest(10.0);
facttest(69.0);
facttest(1000000.0);
return 0;
}
0.0! = 1.0e0
1.0! = 1.0e0
2.0! = 2.0e0
6.0! = 7.20e2
10.0! = 3.628800e6
69.0! = 1.711224524281441e98
1000000.0! = 8.263931668544735e5565708
In a comment, you've finally said that you don't need exact results.
Just use floating-point. The largest intermediate result you'll need to handle is 59!, which is about 1.3868e80; type double is more than big enough to hold that value.
Write a function like:
double factorial(int n);
(I presume you know how to implement it) and use that.
If you're going to be doing a lot of these calculations, you might want to cache the results by storing them in an array. If you define an array like:
double fact[60];
then you can store the value of N! in fact[N] for N from 0 to 59 -- and you can fill the entire array in about the time it would take to compute 59! just once. Otherwise, you'll be doing several dozen floating-point multiplications and divisions on each calculation -- which is trivial if you do it once, but could be significant if you do it, say, thousands or millions of times.
If you needed exact results, you could use an extended integer library like GNU MP, as others have suggested. Or you could use a language (like Python, for example) that has built-in support for arbitrary-length integers.
Or you could probably perform the multiplications and divisions in an order that avoids overflow; I don't know exactly how to do that, but since n! / ((n-v)! * v!)) is a common formula I strongly suspect that work has already been done.
You can't work with such long numbers as 59! in simple way.
However you can use special C libraries which are working with long numbers bigger than 8 bytes, for example GMP
The code I have written is as follows:
#include<stdio.h>
#include<math.h>
#include<string.h>
int strToint(char []);
int main()
{
char str[20];
printf("Enter the string-");
gets(str);
printf("\nthe integer is %d ",strToint(str));
return 0;
}
int strToint(char str[])
{
int i,a,sum=0,k,j;
a=strlen(str);
for(i=0;i<a;i++)
{
k=str[i]-'0';
j=pow(10,a-i-1);
sum+=k*j;
}
return sum;
}
If I enter the input as, say 567, I get 562 but I do not see why. I feel this is probably related to the pow function.
Help is appreciated. Thanks!
pow() is a floating point function and its behaviour varies from system to system. There's no requirement placed by the standard on its accuracy. It seems that yours is not returning values with the accuracy that you would require.
You do not need to implement functions to convert text to integer since the standard library contains functions that do that. An obvious choice would be sscanf.
But if you must implement such a function, you should use integer arithmetic. Any such code should handle negative values, and check for invalid input. For instance. What happens when you pass "a" to your function?
I tested your code and got the expected result. Maybe the problem is related with function pow.
You could write the function simpler without using functions that deal with real numbers.
For example
int strToint( const char str[] )
{
int sum = 0;
for ( ; *str; ++str )
{
sum = 10 * sum + *str - '0';
}
return sum;
}
Take into account that function gets is unsafe. It is better to use function fgets. For example
fgets( str, 20, stdin );
size_t n = strlen( str );
if ( str[n - 1] == '\n' ) str[n - 1] = '\0';
On the first call to pow(10,2) the library's weak pow() returns 99.999... which is truncated to 99 on assignment to j.
Since the first digit is 5, the final sum is 5 less. (100*5 vs 99*5)
If code must use FP functions, best to round before integer assignment
j = round(pow(10,...));
As #Vlad points out, all FP math can be avoided.
--
Floating point functions are not required by C to be accurate. A good pow() function though should have provided an exact answer here, that is why it worked on so many other machines.
For a complete atoi, there are many posts, such as FromStringToInteger
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am working on a personal project where one part of it deals with counting squares and cubes under a certain bound (in this case 10,000). So, I wrote a simple C program I thought would work to verify my results. Here is the little program I put together to see all of the cubes:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
int main() {
double i;
int cubes = 0;
for (i = 1; i < 10000; i++) {
if ( i == cbrt(i) * cbrt(i) * cbrt(i) ) {
printf("%f --- %f\n",i, cbrt(i));
cubes++;
}
}
printf("%i\n", cubes);
return 0;
}
I got the (incorrect) output : 24. If you want to look at this see the problem look at numbers 15 and 20 on the output. Why I am getting the wrong answer (the correct answer is 21) is an entirely different matter. My question arose when I was messing around with my code to try and fix this and I temporarily changed it to this:
int main() {
double i;
int cubes = 0;
for (i = 1; i < 10000; i++) {
double temp = (cbrt(i) * cbrt(i) * cbrt(i));
if ( i == temp ) {
printf("%f -> %f\n", i, temp);
cubes++;
}
}
printf("%i\n", cubes);
return 0;
}
Now, the program is printing every number between 1 and 9999. So, am I missing something ridiculously easy or what is going on? All I did was instead of having cbrt(i)*cbrt(i)*cbrt(i) in the if conditional I set a double variable equal to result and placed that in the conditional. Why is my program doing this?
I am not sure why this got down voted. I feel like this is a legitimate question. Sorry S.O. community...
double cbrt(double x) returns the closest representable cubic root of x.
The inexactness of the result, then cubed, may not exactly equal 'x' again.
Why 2nd program differs:
C is not obliged to perform double math only to double precision. It may use wider (long double). Depending on many things, the 2nd code appears to have done more in long double than the first. With the extra precision, its easy to see that the results, rounded to double appear exact.
C11dr ยง5.2.4.2.2 9 Except for assignment and cast (which remove all extra range and precision), the values yielded by operators with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type.
Why a typical program run (of either code) produces a result of about 3333.
Consider the double numbers from 2 to 4 and 8 to 64. double numbers are logarithmically distributed. There are as many different double from 2 to 4 as 8 to 16 as 16 to 32 as 32 to 64.
So now all 3 sets from 8 to 64 have a cube root of some answer in the 1 set of 2 to 4. Now if we cube the numbers 2 to 4, we get answers in the range 8 to 64. 1 set of numbers mapping into 3 sets. The round trip is not exact. See Pigeonhole principle. IOW: On average, 3 numbers in the range 8 to 64 have the same cubic root. Then the cube of that root will be 1 of the 3 original.
To find the count of the perfect integer cubes 0 to N
unsigned Perfect_Cube_Count(unsigned n) {
if (n == 0)
return 1;
unsigned i;
// overflow not possible
for (i = 0; i*i < n/i; i++);
return i;
}
Or
// valid for 0 <= x <= something_well_over_1e9
double Perfect_Cube_Count_d(double x) {
double y = cbrt(x);
return floor(y) + 1;
}
You probably want, as Andrew guessed, whole-number cube roots. Float math is quite tricky because of rounding errors. Generally you cannot rely on equality but must compare with an error margin.
To solve your problem though I'd construct the 21 cubes beforehand and then iterate over integers, comparing against the pre-constructed cubes. Or is that cheating? ;-)
In Samuel Becket's novel Watt there is a chapter about a Scottish "Math genius" who could in his head compute all integer third roots of integer cubes up to 10000 or so, too!
My uess, is your compiler does an optimization in the second case, eli inating cbrt calls. It just says the result of cbrt is strictly defined by the standard, so it might as well be always thte case that (i == temp)
You can twak this by some command line arguments, and force it to do exactly what is written in the code. As I recall, this should thhe default thing to do for C compilers regarding float arthimetic, but your compiler may think it is smarter than you or something.
EDIT
And yes, this code has nothing to do with finding perfect cubes...
EDIT
Totally not an answer to the question, but as a quick exercise, this I wrote this:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
static unsigned long count_cubes(unsigned long max_n)
{
unsigned long n = 1;
while (n*n*n <= max_n) {
++n;
}
return n-1;
}
int main(int argc, char **argv)
{
unsigned long max_n;
char *p;
if (argc < 2) {
return EXIT_FAILURE;
}
max_n = strtoul(argv[1], &p, 10);
if (max_n < 1 || max_n == ULONG_MAX) {
return EXIT_FAILURE;
}
printf("%lu\n", count_cubes(max_n));
return EXIT_SUCCESS;
}
Note: no need for floating point arithmetic
EDIT
Sorry, I really got into this...
This one can be a bit faster:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <math.h>
static unsigned long count_cubes(unsigned long max_n)
{
unsigned long n;
if (max_n < 256) {
n = 1;
}
else {
n = cbrtl(max_n) - 1;
}
while (n*n*n <= max_n) {
++n;
}
return n-1;
}
int main(int argc, char **argv)
{
unsigned long max_n;
char *p;
if (argc < 2) {
return EXIT_FAILURE;
}
max_n = strtoul(argv[1], &p, 10);
if (max_n < 1 || max_n == ULONG_MAX) {
return EXIT_FAILURE;
}
printf("%lu\n", count_cubes(max_n));
return EXIT_SUCCESS;
}
EDIT ( last time, I promise... )
To show an explanation of my little loop above, starting at cbrt(max_n)-1, I tried the one suggested by #chux , here are some results with slightly larger numbers:
PerfectCubes(18446724184312856125) == 2642246
which is fine but also
PerfectCubes(18446724184312856125-10) == 2642246
which is totally not fine, since 18446724184312856125 == 2642245^3 , meaning there are 2642245 perfect cubes <= 18446724184312856125-10 .
This also results from inaccuracies in floating point representation. You can try it for yourself, if your computer is somewhat similar to mine:
printf("%f\n", cbrt( 2642245UL * 2642245UL * 2642245UL));
/* prints 2642245.000000 */
printf("%f\n", cbrt( 2642245UL * 2642245UL * 2642245UL - 10UL));
/* prints 2642245.000000 */
These two numbers clearly don't have the same cubic root, yet cbrt returns the same results. In this case, floor doesn't help either. Anyways, one always needs to be very careful using floating point arithmetics. And now I really should go to sleep.
I am attempting to do some statistics-related functions so I can carry out a few related procedures (ie: statistics calculations for probabilities, generate Pascal's triangle for an arbitrary depth, etc).
I have encountered an issue where I am likely dealing with overflow. For example, if I want to calculate nPr for (n=30,p=1), I know that I can reduce it to:
30P1 = 30! / (30 - 1)!
= 30! / (29)!
= 30! / 29!
= 30
However, when calculating using the functions below, it looks like I will always get invalid values due to integer overflow. Are there any workarounds that don't require the use of a library to support arbitrarily large numbers? I've read up a bit in other posts on the gamma functions, but couldn't find concrete examples.
int factorial(int n) {
return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
}
int nCr(int n, int r) {
return (nPr(n,r) / factorial(r));
//return factorial(n) / factorial(r) / factorial(n-r));
}
int nPr(int n, int r) {
return (factorial(n) / factorial(n-r));
}
Here is a way to calculate without using gamma functions.
It relies on the fact that n_C_r = (n/r) * ((n-1)C(r-1))
and that for any positive value, n_C_0 = 1
so we could use it write a recusrive function like below
public long combination(long n, long r) {
if(r==0)
return 1;
else {
long num = n * combination(n - 1, r - 1);
return num/r;
}
}
I think you have two choices:
Use a big integer library. This way you won't lose precision (floating point might work for some cases, but is a poor substitute).
Restructure your functions, so they won't reach high intermediate values. E.g. factorial(x)/factorial(y) is the product of all numbers from y+1 to x. So just write a loop and multiply. This way, you'll only get an overflow if the final result overflows.
If you don't have to deal with signed values (and it doesn't appear that you do), you could try using a larger integral type, e.g., unsigned long long. If that doesn't suffice, you'd need to use a non-standard library that supports arbitrarily long integers. Note that the use of the long long type requires C99 compiler support (if you use GCC, might have to compile with -std=c99).
Edit: you might be able to fit more into a long double, which is 80-bits on some systems.
I might be being dense, but it seems to me that going to doubles and the gamma function is overkill here.
Are there any workarounds that don't require the use of a library to support arbitrarily large numbers?
Sure there are. You know exactly what you're dealing with at all times - products of ranges of integers. A range of integers is a special case of a finite list of integers. I have no idea what an idiomatic way of representing a list is in C, so I'll stick to C-ish pseudocode:
make_list(from, to)
return a list containing from, from+1, ..., to
concatenate_lists(list1, list2)
return a list with all the elements from list1 and list2
calculate_list_product(list)
return list[0] * list[1] * ... * list[last]
calculate_list_quotient(numerator_list, denominator_list)
/*
be a bit clever here: form the product of the elements of numerator_list, but
any time the running product is divisible by an element of denominator_list,
divide the running product by that element and remove it from consideration
*/
n_P_r(n, r)
/* nPr is n! / (n-r)!
which simplifies to n * n-1 * ... * r+1
so we can just: */
return calculate_list_product(make_list(r+1, n))
n_C_r(n, r)
/* nCr is n! / (r! (n-r)!) */
return calculate_list_quotient(
make_list(1, n),
concatenate_lists(make_list(1, r), make_list(1, n-r))
)
Note that we never actually calculate a factorial!
You look like you are on the right track, so here you go:
#include <math.h>
#include <stdio.h>
int nCr(int n, int r) {
if(r>n) {
printf("FATAL ERROR"); return 0;
}
if(n==0 || r==0 || n==r) {
return 1;
} else {
return (int)lround( ((double)n/(double)(n-r)/(double)r) * exp(lgamma(n) - lgamma(n-r) - lgamma(r)));
}
}
int nPr(int n, int r) {
if(r>n) {printf("FATAL ERROR"; return 0;}
if(n==0 || r==0) {
return 1;
} else {
if (n==r) {
r = n - 1;
}
return (int)lround( ((double)n/(double)(n-r)) * exp(lgamma(n) - lgamma(n-r)));
}
}
To compile, do: gcc -lm myFile.c && ./a.out
Note that the accuracy of your results is limited by the bit-depth of the double data type. You should be able to get good results with this, but be warned: replacing all the ints above with long long unsigned may not necessarily guarantee accurate results for larger values of n,r. At some point, you will still need some math library to handle arbitrarily large values, but this should help you avoid that for smaller input values.
I have written the following sample code to find the harmonic value of N. (1+1/2+1/3+...1/N). Read the comments in the code written in BOLD and help me to find why is this happening.
#include <stdio.h>
float harmonic(float n, float har) {
if(n==0) {
return 0;
}
if(n==1) {
printf("%f\n", har+1.0f);***/* This prints value 1.5000*/***
return har+1.0f;
}else{
harmonic(n-1, (har+(1/n)));
}
}
int main()
{
printf("%f\n", harmonic(2, 0.0f)); **/* But this prints value nan(Not a Number)*/**
return 0;
}
Thanks,
Naga
I think you want to do:
return harmonic(n-1, (har+(1/n)));
My first thought was that you should almost never compare floats with simple equality so "if(n==0)" should be "if(n<=EPSILON)" and "if(n==1)" should be "if(n<= 1.0f + EPSILON)" where EPSILON is a small positive fraction, maybe 1.0e-5. Depends on how much precision you can depend on.
But then I realized that n should be an int. Cast it to a float before the division. As the comparisons with "n" stand you risk infinite recursion.
Consider using a double instead of a float.
Matthew Flaschen's answer gets to real reason you get the NaN message. The original code doesn't return anything from the "else" so the caller is probably reading garbage from the stack. Hence, the NaN.