Re[15]: Немножко о С# 3
От: Klapaucius  
Дата: 23.03.07 13:00
Оценка: 47 (3)
Здравствуйте, Cyberax, Вы писали:

C>Не ортогонально. Оно у тебя просто прозрачно боксирует value-типы — и "возвращаемся обратно на клетку 1", получая весь оверхед, связаный с объектами.


Вообще-то это не так.
Вот доказательство:
Как сделать на c# обобщенную арифметику? Это достаточно просто, хотя и выглядит весьма уродливо. Но работает.
Можно построить целую иерархию "классов типов":
    public interface CComparable<T>
    {
        bool GT(T a, T b);
        bool LT(T a, T b);
        bool Eq(T a, T b, T eps);
    }

    public interface CEq<T>
    {
        bool Eq(T a, T b);
        bool NonEq(T a, T b);
    }

    public interface COrdered<T> : CComparable<T>, CEq<T>
    {
        bool GTorEq(T a, T b);
        bool LTorEq(T a, T b);
    }

    public interface CNumber<T> : CComparable<T>
    {
        T Add(T a, T b);
        T Sub(T a, T b);
        T AddNeutral { get;} // 0
        T Prod(T a, T b);
        T ProdNeutral { get;} // 1
        T Abs(T a);
        T Negate(T a);
        T Signum(T a);
    }

    public interface CFractional<T> : CNumber<T>
    {
        T From(double a);
        T From(float a);
        T Quot(T a, T b);
        T Inv(T a);
    }

    public interface CInteger<T> : CNumber<T>, COrdered<T>
    {
        T From(int a);
        T From(long a);
        T Div(T a, T b);
        T Mod(T a, T b);
    }

    public interface CReal<T> : CFractional<T>
    {
        T Sqr(T a);
        T Sqrt(T a);
    }


А теперь, написать имплементации, например RealDouble:
    public struct RealDouble : CReal<double> // обратите внимание на struct
    {
        #region CFractional<double> Members

        public double From(double a)
        {
            return a;
        }

        public double From(float a)
        {
            return a;
        }

        public double Quot(double a, double b)
        {
            return a / b;
        }

        public double Inv(double a)
        {
            return 1 / a;
        }

        #endregion

        #region CNumber<double> Members

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

        public double Sub(double a, double b)
        {
            return a - b;
        }

        public double AddNeutral
        {
            get { return 0.0; }
        }

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

        public double ProdNeutral
        {
            get { return 1.0; }
        }

        public double Abs(double a)
        {
            return Math.Abs(a);
        }

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

        public double Signum(double a)
        {
            return Math.Sign(a);
        }

        #endregion

        #region CComparable<double> Members

        public bool GT(double a, double b)
        {
            return a > b;
        }

        public bool LT(double a, double b)
        {
            return a < b;
        }

        public bool Eq(double a, double b, double eps)
        {
            return Math.Abs(a - b) < eps;
        }

        #endregion

        #region CReal<double> Members

        public double Sqr(double a)
        {
            return a * a;
        }

        public double Sqrt(double a)
        {
            return Math.Sqrt(a);
        }

        #endregion
        }


Теперь сделаем комплексные числа:
    public struct Complex
    {
        public Complex(double re, double im)
        {
            Re = re;
            Im = im;
        }
        public double Re;
        public double Im;
        public static Complex operator +(Complex a, Complex b)
        {
            return new Complex(a.Re + b.Re, a.Im + b.Im);
        }
    }

    public struct Complex<T, C>
        where C : struct, CReal<T>
    {
        static C c = new C();

        public Complex(T re, T im)
        {
            Re = re;
            Im = im;
        }
        public T Re;
        public T Im;
        public static Complex<T, C> operator +(Complex<T, C> a, Complex<T, C> b)
        {
            return new Complex<T, C>(c.Add(a.Re, b.Re), c.Add(a.Im, b.Im));
        }
    }


Идея ясна? Если правы Вы, то во втором случае будут виртуальные вызовы (даже хуже, потому что CReal<T> это интерфейс)
Я же утверждаю, что никаких виртуальных вызовов не будет, более того, функция будет заинлайнена JIT.

Теперь пишем вот такой вот тест:
    class Program
    {
        static void Main(string[] args)
        {
                    System.Threading.Thread.Sleep(2000); // дадим время рантайму.
                
            Stopwatch sw = new Stopwatch();

            int count = 100000000;

            Complex c1 = new Complex();
            Complex c2 = new Complex(0, 1);

            Complex<double, RealDouble> gc1 = new Complex<double, RealDouble>();
            Complex<double, RealDouble> gc2 = new Complex<double, RealDouble>(0, 1);

            for (int i = 0; i < count/1000; i++) // это для того, чтобы исключить из замеров JIT-компиляцию.
            {
                c2 = c2 + c1;
            }

            for (int i = 0; i < count/1000; i++)
            {
                gc2 = gc2 + gc1;
            }

            sw.Start();
            for (int i = 0; i < count; i++)
            {
                c2 = c2 + c1;
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
            sw.Reset();

            sw.Start();
            for (int i = 0; i < count; i++)
            {
                gc2 = gc2 + gc1;
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
            sw.Reset();

            Console.ReadLine();
        }
    }


Компилируем в Release, запускаем без отладчика.
.NET Framework 2.0.50727
Xeon-A(Prestonia) X2, 2666 MHz
Получаем вот что:
2457
2454


quod erat demonstrandum.
... << RSDN@Home 1.2.0 alpha rev. 655>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.