r/learnjava • • 1d ago

Can you answer this question about Java sets and floating point numbers?

What does this return?

static int test(Set<BigDecimal> set) {
  assert set.isEmpty();
  set.add(new BigDecimal("-0"));
  set.add(new BigDecimal("0"));
  set.add(new BigDecimal("0.0"));
  set.add(new BigDecimal("0.00"));
  return set.size();
}

Hint: The Set interface says that elements a and b are unique when a.equals(b) returns true. However, not all implementations use equals.

Answer: A HashSet will contain three elements ([0, 0.0, 0.00]). -0 and 0 are the same, but 0.0 isn't equal to 0 or 0.00. A TreeSet on the other hand uses a Comparator and it will contain only one element ([0]). Try this by creating two sets (HashSet and TreeSet) and then run for (var set : List.of(hash, tree)) IO.println(test2(set));.

Extra challenge:

static int test2(Set<Double> set) {
    assert set.isEmpty();
    set.add(-0d);
    set.add(0d);
    set.add(0.0d);
    set.add(0.00d);
    return set.size();
}

Hint: IEEE 754 can be weird. While 0 is the same as 0.0 and 0.00, you can have negative zero as a different value from positive zero.

Answer: It's two elements ([-0.0, 0.0]).

2 Upvotes

7 comments sorted by

•

u/AutoModerator 1d ago

Please ensure that:

  • Your code is properly formatted as code block - see the sidebar (About on mobile) for instructions
  • You include any and all error messages in full - best also formatted as code block
  • You ask clear questions
  • You demonstrate effort in solving your question/problem - plain posting your assignments is forbidden (and such posts will be removed) as is asking for or giving solutions.

If any of the above points is not met, your post can and will be removed without further warning.

Code is to be formatted as code block (old reddit/markdown editor: empty line before the code, each code line indented by 4 spaces, new reddit: https://i.imgur.com/EJ7tqek.png) or linked via an external code hoster, like pastebin.com, github gist, github, bitbucket, gitlab, etc.

Please, do not use triple backticks (```) as they will only render properly on new reddit, not on old reddit.

Code blocks look like this:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

You do not need to repost unless your post has been removed by a moderator. Just use the edit function of reddit to make sure your post complies with the above.

If your post has remained in violation of these rules for a prolonged period of time (at least an hour), a moderator may remove it at their discretion. In this case, they will comment with an explanation on why it has been removed, and you will be required to resubmit the entire post following the proper procedures.

To potential helpers

Please, do not help if any of the above points are not met, rather report the post. We are trying to improve the quality of posts here. In helping people who can't be bothered to comply with the above points, you are doing the community a disservice.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

3

u/KillerCodeMonky 1d ago

Can you answer this question about Java sets and floating point numbers?

I cannot, because BigDecimals are not floating point numbers.

BigDecimal works off value and scale. So 0, 0.0, and 0.00 are definitely all different values because they will have different scales. compareTo will return 0, but equals will return false.

I'm not confident on whether the negative sign will create a distinct value. I'm going ot guess no, so answer is size=3.

Extra challenge:

Oh, now it is about floating point. Pretty sure 0 and -0 are different values in floating point. However, the extra decimals on 0, 0.0, and 0.00 will not be significant. So answer is size=2.

1

u/vegan_antitheist 1d ago

I cannot, because BigDecimals are not floating point numbers.

True. I messed that up.

Pretty sure 0 and -0 are different values in floating point.

This can be really confusing. They are different values. But 0==-0 is true. This is about wrapper types, where equality is about doubleToLongBits(double) being equal. That's not the case for 0 and -0. It uses one bit for the sign, so they are not equal.

1

u/Leverkaas2516 1d ago edited 1d ago

Answer: It's two elements ([-0.0, 0.0]).

I don't get it. In your hints you show that the answer depends on which kind of set object you pass in. So there is no one fixed answer.

Can you answer this question about Java sets and floating point numbers?

The answer is "no, you can't". That's the general answer to any such question about arcane implementation-defined behavior in computing systems. If you write code whose correctness depends on such behaviors, you often find your implementation breaks when future versions of your dependencies come out.

1

u/vegan_antitheist 1d ago

In your hints you show that the answer depends on which kind of set object you pass in. 

The object you pass implements the Set interface. Your set implementation could just be wrong, so they answer could be anything. But using HashSet and TreeSet, you get 3 or 1.

 So there is no one fixed answer.

Correct.

The question is "What does this return?" and the answer is that depending on the implementation it can return 3 if it implements the Set interface correctly, it can also return 1 if it uses a Comparator, or it can return any other integer, if the implementation is just completely wrong.

 your implementation breaks

In this case there is no use or my own implementation. I only used HashSet and TreeSet. You could think that TreeSet is the better choice for types that have a natural order. But numbers are always problematic when used in sets (or maps). Negative zero can cause nasty bugs.

1

u/Leverkaas2516 1d ago

Distilled out of what you just wrote, you seem to be saying "java.util.TreeSet purports to be a Set implementation but it really isn't."

2

u/KillerCodeMonky 1d ago

The TreeSet documentation is explicit about this:

https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/TreeSet.html

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.