How do I easily implement the Matlab percentile in Java? - java

I need to replicate the Matlab Percentile ( https://www.mathworks.com/help/stats/prctile.html ) for a simple case
percentile(double[] arr, int percentile) in java. I am unable to find any implementations which give me the same result since it seems to have a percentile along with linear interpolation.
Any help or guidance is appreciated!

By directly applying the definition (you can found in the page you've linked)
// `xs` must be sorted
double percentile(double [] xs, int p) {
// The sorted elements in X are taken as the 100(0.5/n)th, 100(1.5/n)th, ..., 100([n – 0.5]/n)th percentiles.
int i = (int) (p * xs.length / 100.0 - 0.5);
// Linear interpolation uses linear polynomials to find yi = f(xi), the values of the underlying function
// Y = f(X) at the points in the vector or array x. Given the data points (x1, y1) and (x2, y2), where
// y1 = f(x1) and y2 = f(x2), linear interpolation finds y = f(x) for a given x between x1 and x2 as follows:
return xs[i] + (xs[i + 1] - xs[i]) * (p / 100.0 - (i + 0.5) / xs.length) / ((i + 1.5) / xs.length - (i + 0.5) / xs.length);
}
using the example on that page
double [] xs1 = new double[] {6.0753, 8.6678, 0.4823, 6.7243, 5.6375, 2.3846, 4.1328, 5.6852, 12.1568, 10.5389};
Arrays.sort(xs1);
double r = percentile(xs1, 42);
System.out.println("Result: " + r);
System.out.println("Error: " + Math.abs(r - 5.6709));
you get
Result: 5.67089
Error: 9.999999999621423E-6

The #josejuan's answer is very good: but is it not necessary to handle the case in which i is equal to xs.length - 1? I would modify the return formula of percentile function as follows:
return i != (xs.length - 1) ? xs[i] + (xs[i + 1] - xs[i]) * (p / 100.0 - (i + 0.5) / xs.length) / ((i + 1.5) / xs.length - (i + 0.5) / xs.length) : xs[i];

Related

Finding line intersect using Cramer's rule - Getting incorrect y coordinate

I'm looking to find the intersect of 2 lines using Cramer's rule. This is for an exercise from the book An Introduction To Java Programming (Exercise 3.25 from Chapter 3 and 8.31 from Chapter 8. They are both basically the same idea just the one from chapter 8 uses arrays).
The exercise tells us to use Cramer's Rule and provides the general formula.
(y1 - y2)x - (x1 - x2)y = (y1 - y2)x1 - (x1 - x2)y1
(y3 - y4)x - (x3 - x4)y = (y3 - y4)x3 - (x3 - x4)y3
My problem is that I'm getting the y coordinate as a negative while I expected it to be a positive.
This is the output that I'm getting.
The intersecting point is at (2.888888888888889, -1.1111111111111112)
This is what I expected to get.
The intersecting point is at (2.888888888888889, 1.1111111111111112)
Here is the code I have come up with.
public class Test{
public static void main(String[] args){
double[][] points = {{2, 2}, {5, -1.0}, {4.0, 2.0}, {-1.0, -2.0}};
double[] result = getIntersectingPoint(points);
if(result == null)
System.out.println("The 2 lines are parallel");
else
System.out.println("The intersecting point is at (" + result[0] + ", " + result[1] + ")");
}
/*
*For two lines to see if they intersect
*(y1 - y2)x - (x1 - x2)y = (y1 - y2)x1 - (x1 - x2)y1
*(y3 - y4)x - (x3 - x4)y = (y3 - y4)x3 - (x3 - x4)y3
*/
public static double[] getIntersectingPoint(double[][] points){
double[] result = new double[2];
double a = points[0][1] - points[1][1]; //y1 - y2;
double b = points[0][0] - points[1][0]; //x1 - x2;
double c = points[2][1] - points[3][1]; //y3 - y4;
double d = points[2][0] - points[3][0]; //x3 - x4;
double e = a * points[0][0] - b * points[0][1]; //(y1 - y2)x1 - (x1 - x2)y1
double f = c * points[2][0] - d * points[2][1]; //(y3 - y4)x3 - (x3 - x4)y3
double determinant = a * d - b * c;
//There is no solution to the equation,
//this shows the lines are parallel
if(determinant == 0)
return null;
//There is a solution to the equation
//this shows the lines intersect.
else{
result[0] = (e * d - b * f) / determinant;
result[1] = (a * f - e * c) / determinant;
}
return result;
}
}
I have searched around and found some solutions in general to the exercise. But I haven't found anything about my issue of getting a negative y coordinate.
Here is a picture of the intersecting lines
To answer my own question...
I finally figured out the problem. At the end of the function getIntersectingPoint there us the following line.
result[0] = (e * d - b * f) / determinant;
this needs to be changed to the following.
result[0] = (b * f - e * d) / determinant;
A little in my defense. I don't really understand Cramer's rule, I was just following what the book was telling me. the book shows the following as the rule. (This is given in Chapter 1 Exercise 1.13).
ax + by = e
cx + dy = f
x = ed - bf / ad - bc
y = af - ec / ad - bc
Given this I just adjusted it to find the line intersect.

I am trying to calculate sine of an angle without using the Math.sin() in java

I am trying to calculate sine of an angle without using the Math.sin(). I got stuck in it's equation as I keep getting the wrong results
note I have a method that changes the angle from degrees to radians
public static double sin(double x, int precision) {
//this method is simply the sine function
double answer = 1, power = 1;
int n = 2,factorial = 1;
while (n<=precision) {
power = (power * x * x *-1) +1 ;
factorial = (factorial * (n +1))* (n-1);
answer = answer + ((power/factorial ));
n = n + 2;
}
return answer;
}
It looks like you're attempting to calculate the sine of angle given in radians using the Maclaurin series, a special case of Taylor series.
sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
Your initial answer is 1 when it should be x. Your initial power is 1 when it should be x also.
double answer = x, power = x;
For some reason you're adding one to the power part of the result when you shouldn't be.
power = (power * x * x * -1);
You'll also need to fix your factorial calculation. Multiply by n + 1 and n, not n + 1 and n - 1.
factorial = (factorial * (n + 1)) * (n);
With these fixes, testing:
for (double angle = 0; angle <= Math.PI; angle += Math.PI / 4)
{
System.out.println("sin(" + angle + ") = " + sin(angle, 10));
}
The results are pretty good considering the limitations of precision for floating point arithmetic.
sin(0.0) = 0.0
sin(0.7853981633974483) = 0.7071067811796194
sin(1.5707963267948966) = 0.999999943741051
sin(2.356194490192345) = 0.7070959900908971
sin(3.141592653589793) = -4.4516023820965686E-4
Note that this will get more inaccurate as the values of x get larger, not just because of the inaccuracy to represent pi, but also because of the floating point calculations for adding and subtracting large values.

Having trouble with my math? Very simple java

Hi I'm in my first coding class. This is my first code using math and I'm struggling to see where I went wrong, I have no errors but the calculations are undefined.
I need to find the area of the triangle using 3 points. I was given the euqations:
s = (side1 + side2 + side3)/2
area = sqrt(s(s-side)(s- side2)(s-side3))
Side = sqrt(x1-y1)+ (x2-y2)
Please help, here's my code:
double sideOne = Math.sqrt(Math.pow((x1cr - x2cr), 2 + Math.pow((y1cr - y2cr), 2)));
double sideTwo = Math.sqrt(Math.pow((x2cr - x3cr), 2 + Math.pow((y2cr - y3cr), 2)));
double sideThree = Math.sqrt(Math.pow((x1cr - x3cr), 2 + Math.pow((y1cr - y3cr), 2)));
double lSide = (sideOne + sideTwo + sideThree) / 2;
double areaTri = Math.sqrt((lSide * (lSide - sideOne) * (lSide - sideTwo) * (lSide - sideThree)));
System.out.println("The area of your triangle is " + areaTri);
Edit: Here's the example my teacher gave:
Here is a sample run:
Enter the coordinates of the first vertex (x1, y1) of the triangle: 1.5 -3.4
Enter the coordinates of the second vertex (x2, y2) of the triangle: 4.6 5
Enter the coordinates of the third vertex (x3, y3) of the triangle: 9.5 -3.4
The area of the triangle is 33.6 sq cms
The problem is how you're calculating sideOne, sideTwo and sideThree.
I believe you calculate sideOne like this:
Then your code should be:
double sideOne = Math.sqrt(Math.pow((x1cr - x2cr), 2) + Math.pow((y1cr - y2cr), 2));
^ ^
1 2
Note that the formula is same, but the placement of bracket is different. A bracket from position 2 is shifted to position 1.
Similar changes should be done while calculating sideTwo and sideThree as well.
Please review the code and the comments. Don't hesitate to ask if it is not clear:
class Test {
//always post MCVE (stackoverflow.com/help/mcve)
public static void main(String[] args) {
double x1cr=1.5, y1cr=-3.4, //side one end points
x2cr=4.6, y2cr=5, //side two end points
x3cr=9.5, y3cr=-3.4; //side three end points
double sideOne = Math.sqrt(squareIt(x1cr, x2cr)+ squareIt(y1cr, y2cr) );
double sideTwo = Math.sqrt(squareIt(x2cr, x3cr) + squareIt(y2cr, y3cr));
double sideThree = Math.sqrt(squareIt(x1cr, x3cr)+ squareIt(y1cr, y3cr));
System.out.println(sideOne+ " "+ sideTwo+ " "+ sideThree);
double lSide = (sideOne + sideTwo + sideThree) / 2;
double areaTri = Math.sqrt((lSide * (lSide - sideOne) * (lSide - sideTwo) * (lSide - sideThree)));
System.out.println("The area of your triangle is " + areaTri);
}
//put the repeating calculation in a function
//it is easy to check such function by say :
// System.out.println(squareIt(5., 3.));
static double squareIt(Double x1, double x2) {
return Math.pow((x1 - x2), 2);
}
}

Simple explanation about checking whether a line segment intersects a sphere or a cube

I'm currently working on a raycaster, but I have one single problem.
Everything is set up, now I just need a bit mathematical help to answer following questions, and I couldn't find any simple explanation and we haven't learned such advanced vector stuff in school yet.
1] I have a line going from, lets say, (0,0,0) to (50,50,50)
now how can I find out if its intersects with a sphere, e.g (m = (10,10,5), r = 5)?
Yes, I searched around the whole internet, but ANYTHING is explained in vectors, but since they are not the same as lines that go from A to B, I never found anything helpful.
2] I have the same line from above, but this time I want to check if it intersects with a Cube, m = (25,30,50), it has a sidelenght of 5 units.
As before, please keep your explanation as simple as possible, an I'm working with Java by the way.
1) Sphere: The idea is to find the distance from the sphere's center to the line. If it is greater than the radius --> outside, vise versa - inside ( and if equal --> on the surface)
The equation of a line which goes through 2 point A, B is
x = A.x + (B.x - A.x)*t
y = A.y + (B.y - A.y)*t
z = A.z + (B.z - A.z)*t
The distance from the point M to a point in the line AB is:
d(t) = Math.sqrt((x - M.x) * (x - M.x) + (y - M.y) * (y - M.y) + (z - M.z) * (z - M.z))
The distance from the point M to the line AB is the shortest d(t)
If we set
g(t) = (x - M.x) * (x - M.x) + (y - M.y) * (y - M.y) + (z - M.z) * (z - M.z)
We will have
d(t) = Math.sqrt(g(t))
To find min(d(t)), we will try to find min(g(t)) instead (because the function derivative will be simpler). And to find min(g(t)), solve the equation derivative(g(t)) = 0
You will find
t = ((B.x - A.x)*(M.x - A.x) + (B.y - A.y)*(M.y - A.y) +
(B.z - A.z)*(M.z - A.z))/((B.x - A.x)*(B.x - A.x) + (B.y - A.y)*(B.y - A.y) + (B.z - A.z)*(B.z - A.z))
Then you can find d (or d*d)
2) Cube: The idea is to find the intersection of the line (AB) with each side of the cube and see if at least 1 side has the intersection inside the square
You don't say anything about whether the cube have sides parallel with coordinate axes, but let's use that case (the simplest :) )
The AB line's equation is the same as in 1)
x = A.x + (B.x - A.x)*t
y = A.y + (B.y - A.y)*t
z = A.z + (B.z - A.z)*t
The equations of all 8 sides are: (in your example, d = 5)
X = M.x - d
X = M.x + d
Y = M.y - d
Y = M.y + d
Z = M.z - d
Z = M.z + d
You should find the intersection between AB with each side of the cube
For example, AB with X = M.x -d
Solve the system of equations:
x = A.x + (B.x - A.x)*t
y = A.y + (B.y - A.y)*t
z = A.z + (B.z - A.z)*t
x = M.x - d
You will find:
x = M.x -d
t = (M.x -d - A.x)/(B.x - A.x) .. then find y, z
The point (x,y,z) is inside the side X = M.x -d of the cube if
M.y - d <= y <= M.y + d (and similar for z)
And do the same for other sides.
NOTE: If you want to check whether the segment [AB] intersects (reaches) the sphere/cube, you need to check one more conditions: The intersection is in the segment [AB]
min(A.x, B.x) <= x <= max(A.x, B.x)
min(A.y, B.y) <= y <= max(A.y, B.y)
..
Hope it can help you!

How to draw a smooth line through a set of points using Bezier curves?

I need to draw a smooth line through a set of vertices. The set of vertices is compiled by a user dragging their finger across a touch screen, the set tends to be fairly large and the distance between the vertices is fairly small. However, if I simply connect each vertex with a straight line, the result is very rough (not-smooth).
I found solutions to this which use spline interpolation (and/or other things I don't understand) to smooth the line by adding a bunch of additional vertices. These work nicely, but because the list of vertices is already fairly large, increasing it by 10x or so has significant performance implications.
It seems like the smoothing should be accomplishable by using Bezier curves without adding additional vertices.
Below is some code based on the solution here:
http://www.antigrain.com/research/bezier_interpolation/
It works well when the distance between the vertices is large, but doesn't work very well when the vertices are close together.
Any suggestions for a better way to draw a smooth curve through a large set of vertices, without adding additional vertices?
Vector<PointF> gesture;
protected void onDraw(Canvas canvas)
{
if(gesture.size() > 4 )
{
Path gesturePath = new Path();
gesturePath.moveTo(gesture.get(0).x, gesture.get(0).y);
gesturePath.lineTo(gesture.get(1).x, gesture.get(1).y);
for (int i = 2; i < gesture.size() - 1; i++)
{
float[] ctrl = getControlPoint(gesture.get(i), gesture.get(i - 1), gesture.get(i), gesture.get(i + 1));
gesturePath.cubicTo(ctrl[0], ctrl[1], ctrl[2], ctrl[3], gesture.get(i).x, gesture.get(i).y);
}
gesturePath.lineTo(gesture.get(gesture.size() - 1).x, gesture.get(gesture.size() - 1).y);
canvas.drawPath(gesturePath, mPaint);
}
}
}
private float[] getControlPoint(PointF p0, PointF p1, PointF p2, PointF p3)
{
float x0 = p0.x;
float x1 = p1.x;
float x2 = p2.x;
float x3 = p3.x;
float y0 = p0.y;
float y1 = p1.y;
float y2 = p2.y;
float y3 = p3.y;
double xc1 = (x0 + x1) / 2.0;
double yc1 = (y0 + y1) / 2.0;
double xc2 = (x1 + x2) / 2.0;
double yc2 = (y1 + y2) / 2.0;
double xc3 = (x2 + x3) / 2.0;
double yc3 = (y2 + y3) / 2.0;
double len1 = Math.sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
double len2 = Math.sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
double len3 = Math.sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));
double k1 = len1 / (len1 + len2);
double k2 = len2 / (len2 + len3);
double xm1 = xc1 + (xc2 - xc1) * k1;
double ym1 = yc1 + (yc2 - yc1) * k1;
double xm2 = xc2 + (xc3 - xc2) * k2;
double ym2 = yc2 + (yc3 - yc2) * k2;
// Resulting control points. Here smooth_value is mentioned
// above coefficient K whose value should be in range [0...1].
double k = .1;
float ctrl1_x = (float) (xm1 + (xc2 - xm1) * k + x1 - xm1);
float ctrl1_y = (float) (ym1 + (yc2 - ym1) * k + y1 - ym1);
float ctrl2_x = (float) (xm2 + (xc2 - xm2) * k + x2 - xm2);
float ctrl2_y = (float) (ym2 + (yc2 - ym2) * k + y2 - ym2);
return new float[]{ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y};
}
Bezier Curves are not designed to go through the provided points! They are designed to shape a smooth curve influenced by the control points.
Further you don't want to have your smooth curve going through all data points!
Instead of interpolating you should consider filtering your data set:
Filtering
For that case you need a sequence of your data, as array of points, in the order the finger has drawn the gesture:
You should look in wiki for "sliding average".
You should use a small averaging window. (try 5 - 10 points). This works as follows: (look for wiki for a more detailed description)
I use here an average window of 10 points:
start by calculation of the average of points 0 - 9, and output the result as result point 0
then calculate the average of point 1 - 10 and output, result 1
And so on.
to calculate the average between N points:
avgX = (x0+ x1 .... xn) / N
avgY = (y0+ y1 .... yn) / N
Finally you connect the resulting points with lines.
If you still need to interpolate between missing points, you should then use piece - wise cubic splines.
One cubic spline goes through all 3 provided points.
You would need to calculate a series of them.
But first try the sliding average. This is very easy.
Nice question. Your (wrong) result is obvious, but you can try to apply it to a much smaller dataset, maybe by replacing groups of close points with an average point. The appropriate distance in this case to tell if two or more points belong to the same group may be expressed in time, not space, so you'll need to store the whole touch event (x, y and timestamp). I was thinking of this because I need a way to let users draw geometric primitives (rectangles, lines and simple curves) by touch
What is this for? Why do you need to be so accurate? I would assume you only need something around 4 vertices stored for every inch the user drags his finger. With that in mind:
Try using one vertex out of every X to actually draw between, with the middle vertex used for specifying the weighted point of the curve.
int interval = 10; //how many points to skip
gesture.moveTo(gesture.get(0).x, gesture.get(0).y);
for(int i =0; i +interval/2 < gesture.size(); i+=interval)
{
Gesture ngp = gesture.get(i+interval/2);
gesturePath.quadTo(ngp.x,ngp.y, gp.x,gp.y);
}
You'll need to adjust this to actually work but the idea is there.

Categories