Whiteship's Note


Double.MAX_VALUE는 좀 특이하군요 @_@

Java : 2009.05.19 21:07


System.out.println(Double.compare(Double.MAX_VALUE, Double.MAX_VALUE - 1.0));

이렇게 하면 무슨 값이 출력 될까요? 앞에 있는 인자가 더 크니까 양수가 나와야 합니다.
그러나 해보시면 아시겠지만, 0이 나옵니다.

난 너무 커서 1 같이 작은 수는 빼봤자 그게 그거야...

라는 건가요.. 이건 좀 @_@
왜이러는 걸까요?
정확하게 비교하려면 어떻게 해야 할까요?

한가지 찾은 방법은 longValue() 이용해서 long으로 바꾼 다음에 계산하는 겁니다.
그러나.. 불편하자나요~
top

  1. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.05.19 23:34 PERM. MOD/DEL REPLY

    기선님께서 언급하신 longValue() 를 이용한 방법으로도 정확한 계산, 비교는 힘듭니다.
    비교는 되겠지만, 말 그대로 정확한 계산에 의한 비교는 아닙니다.
    doubleToLongBits 를 사용할수도 있긴 합니다만 이것 역시 정확한 계산은 힘들죠.

    간단한 예를 통해서 왜 그런지 알아보겠습니다.
    (사실 이런 포스트 보다 긴 댓글은 제 블로그에 직접 올려야 하는데...죄송합니다... ㅡ_ㅡ;;; )

    System.out.println("double -> longbits : " + Double.doubleToLongBits(Double.MAX_VALUE));
    System.out.println("double -> longbits - 1: " + (Double.doubleToLongBits(Double.MAX_VALUE) - 1));
    System.out.println("Double.MAX_VALUE : " + Double.MAX_VALUE);
    System.out.println("double -> longbits - 1 -> double: " + Double.longBitsToDouble(Double.doubleToLongBits(Double.MAX_VALUE) - 1));

    이코드를 돌리면 결과가 이렇게 나옵니다.
    double -> longbits : 9218868437227405311
    double -> longbits - 1: 9218868437227405310
    Double.MAX_VALUE : 1.7976931348623157E308
    double -> longbits - 1 -> double: 1.7976931348623155E308
    double에서 longbits로 바꾸고 하나 빼니까 1이 줄어들었는데,
    다시 double로 바꾸니까 차이는 0.0000000000000002E308 만큼이나 생깁니다.

    그럼 double에서 longbits로 바꾸고 1을 뺀다음에
    다시 double로 바꿨다가 longbits로 재변환후 이번에는 뺀 1을 다시 더한후에 dobule로 바꿔서
    그 값이 원래 값과 같은지 보겠습니다. 정상적이면 같아야 겠죠.

    System.out.println("Double.MAX_VALUE : " + Double.MAX_VALUE);
    System.out
    .println("double -> longbits - 1 -> double -> longbits + 1 -> double: "
    + Double.longBitsToDouble(Double.doubleToLongBits((Double.longBitsToDouble(Double
    .doubleToLongBits(Double.MAX_VALUE) - 1))) + 1));
    결과는

    Double.MAX_VALUE : 1.7976931348623157E308
    double -> longbits - 1 -> double -> longbits + 1 -> double: 1.7976931348623157E308
    다행히 이건 결과가 제대로 나옵니다.

    그럼 이제 기선님께서 언급하신 longValue()를 사용해 보겠습니다.
    똑같은 과정입니다만, 사실 longValue() method가 하는 일은
    (long) 을 써서 casting을 하는것 뿐이므로 불필요한 Double object생성을 막기 위해
    그냥 casting으로 대체해서 해보겠습니다.

    System.out.println("double -> long : " + (long) Double.MAX_VALUE);
    System.out.println("double -> long - 1: " + ((long) Double.MAX_VALUE - 1));
    System.out.println("Double.MAX_VALUE : " + Double.MAX_VALUE);
    System.out.println("double -> long - 1 -> double: " + (double) ((long) Double.MAX_VALUE - 1));

    결과는 이렇습니다.
    double -> long : 9223372036854775807
    double -> long - 1: 9223372036854775806
    Double.MAX_VALUE : 1.7976931348623157E308
    double -> long - 1 -> double: 9.223372036854776E18

    다시 double 바꾸니 엉뚱한 결과가 나옵니다.
    이번엔 아까처럼 1을 뺀후에 1을 다시 더하는 걸 해보겠습니다.

    System.out.println("Double.MAX_VALUE : " + Double.MAX_VALUE);
    System.out.println("double -> long - 1 -> double -> long + 1 -> double: " + (double) ((long) ((double) ((long) Double.MAX_VALUE - 1)) + 1));

    같은 값이어야할 결과는 역시 전혀 다른 녀석이 나옵니다.
    Double.MAX_VALUE : 1.7976931348623157E308
    double -> long - 1 -> double -> long + 1 -> double: -9.223372036854776E18

    사실 float 나 double은 숫자가 커질경우 정확한 계산을 위해서 쓰면 위험합니다.
    특히 float는 작은 수에서도 문제가 있구요.

    그래서 큰액수의 돈이 왔다 갔다 하는 금융권에서 이걸 썼다가는... 덜덜덜...
    그런 경우는 BigDecimal 을 이용하셔야 합니다.
    사실 전 금융권에 있는게 아니라서 BigDecimal을 써본적이 없습니다...^^;;;
    그냥 제가 알고 있는게 그렇다는 겁니다... 더 좋은 방법이 있으면 공유 좀... :)

    말나온 김에,
    Double.MAX_VALUE로 BigDecimal 두개를 만들고, 하나에서 BigDecimal 1을 뺀후에 비교해 보겠습니다.
    (저도 이참에 사용을 경험해 볼겸...^^;;; )

    BigDecimal bigDecimal = BigDecimal.valueOf(Double.MAX_VALUE);
    BigDecimal bigDecimal2 = BigDecimal.valueOf(Double.MAX_VALUE).subtract(BigDecimal.valueOf(1));
    System.out.println("bigDecimal.compareTo(bigDecimal2): " + bigDecimal.compareTo(bigDecimal2));
    System.out.println("bigDecimal: " + bigDecimal);
    System.out.println("bigDecimal2: " + bigDecimal2);

    결과는
    bigDecimal.compareTo(bigDecimal2): 1
    bigDecimal: 1.7976931348623157E+308
    bigDecimal2: 179769313486231569999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
    비교는 당연히 bigDecimal이 1을 뺀 bigDecimal2보다 크기 때문에 1이 나오고
    둘의 값도 아주 정확하게 나옵니다. 9가 292개 인걸 확인했습니다.

    다음부터는 이런건 블로그를 통해서 하도록 하겠습니다...ㅡ_ㅡ;;;

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.05.19 23:45 PERM MOD/DEL

    감사합니다. @_@ 오래전에 부동소수형이 정확한 계산에는 부적절하니까 BidDecimal을 사용해야 한다는 걸 공부한 적이 이었는데 까맣게 잊어버리고 있었습니다.

    http://whiteship.me/189

    댓글은 길어도 관계 없습니다. 좋은 내용 감사합니다.

  2. Favicon of http://entworks.tistory.com BlogIcon 엔트웍스 2009.05.20 09:11 PERM. MOD/DEL REPLY

    자바 퍼즐러에서 본 것 같은데,
    1이 아니라 어느 정도 이상의 큰 숫자를 빼면 다르다고 나올 겁니다.
    여기서 시사하는 바는,
    Double.MAX_VALUE는 비교연산의 대상으로만 삼아야한다고 기억하는 것이 아닐까 하네요.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.05.20 09:38 신고 PERM MOD/DEL

    나누기 10000 쯤 하니까 쪼금 바뀌긴 하더라구요.

    그러나.. 댓글 주신 것처럼 비교 대상으로 만 사용하고, 실제 값을 비교할 때는 BigDecimal을 사용하는게 좋겠네요. 감사합니다~ :)

Write a comment.


자바의 숨겨진 기능들

Java : 2008.09.22 23:35


대엽님 블로그에서 잼난 글을 발견하고 링크를 따라가보니, 정말 놀라운 것들로 가득찬 페이지를 발견했습니다. 스크롤을 내려가면서 아는 것도 가끔씩 등장은 하는데, 윗 부분은 정말 신기한 것들로 가득합니다. 캬~ 저런게 있었구나.. 싶을 정도로요.

저 포럼은 예전에 영회형 블로그에 올라왔던, Stack과 Heap에 대한 설명에 대해서도 굉장히 잘 설명한 댓글이 달렸던것 같은데, 수준이 상당히 높은 포럼인듯 합니다. 멋지네요.

그 중에 몇 개 살펴봅니다.

1. 더블 괄호
http://www.c2.com/cgi/wiki?DoubleBraceInitialization

더블 괄호 사용해서 컬렉션 객체 만드는 방법인데, 첨 보는 방법입니다. 하지만 개인적으론 저것 보단 자주 사용하고 있는  Arrays.asList()가 명시적이어서 더 좋네요.

2. 상위 타입 제한

public class Baz<T extends Foo & Bar> {}

이런식으로 &를 써서 여러 타입으로 제한할 수도 있었군요;

3. 동적 프록시

http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html

이건 좀 공부해야겠습니다.

4. enum

http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9

이넘. 자세히 보진 않았지만, 역시 잘 알아두는게 좋겠죠.

5. concurrent

http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.html

역시나. 잘 모르는 부분. 기초 공부가 넘 게을렀네..

top

  1. Favicon of http://yunsunghan.tistory.com BlogIcon Max 2008.09.23 09:03 PERM. MOD/DEL REPLY

    대부분 머리아픈 이야기들이죠....ㅡㅜ
    비슷하게는... 송치형씨가 번역한 자바퍼즐러라는 책에 이런류의 재미난(?) 예제가 많던것 같아요.

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.09.23 09:11 PERM MOD/DEL

    넹. ㅋㅋ

    전 머리 아픈거보다 enum, proxy, concurrency쪽에 관심이 좀 생기더라구요.

  2. Favicon of http://iolothebard.tistory.com/ BlogIcon iolo 2008.09.23 10:43 PERM. MOD/DEL REPLY

    딱히 숨겨진 기능까진 아닌거 같은데요...
    동적 프록시가 없었다면 스프링의 반쪽은 존재하지도 못했어요~

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.09.23 13:22 신고 PERM MOD/DEL

    네.. 숨겨져있다기 보단, 평소에 자주 안 쓰지만 중요한 것들을 나열해 둔걸로 보입니다.ㅋ

    스프링 AOP를 말씀하시는 것 같네요. :)

  3. Favicon of https://ebom.tistory.com BlogIcon 타블로 2008.09.24 14:21 신고 PERM. MOD/DEL REPLY

    여기 잘 정리 되어있네요...

    자주 이용해야겠어요...

    수고하세요...

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.09.24 16:52 신고 PERM MOD/DEL

Write a comment.


윈도우 시간과 자바에 찍히는 시간이 안맞을 때

모하니?/Coding : 2008.06.02 00:01


-Duser.timezone=Asia/Seoul

 Timezone.getDefault()를 호출하여 자바 창에 찍어보면 기준시간대가 Asia/Seoul이 아닐 것입니다. 이걸 프로그램 내부에서 Timezone 객체를 사용하여 세팅할 수도 있지만, 위의 인자를 자바 컨테이너 실행시에 옵션으로 줄 수도 있습니다. 웹 애플인 경우에는 후자로, 간단한 독립적인 애플일 경우에는 전자로...

top

TAG 자바,

Write a comment.


JCO 한국 자바 개발자 컨퍼런스





오오.. 아이팟 터치..

'모하니? > 그냥 놀아' 카테고리의 다른 글

오랜만에 기대중인 게임 GTA 4  (4) 2008.04.24
도미노 피자 VIP 되다..  (0) 2008.04.17
가자.. 2008 자바원  (2) 2008.03.26
마이크로소프트 유럽의 스팸 메일(?)  (2) 2008.03.14
제 9회 JCO 후기  (10) 2008.02.17
JCO 한국 자바 개발자 컨퍼런스  (2) 2008.01.28
크리스마스 트리 연필깎기  (2) 2007.12.25
로드 존슨 Toy  (1) 2007.12.13
제 6회 스프링 세미나  (2) 2007.12.10
TSE 2007 가상 스캐쥴  (2) 2007.11.29
Ajax 인 프랙티스  (0) 2007.11.08
top

  1. Favicon of http://mudchobo.tomeii.com BlogIcon 머드초보 2008.01.29 13:26 PERM. MOD/DEL REPLY

    어라.....댓글을 남겼는데 왜 사라졌지-_-;
    그.....링크가....jco.co.kr로 되어있어서 대출사이트로 들어가져요 ^^
    태글은 절대 아닙니다 ㅠㅠ

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.01.29 16:24 PERM MOD/DEL

    크헉 ㅋㅋ 감사합니다. 수정하겠습니다.

Write a comment.