I'm working on a Java program that prints a sine wave to the console. This is what I've written so far:
int num = 7;
for (double y = 2; y >= 0; y-=0.2) {
for (double x = 0; x <= num; x+=0.2) {
if ( ((0.1+x) >= Math.asin((double)y-1)) && (((double)x-0.1) <= Math.asin((double)y-1)) )
System.out.print('*');
else
System.out.print(' ');
}
System.out.println();
}
Essentially, this program treats each character on each line as a 0.2 x 0.2 area on a coordinate plane. If the sine function crosses this area, an asterisk is printed to the screen. Otherwise, a space is printed.
When run, this is printed to the console:
*
*
*
*
*
*
Can anybody tell me why my program stops after printing the first quarter of the wave?
The reason it only prints the first quarter of the sine wave is because of the indicated range of Math.asin:
Returns the arc sine of a value; the returned angle is in the range -pi/2 through pi/2.
Once you advance x past Math.PI / 2, then the if statement's condition will always be false.
You can take advantage of the fact that
sin(π - x) = sin(x)
and
sin(2π - x) = -sin(x)
by including more conditions. (I've also removed the unnecessary casts to double for clarity.)
if ( (0.1+x >= Math.asin(y-1)) && (x-0.1 <= Math.asin(y-1)) ||
(0.1+x >= Math.PI - Math.asin(y-1)) && (x-0.1 <= Math.PI - Math.asin(y-1))
(2*Math.PI -(0.1 + x) <= -Math.asin(y-1)) && (2*Math.PI -(x-0.1) >= -Math.asin(y-1)) )
Output:
*
* *
* *
* * *
* * *
* * *
* *
* *
* *
* *
*
The problem seems to arise from the condition of your if-statement, which almost always evaluates to false. You should check the calculus behind your conditional expression. I find increasing num does not really help here.
Maybe you should print another character instead of a whitespace by replacing System.out.print(' '); with System.out.print('_'); for instance. This way you may be able to figure out why your program behaves that way. Reworking that algorithm of yours may also be helpful.
Edit: Whoops, skimmed the code a little too fast. This is wrong.
Well, you set num to 7, then in your loop you take x from 0 to num-1, so you're only looping over 7 columns. Increase num and your graph should add additional columns. You'll have to increase the range of y values you loop over too, if you want the graph to extend to negative numbers.
However, your algorithm is extremely inefficient. You're calculating asin(y-1) twice for every square on your graph, when all you really need to do is calculate sin(x) once for every column. Why not just fill an array with precalculated sine values and then consult the array while drawing the graph? (I realize, of course, that on a modern computer it's fast enough to be practically irrelevant either way.)
Thank you all for the help! Based on #dasblinkenlight's suggestion to use sin instead of asin, I found a very simple solution:
int num = 7;
for (double y = 1; y >= -1; y-=0.2) {
for (double x = 0; x <= num; x+=0.2) {
double sin = Math.sin(x);
if ( (0.1+y) >= sin && (y-0.1) <= sin )
System.out.print('*');
else
System.out.print(' ');
}
System.out.println();
}
This prints this to the console:
*****
** *
* **
* * **
* * *
* * *
* *
* *
* *
** **
****
Related
I am currently working on a Java math library which will include a variety of correctly rounded functions (i.e. sqrt, cbrt, exp, sin, gamma, and ln). I have already used the Babylonian method to write a square root algorithm that is correct to within 1 ulp of the correct answer. However, I cannot figure out how to properly calculate which way the number should be rounded to represent the best possible approximation to the actual square root of the input. Answers containing principles which can be extended to other functions would be preferred, but I have heard that sqrt is a simpler case than many transcendental functions, and specialized solutions would also be much appreciated.
Also, here is a cleaned-up version of my code as of this question's original submission:
public static double sqrt(double x) {
long bits = Double.doubleToLongBits(x);
// NaN and non-zero negatives:
if (Double.isNaN(x) || x < 0) return Double.NaN;
// +-0 and 1:
if (x == 0d || x == 1d) return x;
// Halving the exponent to come up with a good initial guess:
long exp = bits << 1;
exp = (exp - 0x7fe0000000000000L >> 1) + 0x7fe0000000000000L >>> 1 & 0x7ff0000000000000L;
double guess = Double.longBitsToDouble(bits & 0x800fffffffffffffL | exp);
double nextUp, nextDown, guessSq, nextUpSq, nextDownSq;
// Main loop:
while (true) {
guessSq = guess * guess;
if (guessSq == x) return guess;
nextUp = Math.nextUp(guess);
nextUpSq = nextUp * nextUp;
if (nextUpSq == x) return nextUp;
if (guessSq < x && x < nextUpSq) {
double z = x / nextUp;
if (z * nextUp > x) z = Math.nextDown(z);
return z < nextUp ? nextUp : guess;
}
nextDown = Math.nextDown(guess);
nextDownSq = nextDown * nextDown;
if (nextDownSq == x) return nextDown;
if (nextDownSq < x && x < guessSq) {
double z = x / guess;
if (z * guess > x) z = Math.nextDown(z);
return z < guess ? guess : nextDown;
}
// Babylonian method:
guess = 0.5 * (guess + x / guess);
}
}
As you can see, I was using division as a test. However, I believe that requires the division to round towards 0, which obviously doesn't happen in Java.
By the Taylor theorem, the square root function is locally approximated by a linear function, of slope 1/2√x, which is positive. So you can relate the error to the error in the square, x - (√x)², where √x is understood to be the approximate root. Then you round in the direction that minimizes this error.
Anyway, the computation of x - (√x)² is subjected to catastrophic cancellation and you may need extended accuracy to compute it reliably. Not sure the benefit is worth the effort.
If you are unsure of what "Poisson Distrubtion using Normal Approximation" means, follow this link and check the texts inside the yellow box.
https://onlinecourses.science.psu.edu/stat414/node/180
Here, is the simple snapshot of the math from the link.
P(Y≥9) = P(Y>8.5) = P(Z>(8.5−6.5)/√6.5) = P(Z>0.78)= 0.218
So to get the value in .218, we use Simpson's integration rule which
integrates the function(Implemented in method named "f" from code below) from "negative
infinity" to the value that equals to this >> "((8.5−6.5)/√6.5))"
R successfully gives the correct output. But in Java when i implemented the code
below copied from "http://introcs.cs.princeton.edu/java/93integration/SimpsonsRule.java.html"
I get "0.28360853976343986" which should have been ".218" Is it any how because of the negative infinity value I am using, which is "Double.MIN_VALUE"
This is the code in Java. See at the very end for my INPUTS in the main method.
* Standard normal distribution density function.
* Replace with any sufficiently smooth function.
**********************************************************************/
public static double f(double x) {
return Math.exp(- x * x / 2) / Math.sqrt(2 * Math.PI);
}
/**********************************************************************
* Integrate f from a to b using Simpson's rule.
* Increase N for more precision.
**********************************************************************/
public static double integrate(double a, double b) {
int N = 10000; // precision parameter
double h = (b - a) / (N - 1); // step size
// 1/3 terms
double sum = 1.0 / 3.0 * (f(a) + f(b));
// 4/3 terms
for (int i = 1; i < N - 1; i += 2) {
double x = a + h * i;
sum += 4.0 / 3.0 * f(x);
}
// 2/3 terms
for (int i = 2; i < N - 1; i += 2) {
double x = a + h * i;
sum += 2.0 / 3.0 * f(x);
}
return sum * h;
}
// sample client program
public static void main(String[] args) {
double z = (8.5-6.5)/Math.sqrt(6.5);
double a = Double.MIN_VALUE;
double b = z;
System.out.println(integrate(a, b));
}
Anybody has any ideas? I tried using Apache math's "PoissonDistribution" class's method "normalApproximateProbability(int x)". But the problem is this method takes an "int".
Anyone has any better ideas on how do I get the correct output or any other code. I have used another library for simpson too but I get the same output.
I need this to be done in Java.
I tried to test the code by writing another method that implements Simpson's 3/8 rule instead of your integrate function. It gave the same result as the one you obtained at first time. So i think the difference arises most probably from rounding errors.
I'm trying to make a program that calculates the required score to level in a game and the equation works fine on my calculator but not when i try changing it to work with java.
the equation is 5,000 / 3 * (4n^3 - 3n^2 - n) + 1.25 * 1.8^(n - 60) for example level 49 you should need to have a total score of 772240000 points and the calculator gives this answer but my java program doesn't. here is the code i tried.
for (int i = 0; i <= 100; i++) {
double score = (double) ((5000 / 3) * (Math.pow(4 * i, 3) - Math.pow(3 * i, 2) - i) + (1.25 * Math.pow(1.8, i - 60)));
System.out.println("Level " + i + " requires " + (long) score);
}
This doesnt seem to work right and gives 12513130000 as the required points for lvl 49. If anyone can get it to work would you miind explaining what i did wrong.
You're messing up your Math.pow calls, but you can avoid some of them entirely:
double score = (double) ((5000 / 3) * (4 * i * i * i - 3 * i * i - i) + (1.25 * Math.pow(1.8, i - 60)));
Here's what's wrong: Math.pow(4 * i, 3) is actually (4i)^3 and not 4(i^3). To do the latter, you would need the following:
4 * Math.pow(i, 3)
I'm not entirely sure about the integer division part (you are casting it to double), but you may have to change 5000 / 3 to 5000.0 / 3.
Your problem is inside Math.pow - you're multiplying your index value by a scalar each time.
4 * Math.pow(i, 3)
And
3 * Math.pow(i, 2)
Should fix it.
Edit: And the integer division mentioned in other answers.
I am using Math.PI in my example, so it is a double. It is a simple code but there is a bit I am not sure how to do:
I want the code to calculate the fundamental period X of a sin or cos function with a multiplier value a given by the user. The n value is initialized at n=1 and is an integer value.
If the result of (2 * pi * n)/a = X is lower than pi then n should increment, and it should keep going until that number is a multiple of pi, then print the result.
Just to clarify: a is a multiplier of x which goes in the function sin or cos like this:
cos(ax)
sin(ax)
The bit I am having the trouble with is working out whether the number is a multiple of pi (provided it's already greater than pi, that is).
This is about as far as I got and it's incomplete.
public void printSinusoidalPeriod(double multiplier /* this would be `a` */){
double pi=Math.PI;
double p = (2 * pi * (double) n) / multiplier;
while(p<pi){
if(n%pi==0){
n=n+1;
System.out.println(n);
p = (2 * pi * (double) n) / multiplier;
}
}
p= (double)Math.round(p * 100) / 100;
System.out.println("period of function is = " + p + " and n = " + n);
}
It seems like it's not going into the if statement and getting caught in the while loop
If I understand your problem correctly, I had to solve a similar problem to this before using php. Not sure what the correct syntax is for javascript but maybe you should keep a counter that continues until (x/pi) is an integer which would indicate it is a multiple of pi..
I know this isn't the correct code but something like:
while (!isint(x/pi)) {
x++;
}
if (isint(x/pi)) {
//CODE TO EXECUTE
}
If I understand you correctly
while((2 * pi * n)/a)<pi)
{
if(!(n%pi==0))
{
n++;
}
}
multiple of y is the part you need to figure out yourself. but this should help you with the logic, If I have understood u correctly.
You appear to be calculating when
(2 * pi * n)/a = m * pi where m is some integer multiple.
so
2 * pi * n = m * pi * a
2 * n = m * a
n = m * a / 2
You other constraint is
(2 * pi * n)/a < pi
so
2 * pi * n < pi * a
2 * n < a
n < a / 2;
For both equations to be true, m must be an integer less than 1, but since you are starting at 1 for n it will never be true.
Ok here's how I did it in the end, with the help of the suggestions here.
public void printSinusoidalPeriod(double a){
double pi=Math.PI;
double p=m*pi;
while(n<a/2){
if((double)Math.round((n*pi)%pi)!=0.01){
n=n+1;
m = (int) Math.round(((2 * (double) n) / a));
p= (double)Math.round(m * pi * 100) / 100;
p=p*n;
}
}
System.out.println("period of function is = " + p + " and n = " + n);
System.out.println("Check: p/n = " + p/n);
}
Please let me know if you can spot any problems with the logic. I have not gone through many possibities yet, but the ones I did, looked okay to me.
I have to create the sin function from scratch in my Comp Sci class, and I am getting close to a solution. However, I am still having a few problems. If I put in a value of .5PI or less it works, but otherwise I get the incorrect result. Here is the code I have so far:
double i=1;
double sinSoFar = 0;
int term = 1;
while(i >= .000001)
{
i = pow(-1, term + 1) * pow(sinOf, 2*term-1) / factorial(2*term-1);
sinSoFar=sinSoFar + i;
term++;
}
Like Federico pointed, the problem probably is in your factorial() or pow(). I ran a test that worked fine replacing your functions with the pow() function provided in the Math class, and this factorial():
public static long factorial(long n) {
if (n < 0) throw new RuntimeException("Underflow error in factorial");
else if (n > 20) throw new RuntimeException("Overflow error in factorial");
else if (n == 0) return 1;
else return n * factorial(n-1);
}
Some advices:
Start with term = 0. The canonical MacLaurin expansion also does
compute the powers and the factorial while you are cycling (that is, updating them at each step). Maybe the problem is within pow() or factorial().
EDIT. Suggestion: once you have computed the k-th term, you can compute the (k+1)-th one by:
Multiplying by (-1)
Multiplying by sinOf^2
Dividing by (2k+2)(2k+3)
In this way you can completely avoid the computation of powers and factorials.
As far as values outside of 0 - 1/2PI, they can all be computed from values inside the range.
// First, normalize argument angle (ang) to -PI to PI,
// by adding/subtracting 2*PI until it's within range
if ( ang > 1/2PI ) {
sin = sin ( PI - ang );
}
else if ( ang < 0 ) {
sin = -1 * sin( -1 * ang );
}
else {
// your original code
}