2009-12-04 2 views
3

저는 Java/Groovy 프로그램을 만들고 있습니다. 나는 사용자가 입력 한 숫자를 저장하는 double 변수를 가지고있다. 내가 정말로 알고 싶은 것은 사용자가 소수점 오른쪽에 입력 한 숫자의 숫자입니다. 뭔가 같은 :Java double에서 소수점 이하의 자리수를 얻는 방법이 있습니까?

double num = 3.14 
num.getPlaces() == 2 

물론 IEEE 플로팅 포인트를 사용하고 있기 때문에 두 배로는이 작업을 수행 할 수 없으며 모두 근사치입니다.

사용자가 입력 한 문자열을 얻을 수 없다는 가정하에 값이 저장되어있는 double 값만 액세스 할 수 있다고 가정 할 때 BigDecimal 또는 somesuch를 사용하여 두 번 제거 할 수있는 방법이 있습니까? 실제 "소수점 이하 자릿수? Double이 화면에 표시되면 올바르게 맞 춥니 다. 그래서 최소한 추측할만한 방법이 있다고 가정합니다.)

+0

각주 : 이것은 혼합 Java/Groovy 코드베이스이므로 Groovy 기반의 마법을 사용하는 모든 솔루션이 환영받을 것입니다. –

+0

사용자가 소수점 뒤에 입력 한 숫자의 수 또는 소수점 뒤에 인쇄 할 자릿수를 알고 싶습니까? 그것들은 완전히 다른 두 가지 문제입니다. – erickson

+0

사용자가 입력 한 값입니다. 좋은 지적. –

답변

14

아니요, 다른 문자열이 많이 있기 때문에 ... 할 수 없습니다. 사용자는 모두 동일한 값으로 구문 분석 될 수 있습니다.

"실제"숫자는 사용자가 입력 한 것보다 더 많은 소수 자리가 거의 확실합니다. 예를 들어, 3.14는 정확히 3.140000000000000124344978758017532527446746826171875로 저장됩니다. 사용자가 인 을 표시하고 싶지 않습니다.

이 문제를 명확하게하기 위해, 당신은 사용자가 실제로 입력 여부를 이중 값에서 알 수 없습니다

3.14 
3.140 
3.140000 
3.14000000000000012434 

그 네 개의 문자열이 모두는 당신에게 동일한 값을 줄 것이다 - 그것은 분명한 것을 확인해야하는 당신 아마도 사용자가에 입력 한 내용을 다시하지 수 있습니다.

하면 모든 가능, 파싱 코드를 변경하고 전역 BigDecimal를 사용합니다.

+1

Nitpick : 코드에서 3.14를 사용한다면'Math.PI'를 대신 사용해보십시오. – Powerlord

+9

@ R.Bemrose : 3.14라는 숫자가 실제로 pi를 의미하지 않으면 아무데도 오지 않는다고 생각합니까? –

+3

lol @ 대신 π를 사용하십시오. 아마도 그가 찾고있는 대답이 아닙니다 ... –

3

당신은 바로 복식으로 이상한 일이 있습니다. 출력되는 것은 변수의 내용과 다릅니다. 예를 들어

: 손상이 이중으로 문자열의 변환에서 이루어집니다

groovy:000> "123.0001".toBigDecimal() 
===> 123.0001 
groovy:000> "123.0001".toDouble() 
===> 123.0001 
groovy:000> new BigDecimal("123.0001".toDouble()) 
===> 123.000100000000003319655661471188068389892578125 

주의, 이중이 BigDecimal로 전달하지. BigDecimal에 double을 공급하면 toString이 거짓말하기 때문에 실제 double을 실제로 볼 수 있습니다.

Jon Skeet이 지적했듯이 여기에는 정확도가 옵션이 아닙니다. 그러나 화면에 인쇄 값을 가정하면 두 배에 toString를 호출 한 결과이며,이 같은 이중의 toString 버전보다 더 잘못하지 BigDecimal를 얻을 수있을 것입니다 :

groovy:000> d = "123.0001".toDouble() 
===> 123.0001 
groovy:000> d.toString() 
===> 123.0001 
groovy:000> new BigDecimal(d.toString()) 
===> 123.0001 

따라서 BigDecimal을 사용할 필요가 없습니다. 실제로는 다음과 같이 할 수 있습니다.

groovy:000> d = 123.0001 
===> 123.0001 
groovy:000> s = d.toString() 
===> 123.0001 
groovy:000> s.substring(s.indexOf('.')).length() - 1 
===> 4 

죄송합니다. 편집하여 의견을 무효화하십시오.

여기 BTW는 그루비로 번역 된 Steve의 답변에 가까운 것입니다.(나는 로케일이 엉망으로 된 기계에서 이것을 실행하면 소수점을위한 마침표를 사용하지 않기 때문에 반환 값 0보다 오히려 폭파 할 것이기 때문에 소수점을 찾을 수 없습니다.)

def getPlaces(d) { 
    s = d.toString() 
    s.substring(s.indexOf(".")).length() - 1 
} 
+0

나를 믿어라, 만일 내가 옵션을 가지고 있으면 나는 가지 않을 것이다. 하지만 기존 코드베이스와 그 모든 것을 알고 있습니다. 나는 데이터를 수집하는 모듈에 대해서도 일하지 않기 때문에, 나는 단지 나에게 양손을 건다. :) –

+0

남자, 적어도 내 것은 회계 번호가 아니기 때문에 가끔 반올림 오류는 괜찮습니다. –

+0

"문자열이 이중으로 변환 될 때 손상이 발생했음을 알 수 있습니다 ..."라는 말은 흥미로운 차례입니다. 평범한 독자에게는 '피해'는 단지 두배가 근사치라는 것입니다. 최소 2 배와 최대 2 배 사이의 대다수의 숫자는 나타낼 수 없습니다. 그것은 최선을 다합니다. :) Double.toString()은 3.1400000000000001243 대신 3.14를 의미 할 가능성이 더 높기 때문에 우리가 의미하는 바를 다시 적용하려고 시도합니다. – PSpeed

0

이중으로 붙어 있으면 문자열로 변환하고 소수점 이하의 문자 수를 계산하십시오. 1.99999999998과 같은 숫자를 표시하는 마법이 있다고 생각합니다. "2"

0

그래서 사용자가 입력 한 값이면. 값을 String으로 승인하십시오. 그런 다음 문자열 함수를 사용하여 "."문자의 위치를 ​​찾을 수 있습니다. 그런 다음 문자열의 길이에서 해당 숫자를 빼서 찾으려는 전화 번호를 얻으십시오. 물론 그것을 다듬어서 (실제로) 입력 된 숫자인지 확인하십시오.

+1

질문에 특별히 문자열에 대한 액세스 권한이 없다고 언급하면 ​​double 값만 있습니다. –

1

절대적으로 두 배를 사용해야하고 실행할 작은 유틸리티 메소드가 있다면 괜찮습니다. 그것을 통해, 당신은 이와 비슷한 것을 쓸 수 있습니다. 사용자가 입력 한 문자열 값에 액세스 할 수 없다고했는데 문자열로 변환하고 이와 같은 작업을 수행 할 수없는 이유가 무엇입니까?

static int getPlaces(double num) { 
    String numString = String.valueOf(num); 

    return numString.indexOf(".0")==numString.length()-2?0:numString.length()-numString.indexOf(".")-1; 
} 

다음, 대신 예를

num.getPlaces() == 2 

의 당신은 당신의 코멘트 주어진, 난이 도움이되기를 바랍니다

getplaces(num) == 2 

..

업데이트를 할 수 That the user entered. Good point.

사용자가 소수점이없는 정수 (예 : 5)를 입력하고 이중으로 입력하면 사용자가 얻은 것 이외의 무엇인가를 얻습니다./그는 5를 입력했지만 5.0을 받게됩니다. 사용자가 실제로 5 또는 5.0을 입력했는지 여부는 알 수 없습니다.

+0

BTW, 그 방법을 쓰는 그루비 한 방법이 없다는 것을 유감스럽게 생각합니다. 나는 단지 자바를 알고 .. – steve

2

예, 가능합니다. 적어도 마음에 들지 않으면 때때로 잘못된 결과를 얻습니다. 우리는 사용자가 게으르고 12 개의 유효 자릿수 이상을 입력했다고 가정해야합니다.

그런 다음 다음을 수행하십시오

  • 생성자에 주어진 이중으로 인 BigDecimal를 작성합니다. 그러면 정확한 십진수 표현으로 double이 변환됩니다.

  • 분수 만 가져옵니다.

  • BigDecimal.toString()을 가져 와서 세 개 이상의 연속 '0'또는 '9'자릿수를 찾으십시오.

  • 세 자리 숫자 다음의 부분을 잘라냅니다. 자릿수가 9 인 경우 끝에 "1"을 추가하십시오. 그런 다음 모든 후행 0을 제거하십시오.

  • 나머지 소수 자릿수

경고

을 개수 :이 조금 느려질 수 있습니다.

이중의 중요한 비트 수만 있으면 더 빠르고 쉽게 얻을 수 있지만 10 진수 -> 이진 변환은 불행하게도 거의 모든 비트를 사용합니다.

0

BigDecimal로 변환하십시오. BigDecimal.scale() = places of number

관련 문제