문제

간단한 C# 기능이 있습니다.

public static double Floor(double value, double step)
{
    return Math.Floor(value / step) * step;
}

이는 "값"보다 낮거나 동일 한 더 높은 숫자를 "단계"의 배수입니다. 그러나 다음 테스트에서 볼 수 있듯이 정밀도가 부족합니다.

[TestMethod()]
public void FloorTest()
{
    int decimals = 6;
    double value = 5F;
    double step = 2F;
    double expected = 4F;
    double actual = Class.Floor(value, step);
    Assert.AreEqual(expected, actual);
    value = -11.5F;
    step = 1.1F;
    expected = -12.1F;
    actual = Class.Floor(value, step);
    Assert.AreEqual(Math.Round(expected, decimals),Math.Round(actual, decimals));
    Assert.AreEqual(expected, actual);
}

첫 번째와 두 번째 어설 즈는 괜찮지 만 세 번째는 실패합니다. 결과는 6 번째 십진 자리까지 동일하기 때문입니다. 왜 그런 겁니까? 이것을 수정할 방법이 있습니까?

업데이트 테스트를 디버그하면 값이 6 번째 대신 8 번째 십진 자리까지 값이 동일하다는 것을 알 수 있습니다. 아마도 Math.round가 약간의 부정확성을 소개하기 때문일 수 있습니다.

메모 내 테스트 코드에서 나는 "F"접미사 (명시 적 플로트 상수)를 썼으며, 여기서 "D"(Double)를 의미하므로 변경하면 더 정밀도를 가질 수 있습니다.

도움이 되었습니까?

해결책

모든 f 포스트 픽스를 생략하면 (즉 -12.1 대신에 -12.1F) 당신은 몇 자릿수에 평등을 얻을 것입니다. 상수 (및 특히 예상 값)는 이제 F. 의도적으로 그렇게한다면 설명 해주세요.

그러나 나머지는 평등에 대한 이중 또는 플로트 값을 비교할 때 다른 답변과 동의하지만 신뢰할 수 없습니다.

다른 팁

나는 실제로 그들이 플로트와 복식을 위해 == 운영자를 구현하지 않았 으면 좋겠다. 더블 또는 플로트가 다른 값과 동일인지 묻는 것은 거의 항상 잘못된 일입니다.

컴퓨터의 부동 소수점 산술은 정확한 과학이 아닙니다 :).

사전 정의 된 소수의 소수에 대한 정확한 정밀도를 원한다면 두 배 대신 소수점을 사용하거나 사소한 간격을 수용하십시오.

http://en.wikipedia.org/wiki/floating_point#accuracy_problems

예를 들어, 0.1 및 0.01 (이진)의 비 표현 가능성은 0.1을 제곱하려는 시도가 0.01이거나 가장 가까운 대표적인 수가 아니라는 것을 의미합니다.

숫자 시스템의 기계 해석 (이진)을 원하는 경우 플로팅 포인트 만 사용하십시오. 당신은 10 센트를 대표 할 수 없습니다.

정밀도를 원한다면 System.decimal을 사용하십시오. 속도를 원한다면 System.Double (또는 System.Float)을 사용하십시오. 부동 소수점 번호는 "무한 정밀도"숫자가 아니므로 평등에는 공차가 포함되어야합니다. 숫자에 합리적인 숫자가있는 한 괜찮습니다.

  • 매우 크고 작은 숫자로 수학을하고 싶다면 float 또는 double을 사용하지 마십시오.
  • 무한한 정밀도가 필요한 경우 플로트 나 이중을 사용하지 마십시오.
  • 매우 많은 수의 값을 집계하는 경우 Float 또는 Double을 사용하지 마십시오 (오류는 스스로 복합적으로 나타납니다).
  • 속도와 크기가 필요한 경우 플로트 또는 이중을 사용하십시오.

보다 이것 정밀도가 수학 연산의 결과에 어떤 영향을 미치는지에 대한 자세한 분석에 대한 답변 (나도).

이 질문에 대한 답을 확인하십시오. 평등에 대한 부동 소수점 값을 0으로 확인하는 것이 안전합니까?

정말로, "허용 내에서 ..."를 확인하십시오.

플로트와 복식은 모든 숫자를 정확하게 저장할 수 없습니다. 이것은 IEEE 플로팅 포인트 시스템의 제한입니다. 충실한 정밀도를 갖기 위해서는보다 고급 수학 라이브러리를 사용해야합니다.

특정 지점을지나 정밀도가 필요하지 않으면 10 진수가 더 잘 작동 할 것입니다. 두 배보다 정밀도가 높습니다.

비슷한 문제의 경우, 대부분의 테스트 사례 (최대 5 자리 정밀도)의 성공으로 보이는 다음 구현을 사용하게됩니다.

public static double roundValue(double rawValue, double valueTick)
{
    if (valueTick <= 0.0) return 0.0;

    Decimal val = new Decimal(rawValue);
    Decimal step = new Decimal(valueTick);
    Decimal modulo = Decimal.Round(Decimal.Divide(val,step));

    return Decimal.ToDouble(Decimal.Multiply(modulo, step));
}

때로는 결과가 Strict : FP IEEE 754에서 기대하는 것보다 더 정확합니다. HW는 계산에 더 많은 비트를 사용하기 때문입니다. 보다 C# 사양 그리고 이 기사

Java에는 strictfp 키워드가 있으며 C ++에는 컴파일러 스위치가 있습니다. .NET에서 그 옵션이 그립습니다

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top