.NET 7 Preview 5 – Generic Math
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 11.06.22 12:44
Оценка: 133 (4) +1 -1
Наконец то!
.NET 7 Preview 5 – Generic Math

Для понимания
Статические методы абстрактного интерфейса
Statics in Interfaces
и солнце б утром не вставало, когда бы не было меня
Отредактировано 12.06.2022 16:42 Serginio1 . Предыдущая версия . Еще …
Отредактировано 11.06.2022 15:06 Serginio1 . Предыдущая версия .
Re: .NET 7 Preview 5 – Generic Math
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.06.22 11:47
Оценка: +2 :))
Здравствуйте, Serginio1, Вы писали:

S>Наконец то!

S>.NET 7 Preview 5 – Generic Math

О, наконец-то!
Теперь главное — вспомнить, зачем я их так долго ждал
Ведь помню были какие-то мега-идеи того, для чего всё это мне было нужно
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: .NET 7 Preview 5 – Generic Math
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 13.06.22 12:50
Оценка:
Здравствуйте, Sinclair, Вы писали:
S>Теперь главное — вспомнить, зачем я их так долго ждал
S>Ведь помню были какие-то мега-идеи того, для чего всё это мне было нужно
Ну вот есть время до выхода .Net 7 что бы вспомнить.
и солнце б утром не вставало, когда бы не было меня
Re: .NET 7 Preview 5 – Generic Math
От: BlackEric http://black-eric.lj.ru
Дата: 17.07.22 10:14
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Наконец то!

S>.NET 7 Preview 5 – Generic Math

S>Для понимания

S>Статические методы абстрактного интерфейса
S> Statics in Interfaces

А оно разве в 6 dotnet не вошло? Или это развитие того, что в 6?
https://github.com/BlackEric001
Re[2]: .NET 7 Preview 5 – Generic Math
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 17.07.22 11:32
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>А оно разве в 6 dotnet не вошло? Или это развитие того, что в 6?

Оно в превью было, но в релиз я так понял не вошло.
Тут смысл в C# 11 и .NET 7 включают предварительную версию статических абстрактных элементов в интерфейсах
и солнце б утром не вставало, когда бы не было меня
Re: offtop: сортировщики гномиков
От: syrompe  
Дата: 19.07.22 14:16
Оценка:
  пример из статьи
public static TResult StandardDeviation<T, TResult>(IEnumerable<T> values)
    where T : INumber<T>
    where TResult : IFloatingPointIeee754<TResult>
{
    TResult standardDeviation = TResult.Zero;

    if (values.Any())
    {
        TResult average = Average<T, TResult>(values);
        TResult sum = Sum<TResult, TResult>(values.Select((value) => {
            var deviation = TResult.CreateSaturating(value) - average;
            return deviation * deviation;
        }));
        standardDeviation = TResult.Sqrt(sum / TResult.CreateSaturating(values.Count() - 1));
    }

    return standardDeviation;
}


Они среднеквадратическое за два прохода считают что ли?
Похоже и среднее тоже по методу "сложить и поделить" ...
Re[2]: offtop: сортировщики гномиков
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.07.22 04:19
Оценка: +1
Здравствуйте, syrompe, Вы писали:
S>Они среднеквадратическое за два прохода считают что ли?
По исходнику — да. Ну это ж пример на пальцах.
S>Похоже и среднее тоже по методу "сложить и поделить" ...
В статье прямо над кодом StandardDeviation приведён код Average:
public static TResult Average<T, TResult>(IEnumerable<T> values)
    where T : INumber<T>
    where TResult : INumber<TResult>
{
    TResult sum = Sum<T, TResult>(values);
    return TResult.CreateChecked(sum) / TResult.CreateChecked(values.Count());
}

Ну, и код Sum тоже приведён:
public static TResult Sum<T, TResult>(IEnumerable<T> values)
    where T : INumber<T>
    where TResult : INumber<TResult>
{
    TResult result = TResult.Zero;

    foreach (var value in values)
    {
        result += TResult.CreateChecked(value);
    }

    return result;
}

Так что да — сложить и поделить. А вы бы что предложили? Меня в приведённых примерах беспокоит разве что потеря точности.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: offtop: сортировщики гномиков
От: syrompe  
Дата: 20.07.22 07:58
Оценка:
S>Так что да — сложить и поделить. А вы бы что предложили? Меня в приведённых примерах беспокоит разве что потеря точности.

С интами будет переполнение в аккумуляторе. Можно аккумулятор long сделать это в принципе решит проблему, но не ложится на эти абстракции.
С float при суммировании будут складываться числа разных размерностей со всеми вытекающими.

S(0)=0
S(n+1)=(a_n+1-S(n))/(n+1)+S(n)

По этой методе недостатков округления сильно меньше (они есть, но результат устойчив). Вот забыл совсем как формула называется, если кто помнит подскажите плз.

Но что с дисперсией что со средним абстракции подтекают.
Re[4]: offtop: сортировщики гномиков
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.07.22 08:49
Оценка:
Здравствуйте, syrompe, Вы писали:
S>С интами будет переполнение в аккумуляторе. Можно аккумулятор long сделать это в принципе решит проблему, но не ложится на эти абстракции.
Не будет. Вы не можете параметризовать приведённый метод StandardDeviation интами, т.к. ни int ни long не реализуют IFloatingPointIeee754<T>.
А для Average всё прекрасно ложится — делаете Average<int, long>(t).

S>С float при суммировании будут складываться числа разных размерностей со всеми вытекающими.

Да, это то, на что я намекал в

Меня в приведённых примерах беспокоит разве что потеря точности.


S>

S>S(0)=0
S>S(n+1)=(a_n+1-S(n))/(n+1)+S(n)

S>По этой методе недостатков округления сильно меньше (они есть, но результат устойчив). Вот забыл совсем как формула называется, если кто помнит подскажите плз.
Тут есть некоторая сложность. Если по этой методе усреднять целые числа, то получится пежня из-за округления промежуточных результатов.
Попробуйте посчитать Average<int, long>(new[] {1, 2, 3, 4, 5}).
Заставлять всегда считать среднее только в плавающей запятой — так себе идея.
Можно сделать две версии — IntAverage и FloatAverage, т.к. в дотнете нельзя сделать перегрузки методов, которые бы отличались только констреинтами на дженериках.
А можно просто взять для суммирования Алгоритм Кэхэна. Для плавающей запятой он минимизирует погрешности; для целых чисел его, скорее всего, JIT сведёт к тому же бинарному коду, что и простое суммирование.

Но для достижения счастья нам, конечно же, понадобится что-то вроде этого: http://blog.zachbjornson.com/2019/08/11/fast-float-summation.html
То есть вычисление суммы всё же придётся делать не-дженерик, а специфично для конкретного типа. В реальной боевой библиотеке код Sum<T, TResult> скорее всего будет выглядеть как набор if(typeof(T) == typeof(int64))..., т.к. в дотнете это единственный способ сделать специализацию дженерика без потери производительности.
Зато вот код Average и StandardDeviation опишется обобщённым способом.

Правда, потом нас не устроит вычисление суммы квадратов отдельным проходом. Мы выкинем нафиг функцию Average, и запилим алгоритмы в зависимости от используемых типов. То есть — берём за основу что-то отсюда: https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance, и ускоряем при помощи SIMD.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: offtop: сортировщики гномиков
От: syrompe  
Дата: 20.07.22 12:40
Оценка:
S>А для Average всё прекрасно ложится — делаете Average<int, long>(t).
мне бы хотелось таки int на входе, long в сумме и double на выходе:


  System.Linq.Enumerable.Average
        public static double Average(this IEnumerable<int> source) {
            if (source == null) throw Error.ArgumentNull("source");
            long sum = 0;
            long count = 0;
            checked {
                foreach (int v in source) {
                    sum += v;
                    count++;
                }
            }
            if (count > 0) return (double)sum / count;
            throw Error.NoElements();
        }
Re[6]: offtop: сортировщики гномиков
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.07.22 13:42
Оценка: 7 (1) +1
Здравствуйте, syrompe, Вы писали:

S>>А для Average всё прекрасно ложится — делаете Average<int, long>(t).

S>мне бы хотелось таки int на входе, long в сумме и double на выходе.
Ну, если хочется, то почему нет?
public static TResult Average<T, TSum, TResult>(IEnumerable<T> values)
    where T : INumber<T>
    where TSum : INumber<TSum>
    where TResult : INumber<TResult>
 
{
    TSum sum = Sum<T, TSum>(values);
    return TResult.CreateChecked(sum) / TResult.CreateChecked(values.Count());
}

Хотя при таких условиях проще уже написать необобщённую версию
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 20.07.2022 14:23 Sinclair . Предыдущая версия .
Re[5]: offtop: сортировщики гномиков
От: Ночной Смотрящий Россия  
Дата: 21.07.22 19:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Можно сделать две версии — IntAverage и FloatAverage, т.к. в дотнете нельзя сделать перегрузки методов, которые бы отличались только констреинтами на дженериках.


Можно в рантайме выбирать алгоритм. Один дополнительный type check на более менее длинных последовательностях сильно не повлияет. В Enumerable именно так выбираются специализированные алгоритмы для ICollection и [].
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[6]: offtop: сортировщики гномиков
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.07.22 03:58
Оценка: 7 (1)
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Можно в рантайме выбирать алгоритм. Один дополнительный type check на более менее длинных последовательностях сильно не повлияет. В Enumerable именно так выбираются специализированные алгоритмы для ICollection и [].

Если правильно реализовать, то в нативном коде тайпчека не будет. Джит умеет оптимизировать if(typeof(IFloatingPointIeee754<T>).IsAssignableFrom(T)): https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABAJgEYBYAKGIAYACY8lAbhvoYGUALbKAA4AZbMAB0AJQCuAOwwBLfDHa0AzE1IMAwgwDeNBoabr5cmFABm2MDAYBJAEL8APABUAfAaP7qRhgF8vQ2J1XAwoKTAMBicALyC9BMDfIxCGMIiomP4QeycoZ3zPFMMfP2S/AG0AKXkMAHEYGXN5MAAKDABPARgICza4gEpBtAZahqaW9q6evoH+YYBdBLTmJAZTaIAxCAg3dzbBhLK/I3l+md7+xxcPQbE7XABBXFx5AHMZUQAbGC2oCD4DrdK5tVzDI4lU4nU6nYgAdgYKFIKlhhgqaJg31wMASaKYiIArEhUUZkv4gA

Но это всё же выглядит как закат солнца вручную.
И, как я уже говорил, на следующем этапе нам придётся сделать switch по конкретным типам, т.к. SIMD-интринсики не обобщаются.

Хотя, можно попробовать сделать генеричную обёртку вокруг интринсиков, с тем же type switch внутри. Но сходу неясно, получится ли результирующий код хоть сколько-то более понятным.
Ну, и для SIMD всё же придётся сделать рантайм-проверку наличия в процессоре соответствующих инструкций. Заинлайнить всё полностью уже не получится — лучшее, что можно сделать, так это при прогреве получить (неуправляемый) указатель на наиболее подходящую версию кода для текущей архитектуры, и диспетчеризовать в неё. Не уверен, что это будет лучше, чем честная рантайм-проверка типа.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: offtop: сортировщики гномиков
От: Ночной Смотрящий Россия  
Дата: 22.07.22 10:49
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


И это тоже.

S>Но это всё же выглядит как закат солнца вручную.


Для подобных задач — не смертельно.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.