문제

현재이 방법이 있습니다.

static boolean checkDecimalPlaces(double d, int decimalPlaces){
    if (d==0) return true;

    double multiplier = Math.pow(10, decimalPlaces); 
    double check  =  d * multiplier;
    check = Math.round(check);      
    check = check/multiplier; 
    return (d==check);      
}

그러나이 방법은 실패합니다 checkDecmialPlaces(649632196443.4279, 4) 아마도 기본 2 숫자에서베이스 10 수학을하기 때문일 것입니다.

그렇다면이 점검은 어떻게 올바르게 수행 할 수 있습니까?

나는 이중 값의 문자열 표현을 얻는 것을 생각한 다음 Regexp로 확인했지만 이상하게 느껴졌습니다.

편집하다:모든 답변에 감사드립니다. 실제로 두 배를 얻는 경우가 있으며 그 경우 다음을 구현했습니다.

private static boolean checkDecimalPlaces(double d, int decimalPlaces) {
    if (d == 0) return true;

    final double epsilon = Math.pow(10.0, ((decimalPlaces + 1) * -1));

    double multiplier = Math.pow(10, decimalPlaces);
    double check = d * multiplier;
    long checkLong = (long) Math.abs(check);
    check = checkLong / multiplier;

    double e = Math.abs(d - check);
    return e < epsilon;
}

나는 round 잘림에. 계산이 이루어진 것 같습니다 round 부정확성을 너무 많이 증가시킵니다. 적어도 실패한 테스트 케이스에서.
여러분 중 일부가 지적했듯이 '진짜'문자열 입력에 도달 할 수 있다면 사용해야합니다. BigDecimal 확인하기 위해 다음과 같이했습니다.

BigDecimal decimal = new BigDecimal(value);
BigDecimal checkDecimal = decimal.movePointRight(decimalPlaces);
return checkDecimal.scale() == 0;

그만큼 double 내가 얻는 가치는 Excel 파일을 읽는 Apache Poi API에서 나옵니다. 나는 몇 가지 테스트를했고 API가 반환되지만 double 숫자 셀에 대한 값 즉시 형식을 형성 할 때 정확한 표현을 얻을 수 있습니다. double 이랑 DecimalFormat:

DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setMaximumIntegerDigits(Integer.MAX_VALUE);
// don't use grouping for numeric-type cells
decimalFormat.setGroupingUsed(false);
decimalFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
value = decimalFormat.format(numericValue);

이것은 또한 이진 형식으로 정확하게 표현할 수없는 값에 대해서도 작동합니다.

도움이 되었습니까?

해결책

바이너리 플로팅 포인트 표현의 정확도에 도달했기 때문에 테스트가 실패합니다. IEEE754 이중 정밀도. 649632196443.4279를 10000으로 곱하면 이진 표현이 잘려 나서 반올림 및 나중에 나누면 오류가 발생하여 기능 결과가 완전히 무효화됩니다.

자세한 내용은 참조하십시오 http://en.wikipedia.org/wiki/floating_point#accuracy_problems

더 좋은 방법은 n+1 소수점 자리는 특정 임계 값 미만입니다. 만약에 d - round(d) 보다 적습니다 epsilon (보다 한계), 소수점 표현 d 소수점 이하 자리가 없습니다. 마찬가지로 (d - round(d)) * 10^n 보다 적습니다 epsilon, D는 최대를 가질 수 있습니다 n 중요한 장소.

사용 존 스키트'에스 DoubleConverter 어디에 있는지 확인합니다 d 당신이 찾고있는 소수점 자리를 잡을만큼 정확하지 않습니다.

다른 팁

목표가 정확히 숫자를 대표하는 것이라면 N 소수점의 오른쪽에있는 중요한 수치, Bigdecimal 사용하는 클래스입니다.

불변의 임의의 자료에 서명 된 소수점 수치. Bigdecimal은 임의의 정밀 정수 값이없는 값과 32 비트 정수 척도로 구성됩니다. 0이거나 양수 인 경우, 스케일은 소수점의 오른쪽에있는 숫자 수입니다. 음수 인 경우, 숫자의 미지급 값은 스케일의 부정의 힘에 10을 곱합니다. 따라서 Bigdecimal이 나타내는 숫자의 값은 (unscaledValue × 10-scale)입니다.

scale 통해 설정할 수 있습니다 세트 스케일 (int)

모든 부동 소수점 산술과 마찬가지로, 평등을 확인하지 말고 오류 (엡실론)가 충분히 작습니다.

교체하는 경우 :

return (d==check);

같은 것

return (Math.abs(d-check) <= 0.0000001);

작동해야합니다. 분명히, Epsilon은 확인하는 소수의 수와 비교하여 충분히 작게 선택해야합니다.

그만큼 double 유형은 바이너리 플로팅 포인트 번호입니다. 마치 마치 부동산 지점 수인 것처럼 그들을 다루는 데 항상 명백한 부정확성이 있습니다. 나는 당신이 원하는 방식으로 작동하도록 당신의 기능을 쓸 수 있다는 것을 모르겠습니다.

당신은 숫자의 원래 소스 (아마도 문자열 입력)로 돌아가서 중요한 경우 소수점 표현을 유지해야 할 것입니다.

Bigdecimal으로 전환 할 수 있다면 Ken G가 설명했듯이, 그것이 당신이 사용해야하는 것입니다.

그렇지 않다면 다른 답변에서 언급 한 것처럼 많은 문제를 처리해야합니다. 나에게, 당신은 이진수 (이중)를 다루고 그 숫자의 소수점 표현에 대한 질문을하고 있습니다. 즉, 당신은 끈에 대해 묻습니다. 나는 당신의 직감이 정확하다고 생각합니다.

나는 이것이 일반적으로 실제로 가능하다는 것을 확신하지 못한다. 예를 들어, 소수점 이하의 자리가 얼마나됩니다 1.0e-13 가지다? 산술을 수행하는 동안 반올림 오류로 인한 경우 실제로 0 변장? 다른 한편으로, 당신은 첫 번째에 0이 아닌 숫자가 있는지 묻습니다. N 소수점 이하는 다음과 같은 일을 할 수 있습니다.

   static boolean checkDecimalPlaces(double d, unsigned int decimalPlaces){
      // take advantage of truncation, may need to use BigInt here
      // depending on your range
      double d_abs = Math.abs(d);
      unsigned long d_i = d_abs; 
      unsigned long e = (d_abs - d_i) * Math.pow(10, decimalPlaces);
      return e > 0;
   }

나는 이것이 문자열로 더 잘 변환하고 지수의 값을 심문한다고 생각합니다.

 public int calcBase10Exponet (Number increment)
 {
  //toSting of 0.0=0.0
  //toSting of 1.0=1.0
  //toSting of 10.0=10.0
  //toSting of 100.0=100.0
  //toSting of 1000.0=1000.0
  //toSting of 10000.0=10000.0
  //toSting of 100000.0=100000.0
  //toSting of 1000000.0=1000000.0
  //toSting of 1.0E7=1.0E7
  //toSting of 1.0E8=1.0E8
  //toSting of 1.0E9=1.0E9
  //toSting of 1.0E10=1.0E10
  //toSting of 1.0E11=1.0E11
  //toSting of 0.1=0.1
  //toSting of 0.01=0.01
  //toSting of 0.0010=0.0010  <== need to trim off this extra zero
  //toSting of 1.0E-4=1.0E-4
  //toSting of 1.0E-5=1.0E-5
  //toSting of 1.0E-6=1.0E-6
  //toSting of 1.0E-7=1.0E-7
  //toSting of 1.0E-8=1.0E-8
  //toSting of 1.0E-9=1.0E-9
  //toSting of 1.0E-10=1.0E-10
  //toSting of 1.0E-11=1.0E-11
  double dbl = increment.doubleValue ();
  String str = Double.toString (dbl);
//  System.out.println ("NumberBoxDefaultPatternCalculator: toSting of " + dbl + "=" + str);
  if (str.contains ("E"))
  {
   return Integer.parseInt (str.substring (str.indexOf ("E") + 1));
  }
  if (str.endsWith (".0"))
  {
   return str.length () - 3;
  }
  while (str.endsWith ("0"))
  {
   str = str.substring (0, str.length () - 1);
  }
  return - (str.length () - str.indexOf (".") - 1);
 }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top