List contains method returns false when using Math.sqrt() as a parameter

435 Views Asked by At

I am refreshing my knowledge in Java and working on an exercise from codewars. The problem is to compare two arrays if the elements are the "same". The meaning of "same" is that the elements in 'b' are the elements in 'a' squared, regardless of the order. The solution that I was trying to do is to get the square root of element in 'b' and check if it does exists in element 'a' using Math.sqrt(). However, when I use that as a parameter for contains(), it always returns false.

So to check if the square root of element 'b' really does exists in 'a', I tried a simple if-else to check a specific element. But when I incorporate it with Math.sqrt(), that's where the problem rise.

Here's the elements of set a and b

int[] a = {121, 144, 19, 161, 19, 144, 19, 11};
int[] b = {121, 14641, 20736, 361, 25921, 361, 20736, 361};

That I have converted to List

List<Integer> setAList = Arrays.stream(setA)//int[] setA - parameter of a function
                                                    .boxed()
                                                    .collect(Collectors.toList());
List<Integer> setBList = Arrays.stream(setB)//int[] setB - parameter of a function
                                                    .boxed()
                                                    .collect(Collectors.toList());

I converted the array to List to take advantage of contains() method. This is my code when I tried to check the specific element

double sqrd = Math.sqrt(setBList.get(6));
return setAList.get(5) == sqrd ? true : false;

And that gave an expected result - true. Now here's the code of when I incorporated it to a for loop

boolean same = true;

for(int indexB : setB) {
    same = setAList.contains(Math.sqrt(indexB)) ? true : false; 
    System.out.println(Math.sqrt(indexB) + " " + same);

}

And here's the result

11.0 false
121.0 false
144.0 false
19.0 false
161.0 false
19.0 false
144.0 false
19.0 false
false

At first I though the problem might be because of the data types but I have tried casting the double to int but I'm still getting the same result.

3

There are 3 best solutions below

2
Bentaye On BEST ANSWER

Not a direct answer, but a workaround to avoid this kind of issues:

As explained in other answers, your problem is a cast problem because you have to deal with double and int values and won't have to face casting issues.

A way to avoid it is to square values in A instead of calculating the square roots of values in B. This way you only ever deal with int values

int[] a = {121, 144, 19, 161, 19, 144, 19, 11};
int[] b = {121, 14641, 20736, 361, 25921, 361, 20736, 361};

// Make a list containing the squares out of the b array
List<Integer> squares = Arrays.stream(b)
    .boxed()
    .collect(Collectors.toList());

// square all the values in B,
// and check that all the resultant values are present in the squares list
boolean same = Arrays.stream(a) // Stream<Integer> containing values in array a
    .map(i -> i* i) // Stream<Integer> containing values in array a squared
    .allMatch(squares::contains); // reduce to a boolean insuring that all values in the Stream<Integer> are present in the squares list

System.out.println(same);
4
Andrew Tobilko On

setAList.get(5) == sqrd gives you the expected result because of the widening primitive conversion of setAList.get(5) (which is an int) to a double.

If you've got setAList.contains(Math.sqrt(indexB)), you need to do the cast manually: setAList.contains((int)Math.sqrt(indexB)).

0
JimmyB On

Looking up exact floating point values, as is done in contains(), is a bad idea most of the time due to the limited precision of floating point values; you can try yourself and see for which numbers Math.sqrt( number ) * Math.sqrt( number ) is not the same as number:

for (int i = 0; i < 100; i++) {
  final double r = Math.sqrt(i);
  final double s = r * r;
  if (s != i) {
    System.out.println(i + " != " + s);
  }
}

(Prints out 51 non-equal roots-squared out of the 100 numbers tested.)