IT이야기

float를 반환하는 메서드에서 결과를 float로 캐스팅하면 결과가 변경됩니다.

cyworld 2021. 9. 30. 21:56
반응형

float를 반환하는 메서드에서 결과를 float로 캐스팅하면 결과가 변경됩니다.


이 코드 False가 .NET 4에서 인쇄 되는 이유는 무엇 입니까? 명시적 캐스트로 인해 예기치 않은 동작이 발생한 것 같습니다.

"부동 소수점이 정확하지 않습니다" 또는 "그렇게 하지 마십시오" 이상의 답변을 원합니다.

float a(float x, float y)
{
  return ( x * y );
}

float b(float x, float y)
{
  return (float)( x * y );
}

void Main()
{
  Console.WriteLine( a( 10f, 1f/10f ) == b( 10f, 1f/10f ) );
}

추신: 이 코드는 릴리스 코드가 아닌 단위 테스트에서 가져왔습니다. 코드는 의도적으로 이런 식으로 작성되었습니다. 결국 실패할 것이라고 생각했지만 정확한 시기와 이유를 알고 싶었습니다. 대답은 부동 소수점 결정론에 대한 일반적인 이해를 뛰어 넘는 이해를 제공하기 때문에 이 기술의 유효성을 증명합니다. 그리고 이것이 이 코드를 이런 식으로 작성하는 요점이었습니다. 의도적인 탐색.

PPS: 단위 테스트는 .NET 3.5에서 통과했지만 .NET 4로 업그레이드한 후에는 실패합니다.


David의 의견은 정확하지만 충분히 강력하지 않습니다. 동일한 프로그램에서 해당 계산을 두 번 수행해도 동일한 결과 가 나온다는 보장은 없습니다 .

C# 사양은 이 점에서 매우 명확합니다.


부동 소수점 연산은 연산의 결과 유형보다 더 높은 정밀도로 수행될 수 있습니다. 예를 들어, 일부 하드웨어 아키텍처는 double 유형보다 범위와 정밀도가 더 큰 "확장" 또는 "long double" 부동 소수점 유형을 지원하고 이 더 높은 정밀도 유형을 사용하여 모든 부동 소수점 연산을 암시적으로 수행합니다. 이러한 하드웨어 아키텍처는 성능이 과도할 때만 정밀도가 낮은 부동 소수점 연산을 수행할 수 있으며, 성능과 정밀도를 모두 상실하는 구현을 요구하기 보다는 C#에서는 모든 부동 소수점 연산에 더 높은 정밀도 유형을 사용할 수 있습니다. . 보다 정확한 결과를 제공하는 것 외에는 측정 가능한 효과가 거의 없습니다. 그러나 형식의 표현에서x * y / z, 곱셈이 이중 범위를 벗어난 결과를 생성하지만 후속 나누기가 임시 결과를 다시 이중 범위로 가져오는 경우 표현식이 더 높은 범위 형식으로 평가된다는 사실로 인해 유한 결과가 대신 생성될 수 있습니다. 무한대.


C# 컴파일러, 지터 및 런타임은 모두 사양에서 요구하는 것보다 더 정확한 결과 를 제공할 수 있는 광범위한 자유도를 가지고 있습니다 . 언제든지 변덕스럽게 -- 일관되게 수행하도록 선택할 필요가 없으며 실제로 그렇게 합니다. 아니다.

그것이 마음에 들지 않으면 이진 부동 소수점 숫자를 사용하지 마십시오. 소수 또는 임의의 정밀도 유리를 사용합니다.

float를 반환하는 메서드에서 float로 캐스팅하는 것이 차이를 만드는 이유를 이해하지 못합니다.

우수한 점.

샘플 프로그램은 작은 변경이 어떻게 큰 효과를 일으킬 수 있는지 보여줍니다. 런타임의 일부 버전에서 float로 캐스팅하면 명시적으로 하지 않는 것과 다른 결과가 나타납니다. float로 명시적으로 캐스트하면 C# 컴파일러는 런타임 에 "이 최적화를 사용하는 경우 초고정밀 모드에서 이 작업을 제거하십시오" 라는 힌트를 제공합니다 . 사양에서 알 수 있듯이 잠재적인 성능 비용이 있습니다.

그렇게 하는 것이 "정답"으로 반올림되는 것은 단지 행복한 우연일 뿐입니다. 이 경우 정확도를 잃으면 올바른 방향으로 잃어버리기 때문에 정답을 얻을 수 있습니다.

.net 4는 어떻게 다른가요?

3.5 런타임과 4.0 런타임의 차이점이 무엇인지 묻습니다. 차이점은 4.0에서 지터는 특정 경우에 더 높은 정밀도로 이동하도록 선택하고 3.5 지터는 그렇지 않기로 선택한다는 것입니다. 그렇다고 해서 이 상황이 3.5에서 불가능했던 것은 아닙니다. 모든 버전의 런타임과 모든 버전의 C# 컴파일러에서 가능했습니다. 당신은 당신의 컴퓨터에서 세부 사항이 다른 경우를 우연히 발견했습니다. 그러나 지터는 항상 이 최적화를 수행하도록 허용되었으며 항상 변덕스럽게 수행되었습니다.

또한 C# 컴파일러는 컴파일 시간에 상수 부동 소수점을 계산할 때 유사한 최적화를 수행하도록 선택할 수 있는 권한이 있습니다. 상수에서 두 개의 동일해 보이는 계산은 컴파일러 런타임 상태의 세부 사항에 따라 다른 결과를 가질 수 있습니다.

보다 일반적으로, 부동 소수점 숫자가 실수의 대수적 속성을 가져야 한다는 기대는 현실과 완전히 일치하지 않습니다. 그들은 그러한 대수적 속성을 가지고 있지 않습니다. 부동 소수점 연산은 연관 되지 않습니다 . 그들은 확실히 당신이 기대하는 것처럼 곱셈 역수의 법칙을 따르지 않습니다. 부동 소수점 숫자는 실제 산술의 근사치일 뿐입니다. 물리적 시스템을 시뮬레이션하거나 요약 통계를 계산하는 등의 작업에 충분히 가까운 근사값입니다.


I have no Microsoft compiler right now and Mono have no such effect. As far as I know GCC 4.3+ uses gmp and mpfr to calculate some stuff in compile time. C# compiler may do the same for non-virtual, static or private methods in same assembly. Explicit cast may interfere with such optimization (but I see no reason why it can't have same behavior). I.e. it may inline with calculating constant expression to some level (for b() it may be for example up to the cast).

GCC as well have the optimization that promotes operation to more highest precision if that makes sense.

So I'd consider both optimization as potential reason. But for both of them I see no reason why doing explicit casting of result may have some additional meaning like "be closer to standard".

ReferenceURL : https://stackoverflow.com/questions/8795550/casting-a-result-to-float-in-method-returning-float-changes-result

반응형