Print numerals in order in a sine wave - java

Background:
I've successfully written code that generates a sine wave from 0 to 2pi. Adjusting the constants xPrecision and yPrecision, you can stretch the graph horizontally or vertically.
I gain this neat output (in Eclipse), when xPrecision = yPrecision = 10:
My query:
I now wish to display digits 0 to 9 instead of the stars. So, the leftmost star is replaced by 0, the second left-most star is replaced by 1, and so on. When you reach 9, the next digit is again zero.
I am clueless as to how to do this. I have looked at wave patterns like this, but they are fixed width patterns, while mine is scalable.
The only way I can think of is converting my output to a 2D character array, then scraping the *s manually from left to right, and replacing them with the digits, and then printing it. However, this is extremely memory consuming at bigger values of x/yPrecision.
What is the most optimized way to achieve this output?
Code to print sine wave:
class sine {
static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
static final int PI = (int) (3.1415 * xPrecision);
static final int TPI = 2 * PI; // twice PI
static final int HPI = PI / 2; // half PI
public static void main(String[] args) {
double xd;
for(int start = (int) (1 * yPrecision), y = start; y >= -start; y--){
double x0 = Math.asin(y / yPrecision),
x1 = bringXValueWithinPrecision(x0),
x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
x3 = bringXValueWithinPrecision(PI/xPrecision - x0);
// for debug
//System.out.println(y + " " + x0 + " " + x1 + " " + x2 + " " + x3);
for(int x = 0; x <= TPI; x++){
xd = (x / xPrecision);
if(x1 == xd || x2 == xd || x3 == xd)
System.out.print("*");
else System.out.print(" ");
}
System.out.println();
}
}
public static double bringXValueWithinPrecision(double num){
// obviously num has 16 floating points
// we need to get num within our precision
return Math.round(num * xPrecision) / xPrecision;
}
}

"Draw" the graph in memory first, then assign digits to its vertical points, and print them in a separate pass.
01
9 2
8 3
7 4
6 5
5 6
4 7
3 8
2 9
1 0
0 1 2
2 1
3 0
4 9
5 8
6 7
7 6
8 5
9 4
0 3
12
See comments in the code for an explanation of how this works:
static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
static final int PI = (int) (3.1415 * xPrecision);
static final int TPI = 2 * PI; // twice PI
static final int HPI = PI / 2; // half PI
public static void main(String[] args) {
// This part is the same as OP's code, except that instead of printing '*'
// it stores the corresponding row number in the array of rows
double xd;
int[] row = new int[100];
Arrays.fill(row, -1);
int r = 0;
int maxc = 0; // Mark the rightmost column of all iterations
for(int start = (int) (1 * yPrecision), y = start; y >= -start; y--){
double x0 = Math.asin(y / yPrecision),
x1 = bringXValueWithinPrecision(x0),
x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
x3 = bringXValueWithinPrecision(PI/xPrecision - x0);
int c = 0;
for(int x = 0; x <= TPI; x++, c++){
xd = (x / xPrecision);
// This is where the asterisk used to go
if(x1 == xd || x2 == xd || x3 == xd)
row[c] = r;
}
maxc = Math.max(c, maxc);
r++;
}
// Walk the assigned rows, and give each one a consecutive digit
int[] digit = new int[100];
int current = 0;
for (int i = 0 ; i != 100 ; i++) {
if (row[i] != -1) {
digit[i] = (current++) % 10;
}
}
// Now walk the rows again, this time printing the pre-assigned digits
for (int i = 0 ; i != r ; i++) {
for (int c = 0 ; c != maxc ; c++) {
if (row[c] == i) {
System.out.print(digit[c]);
} else {
System.out.print(' ');
}
}
System.out.println();
}
}
public static double bringXValueWithinPrecision(double num){
// obviously num has 16 floating points
// we need to get num within our precision
return Math.round(num * xPrecision) / xPrecision;
}
The first part of the code fills row[i] array, which contains row for the asterisk in column i. First few numbers from row[] array would look like this:
10 9 8 7 6 5 4 - 3 2 - 1 - - - 0 0 - - - 1 - 2 3 - 4 5 6 7 8 9 10
- denotes cells with -1, which represents a missing value. The array says that the left-most asterisk is on row 10, the next asterisk is on row 9, then 8, 7, 6, and so on. Asterisks 11 and 12 are on row zero, which is at the top.
The second loop walks rows, skips -1s, and assign consecutive digits to all non-negative positions.
The third loop walks the entire field again going row-by-row, printing values from pre-assigned digit[] array when the current row matches the value in the row[] array.
Demo.

If you replace:
System.out.print("*");
with
System.out.print(""+(x%10));
it seems to nearly work.
56
1 0
9 2
8 3
6 5
5 6
4 7
3 8
2 9
1 0
0 1 2
2 1
3 0
4 9
5 8
6 7
7 6
9 4
0 3
2 1
67
Perhaps some further adjustments might get it perfect.

Doing it in a completely different way produces a different picture but achieves your effect.
Essentially,
for each y
for each x
calculate fx = sin(x)
if fx == y print * else print space
It's very inefficient as it calculates sin(x) x*y times when, if you filled a matrix, you could calculate sin(x) just x times.
static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
private void sine() {
for (double y = 1; y >= -1; y -= 1.0 / yPrecision) {
int n = 0;
for (double x = 0; x < 2.0 * Math.PI; x += 1.0 / xPrecision, n++) {
double fx = Math.sin(x);
boolean star = Math.round(fx*xPrecision) == Math.round(y*yPrecision);
System.out.print((star ? ""+(n%10) : " "));
}
System.out.println();
}
}
public void test(String[] args) {
sine();
}
Gives you:
345678
12 901
90 2
8 34
67 5
5 6
4 7
3 8
2 9
1 0
0 1
2 2
3 1
4 0
56 9
7 8
8 67
9 5
01 34
23 12
4567890

Since this is Java, how about let's actually use some objects as objects rather than just as places to define a couple of functions.
Treat your wavy graph as if it is a composition of several different "branches" of the inverse sine function. (Mathematically, that's how we explain the way your version of the program uses Math.asin to produce multiple coordinates for stars.)
Branch 0 is the initial rising part of the curve,
Branch 1 is the falling part of the curve after Branch 0,
Branch 2 is the rising part of the curve after Branch 1, and so forth.
The branches cross the middle line of the output at x values 0,
PI, 2*PI, 3*PI, and so forth.
Depending on how far you want the graph to extend to the right, it is easy to determine how many branches you need.
For example, to plot from 0 to 8*PI you need nine branches
(Branch 0, Branch 8, and the seven branches between those two).
You can implement each branch using an object of some class,
let's call it ArcSineBranch.
It has a constructor, ArcSineBranch(int), that takes the branch number as a parameter.
Create some sort of ordered list (which could just be an ArcSineBranch[] array) and put these branch objects in it,
making sure the branch numbers go in sequence from 0 up to the largest number needed.
You'll also want to implement some way to tell the first ArcSineBranch where its leftmost end is--in the example in the question, the leftmost end of first branch is at y == 0, whereas for all other rising branches it is at y == -start and for all falling branches it is at y == start.
Now you call a mutator function of the first ArcSineBranch that tells it its leftmost symbol is 0. Treat this as an integer (rather than a string) for now to make the arithmetic easier.
You then query the first ArcSineBranch for the rightmost symbol it will write, which it can compute from the leftmost symbol and the number of lines it will write symbols on.
You also query it for the x coordinate of that rightmost symbol.
(The object computes the x-coordinate of the symbol for any y-coordinate by either adding or subtracting a rounded multiple of Math.asin(y / yPrecision) from a multiple of PI.)
Now for each ArcSineBranch in the list, you pass to it the rightmost symbol and x coordinate written by the previous branch.
This ArcSineBranch uses that information to determine the leftmost symbol it writes and the y coordinate of that symbol.
(I am being careful here about the y coordinate in case you choose a value of xPrecision that causes the rightmost x coordinate of one branch to be the same as the leftmost x coordinate of the next; we should only write one symbol at that place in the output, so we want the later branch to skip its leftmost x coordinate and write its leftmost symbol in the next place, one line up or down. But if the x coordinates are different we want the later branch to write a symbol on the same line.)
Now that the later ArcSineBranch "knows" the leftmost symbol it will print and thata symbol's y coordinate, you can query it for its rightmost symbol and x coordinate, and pass those to the next ArcSineBranch, and so forth.
Once you have traversed all the ArcSineBranch objects in this way,
so that each object knows what symbols need to be written for its branch and where to write them, you can loop for (y = start; y >= -start; y--);
within that loop you loop over the list of ArcSineBranch objects;
for each object you query whether it requires a symbol to be written at
y-coordinate y.
If the object requires a symbol to be written,
you query which symbol to write at which x-coordinate,
then space the output to the right until you reach that x-coordinate and write that symbol there.
But of course, first check that this would not plot a symbol beyond the
right-hand edge of the desired graph.
(This check really only applies to the last ArcSineBranch, so you can optimize the code a bit by looping over the other branches first and then dealing with the last ArcSineBranch separately.)
I've already described this algorithm in more detail than I initially wanted to. There should be enough information here to code this into Java in a relatively straightforward way, though there are still some localized details to be worked out.
Note that the design in this answer is intended to use the same mathematical ideas as the code in the question uses to decide where to plot the points.
Specifically, ArcSineBranch(0) produces the x1 values from the original code, ArcSineBranch(1) produces the x3 values, and ArcSineBranch(2) produces the x2 values.
The implementation of this design should plot a digit at the location of each star plotted by the original code, and should plot no other digits.

Care about a different approach?
3030
28 28
26 26
22 22
18 18
12 12
06 06
00 00 00
06 06
12 12
18 18
22 22
26 26
28 28
3030
Solution:
import static java.lang.Math.sin;
import static java.lang.Math.PI;
import static java.lang.Math.abs;
public class Sine {
static final Integer points = 30; // points on x and y axis
public static void main(String[] args) {
// contains graph points
Boolean[][] graph = new Boolean[points + 1][points + 1];
for (Double x = 0.0; x <= points; x++) {
// x axis pi value
Double pi = (x / points) * 2 * PI;
// sin(x) plot for x
Integer sinx = (int) Math.round((sin(pi) * points / 2) + points / 2);
graph[sinx][x.intValue()] = true;
}
for (Integer i = 0; i <= points; i++) {
for (Integer j = 0; j <= points; j++) {
// space characters on x axis
Integer pt = (int) Math.floor(Math.log10(points) + 1);
String space = String.format("%" + pt + "s", " ");
// padding for p
String p = String.format("%0" + (pt) + "d", abs(i - points / 2) * 2);
System.out.print(graph[i][j] != null ? p : space);
}
System.out.println();
}
}
}
Approach:
points contains the number of characters on x and y axis.
graph contains true or null for each x and y characters.
1st for loop:
Since the value of x in sine graph is from 0 to 2π, we need to convert x accordingly. So pi contains the value of the same range but according to x.
sinx is the Integer value according to x.
No need to explain graph[sinx][x.intValue()] = true;.
2nd for loops:
1st for loop
Execute LOOPLABEL.
Break to next line at the end.
2nd for loop(LOOPLABEL)
pt holds the number for padding on y axis.
space is the space characters to be printed on y axis.
p is the converted range between 0 to points.
Printing graph[i][j]
DEMO

By using the fact that each row has one point (on each slope), you can calculate which digit to display at each point without using extra memory or loops. Here's my example. Note that I only checked that this example only works if xPrecision and yPrecision are integers. You'll have to modify it if you want to use doubles.
class sine {
static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
static final int PI = (int) Math.round(Math.PI * xPrecision);
static final int TPI = 2 * PI; // twice PI
static final int HPI = PI / 2; // half PI
static final int cycles = 2; // prints from x=0 to 2*cycles*pi
public static void main(String[] args) {
double xd;
int cycleoffset, cycleoffset2, topbottomoffset = 1;
for (int start = (int) (1 * yPrecision), y = start; y >= -start; y--) {
double x0 = Math.asin(y / yPrecision), x1 = bringXValueWithinPrecision(x0),
x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
x3 = bringXValueWithinPrecision(PI / xPrecision - x0), tmp;
if (y == start) {
if (x1 == x3) // when there is only one point at the top/bottom
topbottomoffset = 0;
else if (x1 > x3) // swap x1 and x3
{
tmp = x1;
x1 = x3;
x3 = tmp;
}
} else if (y == -start) {
// I don't think this is needed, but just for safety make sure there is only one point on the bottom if there was only one point at the top
if (topbottomoffset == 0)
x2 = x3;
else if (x2 < x3) // swap x2 and x3
{
tmp = x2;
x2 = x3;
x3 = tmp;
}
}
cycleoffset = (int) (4 * yPrecision + 2 * topbottomoffset);
cycleoffset2 = -cycleoffset;
int start1 = topbottomoffset + 2 * (int) yPrecision, start2 = 2 * topbottomoffset + 4 * (int) yPrecision;
for (int x = 0, lim = cycles * TPI; x <= lim; x++) {
xd = ((x % TPI) / xPrecision);
if (x % TPI == 0)
cycleoffset2 += cycleoffset;
// x = 0 to pi/2
if (x1 == xd)
System.out.print((cycleoffset2 + y) % 10);
// x = 3pi/2 to 2pi
else if (x2 == xd)
System.out.print((cycleoffset2 + start2 + y) % 10);
// x = pi/2 to 3pi/2
else if (x3 == xd)
System.out.print((cycleoffset2 + start1 - y) % 10);
else
System.out.print(" ");
}
System.out.println();
}
}
public static double bringXValueWithinPrecision(double num) {
// obviously num has 16 floating points
// we need to get num within our precision
return Math.round(num * xPrecision) / xPrecision;
}
}
EDIT
The digits for the different ranges are calculated as follows
0 < x < π/2 : This one is simplest since it is the first range. Since the middle row is y=0 and that is where the sine wave starts, we can just use y to find the digit.
π/2 < x < 3π/2 : The digits here count up as we go down, but y decreases as we go down. So we have to use a -y term. On the top row, y=yPrecision, and the last digit from the previous range was yPrecision. So we use 2*yPrecision - y, because that includes the -y, and is equal to yPrecision at the first term (where y=yPrecision).
3π/2 < x < 2π : The digits here count down as we go down, so we need a +y term, but the tricky part is figuring where to start. Since the sine wave by this point has gone from 0 to yPrecision to 0 to -yPrecision, the bottom point (x=3π/2) should start at 3*yPrecision. Since y=-yPrecision at the bottom point, we use 4*yPrecision + y, since that includes a +y and is equal to 3*yPrecision at the first term (where y=-yPrecision).
The topbottomoffset term : Depending on the values used for xPrecision and yPrecision, there can be one or two points plotted on the top and bottom rows. If there are two points, we need to add one to digits in the π/2 to 3π/2 range, and two to the digits in the 3π/2 to 2π range.
The cycleoffset term : If multiple cycles of the sine wave are plotted, additional cycles need to start from the last digit used in the previous cycle. Each cycle goes from 0 to yPrecision to 0 to -yPrecision to 0, which is equal to 4*yPrecision. So each new cycle needs to start at 4*yPrecision*[the number of previous cycles]. If there are two points on the top and bottom rows, those need to be factored in as well.
Swapping values: When there are two points on the top row, then x1>x3. This happens because when y=yPrecision, we're taking Math.asin(1), which happens to be exactly pi/2=1.5707963267948966 in Java's double system. On lower xPrecision (<100.0), the rounding done by bringXValueWithinPrecision brings x1 up to 1.58 while x3 down to nearly 1.56. Hence, they need to be swapped in order to get the correct numerical order.

Here's my solution, which basically uses the half of the sine in 4 for loops:
from half to 0
from 0 to half
from half to the end
from the end to the half
And in each loop replace only the first asterisk.
class sine {
static final double xPrecision = 14.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 14.0; // (1/yPrecision) is the precision on y-values
static final int PI = (int)(3.1415 * xPrecision);
static final int TPI = 2 * PI; // twice PI
static final int HPI = PI / 2; // half PI
public static void main(String[] args) {
double xd;
String str = "";
for (int start = (int)(1 * yPrecision), y = start; y >= -start; y--) {
double x0 = Math.asin(y / yPrecision),
x1 = bringXValueWithinPrecision(x0),
x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
x3 = bringXValueWithinPrecision(PI / xPrecision - x0);
// for debug
//System.out.println(y + " " + x0 + " " + x1 + " " + x2 + " " + x3);
for (int x = 0; x <= TPI; x++) {
xd = (x / xPrecision);
if (x1 == xd || x2 == xd || x3 == xd)
str += "*";
else str += " ";
}
str += "\n";
}
String[] rows = str.split("\n");
int half = (int)(1 * yPrecision);
// we use this half in for loops, from half to 0, from 0 to half, from half to the end and from the end to the half, and replace only the first asterisk.
int val = 0;
for (int i = half; i >= 0; i--) {
if (val == 10) val = 0;
rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
}
for (int i = 0; i <= half; i++) {
if (val == 10) val = 0;
rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
}
for (int i = half + 1; i < rows.length; i++) {
if (val == 10) val = 0;
rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
}
for (int i = rows.length - 1; i >= half; i--) {
if (val == 10) val = 0;
rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
}
System.out.println(String.join("\n", rows));
}
public static double bringXValueWithinPrecision(double num) {
// obviously num has 16 floating points
// we need to get num within our precision
return Math.round(num * xPrecision) / xPrecision;
}
}
Result:
01
9 2
8 3
7 4
6 5
5 6
4 7
3 8
2 9
1 0
0 1 2
2 1
3 0
4 9
5 8
6 7
7 6
8 5
9 4
0 3
12

Add a counter in your loop and reset it when 9 is reached:
for(int x = 0, counter = 0; x <= TPI; x++, counter++){
xd = (x / xPrecision);
if(x1 == xd || x2 == xd || x3 == xd) {
System.out.print("" + counter);
if (counter == 9) {
counter = 0;
}
} else {
System.out.print(" ");
}
}

Related

Maximum height of the staircase

Given an integer A representing the square blocks. The height of each square block is 1. The task is to create a staircase of max height using these blocks. The first stair would require only one block, the second stair would require two blocks and so on. Find and return the maximum height of the staircase.
Your submission failed for the following input: A : 92761
Your function returned the following : 65536
The expected returned value : 430
Approach:
We are interested in the number of steps and we know that each step Si uses exactly Bi number of bricks. We can represent this problem as an equation:
n * (n + 1) / 2 = T (For Natural number series starting from 1, 2, 3, 4, 5 …)
n * (n + 1) = 2 * T
n-1 will represent our final solution because our series in problem starts from 2, 3, 4, 5…
Now, we just have to solve this equation and for that we can exploit binary search to find the solution to this equation. Lower and Higher bounds of binary search are 1 and T.
CODE
public int solve(int A) {
int l=1,h=A,T=2*A;
while(l<=h)
{
int mid=l+(h-l)/2;
if((mid*(mid+1))==T)
return mid;
if((mid*(mid+1))>T && (mid!=0 && (mid*(mid-1))<=T) )
return mid-1;
if((mid*(mid+1))>T)
h=mid-1;
else
l=mid+1;
}
return 0;
}
To expand on the comment by Matt Timmermans:
You know that for n steps, you need (n * (n + 1))/2 blocks. You want know, if given B blocks, how many steps you can create.
So you have:
(n * (n + 1))/2 = B
(n^2 + n)/2 = B
n^2 + n = 2B
n^2 + n - 2B = 0
That looks suspiciously like something for which you'd use the quadratic formula.
In this case, a=1, b=1, and c=(-2B). Plugging the numbers into the formula:
n = ((-b) + sqrt(b^2 - 4*a*c))/(2*a)
= (-1 + sqrt(1 - 4*1*(-2B)))/(2*a)
= (-1 + sqrt(1 + 8B))/2
= (sqrt(1 + 8B) - 1)/2
So if you have 5050 blocks, you get:
n = (sqrt(1 + 40400) - 1)/2
= (sqrt(40401) - 1)/2
= (201 - 1)/2
= 100
Try it with the quadratic formula calculator. Use 1 for the value of a and b, and replace c with negative two times the number of blocks you're given. So in the example above, c would be -10100.
In your program, since you can't have a partial step, you'd want to truncate the result.
Why are you using all these formulas? A simple while() loop should do the trick, eventually, it's just a simple Gaussian Sum ..
public static int calculateStairs(int blocks) {
int lastHeight = 0;
int sum = 0;
int currentHeight = 0; //number of bricks / level
while (sum <= blocks) {
lastHeight = currentHeight;
currentHeight++;
sum += currentHeight;
}
return lastHeight;
}
So this should do the job as it also returns the expected value. Correct me if im wrong.
public int solve(int blocks) {
int current; //Create Variables
for (int x = 0; x < Integer.MAX_VALUE; x++) { //Increment until return
current = 0; //Set current to 0
//Implementation of the Gauss sum
for (int i = 1; i <= x; i++) { //Sum up [1,*current height*]
current += i;
} //Now we have the amount of blocks required for the current height
//Now we check if the amount of blocks is bigger than
// the wanted amount, and if so we return the last one
if (current > blocks) {
return x - 1;
}
}
return current;
}

Using arithmetical operations, how many goals were scored?

A man is keeping score of a football (soccer) game. He tracks partial results like this: 1-0, 1-1, 2-1, 2-2, 3-2. The sum of the goals in all of these partial results is 15, and the final result is 3-2, which is 5 goals. Given N which is sum of the goals of the partial results, you need to find number of goals of the final result. Here are some examples:
Input 15
Output 5
Input 6
Output 3
Input 55
Output 10
I can't use loops to solve the problem; I can only use if/else and arithmetical operations. Using just those operations, how can I find hte number of goals of the final result?
It is a summation problem. A record is created every time a goal is scored. The record is always one larger than the previous record. The total is the sum of all records.
Total = summation( number of goals scored )
So is the total is 1 then you know the number of goals is 1 as well.
If the total is three then there were two goals scored (1 and 1+1)
55 = 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 so there were 10 goals scored.
edit Calculating the actual answer is simpler than using the fractional math shown in other answers, but it requires solving a quadratic equation.
Note that the solution to ax**2 + bx + c == 0 is
x = (-b +/- SQRT( b**2 - 4*a*c) / 2*a
T = n(n+1)/2
2T = n**2 + n
n**2 + n - 2T = 0
n = (-1 +/- SQRT( 1 - 4*1*(-2T))) / (2 * 1), n > 0
n = (SQRT( 1 + 8T ) - 1) / 2
so if T = 10, n = (SQRT(81) - 1) / 2 == 4
r ="result"
s = "sum of goals"
n = "number of goals"
r s n
1-0 1 1
1-1 3 2
2-1 6 3
2-2 10 4
3-2 15 5
This tells us that s is just the sum of the first n integers, but we need n(s), not s(n).
Here's an example calculation.
Here's the code for making this happen in java:
class Example {
public static int n(int s) {
return (int) Math.round(-1.0 / 2.0 + Math.sqrt(1.0 / 4.0 + 2.0 * s));
}
public static int s(int n) {
return (n * (n + 1)) / 2;
}
public static void main(String[] args) {
for (int n = 0; n <= 10; n++) {
int s = s(n);
printResult(s);
}
}
private static void printResult(int s) {
int n = n(s);
System.out.println("If the sum of goals is " + s + ", then the number of goals is " + n);
}
}
Here's the output:
If the sum of goals is 0, then the number of goals is 0
If the sum of goals is 1, then the number of goals is 1
If the sum of goals is 3, then the number of goals is 2
If the sum of goals is 6, then the number of goals is 3
If the sum of goals is 10, then the number of goals is 4
If the sum of goals is 15, then the number of goals is 5
If the sum of goals is 21, then the number of goals is 6
If the sum of goals is 28, then the number of goals is 7
If the sum of goals is 36, then the number of goals is 8
The question is ambiguous as to whether square root is allowed, does it strictly count as an arithmetic operation?
If we assume its not allowed and we cannot use any looping we can use Newton's method to give a good approximation to the answer. Others have pointed out that we are basically trying the find the inverse of the triangular numbers T(n)=n(n+1)/2. If we are given a sum S let f(n)=n^2/2+n/2-S we want to solve f(n)=0. Newton's method is a fast iterative method, given an initial guess x0 we can find a better guess x1 using
x1 = x0 - f(x) / df(x)
where df(x)=x-1/2 is the derivative. If we do this 4 times we get a pretty good solution.
public class InverseSqrt {
static float f(float x,float S) {
return x*x/2+x/2-S;
}
static float df(float x,float S) {
return x+0.5f;
}
static float newton(float sum) {
float x = sum/2; // first initial guess
// Apply Newton's method four time
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
return x;
}
public static void main(String[] args) {
int i=0;
int ires=0;
do { // loop through possible number of goals
++i;
float s = i * (i+1) * 0.5f; // calculate the total
float res = newton(s);
ires = (int) (res+0.5); // round to nearest integer
System.out.print("T("+i+")="+(int)s);
System.out.println("\tres="+ires+"\t("+res+")");
} while(ires==i); // break first time it fails
}
}
This works pretty well up to an input of 351 giving an output of 26. But fails for the next input 378 giving 28 rather than 27 goal.
We can improve things a bit by using 5 steps of Newtons method working up to an input of 1176 with an output of 48. Tuning the initial guess improves things dramatically, using a starting guess of n/16 with 5 steps works upto input 42195 output 290.
A much better solution can be found using the Fast inverse squareroot. This can be implemented in Java following this answer.
static float Q_rsqrt( float x )
{
float xhalf = 0.5f*x;
int i = Float.floatToIntBits(x);
i = 0x5f3759df - (i>>1);
x = Float.intBitsToFloat(i);
x = x*(1.5f - xhalf*x*x);
return x;
}
Our Newton iteration method is then
static float newton(float sum) {
float x = Q_rsqrt(1/sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
return x;
}
with only 3 iteration steps.
This works upto Input 1073720960 Output 46340. The next item after than gives an integer overflow in calculating the sum, so it can be said to work for all legal int values.
This might not be counted as a legal solution as it uses floatToIntBits(x) and intBitsToFloat(x) which don't really class as arithmetic operations.
It seems that sum of arithmetic progression S(n) is given, and you have to find n.
Use simple math and calculate n from equation:
S(n) = n * (n + 1) / 2

Creating formula for distance and damage

public double getDamage(double distance){
int damage1 = 30; // (0 - 38.1)
int damage2 = 20; // (50.8 - *)
double range1 = 38.1;
double range2 = 50.8;
double damage = 0; // FORMULA
return damage;
}
I try to create a formula to calculate the amount of damage that has been effected by the distance.
(Variable Distance =)
0 till 38.1 metre It will return 30 damage.
50.8 till Inifite it will return 20 damage.
38.1 till 50.8 it will decrease linear 30 -> 20.
How can I make this method work?
Thanks in advance.
Sounds like this:
double x = (distance - range1) / (range2 - range1);
if (x < 0)
x = 0;
if (x > 1)
x = 1;
return damage1 + x * (damage2 - damage1);
Basically you follow a linear rule and also adjust to stay in your linear interval.
Looks like you want a step formula, not a linear formula. Step formula is basically a bunch of if-else if comparisons in code. Something like this:
public double getDamage(double dist){
if (0 < dist & dist < 38.1)
return 30;
else if ( 38.1 < dist & dist < 50.8 )
return 30 - dist/10;
else
return
}
Edit: just saw you do want it linearly between 38.1 and 50.8.
Use something like this return 30 - dist/10; dist/10 would give you damage of 27 to 23, you'd need to find an appropriate constant (instead of 10) yourself. (Which is easy since its y = mx + b and you have two points by your conditions (38.1, 30) and (50.8, 20). So sub those into y = mx+b and you'll get the formula to use in the 2nd else-if.
The formula you are looking for is a simple variation of the point-slop equation y = m(x-x1) + y1 equation, where m = (damage1 - damage2)/(range1 - range2), x1 = range1, y1 = damage1, and x is the variable distance.
public double getDamage(double distance){
int damage1 = 30;
int damage2 = 20;
double range1 = 38.1;
double range2 = 50.8;
double damage = 0;
if(0 <= distance && distance <= range1)
damage = damage1;
else if (range1 < distance && distance < range2)
damage = (damage1 - damage2)/(range1 - range2) * (distance - range1) + damage1;
else if (distance >= range2)
damage = damage2;
return damage;
}

How to re-implement sin() method in Java ? (to have results close to Math.sin() )

I know Math.sin() can work but I need to implement it myself using factorial(int) I have a factorial method already below are my sin method but I can't get the same result as Math.sin():
public static double factorial(double n) {
if (n <= 1) // base case
return 1;
else
return n * factorial(n - 1);
}
public static double sin(int n) {
double sum = 0.0;
for (int i = 1; i <= n; i++) {
if (i % 2 == 0) {
sum += Math.pow(1, i) / factorial(2 * i + 1);
} else {
sum += Math.pow(-1, i) / factorial(2 * i + 1);
}
}
return sum;
}
You should use the Taylor series. A great tutorial here
I can see that you've tried but your sin method is incorrect
public static sin(int n) {
// angle to radians
double rad = n*1./180.*Math.PI;
// the first element of the taylor series
double sum = rad;
// add them up until a certain precision (eg. 10)
for (int i = 1; i <= PRECISION; i++) {
if (i % 2 == 0)
sum += Math.pow(rad, 2*i+1) / factorial(2 * i + 1);
else
sum -= Math.pow(rad, 2*i+1) / factorial(2 * i + 1);
}
return sum;
}
A working example of calculating the sin function. Sorry I've jotted it down in C++, but hope you get the picture. It's not that different :)
Your formula is wrong and you are getting a rough result of sin(1) and all you're doing by changing n is changing the accuracy of this calculation. You should look the formula up in Wikipedia and there you'll see that your n is in the wrong place and shouldn't be used as the limit of the for loop but rather in the numerator of the fraction, in the Math.pow(...) method. Check out Taylor Series
It looks like you are trying to use the taylor series expansion for sin, but have not included the term for x. Therefore, your method will always attempt to approximate sin(1) regardless of argument.
The method parameter only controls accuracy. In a good implementation, a reasonable value for that parameter is auto-detected, preventing the caller from passing to low a value, which can result in highly inaccurate results for large x. Moreover, to assist fast convergence (and prevent unnecessary loss of significance) of the series, implementations usually use that sin(x + k * 2 * PI) = sin(x) to first move x into the range [-PI, PI].
Also, your method is not very efficient, due to the repeated evaluations of factorials. (To evaluate factorial(5) you compute factorial(3), which you have already computed in the previous iteration of the for-loop).
Finally, note that your factorial implementation accepts an argument of type double, but is only correct for integers, and your sin method should probably receive the angle as double.
Sin (x) can be represented as Taylor series:
Sin (x) = (x/1!) – (x3/3!) + (x5/5!) - (x7/7!) + …
So you can write your code like this:
public static double getSine(double x) {
double result = 0;
for (int i = 0, j = 1, k = 1; i < 100; i++, j = j + 2, k = k * -1) {
result = result + ((Math.pow(x, j) / factorial (j)) * k);
}
return result;
}
Here we have run our loop only 100 times. If you want to run more than that you need to change your base equation (otherwise infinity value will occur).
I have learned a very good trick from the book “How to solve it by computer” by R.G.Dromey. He explain it like this way:
(x3/3! ) = (x X x X x)/(3 X 2 X 1) = (x2/(3 X 2)) X (x1/1!) i = 3
(x5/5! ) = (x X x X x X x X x)/(5 X 4 X 3 X 2 X 1) = (x2/(5 X 4)) X (x3/3!) i = 5
(x7/7! ) = (x X x X x X x X x X x X x)/(7 X 6 X 5 X 4 X 3 X 2 X 1) = (x2/(7 X 6)) X (x5/5!) i = 7
So the terms (x2/(3 X 2)) , (x2/(5 X 4)), (x2/(7 X 6)) can be expressed as x2/(i X (i - 1)) for i = 3,5,7,…
Therefore to generate consecutive terms of the sine series we can write:
current ith term = (x2 / ( i X (i - 1)) ) X (previous term)
The code is following:
public static double getSine(double x) {
double result = 0;
double term = x;
result = x;
for (int i = 3, j = -1; i < 100000000; i = i + 2, j = j * -1) {
term = x * x * term / (i * (i - 1));
result = result + term * j;
}
return result;
}
Note that j variable used to alternate the sign of the term .

2d array representation

The question is not tied to a specific programming language, but rather to minimalistic code and abstraction.
I have this array of 3 rows and 3 columns - imagine a board in which you'd play Tic-Tac-Toe (or naughts and crosses).
When a key(on the Phone) is pressed a value of 0 or 1 is added to the array(1 for X and 0 for O) in the position corresponding to the key pressed(key 9 being board[2][2]).
In building the GUI, I need to map the array coordinates to pixels, such that if:
[0][0] - 10,10
[0][1] - 10,50
[0][2] - 10,90
...
[2][2] - 90,90
the drawing will take place while traversing the array in a nested loop, but I got stuck on how to write in fewest lines of code as possible the mapping between 0 = 10, 1 = 50 and 2 = 90.
One way to go would be to use a switch for each case. Another would be using an if.
Any other ideas to write this in fewer possible lines?
Thanks!
for ( y = 0; y < 3; ++y )
{
for ( x = 0; x < 3; ++x )
{
pos_x = x * 40 + 10;
pos_y = y * 40 + 10;
// Draw...
}
}
for(var i = 0; i < 3; i++) {
for(var j = 0; j < 3; j++) {
int xPos = i * 40 + 10;
int yPos = j * 40 + 10;
//set accordingly
}
}
Use your index value as multiplicator i.e. 90 = 2 * 40 + 10, 50 = 1 * 40 + 10

Categories