Floating point accuracy [duplicate] - java

This question already has answers here:
Floating point arithmetic not producing exact results [duplicate]
(7 answers)
Closed 9 years ago.
I am writing a method which calculates the equation of a 2D Line in the form a*x+b*y=1
//Given two points, find the equation of the line by solving two linear equations and then test the result. (For simplicity, assume that delta !=0 here)
private boolean solveAndRetry(float x1,float y1, float x2,float y2) {
float delta = x1 * y2 - x2 * y1;
float deltaA = y2 - y1;
float deltaB = x1 - x2;
float a = deltaA / delta;
float b = deltaB / delta;
float c = 1;
//test
if (a * x2 + b * y2 == c) {
System.out.println("ok");
return true;
}
else {
System.out.println(a * x2 + b * y2-c);
return false;
}
}
When I ran it, I was expecting there would be all "ok"s, but that's not the case and I don't know why
public static void main(String[] args) {
for (float x = 0; x < 10; x += 0.01f) {
solveAndRetry(1, -1, x, 2);
}
}
Here are some lines in the result
ok
ok
ok
ok
ok
ok
ok
ok
-5.9604645E-8
ok
-5.9604645E-8
ok
ok
ok
1.1920929E-7
ok
ok
-5.9604645E-8
ok

A float has an accuracy of 6 to 7 decimal digits. Since rounding errors cannot be avoided, your results are as good as it can get.
Normally, you would never compare floating point numbers for equality. Instead of x == y always use a comparison with an interval:
Math.abs(x - y) < eps
for a suitably chosen eps.

Related

Detect interception with line

How can I make a algorithm that detects if a point (x, y) intercepts with a line. (x1, y1, x2, y2)?
I have already tried :
boolean onLine(float a, float b, float c, float d, float x, float y){
boolean answer = false;
float[] p1 = new float[] {a, b};
float[] p2 = new float[] {c, d};
float x_spacing = (p2[0] - p1[0]) / ((a+c)/2 + (b+d));
float y_spacing = (p2[1] - p1[1]) / ((a+c)/2 + (b+d));
List<float[]> line = new ArrayList();
float currentX = 0;
float currentY = 0;
while(currentX+a<c&&currentY+b<d){
currentX += x_spacing;
currentY += y_spacing;
line.add(new float[]{a+currentX, b+currentY});
}
for(int j = 0; j < line.size(); j++){
if(x > line.get(j)[0]-x_spacing && x < line.get(j)[0]+x_spacing && y > line.get(j)[1]-
y_spacing && y < line.get(j)[1]+y_spacing){
answer = true;
println("Hit line!");
break;
}
}
return answer;
}
This works sometimes, but is not always consistent.
I am putting this with a physics game, and I need this so the ball can roll down a line.
What are some ways I can improve it so that it works?.
EDIT: Thanks to Felix Castor I got it working. Here is the final Code:
boolean onLine(float x1, float y1, float x2, float y2, float xt, float yt,
float wid, float hit){
float Y = (y2 - y1)/(x2 - x1)* xt + y1 -(y2 - y1)/(x2 - x1) * x1;
boolean answer = false;
if(abs(Y - yt) < 5) answer = true;
if(abs(Y - yt-hit) < 5) answer = true;
if(abs(Y - yt-(hit/2)) < 5) answer = true;
if(abs(Y - yt+hit) < 5) answer = true;
if(abs(Y - yt+(hit/2)) < 5) answer = true;
return answer;
}
Using slope intercept form you can plug in your x and see if the y's are equal.
y = m*x + b
m = (y2 - y1)/(x2 - x1)
b = y1 - (y2 - y1)/(x2 - x1) * x1
So the equation becomes
Y = (y2 - y1)/(x2 - x1)* X + y1 -(y2 - y1)/(x2 - x1) * x1
given a point (xt, yt) you can plug in the xt into X and evaluate then compare the result to yt. If they are equal then the point is on the line.
if Y == yt given xt then the point is on the line.
You will need to handle the case where you have strictly horizontal lines as edge cases. Those will blow up the equation.
Edit: Conditions Changed
Since you are wanting to determine how far from the line a point is I would say the formula for the distance between a point and a line in cartesian space would be the way to go. See Distance from a point to a line section Line Defined By Two Points. The formula looks ugly but it's straight forward.
double numerator = Math.abs((y2 - y1) * xt - (x2 - x1) * yt + x2 * y1 - y2 * x1);
double denominator = Math.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2));
double distance = numerator / denominator;
As before your test point is (xt, yt) and your line is defined by two points (x1, y1) and (x2, y2). Because distance is always >= 0 your test would be:
if( distance <= tolerance) return true
I think this is a better approach if you are interested in a tolerance.

Function for finding the distance between a point and an edge in java

Does anyone have a function in java for finding the shortest distance between a point and a line segment/edge? Every example I find is in another language and uses a bunch of sub functions. It can't be based on the assumption that they are perpendicular.
Update
I ported over a python function to java. If anyone is good at math and can verify I would appreciate it. x and y is the point, and other params are for the line segment.
public float pDistance(float x, float y, float x1, float y1, float x2, float y2) {
float A = x - x1;
float B = y - y1;
float C = x2 - x1;
float D = y2 - y1;
float dot = A * C + B * D;
float len_sq = C * C + D * D;
float param = -1;
if (len_sq != 0) //in case of 0 length line
param = dot / len_sq;
float xx, yy;
if (param < 0) {
xx = x1;
yy = y1;
}
else if (param > 1) {
xx = x2;
yy = y2;
}
else {
xx = x1 + param * C;
yy = y1 + param * D;
}
float dx = x - xx;
float dy = y - yy;
return (float) Math.sqrt(dx * dx + dy * dy);
}
We can simplify things a bit. You don't need to calculate param. What you can do is find a vector v at right angles to the line. The take the dot product of that with the vector (A,B). In 2D its easy enough to find the vector orthogonal to (C,D), its just (-D,C).
public float pDistance(float x, float y, float x1, float y1, float x2, float y2) {
float A = x - x1; // position of point rel one end of line
float B = y - y1;
float C = x2 - x1; // vector along line
float D = y2 - y1;
float E = -D; // orthogonal vector
float F = C;
float dot = A * E + B * F;
float len_sq = E * E + F * F;
return (float) Math.abs(dot) / Math.sqrt(len_sq);
}
If you are worried about performance is can be easier to work with the squared distances then the last line would be
return (float) dot * dot / len_sq;
This saves having to calculate a square root. So if you want to calculate the closest edge, find the squared distances to each edge and select the smallest.
This function find the distance to the infinite line rather than the line segment. This may not be what you want. The solution in the question differs in what happens if the point is beyond the two ends of the line segment. There it find the distance to the closest end point.
From http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
The distance (or perpendicular distance) from a point to a line is the
shortest distance from a point to a line in Euclidean geometry. It is
the length of the line segment which joins the point to the line and
is perpendicular to the line.
You say that "It can't be based on the assumption that they are perpendicular.", but the shortest distance between a point and a line segment represents another line which is perpendicular to the original line. Hence it is the height of the triangle formed by A B and C, where A - the point, B and C are the end points of the line segment.
We know the coordinates of all three points, therefore we can obtain lengths of sides of the triangle. Using Heron's formula: https://www.mathsisfun.com/geometry/herons-formula.html we can obtain the area which is also equal to 0.5 * b * h from: https://www.mathsisfun.com/algebra/trig-area-triangle-without-right-angle.html
private static float distBetweenPointAndLine(float x, float y, float x1, float y1, float x2, float y2) {
// A - the standalone point (x, y)
// B - start point of the line segment (x1, y1)
// C - end point of the line segment (x2, y2)
// D - the crossing point between line from A to BC
float AB = distBetween(x, y, x1, y1);
float BC = distBetween(x1, y1, x2, y2);
float AC = distBetween(x, y, x2, y2);
// Heron's formula
float s = (AB + BC + AC) / 2;
float area = (float) Math.sqrt(s * (s - AB) * (s - BC) * (s - AC));
// but also area == (BC * AD) / 2
// BC * AD == 2 * area
// AD == (2 * area) / BC
// TODO: check if BC == 0
float AD = (2 * area) / BC;
return AD;
}
private static float distBetween(float x, float y, float x1, float y1) {
float xx = x1 - x;
float yy = y1 - y;
return (float) Math.sqrt(xx * xx + yy * yy);
}
I do not know how correct it is, hopefully a real mathematician can correct or back up this solution
If your line passes through two points, you can determine the equation of the line exactly.
If your line is ax + by + c = 0 and your point is (x0, y0), then the distance is given by :
This gives the shortest distance between any line and a point. (a, b, c are real constants)
Edit : In order to find the exact equation from two points on the line, the steps are :
`y − y1 = m(x − x1)` where m is the slope of the line.
Simplifying from this, a = -m, b = 1 and c = m*x1 - y1
If you do not want to implement all this by yourself I can recommend to use JTS. Use the distance method from LineSegment (for lines) or Coordinate (for points) accordingly. Given Points p1 and p2 for your Line and a Point p3 (that you want to calculate the distance) the code would look like that:
// create Line
LineSegment ls = new LineSegment(p1.getX(), p1.getY(), p2.getX(), p2.getY());
//calculate distance between Line and Point
double distanceLinePoint = ls.distance(new Coordinate(p3.getX(), p3.getY()));
// calculate distance between Points (p1 - p3)
double distanceBetweenPoints = new Coordinate(p1.getX(), p1.getY()).distance(new Coordinate(p3.getX(), p3.getY()));

Calculating percentage in java [duplicate]

This question already has answers here:
What's wrong with this division? [duplicate]
(6 answers)
Closed 8 years ago.
If I want to calculate 76/266 = 28.57% in java, what's the best data type to use?
So far, I have:
int x = 76;
int y = 266;
float z = (x * 100) / y;
But doing this, I get 28.0 as an answer. I need to get an answer rounded to the nearest hundredth place. Thanks.
In Java and some other programming languages, there is something called integer arithmetic, which says that if you do (in your case):
int / int = int
In your code, you are doing
(int * int) / int <=> int / int = int
Solutions:
Method 1: Something you can do to get a float is to use a float operand. In your case it can be the 100:
float z = (x * 100.0f) / y;
Here, the operation is
(int * float) / int <=> float / int = float
Method 2: Another way to solve this is to cast an integer to a float:
float z = (x * 100) / (float)y; // int * int / float = float
float z = (float)x * 100 / y; // float * int / int = float
Method 3: As #webSpider mentioned in his answer, you can just declare the variables x and y as float to avoid these problems.
Edit: To round your float result, you can try this:
float z = Math.round(result * 100) / 100f;
where the number of zeros of 100 is the number of decimal places. Note that 100f will be a float because of the postfix f.
float x = 76;
float y = 266;
float z = x * 100 / y;
//=28.571428
If you want to round it, use:
double x = 76;
double y = 266;
double z = Math.round(x * 100 / y* 100.0) / 100.0;
//=28.57
btw, as you see you don't need the parenthesis in your calculation there is a operator precedence ...
Maybe you can use java.math.BigDecimal for your calculation. I believe this is the highest precision datatype in Java
BigDecimal d1 = new BigDecimal(67.67);
BigDecimal d2 = new BigDecimal(67.68);
BidDecimal d3 = d1.divide(d2); // d1 + d2 is invalid
What you are doing in your code is,
multiply an integer x to 100 and then divide the result by integer y. So their output will be integer only.
Then you are storing this int result in a float variable. So it just adds .0 to your result.
To get the result you want you can do any of the following,
1. int x = 76;
int y = 266;
float z = (x * 100.0f) / y;
Note do not write 100.0 because it will be treated as a double number so you will get loss of precision error
2. float x = 76;
int y = 266;
float z = (x * 100) / y;
3. float x = 76;
float y = 266;
float z = (x * 100) / y;

Creating a System of Equations Method in Java

I am trying to establish a Java method to calculate the x and y coordinate based off of three given coordinates and distances. I used the following post:Determining The Coordinates Of A Point Based On Its Known Difference From Three Other Points for guidance. I just can't get this to work properly and don't really understand the math. With my given inputs I should be outputting (1,4), but instead output a bunch of different results depending on what I make d1, d2, d3.
public class Driver {
public static void main (String[] args)
{
double x1 = 1;
double y1 = 1;
double x2= 2;
double y2 = 1;
double x3= 3;
double y3 = 1;
double d1 = 3;
double d2 = 2;
double d3 = 1;
Main control = new Main();
control.GET_POINT(x1,y1,x2,y2,x3,y3,d1,d2,d3);
}
}
Class w/ Method:
public class Main {
public void GET_POINT(double x1, double y1,double x2,double y2,double x3,double y3, double r1, double r2, double r3){
double A = x1 - x2;
double B = y1 - y2;
double D = x1 - x3;
double E = y1 - y3;
double T = (r1*r1 - x1*x1 - y1*y1);
double C = (r2*r2 - x2*x2 - y2*y2) - T;
double F = (r3*r3 - x3*x3 - y3*y3) - T;
// Cramer's Rule
double Mx = (C*E - B*F) /2;
double My = (A*F - D*C) /2;
double M = A*E - D*B;
double x = Mx/M;
double y = My/M;
System.out.println(x);
System.out.println("and ");
System.out.println( y);
}
}
I guess that there is no problem with your program. The problem is that the four points that you chose have the same Y (the distance vectors are colinar). Therefore, M that is the determinant that is used by the cramer method to solve the linear system is always zero. So two divisions by zero arise in your program.
In this case, the solution is much simpler:
(x-xi)^2+(y-yi)^2=di^2
But y-yi=0. Threfore, x-xi=di.
So, I can write
x-x1=d1
x-x2=d2
x-x3=d3
Therefore, using any of these equations you get x=4 and Y is the same of the other points.
[PS: I think it is not a problem, but in the evaluation of Mx and My instead of dividing by 2 I would divide by 2.0 - just to be sure that integer division is not happening]
I hope I helped.
Daniel

Float calculation keeps returning 0.0

I'm writing a method to return a List of Points between 2 Points. Somehow the slope (y2-y1)/(x2-x1) keeps giving me 0.0 all the time regardless startPoint and endPoint positions.
Here is the method:
public ArrayList<Point> calculatePath(Point startPoint, Point endPoint) {
ArrayList<Point> calculatedPath = new ArrayList<>();
int x1 = startPoint.x;
int y1 = startPoint.y;
int x2 = endPoint.x;
int y2 = endPoint.y;
System.out.println("Run");
if ((x2 - x1) != 0) {
float ratio = ((y2 - y1) / (x2 - x1));
System.out.println(ratio);
int width = x2 - x1;
for (int i = 0; i < width; i++) {
int x = Math.round(x1 + i);
int y = Math.round(y1 + (ratio * i));
calculatedPath.add(new Point(x, y));
}
} else {
if (y1 < y2) {
while (y1 == y2) {
calculatedPath.add(new Point(x1, y1));
y1++;
}
} else {
while (y1 == y2) {
calculatedPath.add(new Point(x1, y1));
y1--;
}
}
}
return calculatedPath;
}
Can anyone point out what i'm doing wrong? Thanks
Try casting your ints into floats as well
During your caluclation you need to cast at least one element to float:
float ratio = ((float)(y2 - y1) / (float)(x2 - x1));
That is because:
float a = integer / integer
^^^^^^^^^^^^^^^^^ - The result will be an integer.
Therefore u need to cast at least one of the
to float
This examples shows it easly:
public static void main(String[] args)
{
float resultWithoutCast = 5 / 3;
float resultWithCast = (float)5 /3 ;
System.out.println(resultWithoutCast);
System.out.println(resultWithCast);
}
It will print
1.0
1.6666666
You forgot to cast your int during division. Try something like this:-
float ratio = ((float)(y2 - y1) / (x2 - x1));
When performing arithmetic you need to make sure you use types which allow for the expected result. For example, the issue with your code is you are looking for a floating point result but using int - the problem here is int will simply truncate any floating point.
There are a couple of ways to solving this problem - as already suggested you could use a cast
float ratio = ((float)(y2 - y1) / (x2 - x1));
Or you could use float variables, it makes for more readable code e.g.
float x1 = (float)startPoint.X;
float y1 = (float)startPoint.Y;
...
float ratio = (y2 - y1) / (x2 - x1);
However, this results in more casting.
Alternatively, you could swap out Point for PointF and eliminate casting completely.

Categories