hash value for a line object - java

Here is a reference implementation of Line object, my confusion is from line 40 to line 43, the question is, if two lines are different, but the OR results of slope/intercept happens to be the same, will it have any issues (e.g. treat different lines the same because of the same hash values)? Since I think same hash value means the same Line.
If the current implementation for hash value do have the issue I mentioned, appreciate if anyone could help to provide some insights what are good implementation for hash value in my case.
1 public static Line findBestLine(GraphPoint[] points) {
2 Line bestLine = null;
3 HashMap<Line, Integer> line_count = new HashMap<Line, Integer>();
4 for (int i = 0; i < points.length; i++) {
5 for (int j = i + 1; j < points.length; j++) {
6 Line line = new Line(points[i], points[j]);
7 if (!line_count.containsKey(line)) {
8 line_count.put(line, 0);
9 }
10 line_count.put(line, line_count.get(line) + 1);
11 if (bestLine == null ||
12 line_count.get(line) > line_count.get(bestLine)) {
13 bestLine = line;
14 }
15 }
16 }
17 return bestLine;
18 }
19
20 public class Line {
21 private static double epsilon = .0001;
22 public double slope;
23 public double intercept;
24 private boolean infinite_slope = false;
25 public Line(GraphPoint p, GraphPoint q) {
26 if (Math.abs(p.x - q.x) > epsilon) { // if x’s are different
27 slope = (p.y - q.y) / (p.x - q.x); // compute slope
28 intercept = p.y - slope * p.x; // y intercept from y=mx+b
29 } else {
30 infinite_slope = true;
31 intercept = p.x; // x-intercept, since slope is infinite
32 }
33 }
34
35 public boolean isEqual(double a, double b) {
36 return (Math.abs(a - b) < epsilon);
37 }
38
39 #Override
40 public int hashCode() {
41 int sl = (int)(slope * 1000);
42 int in = (int)(intercept * 1000);
43 return sl | in;
44 }
45
46 #Override
47 public boolean equals(Object o) {
48 Line l = (Line) o;
49 if (isEqual(l.slope, slope) && isEqual(l.intercept, intercept)
50 && (infinite_slope == l.infinite_slope)) {
51 return true;
52 }
53 return false;
54 }
55 }

Since I think same hash value means the same Line.
No, it doesn't. This is a common misconception. If two objects have the same hash code, they may be equal - but they don't have to be. You should never treat equal hash codes as proof that two objects are equal.
The hash code used here is definitely poor in various ways, but it is at least valid.
As an extreme example, it's always valid (but almost always unhelpful) to write:
public override int hashCode() {
return 5;
}
That guarantees that objects which are equal will have the same hash code, which is all that's required for correctness. Beyond correctness, ensuring that non-equal objects have different hash codes is a matter of making it efficient to use the type in a hash-based lookup.

Related

Stack Overflow during Binary Search

I am using binary search to find a balance point between the planets. The method binaryBalance takes in Arraylist of planets which is an object with displacement and mass property. It also takes in the displacement of two planets between which I am trying to find a balance point of. Double x is the inital starting point of the search and I am setting the average displacement of p1 and p2 here. The code runs smoothly but it is off the answer for a minute amount. I try to increase the precision by setting the error interval to more than 1e-10, but I keep getting Stack Overflow error. How do I solve this problem with higher precision?
import java.util.*;
import java.lang.*;
public class Solution {
public static void main(String[] arg) {
Scanner sc = new Scanner(System.in);
int numCase = sc.nextInt();
for (int k = 1; k <= numCase; k++) {
//Initializing Space...
int numPlanets = sc.nextInt();
ArrayList<Planet> space = new ArrayList<>();
int[] weights = new int[numPlanets];
int[] displacements = new int[numPlanets];
for (int i = 0; i < numPlanets; i++) {
displacements[i] = sc.nextInt();
}
for (int i = 0; i < numPlanets;i++) {
weights[i] = sc.nextInt();
}
for (int i = 0; i < numPlanets;i++) {
Planet p = new Planet(displacements[i],weights[i]);
space.add(p);
}
System.out.print("#" + k + " ");
for (int i = 0; i < numPlanets-1; i++) {
double init = (double) (space.get(i).getDisplacement() + space.get(i+1).getDisplacement()) /2;
binaryBalance(space,space.get(i).getDisplacement(),space.get(i+1).getDisplacement(),init);
}
System.out.println();
}
}
public static class Planet {
private int d;
private int m;
public Planet(int d,int m) {
this.d = d;
this.m = m;
}
public void setDisplacement(int d) {
this.d = d;
}
public void setMass(int m) {
this.m = m;
}
public double getG(double dPlanet) {
double betweenDistance = this.d - dPlanet;
return this.m/(betweenDistance*betweenDistance);
}
public int getDisplacement() {
return d;
}
public int getMass() {
return m;
}
}
public static void binaryBalance(ArrayList<Planet> space, double p1, double p2, double x) {
double leftg = 0;
double rightg = 0;
for (int i = 0; i < space.size(); i++) {
if (space.get(i).getDisplacement() < x) {
leftg = leftg + space.get(i).getG(x);
} else {
rightg = rightg + space.get(i).getG(x);
}
}
if (Math.abs(leftg - rightg) < 1e-10) {
System.out.print(String.format("%.10f",x) + " ");
return;
}
if (leftg < rightg) {
binaryBalance(space, p1, x, (p1 + x) / 2);
} else {
binaryBalance(space, x, p2, (p2 + x) / 2);
}
}
Test Cases are:
10
2
1 2 1 1
2
1 2 1 1000
2
457 468 333 321
3
1 2 3 1 2 1
4
2 3 5 7 3 2 7 5
5
3 11 12 19 29 542 661 450 521 366
6
42 75 88 94 113 144 669 551 355 344 294 155
7
62 86 279 323 363 516 579 810 749 736 297 136 107 52
8
10 34 64 73 93 97 101 122 466 463 441 373 315 292 225 83
10
9 14 38 39 48 73 179 190 207 302 560 497 640 722 437 259 449 470 709 520
And the expected answer is:
#1 1.5000000000
#2 1.0306534300
#3 462.5504629633
#4 1.4060952085 2.5939047915
#5 2.5328594461 3.7271944335 6.0999536409
#6 6.3428568767 11.5477377494 15.9641592998 24.9267991615
#7 57.8805685415 81.8651598883 91.0573691382 105.0835650491 133.2934094881
#8 74.2211477711 190.6837563313 305.8269181686 348.3304429927 470.2694219293 555.4943093854
#9 21.5171374463 47.9890597763 68.6536668433 82.9131954023 95.0052272762 99.1999097770 116.4978330953
#10 11.5573600056 24.0238341337 38.4847676134 44.6137453708 64.7500445424 126.9908128982 184.3221650927 197.9760596291 266.0574653677
With the leftg-rightg tolerance of 1e-10, the greatest number of iterations is 47, on the second case where the masses are so different. That won't overflow any stacks, but of course you asked about increasing the accuracy. Unfortunately, it's impossible to even reach 1e-11 on case 6, because of the scale of the numbers involved (as I mentioned in a comment). So you get infinite recursion if you change the tolerance exponent at all.
But maybe a fixed balance tolerance isn't what you're expected to do for this exercise! I get exactly the expected answers (to their given precision) if I instead refine until the interval has "zero" width. (p1 and p2 need not be equal, but there are no floating-point numbers between them. You detect this by noticing that x==p1 || x==p2; x will be whichever ends in a 0 in binary.) This takes at most 53 bisections for these cases: a number which should be familiar to any numerical analyst since it is the effective number of bits in the significand of a double. I didn't check whether a larger p2-p1 tolerance might give the correct answers.
Since it's useless to get (much) above 53 levels deep, the choice of recursion here is harmless (although tail recursion with a void function looks very odd), and changing to iteration won't help at all. Either way, you do have to make sure that it terminates!
Try to use iteration instead of recursion. I also added line with logging of data on each iteration.
public static void binaryBalance(ArrayList<Planet> space, double p1, double p2, double x) {
while(true) {
//You can use this line to log evolution of your data
System.out.println(String.format("p1=%s p2=%s x=%s", p1, p2, x));
double leftg = 0;
double rightg = 0;
for (int i = 0; i < space.size(); i++) {
if (space.get(i).getDisplacement() < x) {
leftg = leftg + space.get(i).getG(x);
} else {
rightg = rightg + space.get(i).getG(x);
}
}
if (Math.abs(leftg - rightg) < 1e-10) {
System.out.print(String.format("%.10f",x) + " ");
return;
}
double p1Tmp = p1;
double p2Tmp = p2;
double xTmp = x;
if (leftg < rightg) {
p1 = p1Tmp;
p2 = xTmp;
x = (p1Tmp + xTmp) / 2;
} else {
p1 = xTmp;
p2 = p2Tmp;
x = (p2Tmp + xTmp) / 2;
}
}
}

Finding the last two digits before the decimal point for the number (4+sqrt(11))^n

I am doing a problem in which I have to find the last two digits before the decimal point for the number [4 + sqrt(11)]n.
For example, when n = 4, [4 + sqrt(11)]4 = 2865.78190... the answer is 65. Where n can vary from 2 <= n <= 109.
My solution - I have tried to build a square root function which calculate the sqrt of 11
which a precision equal to value of n input by the user.
I have used BigDecimal in Java to avoid overflow problems.
public class MathGenius {
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
long a = 0;
try {
a = reader.nextInt();
} catch (Exception e) {
System.out.println("Please enter a integer value");
System.exit(0);
}
// Setting precision for square root 0f 11. str contain string like 0.00001
StringBuffer str = new StringBuffer("0.");
for (long i = 1; i <= a; i++)
str.append('0');
str.append('1');
// Calculating square root of 11 having precision equal to number enter
// by the user.
BigDecimal num = new BigDecimal("11"), precision = new BigDecimal(
str.toString()), guess = num.divide(new BigDecimal("2")), change = num
.divide(new BigDecimal("4"));
BigDecimal TWO = new BigDecimal("2.0");
BigDecimal MinusOne = new BigDecimal("-1"), temp = guess
.multiply(guess);
while ((((temp).subtract(num)).compareTo(precision) > 0)
|| num.subtract(temp).compareTo(precision) > 0) {
guess = guess.add(((temp).compareTo(num) > 0) ? change
.multiply(MinusOne) : change);
change = change.divide(TWO);
temp = guess.multiply(guess);
}
// Calculating the (4+sqrt(11))^n
BigDecimal deci = BigDecimal.ONE;
BigDecimal num1 = guess.add(new BigDecimal("4.0"));
for (int i = 1; i <= a; i++)
deci = deci.multiply(num1);
// Calculating two digits before the decimal point
StringBuffer str1 = new StringBuffer(deci.toPlainString());
int index = 0;
while (str1.charAt(index) != '.')
index++;
// Printing output
System.out.print(str1.charAt(index - 2));
System.out.println(str1.charAt(index - 1));
}
}
This solution works up to n = 200, but then it begins to slow down. It stops working for n = 1000.
What is a good method to deal with problem?
2 -- 53
3 -- 91
4 65
5 67
6 13
7 71
8 05
9 87
10 73
11 51
12 45
13 07
14 33
15 31
16 85
17 27
18 93
19 11
20 25
21 47
22 53
23 91
24 65
25 67
At n=22 the results seem to repeat from the position of n=2.
So keep those 20 values in an array in the same order as in your list e.g. nums[20].
Then when the user provides an n:
return nums[(n-2)%20]
There is now a proof of this pattern repeating here.
Alternatively, if you insist on computing at length; since you calculating the power by looping multiplication (and not BigDecimal pow(n)) you could trim the number you are working with at the front to the last 2 digits and the fractional part.
Here is a much simpler solution for you...
Use the rational representation of 4+sqrt(11):
BigInteger hundred = new BigInteger("100");
BigInteger numerator = new BigInteger("5017987099799880733320738241");
BigInteger denominator = new BigInteger("685833597263928519195691392");
BigInteger result = numerator.pow(n).divide(denominator.pow(n)).mod(hundred);
UPDATE:
As you've mentioned in the comments below, this procedure is prone to precision-loss, and will eventually yield an incorrect result. I found this question to be rather interesting on the mathematical aspect, and so I published a question on MO (https://mathoverflow.net/q/158420/27456).
You can read the answer at https://mathoverflow.net/a/158422/27456.

Basic Java: Finding the Greatest Common Factor

I need to create a program that finds the greatest common factor of two user entered numbers using this formula:
gcd(x, y) = gcd(x – y, y) if x >= y and gcd(x, y) = gcd(x,y-x) if x < y.
For example:
gcd(72, 54) = gcd(72 – 54, 54) = gcd(18, 54)Since 72 > 54, we replace 72 with 72 – 54 = 18 and continue the loop with the new values
Iteration 2: gcd(18, 54) = gcd(18, 54 – 18) = gcd(18, 36)
Since 18 < 54, we replace 54 with 54 – 18 = 36 and continue the loop with the new values
Iteration 3: gcd(18, 36) = gcd(18, 36 – 18) = gcd(18, 18)
Since 18 < 36, we replace 36 with 36 – 18 = 18 and continue the loop with the new values
Iteration 4: gcd(18, 18) = gcd(18 – 18, 18) = gcd(0, 18) = 18
Since 18 >= 18, we replace the first 18 with 18 – 18 = 0
Since one of the values is 0 we do not continue the loop
The nonzero value, 18, is the gcd.
Here's of the code I have so far:
I'm getting the error "Illegal start of expression."
First of all in your logic here:
do {
int gcd1 = (num1-num2);
System.out.println(gcd1 + "," + num2);
}
while (num1 != 0 && num2 != 0);
return
}
You are just printing out gcd1 and num2 without updating num1 and num2.
Also think how you can use recursion to tackle this problem.
If you insist on using a loop, here's the while loop logic:
public static int greatestCommon(int a, int b)
{
while (a != 0 && b != 0)
{
if (a >= b)
{
a = a - b;
}
else
b = b - a;
}
if (a == 0) return b;
else return a;
}
note that you do not need to use a do-while loop since there are situations when you do not need the substraction (if one or both of them are 0).
Use
Math.Max(num1, num2) - Math.Min(num1,num2)
instead of num1-num2
You've already stated the answer (the algorithm) in your first sentence:
gcd(x, y) = gcd(x – y, y) if x >= y and gcd(x, y) = gcd(x,y-x) if x < y.
So how to translate that into code? The left-hand side of the equation is your method prototype, and the right-hand side is your method body:
public static int gcd(x, y) // doesn't HAVE to be public or static
{
gcd(x – y, y) if x >= y and gcd(x, y) = gcd(x,y-x) if x < y
}
but that code in the body doesn't compile, so you need to rewrite the body. Note that "and gcd(x, y) = ..." is a repetition of the method prototype and thus removed:
public static int gcd(x, y)
{
if (x >= y)
{
return ... // you fill this in
}
else if (x < y)
{
return ... // you fill this in
}
}
Note that the final "else-if" check really isn't necessary, but you teacher likely wants to see it there.
EDIT:
Since this likely a classroom exercise in recursion, consider this working example taken from javax.swing.table.DefaultTableModel:
private static int gcd(int i, int j)
{
return (j == 0) ? i : gcd(j, i%j);
}
SIDENOTE: Don't turn this in, as it obviously is not derived from the algorithm given to you, and your teacher will likely mark it wrong.
Since you may not have learned the ternary operator syntax, I'll rewrite it as:
private static int gcd(int i, int j)
{
if (j == 0)
return i;
else
return gcd(j, i%j);
}
This is an example of recursion, where under certain circumstances we can return a known value, but otherwise the method has to call itself again with a different set of parameters.
EDIT 2:
Since an interative approach is needed in lieu of a recursive one, remember that all recursive methods can be rewritten using iteration (i.e., via loops).
Further reading:
Refactoring: Replace Recursion With Iteration

Can't see where I'm dividing by 0?

Here is all the code I think anyone would need to be able to asses my problem
1 import.java.util.Scanner
2 public class ccattano_Sieve{
3 private boolean [] primes = new boolean [50001];
4 private int upper;
5 private int lower;
6
7 public ccattano_Sieve(){
8 upper = 50000;
9 lower = 1;
10 for (int i = 2; i < primes.length; i++){
11 primes[i] = true;
12 }
13 primes[0] = false;
14 primes[1] = false;
15 }
16
17 public void processSieve(){
18 for (int i = 2; i < Math.round(Math.sqrt(50000)); i++){
19 if (primes[i] == true){
20 for (int c = 2; c < (primes.length - 1); i++){
21 if (c % i == 0){
22 primes[c] = false;
23 }
24 else{
25 primes[c] = true;
26 }
27 }
28 }
29 }
30 }
I'm pretty sure my else statement on lines 24 - 26 aren't needed I added it when trying to trouble shoot. But on line 21 when trying to run the code I receive a divide by zero error. The exact error is as follows.
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ccattano_Sieve.processSieve(ccattano_Sieve.java:21)
at ccattano_SieveTest.main(ccattano_SieveTest.java:7)
This line "at ccattano_SieveTest.main(ccattano_SieveTest.java:7)" calls the code I pasted so it can be ignored. So line 21 is the main issue and I can't find a solution.
The modulus operator is the "rest of the division" meaning that it involves a division.
I believe you have a bug on line 20 where you are incrementing i instead of c.
This means the i variable will overflow (reach so high that it will turn negative) and eventually will turn into 0.
You never update the value of c in your inner loop; instead you increase i by the length of your array minus 1 every time up till the square root of 50,000. I'd suspect this is an error and not what you want to do, but I await a comment to the contrary.

NullPointerException on this Hamiltonian Cycle problem

The following code finds the correct hamiltonian cycle for a knight in a chessboard when started on position 0 0 in a 10x10 or 8x8 chessboard but throws a NullPointerException when started anywhere else.
Input here should be
8
8
0
0
for the hamiltonian cycle on a 8x8 chessboard starting in position 0 0, which runs the correct output:
1 16 27 22 3 18 29 32
26 23 2 17 28 31 4 19
15 64 25 36 21 50 33 30
24 37 48 61 56 35 20 5
47 14 63 38 49 60 51 34
42 39 44 57 62 55 6 9
13 46 41 54 11 8 59 52
40 43 12 45 58 53 10 7
on
8
8
1
1
I get:
Exception in thread "main" java.lang.NullPointerException
at horseBETA.mover(horseBETA.java:55)
at horseBETA.search(horseBETA.java:130)
at horseBETA.main(horseBETA.java:164)
Java Result: 1
Why?
import java.util.Scanner;
/**
*
* #author Darwin Martinez
*/
class position{
int x,y;
position() {};
position(int a, int b) { x=a; y=b; }
}
public class horseBETA {
static int number_of_movements = 8;
static int dx[] = {-1, -2, -2, -1, 1, 2, 2, 1};
static int dy[] = {-2, -1, 1, 2, 2, 1, -1, -2};
static int longCycle;
static int N,M,I,J;
static int[][] order;
position solucion[];
static boolean free[][];
static int longitud;
static int dfs_visited[][],stampdfs;
horseBETA(int N, int M, int I, int J) {
longCycle = N*M;
order = new int[N][M];
solucion = new position[longCycle];
free = new boolean [N][M];
dfs_visited = new int[N][M];
for (int i=0;i<N;i++)
for (int j=0;j<M;j++) {
free[i][j] = true;
dfs_visited[i][j] = 0;
}
stampdfs = 0;
position aux=new position(I,J);
int index=(I*N)+J;
solucion[index]=aux;
free[I][J] = false;
longitud = 1;
}
boolean valida(position p) {
return 0<=p.x && p.x<N &&
0<=p.y && p.y<M && free[p.x][p.y];
}
position mover(position p,int i) {
return new position(p.x+dx[i],p.y+dy[i]);
}
boolean es_terminal() {
return longitud == longCycle;
}
boolean is_factible(position p) {
return ((p.x == I+dx[0] && p.y == J+dy[0]) || (p.x == I+dx[1] && p.y == J+dy[1])
|| (p.x == I+dx[2] && p.y == J+dy[2])|| (p.x == I+dx[3] && p.y == J+dy[3])
|| (p.x == I+dx[4] && p.y == J+dy[4])|| (p.x == I+dx[5] && p.y == J+dy[5])
|| (p.x == I+dx[6] && p.y == J+dy[6])|| (p.x == I+dx[7] && p.y == J+dy[7]));
}
boolean prometedor_recurs(position d) {
if (is_factible(d)) return true;
for (int i=0;i<number_of_movements;i++) {
position a = mover(d,i);
if (valida(a) && dfs_visited[a.x][a.y] != stampdfs) {
dfs_visited[a.x][a.y] = stampdfs;
if (prometedor_recurs(a)) return true;
}
}
return false;
}
boolean promising(position d) {
stampdfs++;
return prometedor_recurs(d);
}
void print_solution() {
for (int i=0;i<longCycle;i++)
order[solucion[i].x][solucion[i].y] = i+1;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if(order[i][j]<10)
System.out.print(" "+order[i][j]);
else{
if(order[i][j]>=10&&order[i][j]<100)
System.out.print(" "+order[i][j]);
else
System.out.print(" "+order[i][j]);
}
}System.out.print("\n");
}
System.exit(0);
}
void insertionSort(position p[], int r[], int n) {
int i,j,aux;
position auxp;
for (i=1; i<n; i++) {
aux=r[i]; auxp = p[i];
for (j=i-1; j>=0 && aux<r[j]; j--) {
r[j+1]=r[j]; p[j+1]=p[j];
}
r[j+1]=aux; p[j+1] = auxp;
}
}
public boolean search() {
if (es_terminal()) {
if (is_factible(solucion[longCycle-1])){
print_solution();
return true;
}
} else {
int nchildren = 0;
position p[]=new position[number_of_movements];
int r[]=new int[number_of_movements];
for (int i=0;i<number_of_movements;i++) {
position a = mover(solucion[longitud-1],i);
if (valida(a)) {
int grado = 0;
for (int j=0;j<number_of_movements;j++)
if (valida(mover(a,j)))
grado++;
p[nchildren] = a;
r[nchildren] = grado;
nchildren++;
}
}
insertionSort(p,r,nchildren);
for (int i=0; i<nchildren; i++) {
solucion[longitud] = p[i]; longitud++;
free[p[i].x][p[i].y] = false;
if (promising(p[i]))
search();
free[p[i].x][p[i].y] = true;
longitud--;
}
}return false;
}
public static void main(String[] args) {
Scanner x= new Scanner(System.in);
N = x.nextInt();
M = x.nextInt();
I = x.nextInt();
J = x.nextInt();
horseBETA yy = new horseBETA(N,M,I,J);
if(!yy.search())
System.out.println("\nNo hay solucion");
}
}
Here is a HINT to get you started:
Start with the stacktrace. The first line of the trace says:
at horseBETA.mover(horseBETA.java:55)
This means that the exception occurred in the mover method, and that method consists of just one line:
return new position(p.x+dx[i],p.y+dy[i]);
A NPE is thrown when an attempt is made to dereference a null reference. There are 4 sub-expressions in the line above where object references are dereferenced, and NPEs could possibly occur.
p.x and p.y could throw an NPE if p is null.
dx[i] or dy[i] could throw an NPE if (respectively) dx and dy are null.
Two out of four of those possible causes can be excluded by simple inspection of the code; dx and dy are initialized to non-null values and then never assigned to. That leaves p being null as the probable cause. (You could confirm this with a traceprint or using a debugger.)
Now over to you ...
(I also agree with #Speck. You've got some serious style problems with your code which make it painful to read and hard to debug ... )
First, your code is illegible. If you use accepted style guidelines it will help when debugging.
A couple of things to help improve:
Use names not letters for variables and favor camelCaseVariables. These will help with readability especially when asking a question like this.
Use open and close brackets even for one lined if statements and loops. It will better set off loops and make them more readable and helps prevent bugs in program flow.
Anyway, you may be passing a null position object (capitalize your class names btw) to the mover method. In your IDE, set a breakpoint on that line and make it conditional to stop only when the passed pointer object is null. You'll quickly see why.

Categories