Splitting up an angle between two degree values - java

I have two angles given to me; a starting one and an ending one.
I'm also in a loop with a specified numbers of loops.
I'm trying to split an angle up so at each loop iteration I create something at that angle.
Using 3 particles as an example
Here is the code (within in the loop, degrees are 90 to 180)
for (int i = 0; i < numberOfParticles(3); i++)
{
float percentage = 1f / numberOfParticles;
percentage *= index;
float angle = startingAngle + ((endingAngle - startingAngle) * percentage);
}
My problem is this produces : (instead of 90 (0), 135 (0.5), 180 (1))
Log: 90.0 | percentage: 0.0
Log: 120.0 | percentage: 0.33333334
Log: 149.99998 | percentage: 0.6666667
How would I get this to work with any number (including 7?)

You've got an off-by-one error. If you have 3 particles, you're going to start at 0% and then add 50% 2 times, not 3.
float percentage = 1f / (numberOfParticles - 1);
Make sure you also handle the edge case where numberOfParticles is 1. You don't want to divide by zero.

Related

How could we round a decimal up if it ends in 0.99? [duplicate]

This question already has answers here:
How to round a number to n decimal places in Java
(39 answers)
Closed 3 years ago.
I am doing the following programming exercise: Drying Potatoes. The statement is:
All we eat is water and dry matter.
John bought potatoes: their weight is 100 kilograms. Potatoes contain
water and dry matter.
The water content is 99 percent of the total weight. He thinks they
are too wet and puts them in an oven - at low temperature - for them
to lose some water.
At the output the water content is only 98%.
What is the total weight in kilograms (water content plus dry matter)
coming out of the oven?
He finds 50 kilograms and he thinks he made a mistake: "So much weight
lost for such a small change in water content!"
Can you help him?
Write function potatoes with
int parameter p0 - initial percent of water-
int parameter w0 - initial weight -
int parameter p1 - final percent of water -
potatoes should return the final weight coming out of the oven w1
truncated as an int. Example:
potatoes(99, 100, 98) --> 50
I have tried to figure out how could we calculate the final weight, by hand. Plus, I got help in the following thread: How could we calculate the final weight, knowing the initial and final water percentage, and initial weight‽??
I have written the following code:
class Potatoes {
public static long potatoes(int p0, int w0, int p1) {
System.out.println("\ninitial percent of water p0: "+p0);
System.out.println("initial weight w0: "+w0);
System.out.println("final percent of water p1: "+p1);
double left = (1 + (p1 / (100.0 - p1)));
System.out.println("left: "+left);
double right = (w0 * (1 - (p0/100.0)));
System.out.println("right: "+right);
System.out.println("double result: "+left * right);
System.out.println("int result: "+(int)(left * right));
return (int)(left * right);
}
}
And I have observed that there are some tests where the output is different than expected. The difficulty is that the statement requires us to truncate the final weight to int. But if we do that, there are some edge cases, where the left * right instruction returns a number with a lot of decimals like: .9999999; and it expects the next int (to round it up).
It is better explained with the test cases themselves:
import static org.junit.Assert.*;
import org.junit.Test;
public class PotatoesTest {
private static void dotest(int p0, int w0, int p1, int expected) {
assertEquals(expected, Potatoes.potatoes(p0, w0, p1));
}
#Test
public void testResultDoesNotNeedRounding() {
dotest(99, 100, 98, 50);
dotest(82, 127, 80, 114);
dotest(93, 129, 91, 100);
}
#Test
public void testResultNeedsRoundingUp1(){
dotest(92, 120, 88, 80);
}
#Test
public void testResultNeedsRoundingUp2(){
dotest(91, 132, 89, 108);
}
}
When we execute the previous tests, the console gives us the following output:
initial percent of water p0: 99
initial weight w0: 100
final percent of water p1: 98
left: 50.0
right: 1.0000000000000009
double result: 50.00000000000004
int result: 50
initial percent of water p0: 82
initial weight w0: 127
final percent of water p1: 80
left: 5.0
right: 22.860000000000007
double result: 114.30000000000004
int result: 114
initial percent of water p0: 93
initial weight w0: 129
final percent of water p1: 91
left: 11.11111111111111
right: 9.029999999999994
double result: 100.33333333333326
int result: 100
initial percent of water p0: 92
initial weight w0: 120
final percent of water p1: 88
left: 8.333333333333332
right: 9.599999999999994
double result: 79.99999999999994
int result: 79
expected:<80> but was:<79>
initial percent of water p0: 91
initial weight w0: 132
final percent of water p1: 89
left: 9.090909090909092
right: 11.879999999999995
double result: 107.99999999999997
int result: 107
expected:<108> but was:<107>
So, as you see, the first three tests pass, because of they do not need to be rounded and can be truncated to int. However the two last fail, because of the exercise expects them to round it up.
Besides I have written the following to be able to pass the test cases, however I know there should be a better approach:
class Potatoes {
public static long potatoes(int p0, int w0, int p1) {
System.out.println("\ninitial percent of water p0: "+p0);
System.out.println("initial weight w0: "+w0);
System.out.println("final percent of water p1: "+p1);
double left = (1 + (p1 / (100.0 - p1)));
System.out.println("left: "+left);
double right = (w0 * (1 - (p0/100.0)));
System.out.println("right: "+right);
System.out.println("double result: "+left * right);
System.out.println("int result: "+(int)(left * right));
return String.valueOf(left * right).contains(".99") ? (int)(Math.ceil(left * right)) : (int)(left * right);
}
}
In addition, I have read:
How to round a number to n decimal places in Java
Round a double to 2 decimal places
round up to 2 decimal places in java?
Java Round up Any Number
How could we round a decimal up if it ends in 0.99‽??
EDIT: I have tested and Math.round does not solve this situation. Here we have two more test cases:
import static org.junit.Assert.*;
import org.junit.Test;
public class PotatoesTest {
private static void dotest(int p0, int w0, int p1, int expected) {
assertEquals(expected, Potatoes.potatoes(p0, w0, p1));
}
#Test
public void mathRoundDoesNotWork1(){
dotest(89,53,85,38);
}
#Test
public void mathRoundDoesNotWork2(){
dotest(82,134,77,104);
}
}
Being the code:
class Potatoes {
public static long potatoes(int p0, int w0, int p1) {
System.out.println("\ninitial percent of water p0: "+p0);
System.out.println("initial weight w0: "+w0);
System.out.println("final percent of water p1: "+p1);
double left = (1 + (p1 / (100.0 - p1)));
System.out.println("left: "+left);
double right = (w0 * (1 - (p0/100.0)));
System.out.println("right: "+right);
System.out.println("double result: "+left * right);
System.out.println("int result: "+(int)(left * right));
return Math.round(left*right);
}
}
And we see in the output:
initial percent of water p0: 89
initial weight w0: 53
final percent of water p1: 85
left: 6.666666666666667
right: 5.829999999999999
double result: 38.86666666666666
int result: 38
expected:<38> but was:<39>
initial percent of water p0: 82
initial weight w0: 134
final percent of water p1: 77
left: 4.3478260869565215
right: 24.120000000000008
double result: 104.86956521739134
int result: 104
expected:<104> but was:<105>
The question is: how do we round up only if a double result contains a very close number to the next int, meaning it has the format: 100.999999... (number.{9 n decimals})?
Read this for enlightenment: Computers aren't magical; there are only 2^64 different numbers a double can represent, which means: Not every number is in there (there are infinite numbers between 0 and 1, let alone between minus infinity and positive infinity; clearly 'an infinite infinity' is a lot more than 2^64!). Computers count in binary, humans count in decimal, and these two are not the same.
In the translation from the number in that batch of 2^64 that doubles can represent, to human form, it can look ugly.
The solution is to realize that you cannot print doubles to humans and have them be reasonable. Instead, you need a strategy when rendering them, for example, by including the precision you want to render at. Thus:
System.out.printf("%.2f\n", someDouble); // this is how you print doubles.
System.out.println(someDouble); // this is never a good idea.
String x = String.format("%.2f", someDouble); // If you need it as a string.
The text %.2f is String.format-ese for 'print a double; no more than 2 digits after the separator'.
EDIT: Fixed 'println' to 'printf' in first line of code snippet.

Why does Processing draw my sine wave in a samply way?

I am trying to get Processing to draw a sine wave. However, it appears like a badly sampled version of a sine wave on the output. Do I need to replace the shape with a series of lines, or is there another solution?
I've tried casting the variable to a float, and changing c++ to c += 1.
noFill();
stroke(255);
beginShape();
translate(0, 100);
for (int c = 0; c <= width; c += 1)
{
vertex(c, (float) 100 * sin(c / 50));
}
endShape();
I expect that it traverses the window pixel-by-pixel, creating a smooth shape.
What I actually get is what appears to be sampled, as shown here.
Quantized sine wave
The expression
c / 50
is an integral division. The result is an integral value. If 0 <= c < 50, then the result is 0, if 50 <= c < 100 then the result 1.
To do a floating point division, with a floating point result, on of the 2 values has to be floating point (e.g. c / 50.0).
Change the expression to solve the issue:
vertex(c, 100.0 * sin((float)c / 50.0));

Floating-point precision when dealing with trigonometric functions

I have a Java class that deals with a lot of trigonometric functions using java.lang.Math. The following code determines the average direction of 0 degrees and 180 degrees. The result should be NaN, since 0 degrees and 180 degrees are in opposite directions, canceling each other out. However, when I do:
double[] angles = {0, 180};
double sines = 0;
double cosines = 0;
double avg;
for (int i = 0; i < angles.length; i++) {
double rad = Math.toRadians(angles[i]);
sines += Math.sin(rad);
cosines += Math.cos(rad);
}
double sin = sines / angles.length;
double cos = cosines / angles.length;
System.out.println("Avg sin: " + sin + "\nAvg cos: " + cos); // sin != 0 but it should
double avgRad = Math.atan2(sin, cos);
avg = Math.toDegrees(avgRad);
System.out.println("Average: " + avg);
avg equals 90.0 instead of NaN. This is because the average sine of 180 degrees and 0 degrees results in a very small but positive number (due to the way floating-point precision works). If you run the above code you will see what I mean. How can I avoid this lack of precision? I know that I could round the average sines and cosines as well as the final result, but that seems a little inelegant to me.
I take it granted that you must have considered averaging angles directly (by using mod 360) before you went onto use sin/cos/tan. That being said, I think, you are in right direction in getting what you intended in your code (except possibly the negative sign flip in the last example).
~> java Main 0 180
Avg sin: 6.123233995736766E-17
Avg cos: 0.0
Average: 90.0
~> java Main 0 179
Avg sin: 0.00872620321864172
Avg cos: 7.615242180436521E-5
Average: 89.50000000000011
~> java Main 1 179
Avg sin: 0.017452406437283477
Avg cos: 0.0
Average: 90.0
~> java Main 1 180
Avg sin: 0.008726203218641817
Avg cos: -7.615242180436521E-5
Average: 90.49999999999991
~> java Main 1 181
Avg sin: 1.5959455978986625E-16
Avg cos: 0.0
Average: 90.0
~> java Main 1 182
Avg sin: -0.008723545132608694
Avg cos: 2.2843406864775373E-4
Average: -88.50000000000001

Slowly reduce the number

I have a number that is being increased by an increment on each step. Let's assume that start number is 0 and increment is 100.
On step #5 and later I want to start decreasing the base increment (100). The increment should be decreased smoothly and at step #10 it equals 0.
Here is a graph that basically explains what am I trying to do (y - increment, x - step).
Code representation:
// x - step
// y - increment
var value = 0;
for(var x = 0; x < 10; x++) {
var y = 100;
if(x > 5) {
// y = ???
}
value += y;
}
So the question is how to represent this? It would be also great to have an option to modify the smoothness of this arc.
Thank you!
This will give you a perfect quarter cirle that starts at (5|100) and ends at (10|0).
if (x > 5) {
y = 100 * Math.sqrt( 1 - Math.pow(((x - 5) / 5), 2) );
}
http://fooplot.com/plot/2i8hy2twl4
Explanation (optional)
Warning! May contain mathematics!
Let's start with a simpler case, a quarter circle with a radius of 1 and its center is (0|0). We know that x² + y² = r²(Pythagorean theorem). x and r are known, so we can calculate y this way: y = sqrt(r² - x²). Since our radius is always 1 and 1² is equal to 1, we can break it down to this:
y = sqrt(1 - x²)
The value of y ranges from 0 to 1. We want it to range from 0 to 100 though. To achieve this, we simply multiply the right side by 100.
y = 100 * sqrt(1 - x²)
^^^^^^
To shift the entire thing 5 to the right, we need to subtract 5 from x.
y = 100 * sqrt(1 - (x - 5)²)
^^^^^
Also, we want to stretch it to the right, so that our quarter circle ranges from x = 5 to x = 10 and not to x = 6, so wie divide (x - 5) by 5.
y = 100 * sqrt(1 - ((x - 5) / 5)^2)
^^^^
Everything to do now is to replace sqrt by Math.sqrt and ^2 by Math.pow to make it valid Javascript code.
y = 100 * Math.sqrt( 1 - Math.pow(((x - 5) / 5), 2) );
If that curve is a quarter circle, then the equation that you want is
y = 20 * Math.sqrt(x * (10 - x));
If it's not a quarter circle, then it's anyone's guess.
if (x<=5)
y = 100;
else if (x>=10)
y = 0;
else {
double radius = 100;
double offset = (x-5)*20;
y = Math.sqrt(raidus*radius - offset*offset);
}
http://fooplot.com/plot/offuyxbfzu

strange Math.sin behaviour

I'm making a program that plays a sine wave varying in pitch and I'm dealing with something that i've never seen before: the program should play a sine wave from 220 hz to 0 hz, and I can see the frequency going from 220 to 0, but what I hear is a sine wave that goes from 220 to 0 and then back to 220.
I have no idea how this piece of code can do that
http://pastebin.com/HS36k7XJ (had to post it here because of screwed up layout)
(where t is the time in seconds and f the current frequency (which is calculated by a simple linear interpolation, which behaves properly))
You scale f linearly down to zero. This means that the expression t * Math.PI * 2 will be scaled back to zero as well. The value you pass to sin() goes from 0 initially (because t=0) to some positive value (because t>0 and f>0), back to 0 (because f=0).
Let's look at the values of t * Math.PI * 2 * f over time and the frequencies:
At t=0, the value is 0 and will increase with speed 220
At t=0.5, the value is 345 and will stop increasing
At t=1, the value is 0 again and will decrease with speed -220
It's reversing it's direction because t * Math.PI * 2 is multiplied by f, and f is getting smaller. This means the whole expression will become smaller as t approaches 1.
Try this code instead:
double ct = 0;
for (;;) {
if(t>=1) break;
//System.out.println(t+" "+e.getValueAt(t));
for (int i = 0; i < buff.length; i++) {
double f=lerp(fa,fb,t);
buff[i] = (short) (Short.MAX_VALUE * 0.5 * Math.sin(Math.PI * 2 * ct));
toSoundCard[2 * i] = (byte) buff[i];
toSoundCard[2 * i + 1] = (byte) (buff[i] >> 8); //(i know i could avoid doing this)
t += 1.0 / 44100.0;
ct += f / 44100.0;
}
speaker.write(toSoundCard, 0, toSoundCard.length);
}

Categories