I was trying to generate a pseudo-random angle in processing today using noise but it is not working as I would have hoped.
float xoff = 0;
float inc = 0.01;
void draw(){
float vx = cos( noise(xoff) * 2 * PI));
xoff += inc;
}
This is the important part of my code. What I thought would happen was that vx would be a random float between -1 and 1 but it is almost always negative. What seems to be the problem is that the noise(xoff) is outputting a limited range of values. Only between 0.3 and 0.7. For vx to be positive it needs to be lower than 0.3 and higher than 0.7, but this never almost never happens.
What is going wrong here?
You might adjust the noiseDetail() to include more than 4 octaves or to use a falloff below 0.5.
Related
I'm a bit annoyed with a method I wrote to approximate sine function in Java. Here it is, it's based on Taylor's series.
static double PI = 3.14159265358979323846;
static double eps = 0.0000000000000000001;
static void sin(double x) {
x = x % (2 * PI);
double term = 1.0;
double res = 0.0;
for (int i = 1; term > eps; i++) {
term = term * (x / i);
if (i % 4 == 1) res += term;
if (i % 4 == 3) res -= term;
}
System.out.println(sum);
}
For little values, I got very good approximation of sine, but for large values (e.g pow(10,22)), results seems very very wrong.
Here are the results :
sin(pow(10,22)) // 0.8740280612007599
Math.sin(pow(10,22)) // -0.8522008497671888
Does someone have an idea ? Thank you !
Best regards,
Be reassured that the Java sin function will be off too.
You problem is that the Taylor expansion for sin has a small radius of convergence and convergence is slow even if you're within that radius.
There are floating point considerations too: a floating point double gives you about 15 significant figures of accuracy.
So for large arguments for sin, the accuracy will deteriorate significantly especially given that sin is a periodic function:
sin(x + 2 * pi * n) = sin(x) for any integer n.
Your answer is incorrect for big numbers because you accumulate a lot of rounding errors due to double presentation. When the number is big, then your for loop will iterate a lot before the term becomes smaller than epsilon. In each iteration, a rounding error is accumulated. The result is a very big error in the final value. Read some nice reference on "Numerical Analysis". Anyway, Tylor's series approximate sin near 0, by definition. So, it is normal not to be correct for very big numbers.
The difference actually has nothing to do with the radius of convergence of the Taylor Series and has to do with double precision not being accurate enough to hold the precision required for such big numbers. The radius of the Taylor series for the sine function is infinity.
10^22 is approximately 2^73. Since the mantissa for a double precision number is 52 bits, consecutive values that can be stored with double precision format will be 2^21 apart from each other. Since an evaluation of the sine function requires more resolution than that, you won't be able to reliably get an answer.
So, right now I am trying to calculate the angles of a right triangle using the inverse of Cosine. However, I don't really know how to do it. I know the equation, just not how to convert into code. The equation would be:: Cos-1(A/C); However, that does not seem to work in Java. I also tried
angleX = (int) Math.acos(sideC / sideA);
If sideC and sideA were integers, one would have integer division (2 / 3 == 0).
If you do not expect a result in radians, but degrees, a conversion is needed.
As double is an approximation, use round too.
if (sideA == 0) { ... }
angleX = (int) Math.round(
Math.toDegrees(Math.acos(((double)sideC) / sideA)));
I'm trying to create a wireframe sphere using openGL that has latitude and longitude lines. Currently I'm running into an issue that I think I'm simply overlooking and with a bit of help can quickly correct with creating the sphere. My code is the following inside of a class that creates displays:
double rho = 1;
gl.glBegin(GL2.GL_LINE_LOOP);
for (int i = 0; i< 360; i++){
theta = i/180 * Math.PI;
for (int j = 0; j< 360; j++){
double phi = j/180 * Math.PI;
double x = rho * Math.sin(phi) * Math.cos(theta);
double y = rho * Math.sin(phi) * Math.sin(theta);
double z = rho * Math.sin(phi);
gl.glVertex3d(x, y, z);
}
gl.glEnd();
}
From this code I'm currently not getting anything to display. What am I missing?
There are number of problems in this code:
As already pointed out in the comments, the glBegin() and glEnd() are unbalanced. The glBegin() needs to be inside the first loop.
The second angle should only loop from 0 to 180, not 360. This is based on the definition of spherical coordinates.
In the divisions i/180 and j/180, both values are of type int, therefore the operation is an integer division. With the values used, the result of those divisions will always be 0 or 1.
The calculation of the z-coordinate needs to use cos(phi) instead of sin(phi).
Not wrong, but just recommendations:
There's no need to use double precision values. OpenGL will use single precision anyway.
As mentioned in the comments, the code is using legacy features that are deprecated and deleted in modern versions of OpenGL.
Sticking with the immediate mode drawing, fixing these problems should result in working (untested) code:
float radius = 1.0f;
for (int i = 0; i <= 360; i++) {
gl.glBegin(GL2.GL_LINE_LOOP);
float theta = i * (Math.PI / 180.0f);
for (int j = 0; j <= 180; j++) {
float phi = j * (Math.PI / 180.0f);
float x = radius * Math.sin(phi) * Math.cos(theta);
float y = radius * Math.sin(phi) * Math.sin(theta);
float z = radius * Math.cos(phi);
gl.glVertex3f(x, y, z);
}
gl.glEnd();
}
This will give you the longitude lines. The code for the latitude lines will be very similar, with the two loops swapped.
As for the discussion about deprecated/legacy features, this is somewhat broad to be covered here. So just a very quick summary:
What you're using here is typically called "immediate mode drawing". This is the way OpenGL worked in the original version. More efficient ways of specifying vertex data were introduced around 20 years ago. Initially is was Vertex Arrays, then Vertex Buffer Objects (VBO). Vertex Array Objects (VAO) were introduced later to make the state setup more efficient.
With OpenGL 3.2, which was introduced in 2009, two "profiles" were defined:
Core Profile: Deletes the deprecated legacy features, including immediate mode drawing.
Compatibility Profile: Still supports all features to maintain backwards compatibility.
If you write new code, particularly if you just start learning, there's no good reason to learn legacy features. The initial threshold is slightly higher when using the Core Profile (mainly because it requires you to write your own shaders in GLSL), but it's well worth it. Current versions of OpenGL ES are also much closer to the Core Profile, and do not have any of these legacy featues.
case R.id.bTanx:
temp=(float) (number/0.0174532925);
num=Math.tan(temp);
display.setText("Your Result is " + num);
Guys I'm not able to get "Your Result is 1" when number = 45 ,by this code.Please help.
As tan(45)=1 in degrees.i have converted it.but no desired result.
To convert degrees to radian you first need to convert the degrees to a factor (of the circles circumference) by dividing by 360 degrees. Next you multiply by 2PI rad (which is the circumference of a 'unit circle').
When looking at the units you do this: degrees / degrees * radians = radians
So where you divide by 0.017 (2*PI / 360), you need to multiply instead:
temp = (float) (number * 0.0174532925);
Furthermore it is nicer (more clear) if you do not use 'magic numbers' and add comments (so people know what you are doing):
// Convert to rad
temp = (float) (number * 2 * Math.PI / 360);
And/or even use the available Java functionality:
// Convert to rad
temp = Math.toRadians(number);
I have this function to limit a rotation to the range from 0.0 to 360.0:
private float ClampRotation( float rotation ) {
while( rotation < 0.0f ) rotation += 360.0f;
while( rotation >= 360.0f ) rotation -= 360.0f;
return rotation;
}
This functions works great and it probably can't be more efficient, but I'm just wondering if there are a native Java function that can do the same?
The closest I get is Math.min/max, but it doesn't work as this. A rotation of -10.0 should output 350.0 and not 0.0 as min/max would do.
% (modulus) works on floating point values so use rotation % 360.0f (you will need to add 360.0 afterwards to negative numbers)
Use the modulus operator then account for values less than 0;
private float ClampRotation( float rotation ) {
rotation = rotation % 360f;
if (rotation < 0f) rotation += 360f;
return rotation;
}
it's just math.. you can do it like this:
private float ClampRotation( float rotation ) {
return rotation+360.0f*Math.ceil(-rotation/360.0f);
}
i'm pretty sure it's ok
You have the traditional implementation of wrapping angles which are less than an order of magnitude away the desired range.
Modulus is a bit weird for floating point - it returns negative for negative, so you still have to have a branch, and it involves a division, which is slower on some machines ( as in I've not found a machine where % is significantly less expensive than going round a loop with a couple of subtractions two or three times ).
If your values are within say -1000 to +1000, then your version is both clearer and faster. If your values are wider than that, go for a modulus based version. If it's very important, test both on your hardware with the value ranges you are going to use.