Euler Method in Java, Variable Initial Condition - java

How would I write the Euler method in Java for a variable initial condition? For example, the initial condition that y(w)=0.
The equation I'm trying to solve is:
dy/dx = (y-sqrt(x^2 + y^2))/x
My initial code is simple.
import java.lang.Math;
public class euler
{
public static void main(String arg[])
{
int N = 10;
double h = 1.0/N;
double x0 = w; //This is what I would like to put in
double y0 = 0;
double x = x0, y = y0;
for (int i=0;i < N;i++)
{
y += h*f(x, y);
x += h;
System.out.println("x, y = " + x + ", " + y);
}
}
static double f(double x, double y)
{
return((y-Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)))/x);
}
}
My code should work for any kind of integer value of x0, but how could I get it to work for a variable w?

You get not only one solution, you get a family of solutions parametrized by the initial condition. Through every point (x0,y0) there is a solution, some, but not all, will give the same solution.
Thus y(w)=0 resp. the pair (x0=w, y0=0) will give a solution for every w, there is nothing to solve to get a specific value of w.
?? Could w stand for omega and that for infinity ?? That would be a valid question, to control the asymptotic behavior.
The only critical point of this problem is x=0, and even that only for y(0)<0, since then the differential equation has a singularity.

Related

Java: Rotations and 3D distortions

I'm writing a program that will rotate a rectangular prism around a point. It handles the rotations via 3 rotation methods that each manage a rotation around a single axis (X, Y, and Z). Here's the code
public void spinZ(Spin spin) {
if (x == 0 && y == 0) {
return;
}
double mag = Math.sqrt(x * x + y * y);
double pxr = Math.atan(y / x);
x = Math.cos(spin.zr + pxr) * mag;
y = Math.sin(spin.zr + pxr) * mag;
}
public void spinY(Spin spin) {
if (z == 0 && x == 0) {
return;
}
double mag = Math.sqrt(x * x + z * z);
double pxr = Math.atan(z / x);
x = Math.cos(spin.yr + pxr) * mag;
z = Math.sin(spin.yr + pxr) * mag;
}
public void spinX(Spin spin) {
if (z == 0 && y == 0) {
return;
}
double mag = Math.sqrt(y * y + z * z);
double pxr = Math.atan(z / y);
y = Math.cos(spin.xr + pxr) * mag;
z = Math.sin(spin.xr + pxr) * mag;
}
public void addSpin(Spin spin) {
spinY(spin);
spinX(spin);
spinZ(spin);
}
Spin is a useless class that stores three doubles (which are rotations). These methods basically convert the rotations into 2D vectors (how I store the points) and rotate them as such. The first if statement makes sure the 2D vectors don't a magnitude of 0. They are allowed to, but in that case it's not necessary to carry out the rotation calculations. The other part just handles the trig. The bottom method just ties everything together and allows me to quickly change the order of the rotations (because order should and does affect the final rotation).
The problem isn't with the individual rotations but when they all come together. I can easily get a single rotation around a single axis to work without distorting the rectangular prism. When I put them all together, like if you were to call addSpin().
When spinY is called first, the prism is distorted when the rotations include a Y rotation (if the y component of the rotation is zero, and no rotation around the y-axis should occur, then no distortion occurs). In fact, if spinY() is called anytime but last a distortion of the cube will occur.
The same is the case with spinZ(). If spinZ() is called last, the cube won't get warped. However spinX() can go anywhere and not cause a distortion.
So the question is: Is there a problem with how I'm going about the rotations? The other question is while all rotations cannot be encompassed by rotations along just the X and Y axes or any other pair of distinct axes (like X and Z, or Y and Z), can those three sets collectively make all rotations? To clarify, can the rotations, which cannot be reached by a set of rotations around the X and Y axes, be reached by a set of rotations around the X and Z axes or the Y and Z axes?
I trust the medium I'm using to display the prisms. It's a ray-tracer I made that works well with rectangular prisms. This is a more math-based question, but it has a fairly comprehensive programming component.
These are some parallel calculations that still yield in distortions.
public void spinZ(Spin spin) {
double c = Math.cos(spin.yr);
double s = Math.sin(spin.yr);
double xp = x*c - y*s;
double yp = y*s + x*c;
x = xp;
y = yp;
}
public void spinY(Spin spin) {
double c = Math.cos(spin.yr);
double s = Math.sin(spin.yr);
double zp = z*c - x*s;
double xp = z*s + x*c;
x = xp;
z = zp;
}
public void spinX(Spin spin) {
double c = Math.cos(spin.yr);
double s = Math.sin(spin.yr);
double yp = y*c - z*s;
double zp = z*c + y*s;
y = yp;
z = zp;
}
Your checks for things like
x == 0
are unnecessary and dangerous as a double almost never will have the precise value 0. The atan when you have a division can lead to catastrophic loss of precision as well.
Why are they unnecessary? Because the following performs your rotation in a cleaner (numerically stable) fashion:
double c = Math.cos(spin.yr);
double s = Math.cos(spin.yr);
double zp = z*c - x*s;
double xp = z*s + x*c;
x = xp;
z = zp;
Of course, my example assumes you treat the y rotation with a right handed orientation, but from your sample code you seem to be treating it as left handed. Anyways, the wikipedia article on the Rotation matrix explains the math.

How to get Y value from X value in JFreeChart

I'm using JFreeChart to draw chart. I have XYSeries with points (0, 0), (1, 2), (2, 5) and I want to read Y value for let's say x=1.5.
Is it possible to read value for points which are not in XYSeries? I couldn't find similar topic.
This is not supported directly. It does not make sense in many cases: There simply is no data available for x=1.5. The value there could be 1000.0, or -3.141. You don't know.
However, you're most likely looking for a linear interpolation. The pragmatic approach is thus to find the interval that contains the respective x-value, and interpolate the y-values linearly.
There are some technical caveats. E.g. the XYSeries may be not sorted, or may contain duplicate x-values, in which case there is no unique y-value for a given x-value. But for now, we can assume that the data set does not have these properties.
The following is an example of how this could be implemented. Note that this is not very efficient. If you have to compute many intermediate values (that is, if you intend to call the interpolate method very often), it would be beneficial to create a tree-based data structure that allows looking up the interval in O(logn).
However, if this is not time critical (e.g. if you only intend to show the value in a tooltip or so), you may interpolate the values like this:
import java.util.List;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
public class XYInterpolation
{
public static void main(String[] args)
{
XYSeries s = new XYSeries("Series");
s.add(0,0);
s.add(1,2);
s.add(2,5);
double minX = -0.5;
double maxX = 3.0;
int steps = 35;
for (int i=0; i<=steps; i++)
{
double a = (double)i / steps;
double x = minX + a * (maxX - minX);
double y = interpolate(s, x);
System.out.printf("%8.3f : %8.3f\n", x, y);
}
}
private static double interpolate(XYSeries s, double x)
{
if (x <= s.getMinX())
{
return s.getY(0).doubleValue();
}
if (x >= s.getMaxX())
{
return s.getY(s.getItemCount()-1).doubleValue();
}
List<?> items = s.getItems();
for (int i=0; i<items.size()-1; i++)
{
XYDataItem i0 = (XYDataItem) items.get(i);
XYDataItem i1 = (XYDataItem) items.get(i+1);
double x0 = i0.getXValue();
double y0 = i0.getYValue();
double x1 = i1.getXValue();
double y1 = i1.getYValue();
if (x >= x0 && x <= x1)
{
double d = x - x0;
double a = d / (x1-x0);
double y = y0 + a * (y1 - y0);
return y;
}
}
// Should never happen
return 0;
}
}
(This implementation clamps at the limits. This means that for x-values that are smaller than the minimum x-value or larger than the maximum x-value, the y-value of the minimum/maximum x-value will be returned, respectively)
You can use DatasetUtils.findYValue() from package org.jfree.data.general

Hexagonal Grid (Flat Top) Distance Calculation

I have been working on creating a hexagonal (flat top) grid for a simulation I am working on. I have attempted to work out the distance between the hexagons, from a specified target hexagon.
The solution I have works for most of the time, apart from every odd column from the target hexagon north of the target is shifted up by 1. I know that sounds confusing but I have attached an image to explain what I mean:
As you guys can see, the bottom half of the grid below the target hexagon and every other column above the target Hexagon is correct. I cannot understand why :S
Here is an explanation of the Axial & Cube Co-ords.
http://www.redblobgames.com/grids/hexagons/#coordinates
Here is the code responsible for converting the Axial Co-ords to Cube Co-ords.
public void setQR(int theQ, int theR){
this.q = theQ;
this.r = theR;
this.x = this.q;
this.z = this.r - (this.q - (this.q&1)) /2;
this.y = -(this.x + this.z);
}
And heres the code for working out distance.
FYI, the Hexagons are created from a CentrePoint (CPx, CPy).
private double distance = 0;
public double workOutDistance(Hexagon hexagon, HexagonFood target){
double targetX = target.getCPX();
double targetY = target.getCPY();
double hexagonX = hexagon.getCPX();
double hexagonY = hexagon.getCPY();
double deltaX = (targetX-hexagonX)*-1;
double deltaY = (targetY-hexagonY)*-1;
double deltaXRadius = (deltaX/(SimField.hexSize)/1.5);
double deltaYApothem = (deltaY/(SimField.hexSize/1.155)/2);
hexagon.setQR((int)deltaXRadius, (int)deltaYApothem);
ArrayList<Integer> coords = new ArrayList<>();
coords.add(
Math.abs(hexagon.getX() - target.getX())
);
coords.add(
Math.abs(hexagon.getZ() - target.getZ())
);
coords.add(
Math.abs(hexagon.getY() - target.getY())
);
System.out.println(coords);
distance = Collections.max(coords);
return distance;
}
Can anyone please tell me why this is happening ? Would be greatly appreciated.
EDIT:
After changing Int to Double as suggested by Tim, I get this.
http://i.stack.imgur.com/javZb.png
**
SOLUTION
**
after experimenting with the answers given, This small tweak solves the problem.
changing this..
public void setQR(int theQ, int theR){
this.q = theQ;
this.r = theR;
this.x = this.q;
this.z = this.r - (this.q - (this.q&1)) /2;
this.y = -(this.x + this.z);
}
to this..
public void setQR(int theQ, int theR){
this.q = theQ;
this.r = theR;
this.x = this.q;
if (this.r>0){
this.z = this.r - (this.q - (this.q&1))/2;
}
else {
this.z = this.r - (this.q + (this.q&1))/2;
}
this.y = -(this.x + this.z);
}
You're casting a double to an int when calling setQR(); are you sure that's doing what you expect? Doubles use floating point math, so the number you'd expect to be 2.0 might actually be 1.999999989, which would then be rounded down to 1 when cast to an int.
I'm also skeptical of the line that reads this.z = this.r - (this.q - (this.q&1)) /2;. You're adding 1 when the number is odd, which seems to be the failure case you're experiencing; I'd make sure that line is doing what you're expecting, too.
If you're not stepping through this with a debugger and examining the values, you're doing it wrong.
You could also take an entirely different approach to this problem. You know the X/Y (cartesian) coordinates of your two hexagons, which means you can get each hexagon's cubic coordinates relative to the origin of your hexagonal space. The distance between the two hexagons is simply the sum of the absolute values of the differences between the two hexagons' X, Y and Z cubic coordinates. (That is, dist = |h2.X - h1.X| + |h2.Y - h1.Y| + |h2.Z - h1.Z|) So rather than trying to compute the vector between the two centerpoints and then convert that into cubic coordinates, you could just compute the distance directly in cubic coordinates (just like you would if these were squares in cartesian coordinates)...
Even if you take this approach, though, I'd strongly recommend that you debug what's going on with your original approach. Even if you end up throwing away the code, the exercise of debugging will probably teach you valuable lessons that you'll be able to apply in the future.
Note to readers: "cubic" coordinates aren't 3-dimensional cartesian coordinates, they're a hexagon-specific coordinate system for which a link was provided by the OP.
The fact that the computation (that is, the conversion from offset- to cube coordinates, and the computation of the distance in cube coordinates) seems to be correct suggests that Tim was right with his assumption about the floating point errors.
You should try to change the line
hexagon.setQR((int)deltaXRadius, (int)deltaYApothem);
from your original code to something like
hexagon.setQR((int)Math.round(deltaXRadius), (int)Math.round(deltaYApothem));
Which could solve the issue in this case.
If not ... or... in any case, here's a small example, basically doing the same as you did, but as a MVCE...
import java.awt.Point;
public class HexagonsTest
{
public static void main(String[] args)
{
// Above and below
test(8,6, 8,5, 1);
test(8,6, 8,7, 1);
// Left
test(8,6, 7,5, 1);
test(8,6, 7,6, 1);
// Right
test(8,6, 9,5, 1);
test(8,6, 9,6, 1);
// The first one that was wrong:
test(8,6, 7,4, 2);
}
private static void test(int x0, int y0, int x1, int y1, int expected)
{
int distance = computeStepsDistance(x0, y0, x1, y1);
System.out.println(
"Distance of (" + x0 + "," + y0 + ") to " +
"(" + x1 + "," + y1 + ") is " + distance +
", expected " + expected);
}
private static int computeStepsDistance(int x0, int y0, int x1, int y1)
{
Point cp0 = convertOffsetToCubeCoordinates(x0, y0, null);
Point cp1 = convertOffsetToCubeCoordinates(x1, y1, null);
int cx0 = cp0.x;
int cy0 = cp0.y;
int cz0 = -cx0-cy0;
int cx1 = cp1.x;
int cy1 = cp1.y;
int cz1 = -cx1-cy1;
int dx = Math.abs(cx0 - cx1);
int dy = Math.abs(cy0 - cy1);
int dz = Math.abs(cz0 - cz1);
return Math.max(dx, Math.max(dy, dz));
}
private static Point convertOffsetToCubeCoordinates(
int ox, int oy, Point p)
{
int cx = ox;
int cz = oy - (ox - (ox&1)) / 2;
int cy = -cx-cz;
if (p == null)
{
p = new Point();
}
p.x = cx;
p.y = cy;
return p;
}
}

How to find points of intersection between ellipse and line?

I'm completely stuck.
I have an ellipse, and a line. Line is set by two points, ellipse - by bottom-left and top-right corners. I have to find their points of intersection, using java.
I tried to solve an equation system:
(1) y = kx + m;
x^2/a^2 + y^2/b^2 = 1;
but I could't make things work properly. I assume it's because of java's coordinate system, but it also may be my own mistake somewherem beacuse I'm confused with it.
Is there any better way to find points of intersection and, if not, how can I get them properly?
Thank you in advance.
Code:
double r1 = in_y2-in_y;
double r2 = in_x2-in_x;
double k = r1/r2;
double m = in_y2 - k*in_x2;
double a = Math.abs((double)x2 - (double)x)/2;
double b = Math.abs((double)y2 - (double)y)/2;
double A1 = 1/(a*a) + (k*k)/(b*b);
double B1 = (2*k*m)/b*b;
double C1 = (m*m)/(b*b);
double D = Math.sqrt(B1*B1 - 4*A1*C1);
double ex1 = (-B1 + D/(2*A1));
double ey1 = k*ex1 + m;
double ex2 = (-B1 - D/(2*A1));
double ey2 = k*ex2 + m;
This is probably no longer relevant to the original problem owner, but since I encountered the same question, let me present my answer.
There are three mistakes in the original computation that I can see: (i) the one pointed out by #mprivat, (ii) the bracketing in the assignment to B1 which should instead be
double B1 = (2*k*m)/(b*b);
and (iii) a more fundamental one: the presented computation does not correct for the origin of the ellipse. Since the ellipse is defined by itse circumscribing bounds, there is no guarantee that it is centered on (0,0).
Let's call the center (cx,cy), then the equation for the ellipse becomes
(x-cx)^2/a^2 + (y-cy)^2/b^2 = 1
rather than the original
x^2/a^2 + y^2/b^2 = 1
The simple repair, I think, is to translate the line wrt (cx,cy) and translate the results back, like so:
...
double m = (in_y2-cy) - k*(in_x2-cx);
...
double ex1 = (-B1 + D/(2*A1)) + cx;
double ey1 = k*(ex1-cx) + m + cy;
double ex2 = (-B1 - D/(2*A1)) + cx;
double ey2 = k*(ex2-cx) + m + cy;
The more elegant repair is to solve the correct equation for the ellipse instead, but this results in even more impenetrable formulas for B1 and C1:
double B1 = (2*k*(m-cy))/(b*b) - (2*cx)/(a*a);
double C1 = (m-cy)*(m-cy)/(b*b) - 1 + (cx*cx)/(a*a);
As a final remark, note that this breaks down for vertical lines, as then r2 = 0 so k isn't defined.
Java can't solve the algebra problem, but it can compute the solution once you tell it what to compute.
Sounds like you just need to replace your y in the ellipse's equation with kx+m then solve for x. Looks like it's a simply binomial equation. Write a program that computes x=... based on k, m, a and b. Java can help you compute the roots if you tell it what to compute and what the values of k, m, a and b are.
In your particular case, you want to use Java as a simple calculator...
can you please put your code so that we could see if it's correct?
anyway , here's an algorithm:
http://mathworld.wolfram.com/Ellipse-LineIntersection.html
note that since it has a square root , you might get a solution that is not precise.
Line2D.Double line = new Line2D.Double(x1,y1,x2,y2);
Ellipse2D.Double ellipse = new Ellipse2D.Double(x,y,width,height);
int resolution = 1000;
int x_distance = ellipse.getWidth()/2;
int y_distance = ellipse.getHeight()/2;
double angle = 360.0/(double)resolution;
Point center = new Point(width/2,height/2);
Point point = new Point();
for (int index = 0; index < resolution; index++)
{
int x = (center.x+x_distance)*Math.sin(Math.toRadians(angle*index)));
int y = (center.y+y_distance)*Math.cos(Math.toRadians(angle*index)));
Ellipse2D.Double dot = new Ellipse2D.Double(x,y,1,1);
if (line.intersects(dot.getBounds()))
{
point.setLocation(x,y);
index = resolution;
}
}

Most efficient way to find distance between two circles in java?

So apparently calculating square roots is not very efficient, which leaves me wondering what the best way is to find out the distance (which I've called range below) between two circles is?
So normally I would work out:
a^2 + b^2 = c^2
dy^2 + dx^2 = h^2
dy^2 + dx^2 = (r1 + r2 + range)^2
(dy^2 + dx^2)^0.5 = r1 + r2 + range
range = (dy^2 + dx^2)^0.5 - r1 - r2
Trying to avoid the square root works fine when you just look for the situation when "range" is 0 for collisions:
if ( (r1 + r2 + 0 )^2 > (dy^2 + dx^2) )
But if I'm trying to work out that range distance, I end up with some unwieldy equation like:
range(range + 2r1 + 2r2) = dy^2 + dx^2 - (r1^2 + r2^2 + 2r1r2)
which isn't going anywhere. At least I don't know how to solve it for range from here...
The obvious answer then is trignometry and first find theta:
Tan(theta) = dy/dx
theta = dy/dx * Tan^-1
Then the find the hypotemuse
Sin(theta) = dy/h
h = dy/Sin(theta)
Finally work out the range
range + r1 + r2 = dy/Sin(theta)
range = dy/Sin(theta) - r1 - r2
So that's what I've done and have got a method that looks like this:
private int findRangeToTarget(ShipEntity ship, CircularEntity target){
//get the relevant locations
double shipX = ship.getX();
double shipY = ship.getY();
double targetX = target.getX();
double targetY = target.getY();
int shipRadius = ship.getRadius();
int targetRadius = target.getRadius();
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.atan( ( dY / dX ) );
// find length of line ship centre - target centre
double hypotemuse = dY / Math.sin(theta);
// finally range between ship/target is:
int range = (int) (hypotemuse - shipRadius - targetRadius);
return range;
}
So my question is, is using tan and sin more efficient than finding a square root?
I might be able to refactor some of my code to get the theta value from another method (where I have to work it out) would that be worth doing?
Or is there another way altogether?
Please excuse me if I'm asking the obvious, or making any elementary mistakes, it's been a long time since I've used high school maths to do anything...
Any tips or advice welcome!
****EDIT****
Specifically I'm trying to create a "scanner" device in a game that detects when enemies/obstacles are approaching/ going away etc. The scanner will relay this information via an audio tone or a graphical bar or something. Therefore although I don't need exact numbers, ideally I would like to know:
target is closer/further than before
target A is closer/further than target B, C, D...
A (linear hopefully?) ratio that expresses how far a target is from the ship relative to 0 (collision) and max range (some constant)
some targets will be very large (planets?) so I need to take radius into account
I'm hopeful that there is some clever optimisation/approximation possible (dx + dy + (longer of dx, dy?), but with all these requirements, maybe not...
Math.hypot is designed to get faster, more accurate calculations of the form sqrt(x^2 + y^2). So this should be just
return Math.hypot(x1 - x2, y1 - y2) - r1 - r2;
I can't imagine any code that would be simpler than this, nor faster.
If you really need the accurate distance, then you can't really avoid the square root. Trigonometric functions are at least as bad as square root calculations, if not worse.
But if you need only approximate distances, or if you need only relative distances for various combinations of circles, then there are definitely things you can do. For example, if you need only relative distances, note that squared numbers have the same greater-than relationship as do their square roots. If you're only comparing different pairs, skip the square root step and you'll get the same answer.
If you only need approximate distances, then you might consider that h is roughly equal to the longer adjacent side. This approximation is never off by more than a factor of two. Or you could use lookup tables for the trigonometric functions -- which are more practical than lookup tables for arbitrary square roots.
I tired working out whether firstly the answers when we use tan, sine is same as when we use sqrt functions.
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
double shipX = 5;
double shipY = 5;
double targetX = 1;
double targetY = 1;
int shipRadius = 2;
int targetRadius = 1;
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.toDegrees(Math.atan( ( dY / dX ) ));
// find length of line ship centre - target centre
double hypotemuse = dY / Math.sin(theta);
System.out.println(hypotemuse);
// finally range between ship/target is:
float range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
hypotemuse = Math.sqrt(Math.pow(dX,2) + Math.pow(dY,2));
System.out.println(hypotemuse);
range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
}
The answer which i got was :
4.700885452542996
1.7008854
5.656854249492381
2.6568542
Now there seems a difference between the value with sqrt ones being more correct.
talking abt the performance :
Consider your code snippet :
i calculated the time of performance- which comes out as:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
long lStartTime = new Date().getTime(); //start time
double shipX = 555;
double shipY = 555;
double targetX = 11;
double targetY = 11;
int shipRadius = 26;
int targetRadius = 3;
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.toDegrees(Math.atan( ( dY / dX ) ));
// find length of line ship centre - target centre
double hypotemuse = dY / Math.sin(theta);
System.out.println(hypotemuse);
// finally range between ship/target is:
float range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
long lEndTime = new Date().getTime(); //end time
long difference = lEndTime - lStartTime; //check different
System.out.println("Elapsed milliseconds: " + difference);
}
Answer - 639.3204215458475,
610.32043,
Elapsed milliseconds: 2
And when we try out with sqrt root one:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
long lStartTime = new Date().getTime(); //start time
double shipX = 555;
double shipY = 555;
double targetX = 11;
double targetY = 11;
int shipRadius = 26;
int targetRadius = 3;
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.toDegrees(Math.atan( ( dY / dX ) ));
// find length of line ship centre - target centre
double hypotemuse = Math.sqrt(Math.pow(dX,2) + Math.pow(dY,2));
System.out.println(hypotemuse);
float range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
long lEndTime = new Date().getTime(); //end time
long difference = lEndTime - lStartTime; //check different
System.out.println("Elapsed milliseconds: " + difference);
}
Answer -
769.3321779309637,
740.33215,
Elapsed milliseconds: 1
Now if we check for the difference the difference between the two answer is also huge.
hence i would say that if you making a game more accurate the data would be more fun it shall be for the user.
The problem usually brought up with sqrt in "hard" geometry software is not its performance, but the loss of precision that comes with it. In your case, sqrt fits the bill nicely.
If you find that sqrt really brings performance penalties - you know, optimize only when needed - you can try with a linear approximation.
f(x) ~ f(X0) + f'(x0) * (x - x0)
sqrt(x) ~ sqrt(x0) + 1/(2*sqrt(x0)) * (x - x0)
So, you compute a lookup table (LUT) for sqrt and, given x, uses the nearest x0. Of course, that limits your possible ranges, when you should fallback to regular computing. Now, some code.
class MyMath{
private static double[] lut;
private static final LUT_SIZE = 101;
static {
lut = new double[LUT_SIZE];
for (int i=0; i < LUT_SIZE; i++){
lut[i] = Math.sqrt(i);
}
}
public static double sqrt(final double x){
int i = Math.round(x);
if (i < 0)
throw new ArithmeticException("Invalid argument for sqrt: x < 0");
else if (i >= LUT_SIZE)
return Math.sqrt(x);
else
return lut[i] + 1.0/(2*lut[i]) * (x - i);
}
}
(I didn't test this code, please forgive and correct any errors)
Also, after writing this all, probably there is already some approximate, efficient, alternative Math library out there. You should look for it, but only if you find that performance is really necessary.

Categories

Resources