I'm trying to find ex without using math.h. My code gives wrong anwsers when x is bigger or lower than ~±20. I tried to change all double types to long double types, but it gave some trash on input.
My code is:
#include <stdio.h>
double fabs1(double x) {
if(x >= 0){
return x;
} else {
return x*(-1);
}
}
double powerex(double x) {
double a = 1.0, e = a;
for (int n = 1; fabs1(a) > 0.001; ++n) {
a = a * x / n;
e += a;
}
return e;
}
int main(){
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
scanf("%d", &n);
for(int i = 0; i<n; i++) {
double number;
scanf("%lf", &number);
double e = powerex(number);
printf("%0.15g\n", e);
}
return 0;
}
Input:
8
0.0
1.0
-1.0
2.0
-2.0
100.0
-100.0
0.189376476361643
My output:
1
2.71825396825397
0.367857142857143
7.38899470899471
0.135379188712522
2.68811714181613e+043
-2.91375564689153e+025
1.20849374134639
Right output:
1
2.71828182845905
0.367879441171442
7.38905609893065
0.135335283236613
2.68811714181614e+43
3.72007597602084e-44
1.20849583696666
You can see that my answer for e−100 is absolutely incorrect. Why does my code output this? What can I do to improve this algorithm?
When x is negative, the sign of each term alternates. This means each successive sum switches widely in value rather than increasing more gradually when a positive power is used. This means that the loss in precision with successive terms has a large effect on the result.
To handle this, check the sign of x at the start. If it is negative, switch the sign of x to perform the calculation, then when you reach the end of the loop invert the result.
Also, you can reduce the number of iterations by using the following counterintuitive condtion:
e != e + a
On its face, it appears that this should always be true. However, the condition becomes false when the value of a is outside of the precision of the value of e, in which case adding a to e doesn't change the value of e.
double powerex(double x) {
double a = 1.0, e = a;
int invert = x<0;
x = fabs1(x);
for (int n = 1; e != e + a ; ++n) {
a = a * x / n;
e += a;
}
return invert ? 1/e : e;
}
We can optimize a bit more to remove one loop iteration by initializing e with 0 instead of a, and calculating the next term at the bottom of the loop instead of the top:
double powerex(double x) {
double a = 1.0, e = 0;
int invert = x<0;
x = fabs1(x);
for (int n = 1; e != e + a ; ++n) {
e += a;
a = a * x / n;
}
return invert ? 1/e : e;
}
For values of x above one or so, you may consider to handle the integer part separately and compute powers of e by squarings. (E.g. e^9 = ((e²)²)².e takes 4 multiplies)
Indeed, the general term of the Taylor development, x^n/n! only starts to decrease after n>x (you multiply each time by x/k), so the summation takes at least x terms. On another hand, e^n can be computed in at most 2lg(n) multiplies, which is more efficient and more accurate.
So I would advise
to take the fractional part of x and use Taylor,
when the integer part is positive, multiply by e raised to that power,
when the integer part is zero, you are done,
when the integer part is negative, divide by e raised to that power.
You can even spare more by considering quarters: in the worst case (x=1), Taylor requires 18 terms before the last one becomes negligible. If you consider subtracting from x the immediately inferior multiple of 1/4 (and compensate multiplying by precomputed powers of e), the number of terms drops to 12.
E.g. e^0.8 = e^(3/4+0.05) = 2.1170000166126747 . e^0.05
Related
My code is taking a string format and compose it into a buffer (without sprintf, itoa etc).
I'm having trouble converting a float number to string, as I need to have precision of at most 7 digits with no trailing zeros. as well as convert each number in the float variable to char (but in that matter I don't need any help).
I tried several methods, all including math calculations, but nothing has brought me to the desired outcome.
Here's my code so far, but it is messy and also sometimes gives incorrect outcome. I also believe there is a more clean and less-complicated way to do it.
any help will be widely appreciated.
if (*format == 'f') {
float f = *(float*)ptrs[counter];
char str[30];
int b, c, m, k = 7, i = 0, l = 0;
int a = f;
f -= a;
while (k >= 0) {
l = pow(10, k);
m = a / l;
if (m > 0) {
break;
}
k--;
}
printf("%d", k);
for (l = k + 1; l > 0; l--) {
b = pow(10, l - 1);
c = a / b;
str[i++] = c + 48;
a %= b;
}
str[i++] = '.';
for (l = 0; l < 7; l++) {
f *= 10.0;
b = f;
str[i++] = b + 48;
f -= b;
}
for (i = 0; i < 7; i++) {
*buffer = str[i];
buffer++;
}
counter++;
str[i] = '\0';
for example:
input: float v2 =0.9372;
output: .937199
desired output: 0.9372
input: float v2 =0.25000;
output: 1.25000
desired output: 0.25
he's messy and also sometimes gives incorrect outcome
At some point given the base 2 nature of typical floating point, the programmer needs to make choices:
Short code that gets close to the correct answer.
Exact correct conversion with a fair amount of code. e.g. Function to print a double - exactly
Something in between.
With common floating point encoding, there are also issues of
Infinity
Not-a-number.
Oddities like -0.0
And how portable to make the code?
Sources of inexactness
OP's use of int limits float to about [INT_MIN...INT_MAX]. Code fails for float much outside that range. Could use long long to get some more range without a great deal of code change. Better yet research float modff(float value, float *iptr).
float f = ...;
// int a=f;
long long a=f;
Repeated use of f*=10.0 below with a fractional value in f injects a possible rounding (inexactness), at each iteration.
for(l=0;l<7;l++) {
f*=10.0;
Code makes no effort to round given that f may not be 0.0 after the fraction forming for(l=0;l<7;l++) { f*=10.0; loop. I see this as a place to improve precision. This area is also tricky as the round-up may effect many leading digits when they are 9, eventually needing a shift of the string buffer. In the 0.93721, after this loop, f was about 0.74. Since more than 0.5, a rounding would have given the answer of ".9371999" --> ".9372000".
Code aims for 7 decimal digits after the .. Values, as a decimal in code, assigned to a float match to 6 to 9 significant decimal places - which includes digits to the left of .. Expectations should not get too high.
Improvement idea
When the number of fraction digits desired is small, perform 1 scaling/round
// ASSUME f >= 0.0, (sign handling done before here)
long long a=f;
f-=a;
int int_f = round(f*pow(10, 7));
if (int_f < 10000000) {
later_printf_the_7_digits(int_f);
} else {
a++;
later_printf_the_7_digits(0);
}
I am evaluating value of cos(x) using the Taylor's series which calculates the series up to n terms where n is entered by user.
I am getting correct output for some values (correct up to 4 decimal places, which is very nice) but I am also getting hugely erroneous outputs for some values of x.
Please see my code and tell me what is exactly going wrong here.
input x=0.5 n=10, output cos(x) = 0.877583, which is correct.
input x=-0.8 n=7, output cos(x) = 0.696707, again correct.
input x=5 n=10, output cos(x) = 0.283625, correct.
input: x=10 n=10 output: cos(x) = -34.438612 huge inaccuracy
double x, t=1,s=1;
int i,n;
printf("Enter x\n");
scanf("%lf",&x);
printf("Enter n");
scanf("%d",&n);
for(i=1;i<n;i++){
t*=(-x*x)/((2*(i-1)+2)*(2*(i-1)+1));
s+=t;
}
printf("\n %lf \n", s);
Why is my Taylor series for calculating cosine inaccurate for some inputs?
It has been a while, but I am pretty sure that the domain of x is {0..2} for this calculation, as x is in radians.
A test you can add inside your loop is:
if (s < -1 || s > 1) {
fprintf(stderr, "Range error!: %le\n", s);
exit(1);
}
Also, if you have a unix-y system, here is your program in bc, which does not rely on float point approximation:
scale=20
define t(x,n) {
auto i, s, t
s = 1
t = 1
for (i=1; i<n; i++) {
t*=(-x*x)/((2*(i-1)+2)*(2*(i-1)+1))
s+=t
if (s < -1 || s > 1) {
"range error!\n"; return s
}
}
return s
}
You can run this interactively with bc filename, then type in your examples like t(8, 10).
As for whether the sequences converge for all values of x; my math is probably not good enough to answer that. That is why I chose programming, math is hard.
However, here is a cosine definition from an old systems bclib.b:
define c(x) {
auto a, b, c, d, e, g, y;
y = - x*x;
a = 1;
b = 1;
c = b;
d = 1;
e = 1;
for (a=2; 1 == 1; a += 2) {
b *= y;
c = c*a*(a-1) +b;
d *= a*(a-1);
g = c/d;
if (g == e) return (g);
e = g;
}
}
Which is slightly different from yours, yet does seem to work for any range of input. So, you might want to take a look at what is different....
(note that in bc, the variable scale holds the precision the calculator is working in; so c(8,10) is scale=10; c(8)
I'm learning C programming and made the algorithm below to solve this problem:
The code actually works, but initially the loop was with only 10 repetitions (rep <= 10), and the anwer for p = 3 was almost correct, so I changed rep <= 20. And It gave me just the exact answer from my calculator. And then I tried with a higher number, 12, and the output again was inaccurate. So I ended raising rep <= 35. If I get the loop for higher repetitions I get "-nan", and if the input for p is too high it will be the same. So just have to see the pattern to know that the problem of inaccuracy will get back as I input higher numbers which is not the case because the output will be NaN if I input a high value.
Is it possible to solve it without higher level functions? just want to know if my program is ok for the level in which I am now...
#include <stdio.h>
int main()
{
float p; //the power for e
float power; //the copy of p for the loop
float e = 1; //the e number I wanna raise to the power of p
int x = 1; //the starting number for each factorial generation
float factorial = 1;
int rep = 1; //the repeater for the loop
printf( "Enter the power you want to raise: " );
scanf( "%f", &p );
power = p;
while ( rep <= 35) {
while ( x > 1) {
factorial *= x;
x--;
}
e += p / factorial;
//printf("\nthe value of p: %f", p); (TESTER)
//printf("\nthe value of factorial: %f", factorial); (TESTER)
p *= power; //the new value for p
rep++;
factorial = 1;
x = rep; //the new value for the next factorial to be generated
//printf("\n%f", e); (TESTER)
}
printf("%.3f", e);
return 0;
}
Sorry if I had syntax/orthography errors, I'm still learning the language.
Before we begin, let's write your original code as a function, with some clean-ups:
float exp_original(float x, int rep = 35)
{
float sum = 1.0f;
float power = 1.0f;
for (int i = 1; i <= rep; i++)
{
float factorial = 1.0f;
for (int j = 2; j <= i; j++)
factorial *= j;
power *= x;
sum += power / factorial;
}
return sum;
}
There were some unnecessary variables you used which were removed, but otherwise the procedure is the same: compute the factorial from scratch.
Let's look at the ratio between successive terms in the series:
We can thus simply multiply the current term by this expression to get the next term:
float exp_iterative(float x, int rep = 35)
{
float sum = 1.0f;
float term = 1.0f;
for (int i = 1; i <= rep; i++)
{
term *= x / i;
sum += term;
}
return sum;
}
Seems much simpler, but is it better? Comparison against the C-library exp function (which we assume to be maximally precise):
x exp (C) exp_orig exp_iter
-------------------------------------------
1 2.7182817 2.718282 2.718282
2 7.3890562 7.3890567 7.3890567
3 20.085537 20.085539 20.085539
4 54.598148 54.598152 54.598152
5 148.41316 148.41318 148.41316
6 403.4288 403.42871 403.42877
7 1096.6332 1096.6334 1096.6334
8 2980.958 2980.9583 2980.9587
9 8103.084 8103.083 8103.083
10 22026.465 22026.467 22026.465
11 59874.141 59874.148 59874.152
12 162754.8 162754.77 162754.78
13 442413.41 -nan(ind) 442413.38
14 1202604.3 -nan(ind) 1202603.5
15 3269017.3 -nan(ind) 3269007.3
16 8886111 -nan(ind) 8886009
17 24154952 -nan(ind) 24153986
18 65659968 -nan(ind) 65652048
19 1.784823e+08 -nan(ind) 1.7842389e+08
20 4.8516518e+08 -nan(ind) 4.8477536e+08
The two custom implementations are neck-and-neck in-terms of precision, until x = 13 where the original gives NaN. This is because the highest power term 13^35 = 9.7278604e+38 exceeds the maximum value FLT_MAX = 3.40282e+38. The accumulated term in the iterative version never reaches anywhere near the limit.
I recently started programming and I was doing some exercises when I bumped into one that said:
Write a program that can calculate an approximate value of the e constant with the formula e=1+1/1!+1/2!+1/3!+... using while and if if necessary. You cannot use do...while or for.
I wrote my code and I could almost swear the program needs two while loops, but, as you may be guessing, it doesn't work properly. Here's my code:
#include<stdio.h>
int main()
{
float number=3, factorial=1, constant=0, counter=3, variable=0;
float euler=0;
while(counter>1)
{
variable = number;
while(number>1)
{
factorial = factorial*number;
number--;
} // number is now 0, or that's what I think
constant = (1/factorial)+constant;
counter--;
variable = variable-1; // variable is still number?
number = variable; // to have a variable called number again?
}
euler = constant+1; // the 1 in the original formula...
printf("e = : %f\n", euler);
return 0;
}
It doesn't display the correct answer, hope you can help me. Thanks a lot!
Your iteration is too few times. Iterate more to get more accurate value.
You will have to initialize factorial in each loop to calculate factorial in this way.
You forgot to add 1/1!.
Try this:
#include<stdio.h>
int main(void)
{
float number=30, factorial=1, constant=0, counter=30, variable=0;
float euler=0;
while(counter>1)
{
variable=number;
factorial = 1;
while(number>1)
{
factorial=factorial*number;
number--;
}//number is now 1
constant=(1/factorial)+constant;
counter--;
variable=variable-1;
number=variable;
}
euler=constant+1+(1/1.f);//the 1 and 1/1! in the original formula...
printf("e = : %f\n", euler);
return 0;
}
As pointed by #MikeCAT, various coding errors.
As OP's iteration count was low: 3 resulting in low accuracy. As all the terms are eventually added to 1.0 (missed by OP), once a term plus 1.0 is still 1.0, it is about time to quit searching for smaller terms. Typically about 18 iterations with typical double.
When computing the sum of a series, a slightly more accurate answer is available by summing the smallest terms first, in this case, the last terms as done by OP. This can be done using a recursive summation to avoid lots of factorial recalculation.
double e_helper(unsigned n, double term) {
double next_term = term/n;
if (next_term + 1.0 == 1.0) return next_term;
return next_term + e_helper(n+1, next_term);
}
double e(void) {
return 1.0 + e_helper(1, 1.0);
}
#include <stdio.h>
#include <float.h>
#include <math.h>
int main(void) {
printf("%.*f\n", DBL_DECIMAL_DIG - 1, e());
printf("%.*f\n", DBL_DECIMAL_DIG - 1, exp(1));
puts("2.71828182845904523536028747135266249775724709369995...");
}
Output
2.7182818284590451
2.7182818284590451
2.71828182845904523536028747135266249775724709369995...
#include <stdio.h>
#include <math.h>
int main()
{
printf("e = : %.20lf\n", M_E );
return 0;
}
C math library have constant M_E as Euler's number. But, this may not be what you want.
Finding eulers constant 'e' with the formula e = 1 + 1/1! + 1 /2! ....
only using while loop
For beginners
#include <stdio.h>
int main (void) {
float n =5 , fact = 1 , f , x = 0 , e ,i ; //taking input or n as 5 ,our formula now is e = 1+ 1/1! + 1/2! + 1/3! + 1/4! + 1/5! ; as the formula depends upon the input value of n
while(n >=1 ) { /* We need to find factorial of n no of values, so keeping n in a loop starting with 5....1 , atm n is 5 */
f = n ; // let f = n , i.e, f = 5
fact = 1 ;
while(f >= 1 ){ //This while loops finds the factorial of current n value , ie. 5 ;
fact = fact * f ;
f -- ;
}
i = 1 / fact ; // i finds the 1/fact! of the formula
x = i + x ; // x = i + x ; where x = 0 ; , This eq adds all the 1/fact values , atm its adding 1/ 5 !
n-- ; // n decrements to 4 , and the loop repeats till n = 1 , and finally x has all the 1/factorial part of the eulers formula
}
//exiting all the loops since, we now have the values of all the 1/factorial,i.e x : part of the eulers formula
e = 1 + x ; // eulers e = 1 + x , where x represents all the addition of 1/factorial part of the eulers formula
printf ("e : %f",e ); //Finally printing e
return 0 ;
}
Output :
e : 2.716667
I've written some code to Integrate the function 5x^4 + 4x^3 + 3x^2 + 2x + 1.
#include<stdio.h>
#include<math.h>
float func(float x){
float a;
a = 5*pow(x,4) + 4*pow(x,3) + 3*pow(x,2) + 2*x +1;
return a;
}
int main(){
float numberOfXValues;
float a = 0; //lower limit
float b = 1; //upper limit
float numberOfStrips;
float stripSize;
float finalAnswer;
float sumFirstAndLast; //summation of first and last x value
while(1){
printf("Input number of X values:");
scanf("%f", &numberOfXValues);
numberOfStrips = numberOfXValues - 1;
stripSize = (b - a)/(numberOfStrips);
sumFirstAndLast = 0.5*func(a) + 0.5*func(b);
for (float z = stripSize; z < b; z += stripSize ){
sumFirstAndLast += func(z);
}
finalAnswer = sumFirstAndLast * stripSize;
printf("%f\n", finalAnswer);
}
return 0;
}
And it works for the majority of values, but the output for 13 and 20 is giving the wrong answer. I've looked through it a few times but can't see what could be causing this.
Input number of X values:10
5.039070
Input number of X values:11
5.031651
Input number of X values:12
5.026160
Input number of X values:13
6.271982
Input number of X values:14
5.018732
Input number of X values:15
5.016153
Input number of X values:16
5.014071
Input number of X values:17
5.012367
Input number of X values:18
5.010955
Input number of X values:19
5.009773
Input number of X values:20
5.798243
Input number of X values:21
5.007917
The problem is that in the exit condition of the inner loop, you compare two floating point numbers. After numberOfStrips iterations, it's not guaranteed that z == b because of floating point accuracy. It's entirely possible that z < b or z > b. In the z < b case, the loop it executed another time.
You should make numberOfStrips an integer and rewrite the loop like this:
float z = stripSize;
for (int i = 1; i < numberOfStrips; i++) {
sumFirstAndLast += func(z);
z += stripSize;
}
At a first glance this looks to precision and rounding issues of float.
Therefore change float to double.
For example on my machine I get 6.271982 for an input of 10 when using float while I get 5.021983 as result when using double.
Moreover you should use an epsilon in floating point comparisons.
Placing the line:
printf("%f, %d\n", z, z < b);
Inside the for loop will print the z values each iteration along with the loop condition result. The last output of this will be:
1.000000, 1
Which is pointing that we have already reached the right limit, but still performing the loop body. Literally it is thinking that 1.000 < 1.000. It can happen when working with float numbers, so in order to prevent it, consider looping on some integer number (numberOfXValues for example).