Reputation: 291
Given this method to compute the cosine of x:
public static double myCos(double x){
double alteSumme, neueSumme, summand;
int j = 0;
neueSumme = 1.0;
summand = 1.0;
do
{
j++;
summand *= -x * x / j;
j++;
summand /= j;
alteSumme = neueSumme;
neueSumme += summand;
} while ( neueSumme != alteSumme );
return alteSumme;
}
I get inaccurate results for large x:
I have to transform the domain from the real numbers to the interval [0,PI/2] for accurate results.
So, I wrote this method:
public static double transform(double x){
x = x%(2*Math.PI);
if(!(0<=x&&x<Math.PI)){
x = -(x+Math.PI);
}
if(!(0<=x&&x<Math.PI/2)){
x = -(x-2*Math.abs(x-Math.PI/2));
}
return x;
}
It should work in three steps.
Transform the domain from the reals to [0,2PI).
Transform the domain from [0,2PI) to [0,PI).
Transform the domain from [0,PI) to [0,PI/2]
But somehow it yields wrong results.
Can you help me find my mistake?
EDIT
public class Main {
public static double transform(double x) {
x = x % (2 * Math.PI);
if (!(0 <= x && x < Math.PI)) {
x = -(x + Math.PI);
}
if (!(0 <= x && x < Math.PI / 2)) {
x = -(x - 2 * Math.abs(x - Math.PI / 2));
}
return x;
}
public static double myCos(double x) {
x = transform(x);
double alteSumme, neueSumme, summand;
int j = 0;
neueSumme = 1.0;
summand = 1.0;
do {
j++;
summand *= -x * x / j;
j++;
summand /= j;
alteSumme = neueSumme;
neueSumme += summand;
} while (neueSumme != alteSumme);
return alteSumme;
}
public static void main(String[] args) {
int n = 0;
int k =50;
for (double y = k * Math.PI; y <= (k + 2) * Math.PI; y += Math.PI/4) {
System.out.println(n + ":" + y + ": " + myCos(y) + " " + Math.cos(y));
n++;
}
}
}
Upvotes: 0
Views: 166
Reputation: 9093
UPDATE
Here's an implementation of transform
suited for cos
only.
/**
* @param x any value
* @return x within [0..2PI)
public static double transform(double x) {
x = Math.abs(x); // We can do this because Cosine is symmetric around the y axis.
double y = Math.floor(x / (Math.PI * 2));
return x - y * Math.PI * 2;
}
As requested, here's my test class:
package cosine;
public class Main {
public static double transform(double x) {
x = Math.abs(x);
double y = Math.floor(x / (Math.PI * 2));
return x - y * Math.PI * 2;
}
public static double myCos(double x) {
x = transform(x);
double alteSumme, neueSumme, summand;
int j = 0;
neueSumme = 1.0;
summand = 1.0;
do {
j++;
summand *= -x * x / j;
j++;
summand /= j;
alteSumme = neueSumme;
neueSumme += summand;
} while (neueSumme != alteSumme);
return alteSumme;
}
public static void main(String[] args) {
int n = 0;
for (double y = -20 * Math.PI; y < 20 * Math.PI; y += Math.PI / 3) {
double x = Math.PI / 3 + y;
double tmpa, tmpb;
System.out.println(
n + ":" + x + ": " + (tmpa = myCos(x)) + " " + (tmpb = Math.cos(x)) + " DIFF: " + (tmpa - tmpb));
n++;
}
}
}
UPDATE
Here's a slight improvement by only calculating the cosine over 0..π:
public static double myCos(double x) {
// Cosine is symmetric around the Y axis: get rid of the sign.
x = Math.abs(x);
// Calculate the number of times 2*PI fits in x
double y = Math.floor(x / (Math.PI * 2));
// and subtract that many 2*PI
x -= y * Math.PI * 2;
// x is now within 0 and 2*PI.
// The PI..2PI range is the negated version of 0..PI.
double sign = 1;
if ( x > Math.PI ) {
sign = -1;
// mirror x in the line x=Math.PI:
x = - x + Math.PI; // or: Math.PI * 2 - x
}
/* cosine approximation ... */
return alteSumme * sign;
}
Upvotes: 1