Cut a polygon into 4 parts with equals area. java - java

I need to cut a convex not simple polygon by two perpendicular lines to divide it into 4 equal(area) parts.
I wrote a program, but it does not pass tests.
I think the reason is rounding errors or my function of calculating area.
Please check it, is it correct?
I use shoelace algorithm and heron's formula
Here is the code:
double calcArea() {
double result = 0;
if (size() > 4) {
int j = size() - 1;
for (int i = 0; i < size() - 1; i++) {
result += (points.get(i).getX() + points.get(j).getX())
*
(points.get(j).getY() - points.get(i).getY());
j = i;
}
result = result / (result >= 0 ? 2. : -2.);
} else if(size() == 3) {
double c,a,b, p;
c = Math.sqrt(Math.pow(points.get(0).getY()-points.get(1).getY(),2)+Math.pow(points.get(0).getX()-points.get(1).getX(),2));
a = Math.sqrt(Math.pow(points.get(1).getY()-points.get(2).getY(),2)+Math.pow(points.get(1).getX()-points.get(2).getX(),2));
b = Math.sqrt(Math.pow(points.get(0).getY()-points.get(2).getY(),2)+Math.pow(points.get(0).getX()-points.get(2).getX(),2));
p = (a + b + c) / 2.;
return Math.sqrt(p*(p-a)*(p-b)*(p-c));
}
return result;
}
What I do in:
finding of point(x, y) of cutting polygon.
I cut it by x = a in [ min(x), max(x)]
and calculate S'(part of polygon from x=min(x) to x=a)
if S' = S/2 , i take a for calculating value(a, *)
then the same with y = b whereb in [min(y), max(y)]
Is there more fast method?

Related

Understanding the strictMath java library

I got bored and decided to dive into remaking the square root function without referencing any of the Math.java functions. I have gotten to this point:
package sqrt;
public class SquareRoot {
public static void main(String[] args) {
System.out.println(sqrtOf(8));
}
public static double sqrtOf(double n){
double x = log(n,2);
return powerOf(2, x/2);
}
public static double log(double n, double base)
{
return (Math.log(n)/Math.log(base));
}
public static double powerOf(double x, double y) {
return powerOf(e(),y * log(x, e()));
}
public static int factorial(int n){
if(n <= 1){
return 1;
}else{
return n * factorial((n-1));
}
}
public static double e(){
return 1/factorial(1);
}
public static double e(int precision){
return 1/factorial(precision);
}
}
As you may very well see, I came to the point in my powerOf() function that infinitely recalls itself. I could replace that and use Math.exp(y * log(x, e()), so I dived into the Math source code to see how it handled my problem, resulting in a goose chase.
public static double exp(double a) {
return StrictMath.exp(a); // default impl. delegates to StrictMath
}
which leads to:
public static double exp(double x)
{
if (x != x)
return x;
if (x > EXP_LIMIT_H)
return Double.POSITIVE_INFINITY;
if (x < EXP_LIMIT_L)
return 0;
// Argument reduction.
double hi;
double lo;
int k;
double t = abs(x);
if (t > 0.5 * LN2)
{
if (t < 1.5 * LN2)
{
hi = t - LN2_H;
lo = LN2_L;
k = 1;
}
else
{
k = (int) (INV_LN2 * t + 0.5);
hi = t - k * LN2_H;
lo = k * LN2_L;
}
if (x < 0)
{
hi = -hi;
lo = -lo;
k = -k;
}
x = hi - lo;
}
else if (t < 1 / TWO_28)
return 1;
else
lo = hi = k = 0;
// Now x is in primary range.
t = x * x;
double c = x - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
if (k == 0)
return 1 - (x * c / (c - 2) - x);
double y = 1 - (lo - x * c / (2 - c) - hi);
return scale(y, k);
}
Values that are referenced:
LN2 = 0.6931471805599453, // Long bits 0x3fe62e42fefa39efL.
LN2_H = 0.6931471803691238, // Long bits 0x3fe62e42fee00000L.
LN2_L = 1.9082149292705877e-10, // Long bits 0x3dea39ef35793c76L.
INV_LN2 = 1.4426950408889634, // Long bits 0x3ff71547652b82feL.
INV_LN2_H = 1.4426950216293335, // Long bits 0x3ff7154760000000L.
INV_LN2_L = 1.9259629911266175e-8; // Long bits 0x3e54ae0bf85ddf44L.
P1 = 0.16666666666666602, // Long bits 0x3fc555555555553eL.
P2 = -2.7777777777015593e-3, // Long bits 0xbf66c16c16bebd93L.
P3 = 6.613756321437934e-5, // Long bits 0x3f11566aaf25de2cL.
P4 = -1.6533902205465252e-6, // Long bits 0xbebbbd41c5d26bf1L.
P5 = 4.1381367970572385e-8, // Long bits 0x3e66376972bea4d0L.
TWO_28 = 0x10000000, // Long bits 0x41b0000000000000L
Here is where I'm starting to get lost. But I can make a few assumptions that so far the answer is starting to become estimated. I then find myself here:
private static double scale(double x, int n)
{
if (Configuration.DEBUG && abs(n) >= 2048)
throw new InternalError("Assertion failure");
if (x == 0 || x == Double.NEGATIVE_INFINITY
|| ! (x < Double.POSITIVE_INFINITY) || n == 0)
return x;
long bits = Double.doubleToLongBits(x);
int exp = (int) (bits >> 52) & 0x7ff;
if (exp == 0) // Subnormal x.
{
x *= TWO_54;
exp = ((int) (Double.doubleToLongBits(x) >> 52) & 0x7ff) - 54;
}
exp += n;
if (exp > 0x7fe) // Overflow.
return Double.POSITIVE_INFINITY * x;
if (exp > 0) // Normal.
return Double.longBitsToDouble((bits & 0x800fffffffffffffL)
| ((long) exp << 52));
if (exp <= -54)
return 0 * x; // Underflow.
exp += 54; // Subnormal result.
x = Double.longBitsToDouble((bits & 0x800fffffffffffffL)
| ((long) exp << 52));
return x * (1 / TWO_54);
}
TWO_54 = 0x40000000000000L
While I am, I would say, very understanding of math and programming, I hit the point to where I find myself at a Frankenstein monster mix of the two. I noticed the intrinsic switch to bits (which I have little to no experience with), and I was hoping someone could explain to me the processes that are occurring "under the hood" so to speak. Specifically where I got lost is from "Now x is in primary range" in the exp() method on wards and what the values that are being referenced really represent. I'm was asking for someone to help me understand not only the methods themselves, but also how they arrive to the answer. Feel free to go as in depth as needed.
edit:
if someone could maybe make this tag: "strictMath" that would be great. I believe that its size and for the Math library deriving from it justifies its existence.
To the exponential function:
What happens is that
exp(x) = 2^k * exp(x-k*log(2))
is exploited for positive x. Some magic is used to get more consistent results for large x where the reduction x-k*log(2) will introduce cancellation errors.
On the reduced x a rational approximation with minimized maximal error over the interval 0.5..1.5 is used, see Pade approximations and similar. This is based on the symmetric formula
exp(x) = exp(x/2)/exp(-x/2) = (c(x²)+x)/(c(x²)-x)
(note that the c in the code is x+c(x)-2). When using Taylor series, approximations for c(x*x)=x*coth(x/2) are based on
c(u)=2 + 1/6*u - 1/360*u^2 + 1/15120*u^3 - 1/604800*u^4 + 1/23950080*u^5 - 691/653837184000*u^6
The scale(x,n) function implements the multiplication x*2^n by directly manipulating the exponent in the bit assembly of the double floating point format.
Computing square roots
To compute square roots it would be more advantageous to compute them directly. First reduce the interval of approximation arguments via
sqrt(x)=2^k*sqrt(x/4^k)
which can again be done efficiently by directly manipulating the bit format of double.
After x is reduced to the interval 0.5..2.0 one can then employ formulas of the form
u = (x-1)/(x+1)
y = (c(u*u)+u) / (c(u*u)-u)
based on
sqrt(x)=sqrt(1+u)/sqrt(1-u)
and
c(v) = 1+sqrt(1-v) = 2 - 1/2*v - 1/8*v^2 - 1/16*v^3 - 5/128*v^4 - 7/256*v^5 - 21/1024*v^6 - 33/2048*v^7 - ...
In a program without bit manipulations this could look like
double my_sqrt(double x) {
double c,u,v,y,scale=1;
int k=0;
if(x<0) return NaN;
while(x>2 ) { x/=4; scale *=2; k++; }
while(x<0.5) { x*=4; scale /=2; k--; }
// rational approximation of sqrt
u = (x-1)/(x+1);
v = u*u;
c = 2 - v/2*(1 + v/4*(1 + v/2));
y = 1 + 2*u/(c-u); // = (c+u)/(c-u);
// one Halley iteration
y = y*(1+8*x/(3*(3*y*y+x))) // = y*(y*y+3*x)/(3*y*y+x)
// reconstruct original scale
return y*scale;
}
One could replace the Halley step with two Newton steps, or
with a better uniform approximation in c one could replace the Halley step with one Newton step, or ...

Reducing time complexity of bilinear interpolation

I use bilinear interpolation in my android application. It runs perfectly, but takes a lot of time to get the result.
I test it when xi = 259,920, and yi also = 259,920. The time to response was: Galaxy Note 4 takes 3 sec,
and HTC One M8 takes about 8 sec !. So what I can change or use to reduce the time?!
The code I use for bilinear interpolation:
public static double[] BiInterp(Mat z, ArrayList < Double > xi, ArrayList < Double > yi) {
// Declare matrix indeces
int xi_i, yi_i;
// Initialize output vector
double zi[] = new double[xi.size()];
double s00, s01, s10, s11;
for (int i = 0; i < xi.size(); i++) { // Note: xi.length = yi.length !
xi_i = xi.get(i).intValue(); // X index without round
yi_i = yi.get(i).intValue(); // Y index without round
if (xi_i < z.rows() - 1 && yi_i < z.cols() - 1 && xi_i >= 0 && yi_i >= 0) {
// Four neighbors of sample pixel
s00 = z.get(xi_i,yi_i)[0]; s01 = z.get(xi_i,yi_i + 1)[0];
s10 = z.get(xi_i + 1,yi_i)[0];s11 = z.get(xi_i + 1,yi_i + 1)[0];
int neighbor_no = 4; // As bilinear interpolation take 4 neighbors
double A[][] = new double[neighbor_no][neighbor_no];
A[0][0]=xi_i; A[0][1]=yi_i; A[0][2]=xi_i*yi_i; A[0][3]=1;
A[1][0]=xi_i; A[1][1]=yi_i+1; A[1][2]=xi_i*(yi_i+1); A[1][3]=1;
A[2][0]=xi_i+1; A[2][1]=yi_i; A[2][2]=(xi_i+1)*yi_i; A[2][3]=1;
A[3][0]=xi_i+1; A[3][1]=yi_i+1; A[3][2]=(xi_i+1)*(yi_i+1); A[3][3]=1;
GaussianElimination solveE = new GaussianElimination();
double b[] = {s00,s01,s10,s11};
double x[] = solveE.solve(A, b);
zi[i] = xi.get(i)*x[0] + yi.get(i)*x[1] + xi.get(i)*yi.get(i)*x[2] + x[3];
}
}
return zi;
}
and I use Gaussian elimination to solve the equation of 4 unknown
private static final double EPSILON = 1e-10;
// Gaussian elimination with partial pivoting
public static double[] solve(double[][] A, double[] b) {
int N = b.length;
for (int p = 0; p < N; p++) {
// find pivot row and swap
int max = p;
for (int i = p + 1; i < N; i++) {
if (Math.abs(A[i][p]) > Math.abs(A[max][p])) {
max = i;
}
}
double[] temp = A[p];
A[p] = A[max];
A[max] = temp;
double t = b[p];
b[p] = b[max];
b[max] = t;
// singular or nearly singular
if (Math.abs(A[p][p]) <= EPSILON) {
throw new RuntimeException("Matrix is singular or nearly singular");
}
// pivot within A and b
for (int i = p + 1; i < N; i++) {
double alpha = A[i][p] / A[p][p];
b[i] -= alpha * b[p];
for (int j = p; j < N; j++) {
A[i][j] -= alpha * A[p][j];
}
}
}
// back substitution
double[] x = new double[N];
for (int i = N - 1; i >= 0; i--) {
double sum = 0.0;
for (int j = i + 1; j < N; j++) {
sum += A[i][j] * x[j];
}
x[i] = (b[i] - sum) / A[i][i];
}
return x;
}
As you see in the bilinear code, I take the pixels intensities immediately from the Mat object. However, when I used matrix it takes much less time, such as with note 4 takes 1 sec.
But to convert from Mat image to matrix takes 4 sec. So I preferred to use Mat.
Here is a more simple bilinear interpolation algorithm:
Find the fractional part of yi and use it to interpolate between s00 and s01 to find s0, and between s10 and s11 to find s1
Find the fractional part of xi and use it to interpolate between s0 and s1 to find zi
Basically you are decomposing it into three simple linear interpolations. You can visualize it as an H shape. First you interpolate down the left and right posts of the H to get values part way down each. Then you interpolate along the cross-beam to get the final value in the middle.
The code would be something like this:
xi_i = xi.get(i).intValue(); // X index without round
yi_i = yi.get(i).intValue(); // Y index without round
if (xi_i < z.rows() - 1 && yi_i < z.cols() - 1 && xi_i >= 0 && yi_i >= 0) {
// Four neighbors of sample pixel
s00 = z.get(xi_i,yi_i)[0]; s01 = z.get(xi_i,yi_i + 1)[0];
s10 = z.get(xi_i + 1,yi_i)[0];s11 = z.get(xi_i + 1,yi_i + 1)[0];
// find fractional part of yi:
double yi_frac = yi.get(i) - (double)yi_i;
// interpolate between s00 and s01 to find s0:
double s0 = s00 + ((s01 - s00) * yi_frac);
// interpolate between s10 and s11 to find s1:
double s1 = s10 + ((s11 - s10) * yi_frac);
// find fractional part of xi:
double xi_frac = xi.get(i) - (double)xi_i;
// interpolate between s0 and s1 to find zi:
zi[i] = s0 + ((s1 - s0) * xi_frac);
}
You could also speed the whole thing up (at the expense of accuracy) by using fixed point integers instead of doubles.

How can I find an overlap between two given ranges? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
The community reviewed whether to reopen this question 5 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
Is there an effective way to find the overlap between two ranges?
Practically, the two ranges marked as (a - c), and (b - d), and I assume (c > a) && (d > b).
(b <= a <= d) which means if ((a >= b) && (d > a))
(b <= c <= d) which means if ((c >= b) && (d >= c))
(a <= b <= c) which means if ((b > a) && (c > b))
(a <= d <= c) which means if ((d > a) && (c > d))
But it never ends, because in this way I can find only one range at the time, and in each if I have to check the other cases as well.
For exemple, if the first condition (1) correct, I know what happening with the start of the range (a) I still need to check the others for the end of the range (c).
Not to mention that all this works in the case that (c > a) && (d > b), and not one of them is equal to another.
Two ranges overlap in one of two basic cases:
one range contains the other completely (i.e. both the start and end of one range are between the start and end of the other), or
the start or end of one range is contained within the other range
Conversely, they do not overlap only if neither endpoint of each range is contained within the other range (cases 11 and 12 in your diagram). We can check whether the low end of either range is past the high end of the other, to detect both those cases:
if (a > d || c < b) {
// no overlap
}
else {
// overlap
}
We can invert the condition and then use DeMorgan's laws to swap the order, if that's preferable:
if (a <= d && c >= b) {
// overlap
}
else {
// no overlap
}
To find the actual overlap range, you take the maximum of the two low ends, and the minimum of the two high ends:
int e = Math.max(a,b);
int f = Math.min(c,d);
// overlapping range is [e,f], and overlap exists if e <= f.
All above assumes that the ranges are inclusive, that is, the range defined by a and c includes both the value of a and the value of c. It is fairly trivial to adjust for exclusive ranges, however.
Use apache commons Range and its subclasses, especially the overlap method.
The check for an overlap (just true/false) is actually quite easy:
Assume the ranges [a,b] and [c,d].
You have an overlap if: a <= d and b => c. This also works for a = b and/or c = d.
If you have an overlap then the overlapping range is [max(a,c),min(b,d)].
You can detect the collision of two ranges by using a modified circular collision detection algorithm.
import java.util.Arrays;
public class RangeUtils {
public static void main(String[] args) {
int[] rangeA = { 10, 110 };
int[] rangeB = { 60, 160 };
int[] rangeC = intersectingRange(rangeA, rangeB);
System.out.println("Range: " + Arrays.toString(rangeC)); // Range: [60, 110]
}
// Based on circular collision detection.
public static boolean collisionDetected(int[] rangeA, int[] rangeB) {
int distA = Math.abs(rangeA[1] - rangeA[0]) / 2;
int distB = Math.abs(rangeB[1] - rangeB[0]) / 2;
int midA = (rangeA[0] + rangeA[1]) / 2;
int midB = (rangeB[0] + rangeB[1]) / 2;
return Math.sqrt((midB - midA) * (midB - midA)) < (distA + distB);
}
public static int[] intersectingRange(int[] rangeA, int[] rangeB) {
if (collisionDetected(rangeA, rangeB)) {
return new int[] {
Math.max(rangeA[0], rangeB[0]),
Math.min(rangeA[1], rangeB[1])
};
}
return null;
}
}
Here is a visual example of the code; ported to JavaScript.
var palette = ['#393A3F', '#E82863', '#F6A329', '#34B1E7', '#81C683'];
var canvas = document.getElementById('draw');
var ctx = canvas.getContext('2d');
var rangeA = [10, 110];
var rangeB = [60, 160];
var rangeC = intersectingRange(rangeA, rangeB);
var collisionText = 'Range: [' + rangeC + ']';
var leftOffset = 18;
var topOffset = 24;
drawLines(ctx, [rangeA, rangeB], topOffset);
drawText(ctx, collisionText, leftOffset, topOffset);
drawBoundry(ctx, rangeC, topOffset);
// Based on circular collision detection.
function collisionDetected(rangeA, rangeB) {
var distA = Math.abs(rangeA[1] - rangeA[0]) / 2;
var distB = Math.abs(rangeB[1] - rangeB[0]) / 2;
var midA = (rangeA[0] + rangeA[1]) / 2;
var midB = (rangeB[0] + rangeB[1]) / 2;
return Math.sqrt((midB - midA) * (midB - midA)) < (distA + distB);
}
function intersectingRange(rangeA, rangeB) {
if (collisionDetected(rangeA, rangeB)) {
return [Math.max(rangeA[0], rangeB[0]), Math.min(rangeA[1], rangeB[1])];
}
return null;
}
function drawText(ctx, text, x, y) {
ctx.save();
ctx.font = '18px Arial';
ctx.fillText(text, x, y);
ctx.restore();
}
function drawLines(ctx, lines, topOffset) {
topOffset = topOffset || 0;
var sizeWidth = ctx.canvas.clientWidth;
var sizeHeight = ctx.canvas.clientHeight - topOffset;
var yOffset = sizeHeight / (lines.length + 1);
for (var i = 0; i < lines.length; i++) {
var color = palette[i % palette.length];
var yPos = (i + 1) * yOffset + topOffset;
drawLine(ctx, lines[i], yPos, color)
}
}
function drawLine(ctx, range, index, color) {
ctx.save();
ctx.beginPath();
ctx.moveTo(range[0], index);
ctx.lineTo(range[1], index);
ctx.strokeStyle = color;
ctx.lineWidth = 4;
ctx.stroke();
ctx.restore();
}
function drawBoundry(ctx, bounds, topOffset) {
var sizeHeight = ctx.canvas.clientHeight - topOffset;
var padding = sizeHeight * 0.25;
var y1 = topOffset + padding;
var y2 = sizeHeight + topOffset - padding;
ctx.save();
ctx.beginPath();
ctx.strokeStyle = palette[4];
ctx.setLineDash([5, 5]);
ctx.lineWidth = 2;
ctx.rect(bounds[0], y1, bounds[1] - bounds[0], sizeHeight * 0.5);
ctx.stroke();
ctx.restore();
}
canvas#draw {
background: #FFFFFF;
border: thin solid #7F7F7F;
}
<canvas id="draw" width="180" height="160"></canvas>
Let's make the ranges clearer:
(start1, end1) and (start2, end2)
Double totalRange = Math.max(end1, end2) - Math.min(start1, start2);
Double sumOfRanges = (end1 - start1) + (end2 - start2);
Double overlappingInterval = 0D;
if (sumOfRanges > totalRange) { // means they overlap
overlappingInterval = Math.min(end1, end2) - Math.max(start1, start2);
}
return overlappingInterval;
Based on this answer
Set x=max(a,b), y=min(c,d). If x < y (or x≤y) then (x-y) is a common part of the two ranges (degenerate in case x=y), otherwise they don't overlap.
Based on some other answers to this question I composed the following two code samples:
The first will only return a Boolean indicating whether two ranges overlap:
// If just a boolean is needed
public static boolean overlap(int[] arr1, int[] arr2) {
if((arr1[0] <= arr2[arr2.length - 1]) && (arr2[arr1.length - 1] >= arr2[0])) {
return true;
} else {
return false;
}
}
The second will return an Integer array of the overlapping values in cases where an overlap exists. Otherwise it will return an empty array.
// To get overlapping values
public static int[] overlap(int[] arr1, int[] arr2) {
int[] overlappingValues = {};
if((arr1[0] <= arr2[arr2.length - 1]) && (arr2[arr1.length - 1] >= arr2[0])) {
int z = 0;
for(int a : arr1) {
for(int b : arr2) {
if(a == b) {
overlappingValues[z] = a;
z = z + 1;
}
}
}
} else {
return {};
}
}
Hope this helps.
Based on the updated question I did some research via Google and could find this posting:
Java, find intersection of two arrays
To what I understand at the moment it should match the given requirements. And the code snippet used is quite short and from what I know also looks quite well.
And to account for the remarks in terms of discrete and continuous values I wanted to add another potential solution I could find for continuous ranges:
https://community.oracle.com/thread/2088552?start=0&tstart=0
This solution does not directly return the overlapped ranges but provides an interesting class implementation to do range comparison.

Square Spiral Co-ordinate

I want to find if a point (x,y)where x,y integers satisfy the spiral square.
(0,0) (0,1) (1,1) (1,2) (0,2) (-1,2) (-2,2) (-2,1) (-2,0) ans so on.....
How do I do it?
I want the logic for a java or c++ function.
Here is some pseudocode logic:
Start with x=0, y=0, dist=0, direction=1
Loop
x += (++dist * direction)
WritePoint(x,y)
y += (++dist * direction)
WritePoint(x,y)
direction *= -1
LoopEnd
Take it from there.
Do this operation:
(operator)(operation)(amount)
where operator alternates as x,y,x,y,...(use % operator for that), operation alternates as +,+,-,-,+,+,-,-,+,+...(again use % operator for that) and amount changes as 1,2,3,...
This is my answer. To solve it I found the indexes where you need to change the direction (up to ~i=36) by drawing it then found the formula like you would on a pattern recognition IQ test.
const size = 100;
let x = 500; // 500 is center x
let y = 500; // 500 is center y
let d = 'right';
let n = 1;
for (let i = 0; i < 10; i++) {
// change the direction
if (i === Math.pow(n, 2) - n) {
d = 'right';
} else if (i === Math.pow(n, 2)) {
d = 'down';
} else if (i === Math.pow(n, 2) + n) {
d = 'left';
} else if (i === Math.pow(n, 2) + (n * 2 + 1)) {
d = 'up';
n += 2;
}
// get the current x and y.
if (d === 'right') {
x += size;
} else if (d === 'left') {
x -= size;
} else if (d === 'down') {
y += size;
} else {
y -= size;
}
}

How to re-implement sin() method in Java ? (to have results close to Math.sin() )

I know Math.sin() can work but I need to implement it myself using factorial(int) I have a factorial method already below are my sin method but I can't get the same result as Math.sin():
public static double factorial(double n) {
if (n <= 1) // base case
return 1;
else
return n * factorial(n - 1);
}
public static double sin(int n) {
double sum = 0.0;
for (int i = 1; i <= n; i++) {
if (i % 2 == 0) {
sum += Math.pow(1, i) / factorial(2 * i + 1);
} else {
sum += Math.pow(-1, i) / factorial(2 * i + 1);
}
}
return sum;
}
You should use the Taylor series. A great tutorial here
I can see that you've tried but your sin method is incorrect
public static sin(int n) {
// angle to radians
double rad = n*1./180.*Math.PI;
// the first element of the taylor series
double sum = rad;
// add them up until a certain precision (eg. 10)
for (int i = 1; i <= PRECISION; i++) {
if (i % 2 == 0)
sum += Math.pow(rad, 2*i+1) / factorial(2 * i + 1);
else
sum -= Math.pow(rad, 2*i+1) / factorial(2 * i + 1);
}
return sum;
}
A working example of calculating the sin function. Sorry I've jotted it down in C++, but hope you get the picture. It's not that different :)
Your formula is wrong and you are getting a rough result of sin(1) and all you're doing by changing n is changing the accuracy of this calculation. You should look the formula up in Wikipedia and there you'll see that your n is in the wrong place and shouldn't be used as the limit of the for loop but rather in the numerator of the fraction, in the Math.pow(...) method. Check out Taylor Series
It looks like you are trying to use the taylor series expansion for sin, but have not included the term for x. Therefore, your method will always attempt to approximate sin(1) regardless of argument.
The method parameter only controls accuracy. In a good implementation, a reasonable value for that parameter is auto-detected, preventing the caller from passing to low a value, which can result in highly inaccurate results for large x. Moreover, to assist fast convergence (and prevent unnecessary loss of significance) of the series, implementations usually use that sin(x + k * 2 * PI) = sin(x) to first move x into the range [-PI, PI].
Also, your method is not very efficient, due to the repeated evaluations of factorials. (To evaluate factorial(5) you compute factorial(3), which you have already computed in the previous iteration of the for-loop).
Finally, note that your factorial implementation accepts an argument of type double, but is only correct for integers, and your sin method should probably receive the angle as double.
Sin (x) can be represented as Taylor series:
Sin (x) = (x/1!) – (x3/3!) + (x5/5!) - (x7/7!) + …
So you can write your code like this:
public static double getSine(double x) {
double result = 0;
for (int i = 0, j = 1, k = 1; i < 100; i++, j = j + 2, k = k * -1) {
result = result + ((Math.pow(x, j) / factorial (j)) * k);
}
return result;
}
Here we have run our loop only 100 times. If you want to run more than that you need to change your base equation (otherwise infinity value will occur).
I have learned a very good trick from the book “How to solve it by computer” by R.G.Dromey. He explain it like this way:
(x3/3! ) = (x X x X x)/(3 X 2 X 1) = (x2/(3 X 2)) X (x1/1!) i = 3
(x5/5! ) = (x X x X x X x X x)/(5 X 4 X 3 X 2 X 1) = (x2/(5 X 4)) X (x3/3!) i = 5
(x7/7! ) = (x X x X x X x X x X x X x)/(7 X 6 X 5 X 4 X 3 X 2 X 1) = (x2/(7 X 6)) X (x5/5!) i = 7
So the terms (x2/(3 X 2)) , (x2/(5 X 4)), (x2/(7 X 6)) can be expressed as x2/(i X (i - 1)) for i = 3,5,7,…
Therefore to generate consecutive terms of the sine series we can write:
current ith term = (x2 / ( i X (i - 1)) ) X (previous term)
The code is following:
public static double getSine(double x) {
double result = 0;
double term = x;
result = x;
for (int i = 3, j = -1; i < 100000000; i = i + 2, j = j * -1) {
term = x * x * term / (i * (i - 1));
result = result + term * j;
}
return result;
}
Note that j variable used to alternate the sign of the term .

Categories