I can't understand how the following program creates a natural logarithm (I wonder if it does). I found it on a blog. If it does not create a natural logarithm how would I make one?
void main()
{
int x,i,j;
float sum=0,power=1;
printf("enter x for sum upto 7th term: ");
scanf("%d",&x);
for(i=1;i<=6;i++)
{
power=1;
for(j=0;j<=i;j++)
{
power = power * ((x-1.0)/2.0);
}
sum = (1.0/2) * power + sum;
}
sum=sum + (float)(x-1.0)/x;
printf("%f",sum);
}
The program might be trying to calculate the natural logarithm, but it has lots of problems. Corrections below keeping the OP style
The formula for ln(x) when (x > 0.5) follows
ln(x) = (x-1)/x + (1/2)((x-1)/x)^2 + (1/3)((x-1)/x)^3 + ...
void main() {
int i, j;
float sum = 0.0f;
float power;
float x;
printf("enter x for sum up to 7th term: ");
scanf("%f", &x); // let x be a float rather than limited to int
for (i = 1; i <= 7; i++) { // do all 7 terms here
power = 1.0f;
for (j = 0; j < i; j++) {
power = power * ((x - 1.0f) / x); // need to /x not 2.0
}
sum += (1.0f / i) * power; // need to /i not 2.0
}
//sum = sum + (float) (x - 1.0f) / x; not needed as done in above 1st iteration
printf("ln(%f) = \n%f\n%lf\n", x, sum, log(x));
}
"Taylor Series Centered at 1" in the below link appears wrong as I suspect its terms should have alternating signs.
http://math2.org/math/expansion/log.htm
Related
#include <stdio.h>
#include <math.h>
const int TERMS = 7;
const float PI = 3.14159265358979;
int fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += pow(-1, n) * pow(rad, (2 * n) + 1)/ fact((2 * n) + 1);
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
The code above was implemented to compute sine and cosine using Taylor series.
I tried testing the code and it works fine for sine(120).
I am getting wrong answers for sine(240) and sine(300).
Can anyone help me find out why those errors occur?
You should calculate the functions in the first quadrant only [0, pi/2). Exploit the properties of the functions to get the values for other angles. For instance, for values of x between [pi/2, pi), sin(x) can be calculated by sin(pi - x).
The sine of 120 degrees, which is 40 past 90 degrees, is the same as 50 degrees: 40 degrees before 90. Sine starts at 0, then rises toward 1 at 90 degrees, and then falls again in a mirror image to zero at 180.
The negative sine values from pi to 2pi are just -sin(x - pi). I'd handle everything by this recursive definition:
sin(x):
cases x of:
[0, pi/2) -> calculate (Taylor or whatever)
[pi/2, pi) -> sin(pi - x)
[pi/2, 2pi) -> -sin(x - pi)
< 0 -> sin(-x)
>= 2pi -> sin(fmod(x, 2pi)) // floating-point remainder
A similar approach for cos, using identity cases appropriate for it.
The key point is:
TERMS is too small to have proper precision. And if you increase TERMS, you have to change fact implementation as it will likely overflow when working with int.
I would use a sign to toggle the -1 power instead of pow(-1,n) overkill.
Then use double for the value of PI to avoid losing too many decimals
Then for high values, you should increase the number of terms (this is the main issue). using long long for your factorial method or you get overflow. I set 10 and get proper results:
#include <stdio.h>
#include <math.h>
const int TERMS = 10;
const double PI = 3.14159265358979;
long long fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double powd(double x,int n) {
return n<= 0 ? 1 : x * powd(x,n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += sign * powd(rad, (2 * n) + 1)/ fact((2 * n) + 1);
sign = -sign;
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += sign * powd(rad, 2 * n) / fact(2 * n);
sign = -sign;
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
result:
240
sine(240)= -0.866026
cosine(240)= -0.500001
Notes:
my recusive implementation of pow using successive multiplications is probably not needed, since we're dealing with floating point. It introduces accumulation error if n is big.
fact could be using floating point to allow bigger numbers and better precision. Actually I suggested long long but it would be better not to assume that the size will be enough. Better use standard type like int64_t for that.
fact and pow results could be pre-computed/hardcoded as well. This would save computation time.
const double TERMS = 14;
const double PI = 3.14159265358979;
double fact(double n) {return n <= 0.0 ? 1 : n * fact(n - 1);}
double sine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad, 2 * PI);
double sin = 0;
for (double n = 0; n < TERMS; n++)
sin += pow(-1, n) * pow(rad, (2 * n) + 1) / fact((2 * n) + 1);
return sin;
}
double cosine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad,2*PI);
double cos = 0;
for (double n = 0; n < TERMS; n++)
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
return cos;
}
int main()
{
printf("sine(240)= %lf\n", sine(240));
printf("cosine(300)= %lf\n",cosine(300));
}
I've been working on a program that calculates sin(x), cos(x), and exp(x) without using math.h and compares them to the library values of their functions. I've been forbidden from actually using the basic power(x, n) and fact(n) functions. The only hint is that I have to do division before doing multiplication when combining the functions into one.
double power(double x, int n)
{
int i;
double prod=1.;
for(i=0;i<n;i++){
prod = prod*x;
}
return prod;
}
double fact(int n)
{
int i;
double prod=1.;
for(i=1;i<=n;i++) {
prod = prod*i;
}
return prod;
}
My idea is to somehow nest the for-loops together, and piecemeal the Taylor Expansion formula for each iteration of the loop, but I haven't had luck actually combining the two.
Any help or hint would be appreciated on how to combine these.
The other aspect of the program that confuses me is that there can only be a single input of X per iteration of the program, and therefore no dynamically defined 'n' for the loops.
Use Taylor series for the exponential:
e^x = 1 + x/1! + x^2/2! + x^3/3!...
and using Euler after that you can calculate sinx and cosx.
The trick is to look at the changes between each successive term in the Taylor series expansion. Let's start with ex:
e^x = 1 + x + x^2/2! + x^3/3! + x^4/4! + x^5/5! ...
Notice that each term is x / n times the prior term, where n is the term number. So start with a term of 1, then multiply by the above expression to get the next term.
That gives you the following implementation:
double etox(double x)
{
long double sum = 0;
// term starts at 1
long double term = 1;
// term number
int i = 1;
// continue until the term is below the precision of the current sum
while (sum + term != sum) {
sum += term;
// new term is x/i times the prior term, where i is the term number
term *= (long double)x / i;
i++;
}
return sum;
}
Note that with this implementation, you'll get some degree of error in the least significant digits. If you start adding from a higher term number and work your way back, this can be avoided.
Similarly for sin(x) and cos(x):
sin(x) = x - x^3/3! + x^5/5! - x^7/7! + x^9/9! ...
cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! + x^8/8! ...
Each term is - (x*x) / ((2*n)*((2*n)-1)) times the prior term, where n is the term number.
I'll leave the the implementation of these two as an exercise for the reader.
Part of this comes from my answer for doing this in MIPS assembly: Taylor Series in MIPS assembly
You can do Taylor series on the fly without having to call sub-functions. In the series, each term can be calculated from the previous term in a loop. (i.e. no need to call fact and/or pow repeatedly, where each starts from the beginning). See https://en.wikipedia.org/wiki/Taylor_series
Anyway, here's code for sin and cos:
// mipstaylor/mipstaylor -- fast sine/cosine calculation
#include <stdio.h>
#include <math.h>
#define ITERMAX 10
// qcos -- calculate cosine
double
qcos(double x)
{
int iteridx;
double x2;
double cur;
int neg;
double xpow;
double n2m1;
double nfac;
double sum;
// square of x
x2 = x * x;
// values for initial terms where n==0:
xpow = 1.0;
n2m1 = 0.0;
nfac = 1.0;
neg = 1;
sum = 0.0;
iteridx = 0;
// NOTES:
// (1) with the setup above, we can just use the loop without any special
// casing
while (1) {
// calculate current value
cur = xpow / nfac;
// apply it to sum
if (neg < 0)
sum -= cur;
else
sum += cur;
// bug out when done
if (++iteridx >= ITERMAX)
break;
// now calculate intermediate values for _next_ sum term
// get _next_ power term
xpow *= x2;
// go from factorial(2n) to factorial(2n+1)
n2m1 += 1.0;
nfac *= n2m1;
// now get factorial(2n+1+1)
n2m1 += 1.0;
nfac *= n2m1;
// flip sign
neg = -neg;
}
return sum;
}
// qsin -- calculate sine
double
qsin(double x)
{
int iteridx;
double x2;
double cur;
int neg;
double xpow;
double n2m1;
double nfac;
double sum;
// square of x
x2 = x * x;
// values for initial terms where n==0:
xpow = x;
n2m1 = 1.0;
nfac = 1.0;
neg = 1;
sum = 0.0;
iteridx = 0;
// NOTES:
// (1) with the setup above, we can just use the loop without any special
// casing
while (1) {
// calculate current value
cur = xpow / nfac;
// apply it to sum
if (neg < 0)
sum -= cur;
else
sum += cur;
// bug out when done
if (++iteridx >= ITERMAX)
break;
// now calculate intermediate values for _next_ sum term
// get _next_ power term
xpow *= x2;
// go from factorial(2n+1) to factorial(2n+1+1)
n2m1 += 1.0;
nfac *= n2m1;
// now get factorial(2n+1+1+1)
n2m1 += 1.0;
nfac *= n2m1;
// flip sign
neg = -neg;
}
return sum;
}
// testfnc -- test function
void
testfnc(int typ,const char *sym)
{
double (*efnc)(double);
double (*qfnc)(double);
double vale;
double valq;
double x;
double dif;
int iter;
switch (typ) {
case 0:
efnc = cos;
qfnc = qcos;
break;
case 1:
efnc = sin;
qfnc = qsin;
break;
default:
efnc = NULL;
qfnc = NULL;
break;
}
iter = 0;
for (x = 0.0; x <= M_PI_2; x += 0.001, ++iter) {
vale = efnc(x);
valq = qfnc(x);
dif = vale - valq;
dif = fabs(dif);
printf("%s: %d x=%.15f e=%.15f q=%.15f dif=%.15f %s\n",
sym,iter,x,vale,valq,dif,(dif < 1e-14) ? "PASS" : "FAIL");
}
}
// main -- main program
int
main(int argc,char **argv)
{
testfnc(0,"cos");
testfnc(1,"sin");
return 0;
}
I am making simple calculator and it is e^x function part.
it works for positive number, but it doesn't for negative x.
How can I make it works for negative x too?`
double calculateEx(double x) {
double beforeResult = 1, afterResult = 1, term = 1, error = 1, i = 1, j;
while (error > 0.001) {
afterResult = beforeResult;
for (j = 1; j <= i; j++) {
term *= x;
}
term /= fact(i);
afterResult += term;
error = (afterResult - beforeResult) / afterResult;
if (error < 0) error * -1;
error *= 100;
beforeResult = afterResult;
term = 1;
i++;
}
return beforeResult;
}
double fact (double num) {
int i, j;
double total = 1;
for (i = 2; i <= num; i++) {
total = total * i;
}
return total;
}
When computing exponent via Taylor serie
exp(x) = 1 + x / 1 + x**2/2! + ... + x**n/n!
you don't want any factorials, please, notice that if n-1th term is
t(n-1) = x**(n-1)/(n-1)!
then
t(n) = x**n/n! = t(n-1) * x / n;
That's why all you have to implement is:
double calculateEx(double x) {
double term = 1.0;
double result = term;
/*
the only trick is that term can be positive as well as negative;
we should either use abs in any implementation or putr two conditions
*/
for (int n = 1; term > 0.001 || term < -0.001; ++n) {
term = term * x / n;
result += term;
}
return result;
}
OK, as I wrote in a comment above, I'd use <math.h> if at all possible, but since you asked the question:
To make it work with negative numbers, if x is negative, consider what happens if you negate it.
You can get rid of the factorial function by storing a table of factorials. You won't need that many elements.
I have to write a program that will find a square root using the while loop. I was given this new_guess = (old_guess + (n / old_guess)) / 2.0; but I dont fully understand what to do with it, this is what I have:
int main(void)
{
double n, x, new_guess, old_guess, value;
printf("Enter a number:");
scanf("%lf", &n);
x = 1.00000;
while (new_guess >= n) {
new_guess = (old_guess + (n / old_guess)) / 2.0;
printf("%10.5lf\n", fabs(new_guess));
}
return 0;
}
x is the initial guess. Im really lost on how to do it. This is C also. I know its really wrong but I really dont understand how to make it start because when I enter a number it just stop right away.
Your program has undefined behavior because both new_guess and old_guess are uninitialized when you enter the loop.
The condition is also incorrect: you should stop when new_guess == old_guess or after a reasonable maximum number of iterations.
Here is a modified version:
#include <math.h>
#include <stdio.h>
int main(void) {
double n, x;
int i;
printf("Enter numbers:");
while (scanf("%lf", &n) == 1 && n >= 0.0) {
x = 1.0;
/* Using a while loop as per the assignment...
* a for loop would be much less error prone.
*/
i = 0;
while (i < 1024) {
double new_guess = (x + (n / x)) / 2.0;
if (new_guess == x)
break;
x = new_guess;
i++;
}
printf("%g: %.17g, %d iterations, diff=%.17g\n",
n, x, i, sqrt(n) - x);
}
return 0;
}
Given the start value, the number of iterations grows with the size of n, exceeding 500 for very large numbers, but usually less than 10 for small numbers. Note also that this algorithm fails for n = 0.0.
Here is a slightly more elaborate method, using the floating point break up and combine functions double frexp(double value, int *exp); and double ldexp(double x, int exp);. These functions do not perform any calculation but allow for a much better starting point, achieving completion in 4 or 5 iterations for most values:
#include <math.h>
#include <stdio.h>
int main(void) {
double n, x;
int i, exp;
printf("Enter a number:");
while (scanf("%lf", &n) == 1 && n >= 0.0) {
if (n == 0) {
x = 0.0;
i = 0;
} else {
frexp(n, &exp);
x = ldexp(1.0, exp / 2);
for (i = 0; i < 1024; i++) {
double new_guess = (x + (n / x)) / 2.0;
if (new_guess == x)
break;
x = new_guess;
}
}
printf("%g: %.17g, %d iterations, diff=%.17g\n",
n, x, i, sqrt(n) - x);
}
return 0;
}
It took me a while conceptual to grasp how to code a loop that would calculate a given series in which a factorial was used.
I coded it--then my teacher told us we had to use a single for loop. I can't seem to grasp how to do something like this. It doesn't make sense how you'd keep the running total of the products across several numbers.
Here is my code; which includes a nested for loop. I really appreciate any and all help.
int main() {
/*init variables*/
int N; //number of terms
float NUMER, DENOM = 1;
float FRAC, sum = 0, x;
/*asks user for value of N*/
printf("Input number of terms: ");
scanf("%i", &N);
/*asks user for value of x*/
printf("Input value of x: ");
scanf("%f", &x);
for (int n = 0; n <= N; n++) {
NUMER = (pow(x, n)); //calculates numerator
for (int fac = 1; fac <= n; fac++) { //calculates factorial using for loop
DENOM = n * fac;
}
if (DENOM <= 0)
printf("\n\nError, dividing by zero.\n\n"); //this is for debugging purposes; disregard
FRAC = NUMER / DENOM; //calculates fraction
sum += FRAC; //running sum of series
}
printf("\nSum of the series is %.1f\n\n", sum); //prints sum of series
return 0;
You want DENOM = n!, so you can just start with DENOM = 1
and update the value inside the loop:
DENOM = 1;
for (int n = 0; n <= N; n++) {
NUMER = (pow(x, n)); //calculates numerator
FRAC = NUMER / DENOM; //calculates fraction
sum += FRAC; //running sum of series
DENOM *= n+1;
}
Instead of computing x^n and n! each time through the outer loop, you can initialize
the quotient to 1.0 before the outer loop, then on each pass through the outer loop,
multiply by x/n to get the next term in the series. This will avoid the need
to call pow(x,n), and use an inner loop to calculate the factorial, each pass through
the outer loop.
If you think about what you would do if calculating a factorial by hand, I think you can figure out how to code this pretty easily.
Lets say you are trying to calculate 11!. Well, you would start at 11, and them multiply by 10. Now you have 110. Now multiply by 9. You have 990. Now multiply by 8...
As you can see, the 11, 10, 9, 8... series is what your for loop is going to be. Just keep your 'current answer' in a variable and keep multiplying it by the number provided by your for loop.
That seems...complicated. Terseness is or can be your friend :D
I don't think it needs to be much more complicated than:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char* argv[] )
{
double limit = 10 ; // how far do we want to go?
double x = 2 ; // some value for X
double xn = 1 ; // by definition, for all X, X^0 is 1
double nf = 1 ; // by convention, 0! is 1
double value = 0 ;
double sum = 0 ;
double n = 0 ;
while ( n < limit )
{
value = xn / nf ; // compute the next element of the series
sum += value ; // add that to the accumulator
xn *= x ; // compute the *next* value for X^n
nf *= (++n) ; // compute the *next* value for N!
}
return 0;
}
You get a more stable answer working the loop in reverse. Many infinite sums numerically come out better summing the smallest terms together first.
f(x,n) = x^0/0! + x^1/1! + x^2/2! + ... + x^n/n!
Let the sum be S(x,n) = x/n
Let the sum of the 2 last terms be S(x,n-1) = x/(n-1) + x/(n-1)*S(x,n)
Let the sum of the 3 last terms be S(x,n-2) = x/(n-2) + x/(n-2)*S(x,n-1)
...
Let the sum of the N last terms be S(x,1) = x/(1) + x/(1)*S(x,1)
double e(double x, unsigned n) {
double sum = 0.0;
while (n > 0) {
sum = x*(1 + sum)/n;
n--;
}
sum += 1.0; // The zero term
return sum;
}
Notice that even if n is large like 1000, and the mathematical answer < DBL_MAX, this loop does not run into floating point overflow so easily.
[edit] But if code must be done in a forward loop, the below calculates each term not as separate products that may overflow, but a unified computation.
double e_forward(double x, unsigned n) {
double sum = 1.0;
double term = 1.0;
for (unsigned i = 1; i <= n; i++) {
term *= x / i;
sum += term;
}
return sum;
}