In the following code, I want to replace the termination condition to: if the ratio of guess square and x is close to 1, while loop should terminate. I tried various expressions, but none run the code properly. any suggestion?
# include<stdio.h>
float absolute(float x)
{
if (x < 0)
x = -x;
return x;
}
float square(float x)
{
float guess = 1;
while(absolute(guess*guess - x) >= 0.0001 )
guess = ((x/guess) + guess) / 2;
return guess;
}
int main(void)
{
printf("square root of 2 is %f\n", square(2));
printf("square root of 3 is %f\n", square(3));
return 0;
}
hit the answer: while statement should be like this:
while ( absoluteValue((guess * guess) / x - 1.0) >= 0.0001 )
# include<stdio.h>
double sq_root(double x)
{
double rt = 1, ort = 0;
while(ort!=rt)
{
ort = rt;
rt = ((x/rt) + rt) / 2;
}
return rt;
}
int main(void)
{
int i;
for(i = 2; i<1001; i++) printf("square root of %d is %f\n",i, sq_root(i));
return 0;
}
if the ratio of guess square and x is close to 1
Then why are you subtracting? Use ratio operator:
while(absolute( (guess*guess) / x - 1) >= 0.0001 )
It's possible you can't reach that guess*guess will be enough close to x; imagine e.g. sqrt of 2e38 - every approximation will be no closer than ~1e31 and your exit condition won't ever succeed.
The variant good for all cases is that stopping for this method occur when guess stops to change. So you would write something like
prev_guess = 0; // any initial value is ok
while (guess != prev_guess) {
...
prev_guess = guess;
}
at least it shall work for any IEEE754-compatible implementation not reaching overflow or underflow.
Also you can compare guess and prev_guess for difference (as soon as the goal is usually to match enough accuracy of root, not the value squared back).
Related
One of my C assignments was it to write an approximation of arctan(x) in the language C. The equation which I should base it on is
arctan(x)=\sum {k=0}^{\infty }(-1)^{k} \tfrac{x^{2k+1}}{2k+1}
In addition x is only defined as -1<=x<=1.
Here is my code.
#include <stdio.h>
#include <math.h>
double main(void) {
double x=1;
double k;
double sum;
double sum_old;
int count;
double pw(double y, double n) {
double i;
double number = 1;
for (i = 0; i < n; i++) {
number *= y;
}
return(number);
}
double fc (double y) {
double i;
double number = 1;
for (i = 1; i <= y; i++){
number *= i;
}
return(number);
}
if(x >= (-1) && x <= 1) {
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
printf("My result is: %.17lf\n",sum);
printf("atan(%f) is: %.17f\n", x, atan(x));
printf("My result minus atan(x) = %.17lf\n", sum - atan(x));
} else {
printf("x is not defined. Please choose an x in the intervall [-1, 1]\n");
}
return 0;
}
It seemingly works fine with every value, except value 1 and -1. If x=1, then the output ends with:
...
7207 || 0.78543285189457468
7208 || 0.78536
Whereas the output should look more like this. In this case x=0.5.
25 || 0.46364760900080587
26 || 0.46364760900080587
My result is: 0.46364760900080587
atan(0.500000) is: 0.46364760900080609
My result minus atan(x) atan(x) = -0.00000000000000022
How can I improve my code so that it can run with x=1 and x=-1.
Thanks in advance.
PS: I use my own created pw() function instead of pow(), because I wanted to bybass the restriction of not using pow() as we didn't had that in our lectures yet.
PPS: I'd appreciate any advice as to how to improve my code.
In each iteration, you add (-1)k • x2k+1 / (2k+1), and you stop when there is no change to the sum.
If this were calculated with ideal arithmetic (exact, infinitely precise arithmetic), it would never stop for non-zero x, since you are always changing the sum. When calculating with fixed-precision arithmetic, it stops when the term is so small it does not change the sum because of the limited precision.
When |x| is less than one by any significant amount, this comes quickly because x2k+1 gets smaller. When |x| is one, the term becomes just 1 / (2k+1), which gets smaller very slowly. Not until k is around 253 would the sum stop changing.
You might consider changing your stopping condition to be when sum has not changed from sum_old very much rather than when it has not changed at all.
if(x >= (-1) && x <= 1) {
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
Comparing doubles can be tricky. The conventional way to compare doubles is to test within epsilon. There should be an epsilon value defined somewhere, but for your purposes how many digits are enough to approximate? If you only need like 3 or 4 digits you can instead have
#define EPSILON 0.0001 //make this however precise you need to approximate.
if(x >= (-1) && x <= 1) {
for(k=0; fabs(sum - sum_old) > EPSILON; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
If the issue is that -1,1 iterate too many times either reduce the precision or increase the step per iteration. I am not sure that is what you're asking though, please clarify.
I think the cause of this is for a mathematical reason rather than a programming one.
Away from the little mistakes and adjustments that you should do to your code, putting x = 1 in the infinite series of arctan, is a boundary condition:
In this series, we add a negative value to a positive value then a negative value. This means the sum will be increasing, decreasing, increasing, ... and this will make some difference each iteration. This difference will be smaller until the preciseness of double won't catch it, so the program will stop and give us the value.
But in the sum equation. When we set z = 1 and n goes from 0 to ∞, this will make this term (-1^n) equal to 1 in one time and -1 in the next iteration. Also,
the value of the z-term will be one and the denominator value when n approaches infinity will = ∞ .
So the sum several iterations will be like +1/∞ -1/∞ +1/∞ -1/∞ ... (where ∞ here represents a big number). That way the series will not reach a specific number. This is because z = 1 is a boundary in this equation. And that is causing infinite iterations in your solution without reaching a number.
If you need to calculate arctan(1) I think you should use this formula:
All formulas are from this Wikipedia article.
Here is some modifications that make your code more compact and has less errors:
#include <stdio.h>
#include <math.h>
#define x 0.5 //here x is much easier to change
double pw(double, double); //declaration of the function should be done
int main() { //the default return type of main is int.
double k;
double sum = 0 ; //you should initiate your variables.
double sum_old = 1 ; //=1 only to pass the for condition first time.
//you don't need to define counter here
if(x < -1 || x > 1){
printf("x is not defined. Please choose an x in the interval [-1, 1]\n");
return 0;
}
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
printf("%.0f || %.17lf\n", k, sum);
}
printf("My result is: %.17lf\n",sum);
printf("atan(%f) is: %.17f\n", x, atan(x));
printf("My result minus atan(x) = %.17lf\n", sum - atan(x));
return 0;
}
double pw(double y, double n) { //functions should be declared out of the main function
double i;
double number = 1;
for (i = 0; i < n; i++) {
number *= y;
}
return(number);
}
double fc (double y) {
double i;
double number = 1;
for (i = 1; i <= y; i++){
number *= i;
}
return(number);
}
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;
}
I've been following the guide my prof gave us, but I just can't find where I went wrong. I've also been going through some other questions about implementing the Taylor Series in C.
Just assume that RaiseTo(raise a number to the power of x) is there.
double factorial (int n)
{
int fact = 1,
flag;
for (flag = 1; flag <= n; flag++)
{
fact *= flag;
}
return flag;
}
double sine (double rad)
{
int flag_2,
plusOrMinus2 = 0; //1 for plus, 0 for minus
double sin,
val2 = rad,
radRaisedToX2,
terms;
terms = NUMBER_OF_TERMS; //10 terms
for (flag_2 = 1; flag_2 <= 2 * terms; flag_2 += 2)
{
radRaisedToX2 = RaiseTo(rad, flag_2);
if (plusOrMinus2 == 0)
{
val2 -= radRaisedToX2/factorial(flag_2);
plusOrMinus2++; //Add the next number
}
else
{
val2 += radRaisedToX2/factorial(flag_2);
plusOrMinus2--; //Subtract the next number
}
}
sin = val2;
return sin;
}
int main()
{
int degree;
scanf("%d", °ree);
double rad, cosx, sinx;
rad = degree * PI / 180.00;
//cosx = cosine (rad);
sinx = sine (rad);
printf("%lf \n%lf", rad, sinx);
}
So during the loop, I get the rad^x, divide it by the factorial of the odd number series starting from 1, then add or subtract it depending on what's needed, but when I run the program, I get outputs way above one, and we all know that the limits of sin(x) are 1 and -1, I'd really like to know where I went wrong so I could improve, sorry if it's a pretty bad question.
Anything over 12! is larger than can fit into a 32-bit int, so such values will overflow and therefore won't return what you expect.
Instead of computing the full factorial each time, take a look at each term in the sequence relative to the previous one. For any given term, the next one is -((x*x)/(flag_2*(flag_2-1)) times the previous one. So start with a term of x, then multiply by that factor for each successive term.
There's also a trick to calculating the result to the precision of a double without knowing how many terms you need. I'll leave that as an exercise to the reader.
In the function factorial you are doing an int multiply before assigned to the double return value of the function. Factorials can easily break the int range, such as 20! = 2432902008176640000.
You also returned the wrong variable - the loop counter!
Please change the local variable to double, as
double factorial (int n)
{
double fact = 1;
int flag;
for (flag = 1; flag <= n; flag++)
{
fact *= flag;
}
return fact; // it was the wrong variable, and wrong type
}
Also there is not even any need for a factorial calculation. Note that each term of the series multiplies the previous term by rad and divides by the term number - with a change of sign.
Another fairly naive, 5-minute approach involves computing a look-up table that contains the first 20 or so factorials, i.e 1! .. 20! This requires very little memory and can increase speed over the 'each-time' computation method. A further optimization can easily be realized in the function that pre-computes the factorials, taking advantage of the relationship each has to the previous one.
An approach that efficiently eliminated branching (if X do Y else do Z) in the loops of the two trig functions would provide yet more speed again.
C code
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
const int nMaxTerms=20;
double factorials[nMaxTerms];
double factorial(int n)
{
if (n==1)
return 1;
else
return (double)n * factorial(n - 1.0);
}
void precalcFactorials()
{
for (int i=1; i<nMaxTerms+1; i++)
{
factorials[i-1] = factorial(i);
}
}
/*
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! .......
*/
double taylorSine(double rads)
{
double result = rads;
for (int curTerm=1; curTerm<=(nMaxTerms/2)-1; curTerm++)
{
double curTermValue = pow(rads, (curTerm*2)+1);
curTermValue /= factorials[ curTerm*2 ];
if (curTerm & 0x01)
result -= curTermValue;
else
result += curTermValue;
}
return result;
}
/*
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! .......
*/
double taylorCos(double rads)
{
double result = 1.0;
for (int curTerm=1; curTerm<=(nMaxTerms/2)-1; curTerm++)
{
double curTermValue = pow(rads, (curTerm*2) );
curTermValue /= factorials[ (curTerm*2) - 1 ];
if (curTerm & 0x01)
result -= curTermValue;
else
result += curTermValue;
}
return result;
}
int main()
{
precalcFactorials();
printf("Math sin(0.5) = %f\n", sin(0.5));
printf("taylorSin(0.5) = %f\n", taylorSine(0.5));
printf("Math cos(0.5) = %f\n", cos(0.5));
printf("taylorCos(0.5) = %f\n", taylorCos(0.5));
return 0;
}
output
Math sin(0.5) = 0.479426
taylorSin(0.5) = 0.479426
Math cos(0.5) = 0.877583
taylorCos(0.5) = 0.877583
Javascript
Implemented in javascript, the code produces seemingly identical results (I didn't test very much) to the inbuilt Math library when summing just 7 terms in the sin/cos functions.
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
console.log('starting');
for (var i=1; i<21; i++)
factorials[i-1] = factorial(i);
console.log('calculated');
console.log(" Math.cos(0.5) = " + Math.cos(0.5));
console.log("taylorCos(0.5) = " + taylorCos(0.5));
console.log('-');
console.log(" Math.sin(0.5) = " + Math.sin(0.5));
console.log("taylorSine(0.5) = " + taylorSine(0.5));
}
var factorials = [];
function factorial(n)
{
if (n==1)
return 1;
else
return n * factorial(n-1);
}
/*
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! .......
*/
function taylorSine(x)
{
var result = x;
for (var curTerm=1; curTerm<=7; curTerm++)
{
var curTermValue = Math.pow(x, (curTerm*2)+1);
curTermValue /= factorials[ curTerm*2 ];
if (curTerm & 0x01)
result -= curTermValue;
else
result += curTermValue;
}
return result;
}
/*
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! .......
*/
function taylorCos(x)
{
var result = 1.0;
for (var curTerm=1; curTerm<=7; curTerm++)
{
var curTermValue = Math.pow(x, (curTerm*2));
curTermValue /= factorials[ (curTerm*2)-1 ];
if (curTerm & 0x01)
result -= curTermValue;
else
result += curTermValue;
}
return result;
}
I have a logical problem in my code, maybe it is caused by overflowing but I can't solve this on my own, so I would be thankful if anyone can help me.
In the following piece of code, I have implemented the function taylor_log(), which can count "n" iterations of taylor polynomial. In the void function I am looking for number of iterations (*limit) which is enough to count a logarithm with desired accuracy compared to log function from .
The thing is that sometimes UINT_MAX is not enough iterations to get the desired accuracy and at this point I want to let the user know that the number of needed iterations is higher than UINT_MAX. But my code don't work, for example for x = 1e+280, eps = 623. It just counts, counts and never give result.
TaylorPolynomial
double taylor_log(double x, unsigned int n){
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; i <= n; i++)
{
f_sum *= (x - 1) / x;
sum += f_sum / i;
}
return sum;
}
void guessIt(double x, double eps, unsigned int *limit){
*limit = 10;
double real_log = log(x);
double t_log = taylor_log(x, *limit);
while(myabs(real_log - t_log) > eps)
{
if (*limit == UINT_MAX)
{
*limit = 0;
break;
}
if (*limit >= UINT_MAX/2)
{
*limit = UINT_MAX;
t_log = taylor_log(x, *limit);
}
else
{
*limit = (*limit) *2;
t_log = taylor_log(x, *limit);
}
}
}
EDIT: Ok guys, thanks for your reactions so far. I have changed my code to this:
if (*limit == UINT_MAX-1)
{
*limit = 0;
break;
}
if (*limit >= UINT_MAX/2)
{
*limit = UINT_MAX-1;
t_log = taylor_log(x, *limit);
}
but it still doesn't work correctly, I have set printf to the beggining of taylor_log() function to see the value of "n" and its (..., 671088640, 1342177280, 2684354560, 5, 4, 3, 2, 2, 1, 2013265920, ...). Don't understand it..
This code below assigns the limit to UINT_MAX
if (*limit >= UINT_MAX/2)
{
*limit = UINT_MAX;
t_log = taylor_log(x, *limit);
}
And your for loop is defined like this:
for (unsigned int i = 1; i <= n; i++)
i will ALWAYS be less than or equal to UINT_MAX because there is never going to be a value of i that is greater than UINT_MAX. Because that's the largest value i could ever be. So there is certainly overflow and your loop exit condition is never met. i rolls over to zero and the process repeats indefinitely.
You should change your loop condition to i < n or change your limit to UINT_MAX - 1.
[Edit]
OP coded correctly but must insure a limited range (0.5 < x < 2.0 ?)
Below is a code version that self determines when to stop. Iteration count goes high near x near 0.5 and 2.0. The iteration count needed goes into the millions. Such the alternative coded far below.
double taylor_logA(double x) {
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; ; i++) {
f_sum *= (x - 1) / x;
double sum_before = sum;
sum += f_sum / i;
if (sum_before == sum) {
printf("%d\n", i);
break;
}
}
return sum;
}
Wrongalternative implementation of the series: Ref
Sample alternative - it converges faster.
double taylor_log2(double x, unsigned int n) {
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; i <= n; i++) {
f_sum *= (x - 1) / 1; // / 1 (or remove)
if (i & 1) sum += f_sum / i;
else sum -= f_sum / i; // subtract even terms
}
return sum;
}
A reasonable number of terms will converge as needed.
Alternatively, continue until terms are too small (maybe 50 or so)
double taylor_log3(double x) {
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; ; i++) {
double sum_before = sum;
f_sum *= x - 1;
if (i & 1) sum += f_sum / i;
else sum -= f_sum / i;
if (sum_before == sum) {
printf("%d\n", i);
break;
}
}
return sum;
}
Other improvements possible. example see More efficient series
First, using std::numeric_limits<unsigned int>::max() will make your code more c++-ish than c-ish. Second, you can use the integral type unsigned long long and std::numeric_limits<unsigned long long>::max() for the limit, which is pretty mush the limit for an integral type. If you want a higher limit, you may use long double. floating points also allows you to use infinity with std::numeric_limits<double>::infinity() note that infinity work with double, float and long double.
If neither of these types provide you the precision you need, look at boost::multiprecision
First of all, the Taylor series for the logarithm function only converges for values of 0 < x < 2, so it's quite possible that the eps precision is never hit.
Secondly, are you sure that it loops forever, instead of hitting the *limit >= UINT_MAX/2 after a very long time?
OP is using the series well outside its usable range of 0.5 x < 2.0 with calls like taylor_log(1e280, n)
Even within the range, x values near the limits of 0.5 and 2.0 converge very slowly needing millions+ of iterations. A precise log() will not result. Best to use the 2x range about 1.0.
Create a wrapper function to call the original function in its sweet range of sqrt(2)/2 < x < sqrt(2). Converges, worst case, with about 40 iterations.
#define SQRT_0_5 0.70710678118654752440084436210485
#define LN2 0.69314718055994530941723212145818
// Valid over the range (0...DBL_MAX]
double taylor_logB(double x, unsigned int n) {
int expo;
double signif = frexp(x, &expo);
if (signif < SQRT_0_5) {
signif *= 2;
expo--;
}
double y = taylor_log(signif,n);
y += expo*LN2;
return y;
}
I created this function CalculateCos:
int Factorial (long int n)
{
long int r = 1;
for (int i = 2; i<=n; i++)
{
r = r*i;
}
return r;
}
float CalculateVariable(int CVnumber, int CVloopCounter)
{
float CVresult = 0;
CVresult = pow(CVnumber, (CVloopCounter*2)) / (long int)Factorial(CVnumber*2);
return CVresult;
}
float CalculateCos(int number)
{
float result = 1;
int loopCounter = 1;
int minusOrPlus = 1;
while(loopCounter <= precision && loopCounter <= 8)
{
if(!minusOrPlus)
{
result = result - CalculateVariable(number, loopCounter);
printf("%f\n", result);
minusOrPlus = 1;
}
else
{
result = result + CalculateVariable(number, loopCounter);
printf("%f\n", result);
minusOrPlus = 0;
}
loopCounter++;
}
return result;
}
The reason why I printf after the subtraction or adding, is because it gives me strange output, like:
Enter a number, for the cos function
6
1.000000
0.999997
1.000095
0.996588
1.122822
-3.421593
160.177368
-5729.385254
Result is: -5729.3852539
Official function result is: 0.9601703
Can you help me to get correct results on this?
UPDATE:
Now my solution is:
float CalculateCos(float number)
{
float result = 0;
float step = 1;
int loopCounter = 1;
while(loopCounter <= 5)
{
step = step * (-number) * number / (((2*loopCounter)-1)*((2*loopCounter)-2));
result += step;
loopCounter++;
}
return result;
}
Current problem:
since your Factorial function returns int and you casts it to long int, its result is going to overflow even before the input goes to 16 in your case (14! > max_int).
You're calculating cos using Taylor series:
cos(x) = 1 - x2/2! + x4/4! - x6/6!
+ ...
I'm not going to write code. But there are some things wrong in your program, which can be fixed easily:
The input is in radian, so number should be a float.
Calculating each step of Taylor series using exponentiation and factorial separately leads to overflow very soon. The correct way is maintaining a float variable: step = 1 at first and in kth loop iteration step = step * (- x) * x / ((2*k-1)*(2*k)). In this way, you simply add step to result in the loop and don't need minusOrPlus anymore.
The number of loop iterations is bounded by 8 which is too small, so the result could be not precise enough.
I don't see you use precision variable anywhere. It could be used to check precision of the result. For example, when abs(step) < precision, we're going to terminate the loop.