The teacher asks to remove the pi subtraction cycle in the main function. I don’t know how to write the program so that the correct results will come out for any values.
#include <stdio.h>
#include <math.h>
double sinus(double x);
int main(void) {
double a, x;
scanf("%le", & x);
a = x;
while (fabs(x) > 2 * (M_PI)) {
x = fabs(x) - 2 * (M_PI);
}
if (a > 0)
a = sinus(x);
else a = (-1) * sinus(x);
printf("%le", (double) a);
return 0;
}
double sinus(double x) {
double sum = 0, h, eps = 1.e-16;
int i = 2;
h = x;
do {
sum += h;
h *= -((x * x) / (i * (i + 1)));
i += 2;
}
while (fabs(h) > eps);
return sum;
return 0;
}
#include <stdio.h>
#include <math.h>
double sinus(double x);
int main(void)
{
double a,x;
scanf("%le",&x);
a=x;
x=fmod(fabs(x),2*(M_PI));
if(a>0)
a=sinus(x);
else a=(-1)*sinus(x);
printf("%le",(double)a);
return 0;}
double sinus(double x)
{
double sum=0, h, eps=1.e-16; int i=2;
h=x;
do{
sum+=h;
h*=-((x*x)/(i*(i+1)));
i+=2;}
while( fabs(h)>eps );
return sum;
return 0;
}
… how to write the program so that the correct results will come out for any values.
OP's loop is slow with large x and an infinfite loop with very large x:
while (fabs(x) > 2 * (M_PI)) {
x = fabs(x) - 2 * (M_PI);
}
A simple, though not high quality solution, is to use fmod() in the function itself. #Damien:
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
double sinus(double x) {
x = fmod(x, 2*M_PI); // Reduce to [-2*M_PI ... 2*M_PI]
...
Although function fmod() is not expected to inject any error, the problem is that M_PI (a rational number) is an approximation of π, (an irrational number). Using that value approximation injects error especially x near multiplies of π. This is likely OK for modest quality code.
Good range reduction is a problem as challenging as the trigonometric functions themselves.
See K.C. Ng's "ARGUMENT REDUCTION FOR HUGE ARGUMENTS: Good to the Last Bit" .
OP's sinus() should use additional range reduction and trigonometric properties to get x in range [-M_PI/4 ... M_PI/4] (example) before attempting the power series solution. Otherwise, convergence is slow and errors accumulate.
Related
Im stuck maybe someone here can help me plzzz :)
I did wrong program that calc from radian to degri
I need to build a program like you calc Sin(x) in radian mode in calculator
I put radian x like 1 in radian and it need to give me in radian mode the calc of sin(1)
Like if i put sin(1) it need to give me 0.8414
and i cant use sin() and all this only standart and need to use taylor to calc.
help plz :) :')
my wrong code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
double my_sin(double x);
/*my_sin func calc sin(x) from the main*/
double my_sin(double x){
double min_num = 0.000001;
double radian = x*(3.14/180);
double sol = radian;
int i;
int sign = 1;
int n;
int aseret = 1;
//Calc the solution if i <= 0.000001 it stop calc.
for(i=3;i <= min_num; i = i+2){
n = n * radian * radian;
sign = -(sign); //change the sign every round.
aseret = aseret * i * (i-1); //!3 = 3*2*1.
sol = sol + (pow(x,i)/aseret) *sign; // calc the solution.
}
return sol;
}
/*main func*/
int main()
{
double x = 0;
double result;
printf("please enter the number to check the SIN of it:");
scanf("%lf",&x);
result = my_sin(x);
printf("SIN(%f) = %f\n",x,result);
return 0;
}
Your main problem is that you are comparing the index i with the minimum value of the term. One consequence is that the loop stops immediately. It is the term x^i/i(i-1) which must be compared with the minimum value. As the series is alternating, the error at the end is lower than this minimum value.
It is also useles to perform the conversion to radian, as it seems you are entering a radian value.
Moreover, it is useless and inefficient to use pow() function to calculate x^i. Better to alculate this term iteratively.
Output:
please enter the number to check the SIN of it: 1
SIN(1.000000) = 0.841471
error = -1.59828e-010
Code:
#include <stdio.h>
#include <math.h>
double my_sin(double x){
double min_num = 0.000001;
int sign = 1;
double term = x;
double sol = term;
double x2 = x*x;
int i = 1;
//Calc the solution if term <= 0.000001 it stop calc.
do {
i += 2;
term *= x2 / (i * (i-1));
sign = -sign; //change the sign every round.
sol += term * sign;
} while (term > min_num);
return sol;
}
int main() {
double x;
printf("please enter the number to check the SIN of it: ");
scanf("%lf", &x);
double result = my_sin(x);
printf("SIN(%f) = %f\n", x, result);
double result_exact = sin(x);
double delta = result - result_exact;
printf ("error = %g\n", delta);
return 0;
}
You convert x to radians when it is already in radians.
Your loop condition is wrong, the loop terminates immediately and compares an integer with a double.
The variable n is uninitialised and the result of the expression it is used in is unused in any case.
Unnecessary headers included.
Change as per <<<<<< comments:
#include <stdio.h>
// #include <string.h> // <<<<<<<<<<<<<< REDUNDANT
// #include <ctype.h> // <<<<<<<<<<<<<< REDUNDANT
#include <math.h>
#define LIMIT 10 // <<<<<<<<<<<<<< ADD
double my_sin( double x );
/*my_sin func calc sin(x) from the main*/
double my_sin( double x )
{
// double min_num = 0.000001; // <<<<<<<<<<<<<< REMOVE
// double radian = x*(3.14/180); // <<<<<<<<<<<<<< REMOVE
double sol = x ; // <<<<<<<<<<<<<< CHANGE
// int i; // <<<<<<<<<<<<<< REMOVE
int sign = 1;
// int n = 0 ; // <<<<<<<<<<<<<< REMOVE - NOT USED
int aseret = 1;
//Calc the solution if i <= LIMIT it stop calc. // <<<<<<<<<<<<<< CHANGE
for( int i = 3; i <= LIMIT; i += 2 ) // <<<<<<<<<<<<<< CHANGE
{
// n = n * x * x; // <<<<<<<<<<<<<< REMOVE - RESULT NOT USED
sign = -(sign); //change the sign every round.
aseret = aseret * i * (i - 1); //!3 = 3*2*1.
sol = sol + (pow( x, i ) / aseret) * sign; // calc the solution.
}
return sol;
}
Second part of Q: Then solve the integral between 0 and y of (x^2)(e^(-x^2))dx=0.1 for y using bracketing and bisection.
Here's what I have done so far:
#include <stdio.h>
#include <math.h>
double f(double x, double y);
int main(void) {
int i, steps;
double a, b, y, h, m, lower, upper, x, simp, val;
/*
* Integrate (x^2)(e^(-x^2)) from 0 to y
*/
steps = 20000;
a = 0;
b = y;
h= (b-a)/steps;
/*
* now apply Simpson's rule. Note that the steps should be even.
*/
simp = -f(a, y);
x = a;
for (i =0; i < steps; i += 2) {
simp += 2.0*f(x,y)+4.0*f(x+h, y);
x += 2*h;
}
simp += f(b, y);
simp *= h/3.0;
/*
* print out the answer
*/
printf("The integral from 0 to y with respect to x by Simpson's Rule is %f\n", simp);
/*
* Now we need to bracket and bisect to find y
*/
lower = 0;
/*
* Lower bound is from turning point
*/
upper = 100;
/*
*Upper value given.
*/
while (upper - lower > 10E-10){
m = (lower + upper)/2;
val = f(m, y);
if (val >=0)
upper = m;
if (val <=0)
lower = m;
}
m = (lower + upper)/2;
printf("The value for y is: %lf\n", m);
return 0;
}
double f(double x, double y) {
return pow(x,2)*exp(pow(-x,2))-0.1;
}
Output: The integral from 0 to y with respect to x by Simpson's Rule is -0.000000
The value for y is: 0.302120
It runs but doesn't do exactly what I need it to do. I need to be able to continue working with the integral once I've used 0 and y as the limits. I can't do this. Then continue on and solve for y. It gives me a value for y but is not the same one I get if i solve using online calculators. Also, the output gave zero for the integral even when I changed the equation to be integrated to x^2. Can anyone help explain in as simple terms as possible?
Here I have a little problem. Create something from this formula:
This is what I have, but it doesn't work. Franky, I really don't understand how it should work.. I tried to code it with some bad instructions. N is number of iteration and parts of fraction. I think it leads somehow to recursion but don't know how.
Thanks for any help.
double contFragLog(double z, int n)
{
double cf = 2 * z;
double a, b;
for(int i = n; i >= 1; i--)
{
a = sq(i - 2) * sq(z);
b = i + i - 2;
cf = a / (b - cf);
}
return (1 + cf) / (1 - cf);
}
The central loop is messed. Reworked. Recursion not needed either. Just compute the deepest term first and work your way out.
double contFragLog(double z, int n) {
double zz = z*z;
double cf = 1.0; // Important this is not 0
for (int i = n; i >= 1; i--) {
cf = (2*i -1) - i*i*zz/cf;
}
return 2*z/cf;
}
void testln(double z) {
double y = log((1+z)/(1-z));
double y2 = contFragLog(z, 8);
printf("%e %e %e\n", z, y, y2);
}
int main() {
testln(0.2);
testln(0.5);
testln(0.8);
return 0;
}
Output
2.000000e-01 4.054651e-01 4.054651e-01
5.000000e-01 1.098612e+00 1.098612e+00
8.000000e-01 2.197225e+00 2.196987e+00
[Edit]
As prompted by #MicroVirus, I found double cf = 1.88*n - 0.95; to work better than double cf = 1.0;. As more terms are used, the value used makes less difference, yet a good initial cf requires fewer terms for a good answer, especially for |z| near 0.5. More work could be done here as I studied 0 < z <= 0.5. #MicroVirus suggestion of 2*n+1 may be close to my suggestion due to an off-by-one of what n is.
This is based on reverse computing and noting the value of CF[n] as n increased. I was surprised the "seed" value did not appear to be some nice integer equation.
Here's a solution to the problem that does use recursion (if anyone is interested):
#include <math.h>
#include <stdio.h>
/* `i` is the iteration of the recursion and `n` is
just for testing when we should end. 'zz' is z^2 */
double recursion (double zz, int i, int n) {
if (!n)
return 1;
return 2 * i - 1 - i * i * zz / recursion (zz, i + 1, --n);
}
double contFragLog (double z, int n) {
return 2 * z / recursion (z * z, 1, n);
}
void testln(double z) {
double y = log((1+z)/(1-z));
double y2 = contFragLog(z, 8);
printf("%e %e %e\n", z, y, y2);
}
int main() {
testln(0.2);
testln(0.5);
testln(0.8);
return 0;
}
The output is identical to the solution above:
2.000000e-01 4.054651e-01 4.054651e-01
5.000000e-01 1.098612e+00 1.098612e+00
8.000000e-01 2.197225e+00 2.196987e+00
How is the fmod function implemented?
I tried the following:
#include <stdio.h>
#include <math.h>
float floatMod(float a, float b)
{
return (a/b - floor(a/b));
}
int main()
{
printf("%f\n", fmod(18.5,4.2));
printf("%f\n", floatMod(18.5,4.2));
}
But the output is not the same...
Your fmod function should be:
float floatMod(float a, float b)
{
return (a - b * floor(a / b));
}
LIVE DEMO
UPDATE 7-Feb-2020
As pointed out by #s3cur3 et al in the comments below, the implementation above does not give correct results (as in matching the standard library fmod() function) when the first argument is negative. Using the definition in this answer a more correct implementation would be:
float floatMod(float a, float b)
{
return a - (round(a / b) * b);
}
LIVE DEMO
Apparently the update is broken too (see comment from #Bernard below) - I would delete the answer but it's been accepted, so I'll try and get back to it and fix it in the near future.
A correct implementation of fmod function in C/C++ is:
#include <iostream>
using namespace std;
#include <math.h> //for trunc()
double MyFmod(double x, double y) {
return x - trunc(x / y) * y;
}
//test it
int main()
{
double values[13] = {-10.9, -10.5, -10.4, -0.9, -0.5, -0.1, 0, 0.1, 0.5, 0.9, 10.4, 10.5, 10.9};
for (size_t i = 0; i < 12; ++i)
cout << fmod(values[i], 3.0) <<" "<< MyFmod(values[i], 3.0) << endl;
for (size_t i = 0; i < 12; ++i)
cout << fmod(values[i], -3.0) <<" "<< MyFmod(values[i], -3.0) << endl;
return 0;
}
A correct implementation of fmod function in Java is:
//trunc() implementation in Java:
double truncate(double x) {
return x < 0 ? -Math.floor(-x) : Math.floor(x);
//or return x < 0 ? Math.ceil(x) : Math.floor(x);
}
double MyFmod(double x, double y) {
return x - truncate(x / y) * y;
}
One also could use fma instruction to improve precision (although this will work correctly only when result of trunc(x/y) is computed exactly):
C/C++: fma(trunc(x / y), -y, x);
Java: Math.fma(truncate(x / y), -y, x);
Note: When the accuracy of double is not enough, all the above implementations are probably inferior to the compiler's math library. In my compiler, std::fmod(1e19, 3) computes 1.0 (accurate result), while MyFmod with same arguments, returns -512.
I need to write my own asin() function without math.h library with the use of Taylor series. It works fine for numbers between <-0.98;0.98> but when I am close to limits it stops with 1604 iterations and therefore is inaccurate.
I don't know how to make it more accurete. Any suggestions are very appreciated!
The code is following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define EPS 0.000000000001
double my_arcsin(double x)
{
long double a, an, b, bn;
a = an = 1.0;
b = bn = 2.0;
long double n = 3.0;
double xn;
double xs = x;
double xp = x;
int iterace = 0;
xn = xs + (a/b) * (my_pow(xp,n) / n);
while (my_abs(xn - xs) >= EPS)
{
n += 2.0;
an += 2.0;
bn += 2.0;
a = a * an;
b = b * bn;
xs = xn;
xn = xs + (a/b) * (my_pow(xp,n) / n);
iterace++;
}
//printf("%d\n", iterace);
return xn;
}
int main(int argc, char* argv[])
{
double x = 0.0;
if (argc > 2)
x = strtod(argv[2], NULL);
if (strcmp(argv[1], "--asin") == 0)
{
if (x < -1 || x > 1)
printf("nan\n");
else
{
printf("%.10e\n", my_arcsin(x));
//printf("%.10e\n", asin(x));
}
return 0;
}
}
And also a short list of my values and expected ones:
My values Expected values my_asin(x)
5.2359877560e-01 5.2359877560e-01 0.5
1.5567132089e+00 1.5707963268e+00 1 //problem
1.4292568534e+00 1.4292568535e+00 0.99 //problem
1.1197695150e+00 1.1197695150e+00 0.9
1.2532358975e+00 1.2532358975e+00 0.95
Even though the convergence radius of the series expansion you are using is 1, therefore the series will eventually converge for -1 < x < 1, convergence is indeed painfully slow close to the limits of this interval. The solution is to somehow avoid these parts of the interval.
I suggest that you
use your original algorithm for |x| <= 1/sqrt(2),
use the identity arcsin(x) = pi/2 - arcsin(sqrt(1-x^2)) for 1/sqrt(2) < x <= 1.0,
use the identity arcsin(x) = -pi/2 + arcsin(sqrt(1-x^2)) for -1.0 <= x < -1/sqrt(2).
This way you can transform your input x into [-1/sqrt(2),1/sqrt(2)], where convergence is relatively fast.
PLEASE NOTICE: In this case I strongly recommend #Bence's method, since you can't expect a slowly convergent method with low data accuracy to obtain arbitrary precision.
However I'm willing to show you how to improve the result using your current algorithm.
The main problem is that a and b grows too fast and soon become inf (after merely about 150 iterations). Another similar problem is my_pow(xp,n) grows fast when n grows, however this doesn't matter much in this very case since we could assume the input data goes inside the range of [-1, 1].
So I've just changed the method you deal with a/b by introducing ab_ratio, see my edited code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define EPS 0.000000000001
#include <math.h>
#define my_pow powl
#define my_abs fabsl
double my_arcsin(double x)
{
#if 0
long double a, an, b, bn;
a = an = 1.0;
b = bn = 2.0;
#endif
unsigned long _n = 0;
long double ab_ratio = 0.5;
long double n = 3.0;
long double xn;
long double xs = x;
long double xp = x;
int iterace = 0;
xn = xs + ab_ratio * (my_pow(xp,n) / n);
long double step = EPS;
#if 0
while (my_abs(step) >= EPS)
#else
while (1) /* manually stop it */
#endif
{
n += 2.0;
#if 0
an += 2.0;
bn += 2.0;
a = a * an;
b = b * bn;
#endif
_n += 1;
ab_ratio *= (1.0 + 2.0 * _n) / (2.0 + 2.0 * _n);
xs = xn;
step = ab_ratio * (my_pow(xp,n) / n);
xn = xs + step;
iterace++;
if (_n % 10000000 == 0)
printf("%lu %.10g %g %g %g %g\n", _n, (double)xn, (double)ab_ratio, (double)step, (double)xn, (double)my_pow(xp, n));
}
//printf("%d\n", iterace);
return xn;
}
int main(int argc, char* argv[])
{
double x = 0.0;
if (argc > 2)
x = strtod(argv[2], NULL);
if (strcmp(argv[1], "--asin") == 0)
{
if (x < -1 || x > 1)
printf("nan\n");
else
{
printf("%.10e\n", my_arcsin(x));
//printf("%.10e\n", asin(x));
}
return 0;
}
}
For 0.99 (and even 0.9999999) it soon gives correct results with more than 10 significant digits. However it gets slow when getting near to 1.
Actually the process has been running for nearly 12 minutes on my laptop calculating --asin 1, and the current result is 1.570786871 after 3560000000 iterations.
UPDATED: It's been 1h51min now and the result 1.570792915 and iteration count is 27340000000.