How to implement the "fast inverse square root" in Java? - java

I've heard of the "fast inverse square root", discussed here, and I wanted to put it in my Java program (just for research purposes, so ignore anything about the native libraries being faster).
I was looking at the code, and the C code directly converts the float into an int with some C pointer magic. If you try to do this in Java with casts, it doesn't work: java truncates the float (as you would expect), and you can't get the pointer of a primitive (as you can in C).
So how do you do this?

Remember to benchmark your code before using this.
If it turns out you don't need it, or it's slower on the CPU architecture you are using, then it's better to go without having this obtuse code in your project.
The Java libraries have a way to get from the float number to the raw bits.
As seen in the Javadoc for java.lang.Float ( http://docs.oracle.com/javase/6/docs/api/java/lang/Float.html ), we have the floatToIntBits function, as well as intBitsToFloat.
This means we can write the "fast inverse square root" in Java as follows:
public static float invSqrt(float x) {
float xhalf = 0.5f * x;
int i = Float.floatToIntBits(x);
i = 0x5f3759df - (i >> 1);
x = Float.intBitsToFloat(i);
x *= (1.5f - xhalf * x * x);
return x;
}
Here is the version for doubles:
public static double invSqrt(double x) {
double xhalf = 0.5d * x;
long i = Double.doubleToLongBits(x);
i = 0x5fe6ec85e7de30daL - (i >> 1);
x = Double.longBitsToDouble(i);
x *= (1.5d - xhalf * x * x);
return x;
}
Source: http://www.actionscript.org/forums/showthread.php3?t=142537

For Riking's answer, even the double one can return stuff like 0.9983227945440889 for the square root of one.
To increase accuracy, you can use this version of it I made:
public static double Q_rsqrt(double number){
double x = number;
double xhalf = 0.5d*x;
long i = Double.doubleToLongBits(x);
i = 0x5fe6ec85e7de30daL - (i>>1);
x = Double.longBitsToDouble(i);
for(int it = 0; it < 4; it++){
x = x*(1.5d - xhalf*x*x);
}
x *= number;
return x;
}
You can edit how long before the for loop terminates however you want, but 4 times seems to get it down to the maxiumum accuracy for a double. If you want perfect accuracy (or if long strings of decimals where they shouldnt be bother you), use this version.

Related

Trying to rotate about a point, but lose precision no matter what

Im trying to make some objects (represented by points) rotate around a fixed point, but while they rotate, they get closer and closer to the point of rotation. Here is a screenshot taken early of the rotating triangles:
and here is a shot taken moments later
As you can tell the distance from the center is shortened as well as their distance from each other. Here is the code I'm using to rotate the points about a another point:
public void rotateAboutPoint(double x, double y, double angleRad){
for(int i = 0; i<rep.size(); i++){
rep.get(i).x = (Math.cos(angleRad) * (rep.get(i).x - x) - Math.sin(angleRad)*(rep.get(i).y - y) + x);
rep.get(i).y = (Math.sin(angleRad) * (rep.get(i).x - x) + Math.cos(angleRad)*(rep.get(i).y - y) + y);
}}
I used the same algorithm used here. Everything works fine except the objects shrink. I've tried using more precise types, which doesn't help. I've tried wrapping the expressions with Math.Round() to see if that would help by rounding up when necessary. Any thoughts?
The value of rep.get(i).x you need for the second formula should be the original value, not the new value. Just use a temporary variable. I think this should work.
public void rotateAboutPoint(double x, double y, double angleRad){
for(int i = 0; i<rep.size(); i++){
double temp = (Math.cos(angleRad) * (rep.get(i).x - x) - Math.sin(angleRad)*(rep.get(i).y - y) + x);
rep.get(i).y = (Math.sin(angleRad) * (rep.get(i).x - x) + Math.cos(angleRad)*(rep.get(i).y - y) + y);
rep.get(i).x = temp;
}}

How do I fix this heart?

Seeing as Valentine's Day is fast approaching, I decided to create a heart. So I found this heart from mathematica.se:
I played around in Mathematica (solved for z, switching some variables around) to get this equation for the z-value of the heart, given the x and y values (click for full-size):
I faithfully ported this equation to Java, dealing with a couple out-of-bounds cases:
import static java.lang.Math.cbrt;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
...
public static double heart(double xi, double yi) {
double x = xi;
double y = -yi;
double temp = 5739562800L * pow(y, 3) + 109051693200L * pow(x, 2) * pow(y, 3)
- 5739562800L * pow(y, 5);
double temp1 = -244019119519584000L * pow(y, 9) + pow(temp, 2);
//
if (temp1 < 0) {
return -1; // this is one possible out of bounds location
// this spot is the location of the problem
}
//
double temp2 = sqrt(temp1);
double temp3 = cbrt(temp + temp2);
if (temp3 != 0) {
double part1 = (36 * cbrt(2) * pow(y, 3)) / temp3;
double part2 = 1 / (10935 * cbrt(2)) * temp3;
double looseparts = 4.0 / 9 - 4.0 / 9 * pow(x, 2) - 4.0 / 9 * pow(y, 2);
double sqrt_body = looseparts + part1 + part2;
if (sqrt_body >= 0) {
return sqrt(sqrt_body);
} else {
return -1; // this works; returns -1 if we are outside the heart
}
} else {
// through trial and error, I discovered that this should
// be an ellipse (or that it is close enough)
return Math.sqrt(Math.pow(2.0 / 3, 2) * (1 - Math.pow(x, 2)));
}
}
The only problem is that when temp1 < 0, I cannot simply return -1, like I do:
if (temp1 < 0) {
return -1; // this is one possible out of bounds location
// this spot is the location of the problem
}
That's not the behavior of the heart at that point. As it is, when I try to make my image:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import static java.lang.Math.cbrt;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
public class Heart {
public static double scale(int x, int range, double l, double r) {
double width = r - l;
return (double) x / (range - 1) * width + l;
}
public static void main(String[] args) throws IOException {
BufferedImage img = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_RGB);
// this is actually larger than the max heart value
final double max_heart = 0.679;
double max = 0.0;
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
double xv = scale(x, img.getWidth(), -1.2, 1.2);
double yv = scale(y, img.getHeight(), -1.3, 1);
double heart = heart(xv, yv); //this isn't an accident
// yes I don't check for the return of -1, but still
// the -1 values return a nice shade of pink: 0xFFADAD
// None of the other values should be negative, as I did
// step through from -1000 to 1000 in python, and there
// were no negatives that were not -1
int r = 0xFF;
int gb = (int) (0xFF * (max_heart - heart));
int rgb = (r << 16) | (gb << 8) | gb;
img.setRGB(x, y, rgb);
}
}
ImageIO.write(img, "png", new File("location"));
}
// heart function clipped; it belongs here
}
I get this:
Look at that dip at the top! I tried changing that problematic -1 to a .5, resulting in this:
Now the heart has horns. But it becomes clear where that problematic if's condition is met.
How can I fix this problem? I don't want a hole in my heart at the top, and I don't want a horned heart. If I could clip the horns to the shape of a heart, and color the rest appropriately, that would be perfectly fine. Ideally, the two sides of the heart would come together as a point (hearts have a little point at the join), but if they curve together like shown in the horns, that would be fine too. How can I achieve this?
The problem is simple. If we look at that horseshoe region, we get imaginary numbers. For part of it, it should belong to our heart. In that region, if we were to evaluate our function (by math, not by programming), the imaginary parts of the function cancel. So it should look like this (generated in Mathematica):
Basically, the function for that part is almost identical; we just have to do arithmetic with complex numbers instead of real numbers. Here's a function that does exactly that:
private static double topOfHeart(double x, double y, double temp, double temp1) {
//complex arithmetic; each double[] is a single number
double[] temp3 = cbrt_complex(temp, sqrt(-temp1));
double[] part1 = polar_reciprocal(temp3);
part1[0] *= 36 * cbrt(2) * pow(y, 3);
double[] part2 = temp3;
part2[0] /= (10935 * cbrt(2));
toRect(part1, part2);
double looseparts = 4.0 / 9 - 4.0 / 9 * pow(x, 2) - 4.0 / 9 * pow(y, 2);
double real_part = looseparts + part1[0] + part2[0];
double imag_part = part1[1] + part2[1];
double[] result = sqrt_complex(real_part, imag_part);
toRect(result);
// theoretically, result[1] == 0 should work, but floating point says otherwise
if (Math.abs(result[1]) < 1e-5) {
return result[0];
}
return -1;
}
/**
* returns a specific cuberoot of this complex number, in polar form
*/
public static double[] cbrt_complex(double a, double b) {
double r = Math.hypot(a, b);
double theta = Math.atan2(b, a);
double cbrt_r = cbrt(r);
double cbrt_theta = 1.0 / 3 * (2 * PI * Math.floor((PI - theta) / (2 * PI)) + theta);
return new double[]{cbrt_r, cbrt_theta};
}
/**
* returns a specific squareroot of this complex number, in polar form
*/
public static double[] sqrt_complex(double a, double b) {
double r = Math.hypot(a, b);
double theta = Math.atan2(b, a);
double sqrt_r = Math.sqrt(r);
double sqrt_theta = 1.0 / 2 * (2 * PI * Math.floor((PI - theta) / (2 * PI)) + theta);
return new double[]{sqrt_r, sqrt_theta};
}
public static double[] polar_reciprocal(double[] polar) {
return new double[]{1 / polar[0], -polar[1]};
}
public static void toRect(double[]... polars) {
for (double[] polar: polars) {
double a = Math.cos(polar[1]) * polar[0];
double b = Math.sin(polar[1]) * polar[0];
polar[0] = a;
polar[1] = b;
}
}
To join this with your program, simply change your function to reflect this:
if (temp1 < 0) {
return topOfHeart(x, y, temp, temp1);
}
And running it, we get the desired result:
It should be pretty clear that this new function implements exactly the same formula. But how does each part work?
double[] temp3 = cbrt_complex(temp, sqrt(-temp1));
cbrt_complex takes a complex number in the form of a + b i. That's why the second argument is simply sqrt(-temp1) (notice that temp1 < 0, so I use - instead of Math.abs; Math.abs is probably a better idea). cbrt_complex returns the cube root of the complex number, in polar form: r eiθ. We can see from wolframalpha that with positive r and θ, we can write an n-th root of a complex numbers as follows:
And that's exactly how the code for the cbrt_complex and sqrt_complex work. Note that both take a complex number in rectangular coordinates (a + b i) and return a complex number in polar coordinates (r eiθ)
double[] part1 = polar_reciprocal(temp3);
It is easier to take the reciprocal of a polar complex number than a rectangular complex number. If we have r eiθ, its reciprocal (this follows standard power rules, luckily) is simply 1/r e-iθ. This is actually why we are staying in polar form; polar form makes multiplication-type operations easier, and addition type operations harder, while rectangular form does the opposite.
Notice that if we have a polar complex number r eiθ and we want to multiply by a real number d, the answer is as simple as d r eiθ.
The toRect function does exactly what it seems like it does: it converts polar coordinate complex numbers to rectangular coordinate complex numbers.
You may have noticed that the if statement doesn't check that there is no imaginary part, but only if the imaginary part is really small. This is because we are using floating point numbers, so checking result[1] == 0 will likely fail.
And there you are! Notice that we could actually implement the entire heart function with this complex number arithmetic, but it's probably faster to avoid this.

Java performance optimization

For a JOGL game I get very low fps, now with some testing I found out the problem is not in the JOGL part, but in pure Java calculations. I need to define a lot of float variables, which takes up 90% of the time.
I have tested for 45 float variables, where only 16 get an initial value. The rest is just float z1; float z2;, etc. This took around 5-10 milliseconds, according to System.currentTimeMillis().
But this code with the 45 floats is in a method called by a double loop. In total this method is called 49 times (7*7). All this is inside the JOGL method to draw the game in a JFrame, but because of this many float variables it takes a total of 100ms, which means only 10fps.
So basically the problem is that I have to initialize 45*49=2205 floats. Is there any way to optimize this to get a better fps?
For example, would a double be faster than a float? Or would it help to define the variables first outside the loop, and give them their value inside the loop? Does anyone know a way to make this code run faster? Thanks a lot in advance.
EDIT
As requested, here is the source code:
for (int x = -4; x < 3; x++) { // Loops 7 times
for (int y = -4; y < 3; y++) { // Loops 7 times
long t1 = System.currentTimeMillis();
float z0 = terrain.getHeight(x-1, y-1); // Simple method, but takes up about half of the time
float z1 = terrain.getHeight(x , y-1);
float z3 = terrain.getHeight(x+1, y-1);
float z4 = terrain.getHeight(x+2, y-1);
float z5 = terrain.getHeight(x-1, y );
float z6 = terrain.getHeight(x , y );
float z7;
float z8;
float z9;
float z10 = terrain.getHeight(x+1, y );
float z11 = terrain.getHeight(x+2, y );
float z12;
float z13;
float z14;
float z15;
float z16;
float z17;
float z18;
float z19;
float z20;
float z21;
float z22;
float z23;
float z24;
float z25;
float z26;
float z27;
float z28;
float z29;
float z30;
float z31;
float z32;
float z33 = terrain.getHeight(x-1, y+1);
float z34 = terrain.getHeight(x , y+1);
float z35;
float z36;
float z37;
float z38 = terrain.getHeight(x+1, y+1);
float z39 = terrain.getHeight(x+2, y+1);
float z40 = terrain.getHeight(x-1, y+2);
float z41 = terrain.getHeight(x , y+2);
float z43 = terrain.getHeight(x+1, y+2);
float z44 = terrain.getHeight(x+2, y+2);
t1 = System.currentTimeMillis() - t1;
// Some other code where I use these variables.
// Takes between 0-1 ms in total.
}
}
EDIT
I now tested the getHeight() method, and it takes up about half of the time. The seven variables which use this method add up to about 5 ms, where the total is 10. The following is the code used in getHeight():
public float getHeight(float x, float y) {
long t1 = System.currentTimeMillis();
Coordinate c = new Coordinate(x, y);
for (Entry<Coordinate, Float> e : heightMap.entrySet()) { // heightMap = HashMap<Coordinate, Float>
if (e.getKey().x == c.x && e.getKey().y == c.y) {
System.out.println("getHeight: " + (System.currentTimeMillis() - t1) + " ms");
return e.getValue();
}
}
return 0f;
}
Coordinate is a class I made myself, it has a constructor with two float parameters for x and y, and saves them public, globally in the class itself.
The reason why I am not using heightMap.get(c), is because this always throws a NullPointerException, while the code given above never reaches the last line of return 0f;.
EDIT
Found the solution to the problem in this [link] (Why are custom objects not equivalent keys for a HashMap?) question, namely that I had to add public boolean equals(Object other) and public int hashCode() to my custom Coordinate class. Now the getHeight method can work with heightMap.get(c), which removes the loop in there and makes the program a lot faster. The total (with 49 loops) takes around 1 ms now.
Please note that Full Screen Exclusive Mode must be used for some operating systems to give you enough resources.
Defining variables outside of the loop will not help, as Java optimizes your code and defining variables inside a loop actually gives Java hints to increase performance. What I think (and I can only guess, since you posted no code) is, that you may consider using an array of longs. They are very effective to work with in a loop and they're also allocated one after another in your memory, so cache can be used effectively.
To me, fillings 2025 Longs takes slightly above one millisecond, including calls to random.nextLong() method.
public Long fillLongs(int numberofLongs) {
long[] longs = new long[numberofLongs];
Random r = new Random();
long start = System.currentTimeMillis();
for (long l : longs) {
l = r.nextLong();
}
long end = System.currentTimeMillis();
return end - start;
}
Using parallel stream, this task takes even less time. Often under 1 ms.
public Long fillLongs(int numberofLongs) {
Long[] longs = new Long[numberofLongs];
List<Long> longList = Arrays.asList(longs);
Random r = new Random();
long start = System.currentTimeMillis();
longList.parallelStream().forEach(l -> {
l = r.nextLong();
});
long end = System.currentTimeMillis();
return end - start;
}
For high-performance computing in Java you might consider usi JNI (Java Native Interface) - though it requires C++ knowledge. For a quick start take a look here.

Rotation - lack of precision - Java

I hava a class representing a point (x and y coordinates are double type) and a function to rotate the point around another point:
public Point2D rotate(double angle, Point2D origin) {
double sin = Math.sin(angle);
double cos = Math.cos(angle);
x -= origin.getX();
y -= origin.getY();
x = x*cos - y*sin;
y = x*sin + y*cos;
x += origin.getX();
y += origin.getY();
return this;
}
However when I repeat the rotation many times (i.e. by 1 Degree) I loose much of precision. Example:
Point2D point = new Point2D(10, 10);
System.out.println(point);
for(int i = 0; i < 360; i++)
point.rotate(Math.toRadians(1), new Point2D(300, 150));
System.out.println(point);
And the results:
[10.0, 10.0]
[25.5048671135757, 17.40466547204096]
Do you have any idea how to solve this issue? Thanks in advance.
firstly, there's an error in your formula...
the line
x = x*cos - y*sin;
modifies the value of x and the modified value is used in the next line
y = x*sin + y*cos;
You have to use a temp variable to store the new value of x and y, this is what user2602548 meant with his sugestion.
I guess you're already using double since you would otherwise need a cast to float for those two lines.
If you fix the algorithmic error you get something like [9.99999999999659, 9.999999999998778] .
If that's not good enough for you, you could either round after the rotations and if that's also not good enough use a lib that provides trigonometric functions with more precision like apfloat.
Using BigDecimal with that problem won't give you any more precision because the problem here is that the results of sin() and cos() are still only double precision.

How can I convert integer into float in Java?

I have two integers x and y. I need to calculate x/y and as outcome I would like to get float. For example as an outcome of 3/2 I would like to have 1.5. I thought that easiest (or the only) way to do it is to convert x and y into float type. Unfortunately, I cannot find an easy way to do it. Could you please help me with that?
You just need to cast at least one of the operands to a float:
float z = (float) x / y;
or
float z = x / (float) y;
or (unnecessary)
float z = (float) x / (float) y;
// The integer I want to convert
int myInt = 100;
// Casting of integer to float
float newFloat = (float) myInt
You shouldn't use float unless you have to. In 99% of cases, double is a better choice.
int x = 1111111111;
int y = 10000;
float f = (float) x / y;
double d = (double) x / y;
System.out.println("f= "+f);
System.out.println("d= "+d);
prints
f= 111111.12
d= 111111.1111
Following #Matt's comment.
float has very little precision (6-7 digits) and shows significant rounding error fairly easily. double has another 9 digits of accuracy. The cost of using double instead of float is notional in 99% of cases however the cost of a subtle bug due to rounding error is much higher. For this reason, many developers recommend not using floating point at all and strongly recommend BigDecimal.
However I find that double can be used in most cases provided sensible rounding is used.
In this case, int x has 32-bit precision whereas float has a 24-bit precision, even dividing by 1 could have a rounding error. double on the other hand has 53-bit of precision which is more than enough to get a reasonably accurate result.
You just need to transfer the first value to float, before it gets involved in further computations:
float z = x * 1.0 / y;
Here is how you can do it :
public static void main(String[] args) {
// TODO Auto-generated method stub
int x = 3;
int y = 2;
Float fX = new Float(x);
float res = fX.floatValue()/y;
System.out.println("res = "+res);
}
See you !
Sameer:
float l = new Float(x/y)
will not work, as it will compute integer division of x and y first, then construct a float from it.
float result = (float) x / (float) y;
Is semantically the best candidate.

Categories