문제

가 실현 가능한 방법을 사용하여 제네릭을 만들 수학 라이브러리에 의존하지 않는 기본 유형을 선택한 데이터를 저장하는 데?

다시 말해서,다고 가정하자 나는 일부를 작성하려 클래스입니다.분율로 표시될 수 있 두 개의 수 또는 두 개의 복식 또는었습니다.중요한 것은 기본적인 네 개의 연산은 제대로 정의되어 있습니다.그래서,내가 쓸 수 있을 것이다 Fraction<int> frac = new Fraction<int>(1,2) 그리고/또는 Fraction<double> frac = new Fraction<double>(0.1, 1.0).

불행하게도 없습니다 인터페이스를 대표하는 네 개의 기본 작업(+,-,*,/).는 사람을 찾을 실행할 수 있는 가능한 방법으로 구현하는 이?

도움이 되었습니까?

해결책

방법은 여기를 추상적으로 사업자는 상대적으로 고통입니다.

    abstract class MathProvider<T>
    {
        public abstract T Divide(T a, T b);
        public abstract T Multiply(T a, T b);
        public abstract T Add(T a, T b);
        public abstract T Negate(T a);
        public virtual T Subtract(T a, T b)
        {
            return Add(a, Negate(b));
        }
    }

    class DoubleMathProvider : MathProvider<double>
    {
        public override double Divide(double a, double b)
        {
            return a / b;
        }

        public override double Multiply(double a, double b)
        {
            return a * b;
        }

        public override double Add(double a, double b)
        {
            return a + b;
        }

        public override double Negate(double a)
        {
            return -a;
        }
    }

    class IntMathProvider : MathProvider<int>
    {
        public override int Divide(int a, int b)
        {
            return a / b;
        }

        public override int Multiply(int a, int b)
        {
            return a * b;
        }

        public override int Add(int a, int b)
        {
            return a + b;
        }

        public override int Negate(int a)
        {
            return -a;
        }
    }

    class Fraction<T>
    {
        static MathProvider<T> _math;
        // Notice this is a type constructor.  It gets run the first time a
        // variable of a specific type is declared for use.
        // Having _math static reduces overhead.
        static Fraction()
        {
            // This part of the code might be cleaner by once
            // using reflection and finding all the implementors of
            // MathProvider and assigning the instance by the one that
            // matches T.
            if (typeof(T) == typeof(double))
                _math = new DoubleMathProvider() as MathProvider<T>;
            else if (typeof(T) == typeof(int))
                _math = new IntMathProvider() as MathProvider<T>;
            // ... assign other options here.

            if (_math == null)
                throw new InvalidOperationException(
                    "Type " + typeof(T).ToString() + " is not supported by Fraction.");
        }

        // Immutable impementations are better.
        public T Numerator { get; private set; }
        public T Denominator { get; private set; }

        public Fraction(T numerator, T denominator)
        {
            // We would want this to be reduced to simpilest terms.
            // For that we would need GCD, abs, and remainder operations
            // defined for each math provider.
            Numerator = numerator;
            Denominator = denominator;
        }

        public static Fraction<T> operator +(Fraction<T> a, Fraction<T> b)
        {
            return new Fraction<T>(
                _math.Add(
                  _math.Multiply(a.Numerator, b.Denominator),
                  _math.Multiply(b.Numerator, a.Denominator)),
                _math.Multiply(a.Denominator, b.Denominator));
        }

        public static Fraction<T> operator -(Fraction<T> a, Fraction<T> b)
        {
            return new Fraction<T>(
                _math.Subtract(
                  _math.Multiply(a.Numerator, b.Denominator),
                  _math.Multiply(b.Numerator, a.Denominator)),
                _math.Multiply(a.Denominator, b.Denominator));
        }

        public static Fraction<T> operator /(Fraction<T> a, Fraction<T> b)
        {
            return new Fraction<T>(
                _math.Multiply(a.Numerator, b.Denominator),
                _math.Multiply(a.Denominator, b.Numerator));
        }

        // ... other operators would follow.
    }

당신이 실패하는 경우를 구현하는 형식을 사용하여,당신은 당신을 얻을 것이 실패하는 대신 런타임에 컴파일 시간에(나쁜).의 정의 MathProvider<T> 구현상이 될 것 같은(나).는 것이 좋습니다 것입니다 당신이 피하기만 하 C#고 사용하 F#또는 다른 언어 더 이 추상화 수준.

편집: 정의 정의를 추가하고 빼기 Fraction<T>.또 다른 흥미와 간단한 일이지를 구현하 MathProvider 에서 작동하는 추상적이 구문을 나무입니다.이것이 바로 포인트를 하는 것이 자동으로 차별화: http://conal.net/papers/beautiful-differentiation/

다른 팁

저는 이것을 믿는 당신의 질문에 대답:

http://www.codeproject.com/KB/cs/genericnumerics.aspx

여기는 미묘한 문제는 함께 제공됩니다.가정 알고리즘을 포함한 부문,말할 가우시안 해결하기 위하여 제거 방정식의 시스템.당신이 통과하면서 정수,당신은 잘못된 응답을 얻을 것이기 때문에 당신은 수행 정수 division.그러나 전달하는 경우에 두 번 인수하는 일이 일어날 정수 값을 얻을 것이다,당신은 정답이 있습니다.

같은 일이 일어난 사각형 뿌리에서와 같이,Cholesky 분해.고려해 정수 매트릭스는 잘못 가는 반면,인수 분해하는 행렬의 두 배가하는 일이의 정수 값을 잘 될 것입니다.

첫째,클래를 제한해야 합니다 일반적인 매개 변수를 기본(공용 클래스의 일부분 여기서 T:구조체,새로운()).

두번째,당신은 아마를 만들어야 암시적 오버로드 캐스팅 할 수 있도록 핸들을 캐스팅에서 하나 입력하지 않고 다른 컴파일러에서 울고있다.

셋째,당신할 수 있는 하중 초과의 네 가지 기본적인 연산자를 만들뿐 아니라 인터페이스가 더 유연한 때에 결합하는 분수의 다른 유형이 있습니다.

마지막으로,당신은 고려하는 어떻게 처리하는 산수 및 언더플로우.좋은 라이브러리가 매우 명시적으로 처리하는 방법을 오버플로우;그렇지 않으면 믿을 수 없어 결과의 작업의 다른 부분 유형입니다.

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