+0 및 -0은 int 및 float 데이터에 대해 다른 동작을 보여줍니다.


16

나는이 게시물을 부정적이고 양의 0으로 읽었습니다 .

제공해야합니다 나의 이해 다음 코드 truetrue A 출력 등.

그러나 결과를 제공 false하고 true있습니다.

음수 0을 양수 0과 비교하고 있습니다.

public class Test {
     public static void main(String[] args) {
            float f = 0;
            float f2 = -f;
            Float F = new Float(f);
            Float F1 = new Float(f2);
            System.out.println(F1.equals(F));

            int i = 0;
            int i2 = -i;
            Integer I = new Integer(i);
            Integer I1 = new Integer(i2);
            System.out.println(I1.equals(I));
      }
  }

0 Integer과에 대해 다른 동작을하는 이유는 무엇 Float입니까?


11
당신의 javadoc을 선택하면 docs.oracle.com/javase/8/docs/api/java/lang/... 정의가 제대로 작동하려면 해시 테이블 수 있습니다. 또한 -0 정수는 없습니다.
matt

@matt -0이 정수가 아닌 경우 거짓으로 평가되어야합니다.
Joker

3
말할 때 i2 = -i; i2는 i의 정확한 비트 표현을 취하므로이를 식별 할 방법이 없습니다. ii2정확히 동일합니다. 그런 다음 새로운을 만들 때 Integer둘 다 정확히 동일한 값을 감 쌉니다. I1.equals(I)사실입니다.
매트

1
시도 int i = Integer.MIN_VALUE, i2 = -i;...
홀거

1
그런데 new여기에는 래퍼 유형 에 사용할 이유가 없습니다 . 그냥 사용 예Integer i = 0, i2 = -i; System.out.println(i.equals(i2)); Float f1 = 0f, f2 = -f1; System.out.println(f1.equals(f2));
홀거

답변:


19

Int와 float는 Java와는 매우 다릅니다. 정수는 2의 보수 로 인코딩되며 단일 0 값을 갖습니다. Float 는 IEEE 754 ( float의 경우 32 비트 변형 , double의 경우 64 비트 변형 )를 사용합니다. IEEE 754는 다소 복잡하지만이 답변의 목적을 위해 세 개의 섹션이 있으며 그 중 첫 번째 부분은 부호 비트라는 것을 알아야합니다. 즉, 모든 플로트에는 긍정적이고 부정적인 변형이 있습니다 ¹. 여기에는 0이 포함됩니다. 따라서 float는 실제로 "0"값인 +0과 -0을 갖습니다.

따로, 정수가 사용하는 두 가지 보완은 컴퓨터 과학에서 정수를 인코딩하는 유일한 방법은 아닙니다. 하나의 보수 와 같은 다른 방법이 있지만 +0과 -0을 별개의 값으로 갖는 것과 같은 단점이 있습니다. ;-)

float 프리미티브 (및 double)를 비교할 때 Java는 +0과 -0을 동일하게 취급합니다. 그러나 당신이 그것들을 박스에 넣을 때, Java는에 설명 된 것처럼 그것들을 개별적으로 취급합니다 Float#equals. 이것은 equals 메소드가 hashCode구현뿐만 아니라 compareTo(부호있는 값을 포함하여) float 비트를 사용하여 그대로 int로 밀어 넣는 구현 과 일치하게합니다 .

equals / hashCode / compareTo에 대한 다른 옵션을 선택할 수 있었지만 그렇지 않았습니다. 디자인 고려 사항이 무엇인지 잘 모르겠습니다. 그러나 적어도 하나 개의 점에서, Float#equals항상 플로트 원시의에서 분기 거라고 ==: 프리미티브에서, NaN != NaN하지만 모든 개체, o.equals(o)도 참이어야합니다 . 그것은 당신이 있었다면 Float f = Float.NaN, f.equals(f)그래도 의미합니다 f.floatValue() != f.floatValue().


¹ NaN (숫자가 아님) 값에는 부호 비트가 있지만 순서 이외의 다른 의미는 없으며 Java는 순서를 무시합니다.


10

이것은 Float equals 예외 중 하나입니다

두 가지 예외가 있습니다.

f1이 + 0.0f를 나타내고 f2가 -0.0f를 나타내 거나 그 반대의 경우, 등식 테스트의 값은 false입니다.

이유도 설명되어 있습니다.

이 정의는 해시 테이블이 올바르게 작동하도록합니다.

-0과 0은 Float의 비트 31을 사용하여 다르게 나타납니다.

비트 31 (마스크 0x80000000에 의해 선택된 비트)은 부동 소수점 숫자의 부호를 나타냅니다.

이 경우에는 그렇지 않습니다 Integer


질문은 왜인가? 우리가
Joker

@Joker 따옴표가 추가되어 해시 테이블이 제대로 작동하도록 허용
user7294900

4
이 답변 (및 javadoc)이 언급하지 않은 핵심 부분은 부동 소수점에서 +0과 -0은 서로 다른 값-동등하지만 다르다는 것입니다. 기본적으로 플로트에는 세 부분이 있으며 첫 번째 부분은 플로트가 양인지 음인지를 나타내는 단일 비트입니다. 그건 아니 단 하나의 0 값이 (자바로 대표되는)의 int의 경우,.
yshavit

@yshavit 감사합니다. 답변과 같은 내용을 공유해 주시겠습니까?
Joker

3
@Joker 비트 31 (마스크 0x80000000에 의해 선택된 비트)은 부동 소수점 숫자의 부호를 나타냅니다.
user7294900

5

정수의 경우, 2의 칭찬 표현을 사용하므로 정수의 -0과 0 사이에는 차이가 없습니다 . 따라서 정수 예제 ii1정확히 동일합니다.

float의 경우 -0 표현이 있으며 값은 0과 동일하지만 비트 표현은 다릅니다. 따라서 new Float (0f)와 new Float (-0f)는 서로 다른 표현을 갖습니다.

비트 표현의 차이를 볼 수 있습니다.

System.out.println(Float.floatToIntBits(-0f) + ", " + Float.floatToIntBits(0f));

-2147483648, 0

그리고 f선언을 생략하면 -0f정수로 취급되며 출력에 차이가 표시되지 않습니다.


그러나 원시 플로트는 그와 잘 작동하는 것 같습니다. 그렇습니다 0.0f == -0.0f. 따라서 다른 동작은에 java.lang.Float있습니다.
ivant December

3
@ivant IEEE754에 따르면, "정상적인 비교 연산 그러나, 치료 등 NaN이 순서화 및 비교 -0과 같은 동일한 +0" en.m.wikipedia.org/wiki/IEEE_754
앤디 터너

@AndyTurner, 네, 이해합니다. Java에서는 기본 유형 사이에 동작에 차이가 있음을 지적하고 있는데 float, 이는 이와 관련하여 IEEE754를 준수 하는 기본 유형 과 java.lang.Float그렇지 않은 유형입니다. 따라서 비트 표현의 차이만으로는 이것을 설명하기에 충분하지 않습니다.
ivant December
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.