2013-06-17 2 views
5

저는 수학 라이브러리에서 일하고 있습니다. double으로 작업 할 때의 고유 한 문제로 인해 모든 동등 비교 유형을 a == b으로 지정하여 Math.Abs(a - b) <= epsilon으로 코딩하고 있습니다.const 필드에서 과학 표기법을 사용하는 방법?

또한 기본적으로으로, 최대의 정밀도로 서식이 지정된 문자열을 생성하고 싶습니다. 즉, 엡실론0.001 인 경우 기본 형식을 N3으로 지정합니다.

행복하게 나는 다음과 같은 한 :

public static class Math3D 
{ 
    internal const int ROUND = 3; 
    public const double Epsilon = 1e-ROUND; 
} 

을 ... 그리고 컴파일 오류가 발생했습니다. 명백하게 이것은 허용되지 않습니다.

이 제한 사항으로 인해 상호 의존성 상수를 const로 정의 할 수있는 방법이 없습니다. 분명히 내가 readonly 필드로 Epsilon을 정의 할 수 있지만 그렇게하는 것은 어떻게 든 개념적으로 잘못되었다고 느낀다. 이 작업을 수행하는 확실한 방법이 누락 되었습니까?

+0

리터럴 오류 란 무엇입니까? – rae1

+0

당신은 실제로'Epsilon'을위한 수학을하고 0.001의 값을 만들지 않습니다. –

+2

'readonly' 필드를 사용하는 것이 잘못된 이유는 무엇입니까? – xxbbcc

답변

10

변경하려는 경우 이어야합니다. 여기에서 readonly을 사용하십시오. const은 실제로 이 아니며처럼 변경되어야합니다 (예 : π). 그 이유는 constreadonly 사이의 미묘한 차이 때문입니다.

주요 문제는, 그렇지 않으면 당신은 shoot yourself in the foot, badly 수, 당신은 const의 값을 변경하는 경우, 당신은 const 사용 모든 종속 클라이언트를 재 컴파일해야한다는 것입니다. 따라서 일 수있는 값의 경우 const을 사용하지 말고 readonly을 사용하십시오. 값이 결코 변경하려는 경우

그래서, 단지 ROUND의 측면에서 Epsilon 정의에 대해 걱정하지 마십시오 다음 const을 사용하고, 단지 말 :

internal const int ROUND = 3; 
public const double Epsilon = 1e-3; 

당신이 정말로 확인하려면 실수로 다른를 변경하지 않고 하나를 변경하지 않도록, 당신은 생성자에서 작은 체크를 추가 할 수 있습니다

if (Epsilon != Math.Pow(10, -ROUND)) { 
    throw new YouForgotToChangeBothConstVariablesException(); 
} 

당신은 조건부 컴파일을 추가 할 수 있습니다 디버그 릴리스에서만 컴파일됩니다. 그것은 입니다 변경하려는 경우

, static readonly를 사용

internal readonly int ROUND = 3; 
public static readonly double Epsilon = Math.Pow(10, -ROUND); 

을 내가 consts로 interdependant 상수 모두를 정의 할 수있는 방법을 볼이 제한으로. [...] 나는 이것을하는 방법의 분명한 방법을 놓치고 있습니까?

아니, 당신은 ROUNDEpsilon 사이에 이동 Math.Pow 또는 Math.Log를 사용하여 수학의 어떤 종류를해야 그는 const와 컴파일 시간 사용에 대한 허용되지 않습니다. 작은 코드 생성기를 작성하여 단일 입력 값을 기반으로이 두 줄의 코드를 추출 할 수 있지만 실제로 시간을 투자하는 것에는 의문의 여지가 있습니다.

+0

오류가 'const'에 의해 발생하지 않습니다. – rae1

+0

그게 바로 요점입니다. 두 const는 절대로 바뀌지 않을 것이고 그것은 내가 코드가 "말하도록"하고 싶은 것입니다. 개발 중에 우리는 값을 몇 번 미세하게 조정할 수 있었고 어떻게 든 둘 다 연결할 수 있는지 궁금해했습니다. 솔루션이 없다면 최종 코드는 두 개의 독립 const로 제공 될 것입니다. – InBetween

+0

@InBetween : 여러분이 해결하려고하는 문제를 해결하기 위해'const'로하고 싶은 컴파일 시간에 수학을 할 수는 없습니다. – jason

2

1e-ROUND 특히 1e은 유효한 리터럴 정수가 아닙니다. 당신은 식을 런타임까지 알 수없는 때 당신이 const를 사용할 수 없기 때문에

public static readonly double Epsilon = 
    decimal.Parse(
     string.Format("1E-{0}", ROUND), 
     System.Globalization.NumberStyles.Float); 

는 또한, static readonly주의, 같이해야 할 것이다. static readonly은이 시나리오에서 const과 유사하게 작동합니다.

당신이 string의 처리하지 않으려면, 당신은 항상 할 수있는, 당신이 상수를 사용하는 것처럼 당신은 언제나 하드 코드 3.보고 할 수

public static readonly double Epsilon = Math.Pow(10, -ROUND); 
+2

... ""숫자를 문자열로 포맷 한 다음 구문 분석해야합니까? 구식이라 부르지 만 커다란 개념의 우회로가 있습니다. 간단한 산술 계산을 사용하여 숫자를 가져옵니다. –

+0

나는 이것이 아주 좋은 충고라고 생각하지 않는다. 'Math.Pow() '를 사용하면 문제가 없으며 문자열 파싱 연산을 피할 수 있습니다. – xxbbcc

+0

가능한 한 읽을 수 있도록하고 싶습니다. – rae1

1

후 지금까지 값을 바꿀 생각이 없습니다 3 이외의 다른 것에? 따라서 DRY에 대해 너무 걱정할 필요가 없습니다.

public static class Math3D 
{ 
    internal const int ROUND = 3; 
    public const double Epsilon = 1e-3; 
} 

당신은 당신이 다음 const 당신을 위해하지 않고 귀하의 질문에 논쟁이되고, 3 변경할 수 있습니다 생각하는 경우.

1

편집 :

이 귀하의 질문에 직접 대답은 아니지만 당신이 쓰기 가능한 필드로 RoundEpsilon을 변경 고려 했는가? 서식 지정/반올림을 위해 이들을 사용하면 경우에 따라 변경해야한다는 것을 거의 보장합니다. const 또는 readonly 필드는 작동하지 않습니다.

public static class Math3D 
{ 
    internal static int s_Round; 
    internal static double s_Epsilon; 

    static Math3D() 
    { 
     Round = 3; 
    } 

    public static double Epsilon 
    { 
     get 
     { 
      return (s_Epsilon); 
     } 
    } 

    public static int Round 
    { 
     get 
     { 
      return (s_Round); 
     } 
     set 
     { 
      // TODO validate 
      s_Round = value; 
      s_Epsilon = Math.Pow (10, -s_Round); 
     } 
    } 
} 

향후 변경 될 때 깨지지 않는 명확한 솔루션입니다.

+0

+1 OP가 수학 라이브러리에서 작동하는 경우 서식 동작을 사용자 지정하여 반올림 한도를 가져오고 설정하는 속성을 사용하는 것이 좋습니다. –

+0

샘플을 보내 주셔서 감사합니다. 나는 기본적으로 비슷하게 끝내었지만 실제로 소비자가 라이브러리의 정확도 *를 변경하고 기본 "반올림"을 항상 형식 문자열로 사용자 정의 할 수 있도록하는 이유를 알지 못합니다. 문제도. 그래서 해결책은 두 개의'readonly' 필드가 될 것입니다. – InBetween

+0

@InBetween 필자는 정확도를 즉시 변경할 수있는 여러 3D 모델러를 사용했습니다. 이것은 어떤 상황에서는 매우 유용한 기능입니다. 그래서 그것이 내가 제안한 이유입니다. – xxbbcc

관련 문제