[c#] vector<T> как реализовать???

Alexander08

хочу реализовать vector<T> в котором T может быть моим Complex или double или int. не получается перегрузить оператор +, т.к. не хочет складывать значения типа T. как выйти из этой ситуации?

anton7805

в с# есть перегрузка операторов ?

Helga87

Проблема известная, хороших решений этой проблемы нет
Вот такие убогие в C# generics...

evgen5555



т.к. не хочет складывать значения типа T

На такую мутную просьбу даже ворд будет ругаться - не найдено существительное, ассоциирующееся с действием "не хочет". Кто не хочет? Ты не хочет? Или компилятор?

evgen5555

Правильно, а что, эту проблему нельзя заменить не а-ля цэплюсплюсными вещами?

Helga87

Предложения?

Alexander08

2 : я думаю, ты не такой глупый, как ворд и понял о чем я! так что если чем можешь помочь - помогай! а не можешь - так не флуди!
проблема актуальна!

bleyman

Используй какой-нибудь макроподстановщик =)

Dasar

> в с# есть перегрузка операторов ?
есть, конечно.

Dasar

> Предложения?
например, так

interface ITraits<T>
{
T Add(T v1, T v2);
}
class vector<T, Traits> where Traits: ITraits<T>, new
{
static Traits traits = new Traits;
public vector(T data)
{
this.data = data;
}
public static vector<T, Traits> operator +(vector<T, Traits> v1, vector<T, Traits> v2)
{
return new vector<T, Traits>(traits.Add(v1.data, v2.data;
}
T data;
}

Helga87

Проверял. Скорость уменьшается в 5-10 раз, кроме того для каждого типа, для которого мы хотим получить Vector, надо писать свой вычислитель. Это весьма неудобно.

Alexander08

+1
а еще идеи есть?

bleyman

Тебе дать макроподстановщик? =)

Alexander08

меня ни это беспокоит(не лень мне ни класс для каждого типа написать, ни свой кодогенератор забадрить меня беспокоит другое - производительность, которая, как справедливо было замечено ранее, упадет!

bleyman

меня ни это беспокоит(не лень мне ни класс для каждого типа написать, ни свой кодогенератор забадрить меня беспокоит другое - производительность, которая, как справедливо было замечено ранее, упадет!
С чего бы это вдруг у тебя упадёт производительность, если ты откажешься от генериков? Они же всё равно инстанцируются в точно такие же отдельные классы, разве нет?

Helga87

В предложенном примере тормозят не генерики, тормозят виртуальные вызовы вычислителя по сравнению с операцией add.

bleyman

Ну да.
Если использовать кодогенератор, то ничего тормозить не будет.

Helga87

Согласен.
Ты кстати не смотрел на Nemerle? Язычок напоминает C#, тоже компилится в .net, но при этом обладает клевыми фишками, в т.ч. какими-то не до конца текстовыми макросами.

Vodnik

в C# 2005 есть темплейты

Helga87

Перечитай тему. Generics в C# не позволяют сделать того, что хочет автор

Dasar

> Проверял. Скорость уменьшается в 5-10 раз,
это точно?
Сейчас гонял вот такой benchmark
http://www.lambda-computing.com/publications/articles/generi...
но с 1000 прогонов вместо 100.
У меня, вообще, получилось, что generic в два раза быстрее, чем честный +.

Helga87

Проверял, но в августе 2004-го. Тогда на дворе был .net 1.1 и нельзя было использовать генерики. Такое решение с интерфейсом калькулятором было очень медленным, в частности, из-за приведений.
Тест по ссылке погонял. На 10000 получились совсем странные цифры:
 
Non-generic sum took 00:02:02.0156250.
Generic sum took 00:00:38.7031250.

В этом есть что-то глубоко неправильное. Надо будет посмотреть, какой же ассемблерный код получается в том и другом случаях и за счет чего получается такое читерство.

Helga87

Ага, наркоманы на lambda-computing.com.
Введем несколько вариантов тестов.
using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Temp2005.DunhilDBTableAdapters;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Globalization;
namespace Temp2005
{
namespace GenericNumerics
{
using System;
using System.Collections.Generic;
//The interface for calculations.
//This will normally contain much more methods,
// but for the benchmark we have just Add
public interface ICalculator<T>
{
T Add(T a, T b);
}
//You would have to do something similar to this
//for each type you want to use in your list.
public struct DoubleCalculator : ICalculator<double>
{
public double Add(double a, double b) { return a + b; }
}
public class Test
{
//create a large List<double> for benchmarking
static List<double> list;
static Test
{
list = new List<double>(1000000);
for (int i = 0; i < 1000000; i++)
list.Add(i);
}
//the non-generic sum method
public static double Sum(List<double> list)
{
double sum = 0;
double len = list.Count;
for (int i = 0; i < len; i++)
{
sum += list[i];
}
return sum;
}
//the actual non-generic sum method
public static double ArraySum(double[] list)
{
double sum = 0;
double len = list.Length;
for (int i = 0; i < len; i++)
{
sum += list[i];
}
return sum;
}
//the generic sum method. Note the second type parameter.
public static T Sum<T, C>(List<T> list)
where T : new
where C : ICalculator<T>, new
{
C calculator = new C;
T sum = new T;
for (int i = 0; i < list.Count; i++)
sum = calculator.Add(sum, list[i]);
return sum;
}
public static void Main
{
#if(DEBUG)
Console.WriteLine("Warning: Benchmarking in debug mode will not produce meaningful results!");
#endif
int count = 1000;
DateTime time0;
time0 = DateTime.Now;
double[] array = list.ToArray;
for (int i = 0; i < count; i++)
{
ArraySum(array);
}
Console.WriteLine("Non-generic array sum took {0}.", (DateTime.Now - time0;
time0 = DateTime.Now;
for (int i = 0; i < count; i++)
{
double sum = 0;
for (int j = 0; j < list.Count; j++)
{
sum += array[j];
}
}
Console.WriteLine("Non-generic array cycle sum took {0}.", (DateTime.Now - time0;
time0 = DateTime.Now;
for (int i = 0; i < count; i++)
{
Sum(list);
}
Console.WriteLine("Non-generic sum took {0}.", (DateTime.Now - time0;
time0 = DateTime.Now;
for (int i = 0; i < count; i++)
{
Sum<double, DoubleCalculator>(list);
}
Console.WriteLine("Generic sum took {0}.", (DateTime.Now - time0;
time0 = DateTime.Now;
for (int i = 0; i < count; i++)
{
double sum = 0;
for (int j = 0; j < list.Count; j++)
{
sum += list[j];
}
}
Console.WriteLine("Non-generic cycle sum took {0}.", (DateTime.Now - time0;
//Console.ReadLine;
}
}
}
}

Результаты:
Non-generic array sum took 00:00:04.0312500.
Non-generic array cycle sum took 00:00:01.4843750.
Non-generic sum took 00:00:12.2187500.
Generic sum took 00:00:03.7031250.
Non-generic cycle sum took 00:00:04.0937500.
Видим, что тест, предложенный автором статьи, самый медленный. Почему - фиг знает. Но ясно видно, что генерики, хотя и не тормозят процесс, но и не бегут впереди поезда.

Dasar

double len = list.Count;
багу исправь, а то у тебя, вообще, получается, что вызов метода занимает 3 секунды

Dasar

и тесты у тебя какие-то непонятные.
непонятно, что с чем ты сравниваешь.
ps
если List<T> заменить на T[] в обоих версиях (и в Generic, и в не Generic то скорость получается идентичная.

Helga87

Тесты у меня странные, потому что разные. Т.е. их цель была выяснить, как так получается, что решение на генериках быстрее, чем без них. Цель достигнута - оказалось, что если совсем отказаться от генериков, но при этом не использовать ArrayList, то все так же шустро. Осталось только выяснить, почему тормозит передача List<double> в non-generic метод

Dasar

> Осталось только выяснить, почему тормозит передача List<double> в non-generic метод
вот вывод у тебя неправильный, потому что снаружи у тебя длина int-овая, а внутри метода double-ельная, поэтому и непонятно, что с чем ты сравниваешь.

Helga87

ok, поправил на int.
Non-generic array sum took 00:00:03.5625000.
Non-generic array cycle sum took 00:00:01.3906250.
Non-generic sum took 00:00:12.2031250.
Generic sum took 00:00:03.7812500.
Non-generic cycle sum took 00:00:04.1718750.

Dasar

> Non-generic array sum took 00:00:03.5625000.
> Non-generic array cycle sum took 00:00:01.3906250.
имхо, ты не до конца исправил.
так не бывает.

Dasar

напоминаю, что во время тестов должен меняться один параметр, ты же меняешь сразу по 3-4.
в данных тестах, есть 4 параметра:
generic/non-generic
array/list
через метод/без метода
count спрашивать до for-а/во время for-а

Helga87

Бывает. 1 секунда это код:
time0 = DateTime.Now;
for (int i = 0; i < count; i++)
{
double sum = 0;
int len = array.Length;
for (int j = 0; j < len; j++)
{
sum += array[j];
}
}
Console.WriteLine("Non-generic array cycle sum took {0}.", (DateTime.Now - time0;

Helga87

Не в этом случае. В этом случае тесты выясняют только то, что тест, приведенный автором статьи, самый тормозной, а все остальное, кроме полного инлайна, работает примерно одинаково.

Dasar

у меня получилось вот так (на 100 вызовах):

Non-generic (w/o method) array sum took 00:00:00.4531250.
Non-generic (w/o method, local array) array sum took 00:00:00.2031250.
Non-generic array sum took 00:00:00.5312500.
Non-generic list sum took 00:00:00.9218750.
Non-generic array sum(pre count) took 00:00:00.5312500.
Non-generic list sum(pre count) took 00:00:00.8906250.
Generic array sum took 00:00:00.5156250.
Generic list sum took 00:00:00.5937500.
Generic array sum(pre count) took 00:00:00.5156250.
Generic list sum(pre count) took 00:00:00.5781250.

О! оказалось, что еще важно, массив локальный, или внешний
Оставить комментарий
Имя или ник:
Комментарий: