26.06.10 - 12.00

This commit is contained in:
melekhin
2026-06-10 11:58:39 +07:00
parent fd381586e9
commit e1fffb1e94
9 changed files with 3953 additions and 311 deletions

View File

@@ -29,14 +29,18 @@ internal static partial class CastExtensions
mimic.Size = count;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<T> WrapAsList<T>(this T[] array)
internal static List<R> WrapAsList<T, R>(this T[] array)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
// Создаём пустой список с нулевой ёмкостью
var list = new List<T>(0);
var list = new List<R>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<T>, ListLayoutMimic<T>>(ref list);
ref var mimic = ref Unsafe.As<List<R>, ListLayoutMimic<T>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
@@ -47,13 +51,96 @@ internal static partial class CastExtensions
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<R> WrapAsList<T, R>(this T[] array)
internal static List<R?> WrapAsList<T, R>(this T?[] array)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
return Unsafe.As<T[], R[]>(ref array).WrapAsList();
// Создаём пустой список с нулевой ёмкостью
var list = new List<R?>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<R?>, ListLayoutMimic<T?>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
mimic.Size = array.Length;
mimic.Version = 1; // любое ненулевое значение для консистенции
return list;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<double> WrapAsList<T>(this T[] array)
where T : struct, IMensuraUnit, IEquatable<T>
{
// Создаём пустой список с нулевой ёмкостью
var list = new List<double>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<double>, ListLayoutMimic<T>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
mimic.Size = array.Length;
mimic.Version = 1; // любое ненулевое значение для консистенции
return list;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<double?> WrapAsList<T>(this T?[] array)
where T : struct, IMensuraUnit, IEquatable<T>
{
// Создаём пустой список с нулевой ёмкостью
var list = new List<double?>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<double?>, ListLayoutMimic<T?>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
mimic.Size = array.Length;
mimic.Version = 1; // любое ненулевое значение для консистенции
return list;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<double> WrapAsList(this double[] array)
{
// Создаём пустой список с нулевой ёмкостью
var list = new List<double>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<double>, ListLayoutMimic<double>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
mimic.Size = array.Length;
mimic.Version = 1; // любое ненулевое значение для консистенции
return list;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<double?> WrapAsList(this double?[] array)
{
// Создаём пустой список с нулевой ёмкостью
var list = new List<double?>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<double?>, ListLayoutMimic<double?>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
mimic.Size = array.Length;
mimic.Version = 1; // любое ненулевое значение для консистенции
return list;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<R> ReCast<T, R>(this List<T> list)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -70,6 +157,20 @@ internal static partial class CastExtensions
return Unsafe.As<List<T?>, List<R?>>(ref list);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<double> ReCast<T>(this List<T> list)
where T : struct, IMensuraUnit, IEquatable<T>
{
return Unsafe.As<List<T>, List<double>>(ref list);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<double?> ReCast<T>(this List<T?> list)
where T : struct, IMensuraUnit, IEquatable<T>
{
return Unsafe.As<List<T?>, List<double?>>(ref list);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static R[] ReCast<T, R>(this T[] array)
where T : struct, IMensuraUnit, IEquatable<T>

View File

@@ -225,7 +225,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new R[count];
DivideCore(CollectionsMarshal.AsSpan(units), divisor, count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Div<T, R>(this List<T?> units, double divisor)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -237,7 +237,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new R?[count];
DivideCore(CollectionsMarshal.AsSpan(units), divisor, count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R> Div<T, R>(this double dividend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -249,7 +249,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new R[count];
DivideCore(dividend, CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Div<T, R>(this double dividend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -261,7 +261,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new R?[count];
DivideCore(dividend, CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
// === ICollection<T> ===
@@ -634,7 +634,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new T[len];
Div(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Div<T>(this List<T?> units, double divisor)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -645,7 +645,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new T?[count];
Div(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T> Div<T>(this double dividend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -656,7 +656,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new T[count];
Div(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Div<T>(this double dividend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -667,7 +667,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new T?[count];
Div(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
// === ICollection<T> ===
@@ -931,14 +931,13 @@ internal static partial class CollectionsDivideExtensions
// === DivideCore === SIMD
internal static void DivCore<T, R>(this ReadOnlySpan<double> dividends, T unit, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
internal static void DivCore<R>(this ReadOnlySpan<double> dividends, double unit, int len, Span<R> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
// Вместо деления в цикле, умножаем на обратное число (invDivisor)
double invDivisor = 1.0 / unit.ToDouble();
double invDivisor = 1.0 / unit;
var vectorizedInvDivisor = new Vector<double>(invDivisor);
int vectorSize = Vector<double>.Count;
@@ -967,8 +966,7 @@ internal static partial class CollectionsDivideExtensions
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * invDivisor;
}
}
internal static void DivCore<T, R>(this ReadOnlySpan<double?> dividends, T unit, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
internal static void DivCore<R>(this ReadOnlySpan<double?> dividends, double unit, int len, Span<R?> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
@@ -977,15 +975,15 @@ internal static partial class CollectionsDivideExtensions
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
double invDivisor = 1.0 / unit.ToDouble();
double invDivisor = 1.0 / unit;
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
double? u0 = Unsafe.Add(ref srcRef, i);
double? u1 = Unsafe.Add(ref srcRef, i + 1);
double? u2 = Unsafe.Add(ref srcRef, i + 2);
double? u3 = Unsafe.Add(ref srcRef, i + 3);
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
@@ -1003,21 +1001,19 @@ internal static partial class CollectionsDivideExtensions
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
double? div = Unsafe.Add(ref srcRef, i);
var div = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = div.HasValue ? (div.Value * invDivisor).ToUnit<R>() : null;
}
}
//SIMD
internal static void DivCore<T, R>(this T unit, ReadOnlySpan<double> divisors, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
internal static void DivCore<R>(this double unit, ReadOnlySpan<double> divisors, int len, Span<R> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
var dUnit = unit.ToDouble();
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
var vectorizedDividend = new Vector<double>(dUnit);
var vectorizedDividend = new Vector<double>(unit);
int vectorSize = Vector<double>.Count;
int i = 0;
@@ -1042,14 +1038,12 @@ internal static partial class CollectionsDivideExtensions
// Хвост
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = dUnit / Unsafe.Add(ref srcRef, i);
Unsafe.Add(ref dstRef, i) = unit / Unsafe.Add(ref srcRef, i);
}
}
internal static void DivCore<T, R>(this T unit, ReadOnlySpan<double?> divisors, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
internal static void DivCore<R>(this double unit, ReadOnlySpan<double?> divisors, int len, Span<R?> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
var dUnit = unit.ToDouble();
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(divisors);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
@@ -1060,10 +1054,10 @@ internal static partial class CollectionsDivideExtensions
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
double? u0 = Unsafe.Add(ref srcRef, i);
double? u1 = Unsafe.Add(ref srcRef, i + 1);
double? u2 = Unsafe.Add(ref srcRef, i + 2);
double? u3 = Unsafe.Add(ref srcRef, i + 3);
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
@@ -1072,19 +1066,19 @@ internal static partial class CollectionsDivideExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (dUnit / u0.Value).ToUnit<R>() : null;
d1 = u1.HasValue ? (dUnit / u1.Value).ToUnit<R>() : null;
d2 = u2.HasValue ? (dUnit / u2.Value).ToUnit<R>() : null;
d3 = u3.HasValue ? (dUnit / u3.Value).ToUnit<R>() : null;
d0 = u0.HasValue ? (unit / u0.Value).ToUnit<R>() : null;
d1 = u1.HasValue ? (unit / u1.Value).ToUnit<R>() : null;
d2 = u2.HasValue ? (unit / u2.Value).ToUnit<R>() : null;
d3 = u3.HasValue ? (unit / u3.Value).ToUnit<R>() : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
double? div = Unsafe.Add(ref srcRef, i);
var div = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = div.HasValue ? (unit.ToDouble() / div.Value).ToUnit<R>() : null;
dst = div.HasValue ? (unit / div.Value).ToUnit<R>() : null;
}
}
@@ -1246,7 +1240,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.DivCore(divisor, len, destination);
units.DivCore(divisor.ToDouble(), len, destination);
}
internal static void Div<T>(this ReadOnlySpan<double?> units, T divisor, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1256,7 +1250,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.DivCore(divisor, len, destination);
units.DivCore(divisor.ToDouble(), len, destination);
}
internal static void Div<T>(this T dividend, ReadOnlySpan<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1266,7 +1260,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.DivCore(units, len, destination);
dividend.ToDouble().DivCore(units, len, destination);
}
internal static void Div<T>(this T dividend, ReadOnlySpan<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1276,7 +1270,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.DivCore(units, len, destination);
dividend.ToDouble().DivCore(units, len, destination);
}
// === Array ===
@@ -1335,7 +1329,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new T[len];
Div(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Div<T>(this List<double?> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1346,7 +1340,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new T?[count];
Div(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T> Div<T>(this T dividend, List<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1357,7 +1351,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new T[count];
Div(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Div<T>(this T dividend, List<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1368,7 +1362,7 @@ internal static partial class CollectionsDivideExtensions
var resultArray = new T?[count];
Div(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
// === ICollection<T> ===
@@ -1512,33 +1506,33 @@ internal static partial class CollectionsDivideExtensions
}
// === IEnumerable<T> + yeild ===
static IEnumerable<T> DivideIterator<T>(IEnumerable<double> units, T divisor)
static IEnumerable<T> DivideIterator<T>(IEnumerable<double> units, double divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
double invDivisor = 1.0 / divisor.ToDouble();
double invDivisor = 1.0 / divisor;
foreach (var item in units)
yield return (item * invDivisor).ToUnit<T>();
}
static IEnumerable<T?> DivideNullableIterator<T>(IEnumerable<double?> units, T divisor)
static IEnumerable<T?> DivideNullableIterator<T>(IEnumerable<double?> units, double divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
double invDivisor = 1.0 / divisor.ToDouble();
double invDivisor = 1.0 / divisor;
foreach (var item in units)
yield return item.HasValue
? (item.Value * invDivisor).ToUnit<T>() : null;
}
static IEnumerable<T> DivideIterator<T>(T dividend, IEnumerable<double> units)
static IEnumerable<T> DivideIterator<T>(double dividend, IEnumerable<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return (dividend.ToDouble() / item).ToUnit<T>();
yield return (dividend / item).ToUnit<T>();
}
static IEnumerable<T?> DivideNullableIterator<T>(T dividend, IEnumerable<double?> units)
static IEnumerable<T?> DivideNullableIterator<T>(double dividend, IEnumerable<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return item.HasValue
? (dividend.ToDouble() / item.Value).ToUnit<T>() : null;
? (dividend / item.Value).ToUnit<T>() : null;
}
// === IEnumerable<T> ===
@@ -1560,7 +1554,7 @@ internal static partial class CollectionsDivideExtensions
arr.DivCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return DivideIterator(units, divisor);
return DivideIterator<T>(units, divisor.ToDouble());
}
internal static IEnumerable<T?> Div<T>(this IEnumerable<double?> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1580,7 +1574,7 @@ internal static partial class CollectionsDivideExtensions
arr.DivCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return DivideNullableIterator(units, divisor);
return DivideNullableIterator<T>(units, divisor.ToDouble());
}
internal static IEnumerable<T> Div<T>(this T dividend, IEnumerable<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1600,7 +1594,7 @@ internal static partial class CollectionsDivideExtensions
dividend.ToDouble().DivCore(arr, arr.Length, arr);
return arr.ReCast<T>();
}
return DivideIterator(dividend, units);
return DivideIterator<T>(dividend.ToDouble(), units);
}
internal static IEnumerable<T?> Div<T>(this T dividend, IEnumerable<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1620,6 +1614,556 @@ internal static partial class CollectionsDivideExtensions
dividend.ToDouble().DivCore(arr, arr.Length, arr);
return arr.ReCast<T>();
}
return DivideNullableIterator<T>(dividend.ToDouble(), units);
}
// === DivideCore === SIMD
internal static void DivideCore<T>(this ReadOnlySpan<T> units, double divisor, int len, Span<double> dstDouble)
where T : struct, IMensuraUnit, IEquatable<T>
{
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
// Вместо деления в цикле, умножаем на обратное число (invDivisor)
double invDivisor = 1.0 / divisor;
var vectorizedInvDivisor = new Vector<double>(invDivisor);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
// Загрузка, быстрое умножение вместо деления, и сохранение
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
var multiplied = vector * vectorizedInvDivisor;
Unsafe.As<double, Vector<double>>(ref currentDst) = multiplied;
}
// Хвост
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * invDivisor;
}
}
internal static void DivideCore<T>(this ReadOnlySpan<T?> units, double divisor, int len, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
double invDivisor = 1.0 / divisor;
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
T? u0 = Unsafe.Add(ref srcRef, i);
T? u1 = Unsafe.Add(ref srcRef, i + 1);
T? u2 = Unsafe.Add(ref srcRef, i + 2);
T? u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? u0.Value.ToDouble() * invDivisor : null;
d1 = u1.HasValue ? u1.Value.ToDouble() * invDivisor : null;
d2 = u2.HasValue ? u2.Value.ToDouble() * invDivisor : null;
d3 = u3.HasValue ? u3.Value.ToDouble() * invDivisor : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? unit.Value.ToDouble() * invDivisor : null;
}
}
//SIMD
internal static void DivideCore<T>(this double dividend, ReadOnlySpan<T> units, int len, Span<double> dstDouble)
where T : struct, IMensuraUnit, IEquatable<T>
{
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
var vectorizedDividend = new Vector<double>(dividend);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
// Векторное деление: константа делится на покомпонентные элементы массива
var divided = Vector.Divide(vectorizedDividend, vector);
Unsafe.As<double, Vector<double>>(ref currentDst) = divided;
}
// Хвост
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = dividend / Unsafe.Add(ref srcRef, i);
}
}
internal static void DivideCore<T>(this double dividend, ReadOnlySpan<T?> units, int len, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
T? u0 = Unsafe.Add(ref srcRef, i);
T? u1 = Unsafe.Add(ref srcRef, i + 1);
T? u2 = Unsafe.Add(ref srcRef, i + 2);
T? u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? dividend / u0.Value.ToDouble() : null;
d1 = u1.HasValue ? dividend / u1.Value.ToDouble() : null;
d2 = u2.HasValue ? dividend / u2.Value.ToDouble() : null;
d3 = u3.HasValue ? dividend / u3.Value.ToDouble() : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? dividend / unit.Value.ToDouble() : null;
}
}
// === ReadOnlySpan
internal static void Div<T>(this ReadOnlySpan<T> units, T divisor, Span<double> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.DivideCore(divisor.ToDouble(), len, destination);
}
internal static void Div<T>(this ReadOnlySpan<T?> units, T divisor, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.DivideCore(divisor.ToDouble(), len, destination);
}
internal static void Div<T>(this T dividend, ReadOnlySpan<T> units, Span<double> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.ToDouble().DivideCore(units, len, destination);
}
internal static void Div<T>(this T dividend, ReadOnlySpan<T?> units, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.ToDouble().DivideCore(units, len, destination);
}
// === Array ===
internal static double[] Div<T>(this T[] units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T[len];
units.DivideCore(divisor.ToDouble(), len, result);
return result.ReCast();
}
internal static double?[] Div<T>(this T?[] units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T?[len];
units.DivideCore(divisor.ToDouble(), len, result);
return result.ReCast();
}
internal static double[] Div<T>(this T dividend, T[] units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T[len];
dividend.ToDouble().DivideCore(units, len, result);
return result.ReCast();
}
internal static double?[] Div<T>(this T dividend, T?[] units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T?[len];
dividend.ToDouble().DivideCore(units, len, result);
return result.ReCast();
}
// === List<T> ===
internal static List<double> Div<T>(this List<T> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
var resultArray = new double[len];
CollectionsMarshal.AsSpan(units).DivideCore(divisor.ToDouble(), len, resultArray);
return resultArray.WrapAsList();
}
internal static List<double?> Div<T>(this List<T?> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new double?[count];
CollectionsMarshal.AsSpan(units).DivideCore(divisor.ToDouble(), count, resultArray);
return resultArray.WrapAsList();
}
internal static List<double> Div<T>(this T dividend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[count];
dividend.ToDouble().DivideCore(CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList();
}
internal static List<double?> Div<T>(this T dividend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
dividend.ToDouble().DivideCore(CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList();
}
// === ICollection<T> ===
internal static void Div<T>(this ICollection<T> units, T divisor, Span<double> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is T[] array) { array.Div(divisor, destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
int i = 0;
double invDivisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = item.ToDouble() * invDivisor;
}
internal static void Div<T>(this ICollection<T?> units, T divisor, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is T?[] array) { array.Div(divisor, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
int i = 0;
double invDivisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue ? item.Value.ToDouble() * invDivisor : null;
}
internal static void Div<T>(this T dividend, ICollection<T> units, Span<double> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is T[] array) { dividend.Div(array, destination); return; }
if (units is List<T> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
int i = 0;
var div = dividend.ToDouble();
foreach (var item in units)
destination[i++] = div / item.ToDouble();
}
internal static void Div<T>(this T dividend, ICollection<T?> units, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is T?[] array) { dividend.Div(array, destination); return; }
if (units is List<T?> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
int i = 0;
var div = dividend.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue ? div / item.Value.ToDouble() : null;
}
// === IReadOnlyCollection<T> ===
internal static void Div<T>(this IReadOnlyCollection<T> units, T divisor, Span<double> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is T[] array) { array.Div(divisor, destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
int i = 0;
double invDivisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = item.ToDouble() * invDivisor;
}
internal static void Div<T>(this IReadOnlyCollection<T?> units, T divisor, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is T?[] array) { array.Div(divisor, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
int i = 0;
double invDivisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue ? item.Value.ToDouble() * invDivisor : null;
}
internal static void Div<T>(this T dividend, IReadOnlyCollection<T> units, Span<double> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is T[] array) { dividend.Div(array, destination); return; }
if (units is List<T> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
int i = 0;
var div = dividend.ToDouble();
foreach (var item in units)
destination[i++] = div / item.ToDouble();
}
internal static void Div<T>(this T dividend, IReadOnlyCollection<T?> units, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is T?[] array) { dividend.Div(array, destination); return; }
if (units is List<T?> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
int i = 0;
var div = dividend.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue ? div / item.Value.ToDouble() : null;
}
// === IEnumerable<T> + yeild ===
static IEnumerable<double> DivideIterator<T>(IEnumerable<T> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
double invDivisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
yield return item.ToDouble() * invDivisor;
}
static IEnumerable<double?> DivideNullableIterator<T>(IEnumerable<T?> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
double invDivisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
yield return item.HasValue ? item.Value.ToDouble() * invDivisor : null;
}
static IEnumerable<double> DivideIterator<T>(T dividend, IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
var div = dividend.ToDouble();
foreach (var item in units)
yield return div / item.ToDouble();
}
static IEnumerable<double?> DivideNullableIterator<T>(T dividend, IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
var div = dividend.ToDouble();
foreach (var item in units)
yield return item.HasValue ? div / item.Value.ToDouble() : null;
}
// === IEnumerable<T> ===
internal static IEnumerable<double> Div<T>(this IEnumerable<T> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is T[] array) return array.Div(divisor);
if (units is List<T> list) return list.Div(divisor);
if (units is ICollection<T> col)
{
var arr = col.ToArray();
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast();
}
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast();
}
return DivideIterator(units, divisor);
}
internal static IEnumerable<double?> Div<T>(this IEnumerable<T?> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is T?[] array) return array.Div(divisor);
if (units is List<T?> list) return list.Div(divisor);
if (units is ICollection<T?> col)
{
var arr = col.ToArray();
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast();
}
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast();
}
return DivideNullableIterator(units, divisor);
}
internal static IEnumerable<double> Div<T>(this T dividend, IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is T[] array) return dividend.Div(array);
if (units is List<T> list) return dividend.Div(list);
if (units is ICollection<T> col)
{
var arr = col.ToArray();
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
return arr.ReCast();
}
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
return arr.ReCast();
}
return DivideIterator(dividend, units);
}
internal static IEnumerable<double?> Div<T>(this T dividend, IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is T?[] array) return dividend.Div(array);
if (units is List<T?> list) return dividend.Div(list);
if (units is ICollection<T?> col)
{
var arr = col.ToArray();
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
return arr.ReCast();
}
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
return arr.ReCast();
}
return DivideNullableIterator(dividend, units);
}
}

View File

@@ -220,7 +220,7 @@ internal static partial class CollectionsMinusExtensions
var resultArray = new R[count];
MinusCore(CollectionsMarshal.AsSpan(units), subtrahend, count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Minus<T, R>(this List<T?> units, double subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -232,7 +232,7 @@ internal static partial class CollectionsMinusExtensions
var resultArray = new R?[count];
MinusCore(CollectionsMarshal.AsSpan(units), subtrahend, count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R> Minus<T, R>(this double minuend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -244,7 +244,7 @@ internal static partial class CollectionsMinusExtensions
var resultArray = new R[count];
MinusCore(minuend, CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Minus<T, R>(this double minuend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -256,7 +256,7 @@ internal static partial class CollectionsMinusExtensions
var resultArray = new R?[count];
MinusCore(minuend, CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
// === ICollection<T> ===
@@ -624,7 +624,7 @@ internal static partial class CollectionsMinusExtensions
var resultArray = new T[len];
Minus(CollectionsMarshal.AsSpan(units), subtrahend, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Minus<T>(this List<T?> units, double subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -635,7 +635,7 @@ internal static partial class CollectionsMinusExtensions
var resultArray = new T?[count];
Minus(CollectionsMarshal.AsSpan(units), subtrahend, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T> Minus<T>(this double minuend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -646,7 +646,7 @@ internal static partial class CollectionsMinusExtensions
var resultArray = new T[count];
Minus(minuend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Minus<T>(this double minuend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -657,7 +657,7 @@ internal static partial class CollectionsMinusExtensions
var resultArray = new T?[count];
Minus(minuend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
// === ICollection<T> ===
@@ -905,4 +905,689 @@ internal static partial class CollectionsMinusExtensions
}
return MinusNullableIterator(minuend, units);
}
// === MinusCore === SIMD
internal static void MinusCore<R>(this ReadOnlySpan<double> srcDouble, double subtrahend, int len, Span<R> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
var vectorizedSubtrahend = new Vector<double>(subtrahend);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
var subtracted = vector - vectorizedSubtrahend;
Unsafe.As<double, Vector<double>>(ref currentDst) = subtracted;
}
// Хвост
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend;
}
}
internal static void MinusCore<R>(this ReadOnlySpan<double?> units, double subtrahend, int len, Span<R?> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value - subtrahend).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value - subtrahend).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value - subtrahend).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value - subtrahend).ToUnit<R>() : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value - subtrahend).ToUnit<R>() : null;
}
}
//SIMD
internal static void MinusCore<R>(this double minuend, ReadOnlySpan<double> srcDouble, int len, Span<R> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
var vectorizedMinuend = new Vector<double>(minuend);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
// Векторное вычитание: константа уменьшается на покомпонентные элементы массива
var subtracted = vectorizedMinuend - vector;
Unsafe.As<double, Vector<double>>(ref currentDst) = subtracted;
}
// Хвост
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = minuend - Unsafe.Add(ref srcRef, i);
}
}
internal static void MinusCore<R>(this double minuend, ReadOnlySpan<double?> units, int len, Span<R?> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (minuend - u0.Value).ToUnit<R>() : null;
d1 = u1.HasValue ? (minuend - u1.Value).ToUnit<R>() : null;
d2 = u2.HasValue ? (minuend - u2.Value).ToUnit<R>() : null;
d3 = u3.HasValue ? (minuend - u3.Value).ToUnit<R>() : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (minuend - unit.Value).ToUnit<R>() : null;
}
}
// === DivideCore === SIMD
internal static void MinusCore(this ReadOnlySpan<double> srcDouble, double subtrahend, int len, Span<double> dstDouble)
{
var vectorizedSubtrahend = new Vector<double>(subtrahend);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
var subtracted = vector - vectorizedSubtrahend;
Unsafe.As<double, Vector<double>>(ref currentDst) = subtracted;
}
// Хвост
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend;
}
}
internal static void MinusCore(this ReadOnlySpan<double?> units, double subtrahend, int len, Span<double?> destination)
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? u0.Value - subtrahend : null;
d1 = u1.HasValue ? u1.Value - subtrahend : null;
d2 = u2.HasValue ? u2.Value - subtrahend : null;
d3 = u3.HasValue ? u3.Value - subtrahend : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? unit.Value - subtrahend : null;
}
}
//SIMD
internal static void MinusCore(this double minuend, ReadOnlySpan<double> srcDouble, int len, Span<double> dstDouble)
{
var vectorizedMinuend = new Vector<double>(minuend);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
// Векторное вычитание: константа уменьшается на покомпонентные элементы массива
var subtracted = vectorizedMinuend - vector;
Unsafe.As<double, Vector<double>>(ref currentDst) = subtracted;
}
// Хвост
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = minuend - Unsafe.Add(ref srcRef, i);
}
}
internal static void MinusCore(this double minuend, ReadOnlySpan<double?> units, int len, Span<double?> destination)
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? minuend - u0.Value : null;
d1 = u1.HasValue ? minuend - u1.Value : null;
d2 = u2.HasValue ? minuend - u2.Value : null;
d3 = u3.HasValue ? minuend - u3.Value : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? minuend - unit.Value : null;
}
}
// === ReadOnlySpan
internal static void Minus<T>(this ReadOnlySpan<double> units, T divisor, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MinusCore(divisor.ToDouble(), len, destination);
}
internal static void Minus<T>(this ReadOnlySpan<double?> units, T divisor, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MinusCore(divisor.ToDouble(), len, destination);
}
internal static void Minus<T>(this T dividend, ReadOnlySpan<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.ToDouble().MinusCore(units, len, destination);
}
internal static void Minus<T>(this T dividend, ReadOnlySpan<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.ToDouble().MinusCore(units, len, destination);
}
// === Array ===
internal static T[] Minus<T>(this double[] units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T[len];
Minus(units, divisor, result);
return result;
}
internal static T?[] Minus<T>(this double?[] units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T?[len];
Minus(units, divisor, result);
return result;
}
internal static T[] Minus<T>(this T dividend, double[] units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T[len];
Minus(dividend, units, result);
return result;
}
internal static T?[] Minus<T>(this T dividend, double?[] units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T?[len];
Minus(dividend, units, result);
return result;
}
// === List<T> ===
internal static List<T> Minus<T>(this List<double> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
var resultArray = new T[len];
Minus(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Minus<T>(this List<double?> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Minus(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList<T, T>();
}
internal static List<T> Minus<T>(this T dividend, List<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[count];
Minus(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Minus<T>(this T dividend, List<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Minus(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
}
// === ICollection<T> ===
internal static void Minus<T>(this ICollection<double> units, T divisor, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double[] array) { array.Minus(divisor, destination); return; }
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).Minus(divisor, destination); return; }
int i = 0;
double invMinusisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = (item * invMinusisor).ToUnit<T>();
}
internal static void Minus<T>(this ICollection<double?> units, T divisor, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double?[] array) { array.Minus(divisor, destination); return; }
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).Minus(divisor, destination); return; }
int i = 0;
double invMinusisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value * invMinusisor).ToUnit<T>() : null;
}
internal static void Minus<T>(this T dividend, ICollection<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double[] array) { dividend.Minus(array, destination); return; }
if (units is List<double> list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = (dividend.ToDouble() / item).ToUnit<T>();
}
internal static void Minus<T>(this T dividend, ICollection<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double?[] array) { dividend.Minus(array, destination); return; }
if (units is List<double?> list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (dividend.ToDouble() / item.Value).ToUnit<T>() : null;
}
// === IReadOnlyCollection<T> ===
internal static void Minus<T>(this IReadOnlyCollection<double> units, T divisor, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double[] array) { array.Minus(divisor, destination); return; }
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).Minus(divisor, destination); return; }
int i = 0;
double invMinusisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = (item * invMinusisor).ToUnit<T>();
}
internal static void Minus<T>(this IReadOnlyCollection<double?> units, T divisor, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double?[] array) { array.Minus(divisor, destination); return; }
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).Minus(divisor, destination); return; }
int i = 0;
double invMinusisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value * invMinusisor).ToUnit<T>() : null;
}
internal static void Minus<T>(this T dividend, IReadOnlyCollection<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double[] array) { dividend.Minus(array, destination); return; }
if (units is List<double> list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = (dividend.ToDouble() / item).ToUnit<T>();
}
internal static void Minus<T>(this T dividend, IReadOnlyCollection<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double?[] array) { dividend.Minus(array, destination); return; }
if (units is List<double?> list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (dividend.ToDouble() / item.Value).ToUnit<T>() : null;
}
// === IEnumerable<T> + yeild ===
static IEnumerable<T> MinusideIterator<T>(IEnumerable<double> units, double divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
double invMinusisor = 1.0 / divisor;
foreach (var item in units)
yield return (item * invMinusisor).ToUnit<T>();
}
static IEnumerable<T?> MinusideNullableIterator<T>(IEnumerable<double?> units, double divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
double invMinusisor = 1.0 / divisor;
foreach (var item in units)
yield return item.HasValue
? (item.Value * invMinusisor).ToUnit<T>() : null;
}
static IEnumerable<T> MinusideIterator<T>(double dividend, IEnumerable<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return (dividend / item).ToUnit<T>();
}
static IEnumerable<T?> MinusideNullableIterator<T>(double dividend, IEnumerable<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return item.HasValue
? (dividend / item.Value).ToUnit<T>() : null;
}
// === IEnumerable<T> ===
internal static IEnumerable<T> Minus<T>(this IEnumerable<double> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double[] array) return array.Minus(divisor);
if (units is List<double> list) return list.Minus(divisor);
if (units is ICollection<double> col)
{
var arr = col.ToArray();
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
if (units is IReadOnlyCollection<double> roc)
{
var arr = roc.ToArray();
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return MinusideIterator<T>(units, divisor.ToDouble());
}
internal static IEnumerable<T?> Minus<T>(this IEnumerable<double?> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double?[] array) return array.Minus(divisor);
if (units is List<double?> list) return list.Minus(divisor);
if (units is ICollection<double?> col)
{
var arr = col.ToArray();
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
if (units is IReadOnlyCollection<double?> roc)
{
var arr = roc.ToArray();
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return MinusideNullableIterator<T>(units, divisor.ToDouble());
}
internal static IEnumerable<T> Minus<T>(this T dividend, IEnumerable<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double[] array) return dividend.Minus(array);
if (units is List<double> list) return dividend.Minus(list);
if (units is ICollection<double> col)
{
var arr = col.ToArray();
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
return arr.ReCast<T>();
}
if (units is IReadOnlyCollection<double> roc)
{
var arr = roc.ToArray();
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
return arr.ReCast<T>();
}
return MinusideIterator<T>(dividend.ToDouble(), units);
}
internal static IEnumerable<T?> Minus<T>(this T dividend, IEnumerable<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double?[] array) return dividend.Minus(array);
if (units is List<double?> list) return dividend.Minus(list);
if (units is ICollection<double?> col)
{
var arr = col.ToArray();
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
return arr.ReCast<T>();
}
if (units is IReadOnlyCollection<double?> roc)
{
var arr = roc.ToArray();
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
return arr.ReCast<T>();
}
return MinusideNullableIterator<T>(dividend.ToDouble(), units);
}
}

View File

@@ -137,7 +137,7 @@ internal static partial class CollectionsMultiplyExtensions
var resultArray = new R[count];
MultiplyCore(CollectionsMarshal.AsSpan(units), multiplicator, count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Mul<T, R>(this List<T?> units, double multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -149,7 +149,7 @@ internal static partial class CollectionsMultiplyExtensions
var resultArray = new R?[count];
MultiplyCore(CollectionsMarshal.AsSpan(units), multiplicator, count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -402,7 +402,7 @@ internal static partial class CollectionsMultiplyExtensions
var resultArray = new T[len];
Mul(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Mul<T>(this List<T?> units, double multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -413,7 +413,7 @@ internal static partial class CollectionsMultiplyExtensions
var resultArray = new T?[count];
Mul(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -574,4 +574,412 @@ internal static partial class CollectionsMultiplyExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static IEnumerable<T?> Mul<T>(this double multiplicator, IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T> => Mul(units, multiplicator);
// === MultiplyCore === SIMD
internal static void MultiplyCore<R>(this ReadOnlySpan<double> srcDouble, double multiplicator, int len, Span<R> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
var vectorizedMultiplicator = new Vector<double>(multiplicator);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
var multiplied = vector * vectorizedMultiplicator;
Unsafe.As<double, Vector<double>>(ref currentDst) = multiplied;
}
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator;
}
}
internal static void MultiplyCore<R>(this ReadOnlySpan<double?> units, double multiplicator, int len, Span<R?> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value * multiplicator).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value * multiplicator).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value * multiplicator).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value * multiplicator).ToUnit<R>() : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value * multiplicator).ToUnit<R>() : null;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore<R>(this double multiplicator, ReadOnlySpan<double> units,
int len, Span<R> destination) where R : struct, IMensuraUnit, IEquatable<R> => units.MultiplyCore(multiplicator, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore<R>(this double multiplicator, ReadOnlySpan<double?> units,
int len, Span<R?> destination) where R : struct, IMensuraUnit, IEquatable<R> => units.MultiplyCore(multiplicator, len, destination);
// === MultiplyCore === SIMD
internal static void MultiplyCore(this ReadOnlySpan<double> srcDouble, double multiplicator, int len, Span<double> dstDouble)
{
var vectorizedMultiplicator = new Vector<double>(multiplicator);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
var multiplied = vector * vectorizedMultiplicator;
Unsafe.As<double, Vector<double>>(ref currentDst) = multiplied;
}
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator;
}
}
internal static void MultiplyCore(this ReadOnlySpan<double?> units, double multiplicator, int len, Span<double?> destination)
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? u0.Value * multiplicator : null;
d1 = u1.HasValue ? u1.Value * multiplicator : null;
d2 = u2.HasValue ? u2.Value * multiplicator : null;
d3 = u3.HasValue ? u3.Value * multiplicator : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? unit.Value * multiplicator : null;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore(this double multiplicator,
ReadOnlySpan<double> units, int len, Span<double> destination) => units.MultiplyCore(multiplicator, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore(this double multiplicator,
ReadOnlySpan<double?> units, int len, Span<double?> destination) => units.MultiplyCore(multiplicator, len, destination);
// === ReadOnlySpan
internal static void Mul<T>(this ReadOnlySpan<double> units, T multiplicator, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MultiplyCore(multiplicator.ToDouble(), len, destination);
}
internal static void Mul<T>(this ReadOnlySpan<double?> units, T multiplicator, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MultiplyCore(multiplicator.ToDouble(), len, destination);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Mul<T>(this T multiplicator, ReadOnlySpan<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Mul<T>(this T multiplicator, ReadOnlySpan<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator, destination);
// === Array ===
internal static T[] Mul<T>(this double[] units, T multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T[len];
Mul(units, multiplicator, result);
return result;
}
internal static T?[] Mul<T>(this double?[] units, T multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T?[len];
Mul(units, multiplicator, result);
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static T[] Mul<T>(this T multiplicator, double[] units)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static T?[] Mul<T>(this T multiplicator, double?[] units)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
// === List<T> ===
internal static List<T> Mul<T>(this List<double> units, T multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
var resultArray = new T[len];
Mul(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Mul<T>(this List<double?> units, T multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Mul(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
return resultArray.WrapAsList<T, T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<T> Mul<T>(this T multiplicator, List<double> units)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<T?> Mul<T>(this T multiplicator, List<double?> units)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
// === ICollection<T> ===
internal static void Mul<T>(this ICollection<double> units, T multiplicator, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double[] array) { array.MultiplyCore(multiplicator.ToDouble(), array.Length, destination); return; }
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).MultiplyCore(multiplicator.ToDouble(), list.Count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = (item * multiplicator.ToDouble()).ToUnit<T>();
}
internal static void Mul<T>(this ICollection<double?> units, T multiplicator, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double?[] array) { array.MultiplyCore(multiplicator.ToDouble(), array.Length, destination); return; }
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).MultiplyCore(multiplicator.ToDouble(), list.Count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value * multiplicator.ToDouble()).ToUnit<T>() : null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Mul<T>(this T multiplicator, ICollection<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Mul<T>(this T multiplicator, ICollection<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
// === IReadOnlyCollection<T> ===
internal static void Mul<T>(this IReadOnlyCollection<double> units, T multiplicator, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double[] array) { array.MultiplyCore(multiplicator.ToDouble(), array.Length, destination); return; }
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).MultiplyCore(multiplicator.ToDouble(), list.Count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = (item * multiplicator.ToDouble()).ToUnit<T>();
}
internal static void Mul<T>(this IReadOnlyCollection<double?> units, T multiplicator, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double?[] array) { array.MultiplyCore(multiplicator.ToDouble(), array.Length, destination); return; }
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).MultiplyCore(multiplicator.ToDouble(), list.Count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value * multiplicator.ToDouble()).ToUnit<T>() : null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Mul<T>(this T multiplicator, IReadOnlyCollection<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Mul<T>(this T multiplicator, IReadOnlyCollection<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
// === IEnumerable<T> + yeild ===
internal static IEnumerable<T> MultiplyIterator<T>(this IEnumerable<double> units, double multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return (item * multiplicator).ToUnit<T>();
}
internal static IEnumerable<T?> MultiplyNullableIterator<T>(this IEnumerable<double?> units, double multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return item.HasValue
? (item.Value * multiplicator).ToUnit<T>() : null;
}
// === IEnumerable<T> ===
internal static IEnumerable<T> Mul<T>(this IEnumerable<double> units, T multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double[] array) return array.Mul(multiplicator);
if (units is List<double> list) return list.Mul(multiplicator);
if (units is ICollection<double> col)
{
var arr = col.ToArray();
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
if (units is IReadOnlyCollection<double> roc)
{
var arr = roc.ToArray();
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return MultiplyIterator<T>(units, multiplicator.ToDouble());
}
internal static IEnumerable<T?> Mul<T>(this IEnumerable<double?> units, T multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double?[] array) return array.Mul(multiplicator);
if (units is List<double?> list) return list.Mul(multiplicator);
if (units is ICollection<double?> col)
{
var arr = col.ToArray();
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
if (units is IReadOnlyCollection<double?> roc)
{
var arr = roc.ToArray();
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return MultiplyNullableIterator<T>(units, multiplicator.ToDouble());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static IEnumerable<T> Mul<T>(this T multiplicator, IEnumerable<double> units)
where T : struct, IMensuraUnit, IEquatable<T> => Mul(units, multiplicator);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static IEnumerable<T?> Mul<T>(this T multiplicator, IEnumerable<double?> units)
where T : struct, IMensuraUnit, IEquatable<T> => Mul(units, multiplicator);
}

View File

@@ -138,7 +138,7 @@ internal static partial class CollectionsPlusExtensions
var resultArray = new R[count];
PlusCore(CollectionsMarshal.AsSpan(units), summand, count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Plus<T, R>(this List<T?> units, double summand)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -150,7 +150,7 @@ internal static partial class CollectionsPlusExtensions
var resultArray = new R?[count];
PlusCore(CollectionsMarshal.AsSpan(units), summand, count, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -332,7 +332,7 @@ internal static partial class CollectionsPlusExtensions
// === ReadOnlySpan
internal static void Plus<T>(this ReadOnlySpan<T> units, double multiplicator, Span<T> destination)
internal static void Plus<T>(this ReadOnlySpan<T> units, double summand, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
@@ -340,9 +340,9 @@ internal static partial class CollectionsPlusExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.PlusCore(multiplicator, len, destination);
units.PlusCore(summand, len, destination);
}
internal static void Plus<T>(this ReadOnlySpan<T?> units, double multiplicator, Span<T?> destination)
internal static void Plus<T>(this ReadOnlySpan<T?> units, double summand, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
@@ -350,16 +350,16 @@ internal static partial class CollectionsPlusExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.PlusCore(multiplicator, len, destination);
units.PlusCore(summand, len, destination);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Plus<T>(this double multiplicator, ReadOnlySpan<T> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(multiplicator, destination);
internal static void Plus<T>(this double summand, ReadOnlySpan<T> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Plus<T>(this double multiplicator, ReadOnlySpan<T?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(multiplicator, destination);
internal static void Plus<T>(this double summand, ReadOnlySpan<T?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
// === Array ===
internal static T[] Plus<T>(this T[] units, double summand)
@@ -403,7 +403,7 @@ internal static partial class CollectionsPlusExtensions
var resultArray = new T[len];
Plus(CollectionsMarshal.AsSpan(units), summand, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Plus<T>(this List<T?> units, double summand)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -414,7 +414,7 @@ internal static partial class CollectionsPlusExtensions
var resultArray = new T?[count];
Plus(CollectionsMarshal.AsSpan(units), summand, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<T, T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -575,4 +575,416 @@ internal static partial class CollectionsPlusExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static IEnumerable<T?> Plus<T>(this double summand, IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T> => Plus(units, summand);
// === PlusCore === SIMD
internal static void PlusCore<R>(this ReadOnlySpan<double> srcDouble, double summand, int len, Span<R> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
var vectorizedPlustiplicator = new Vector<double>(summand);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
var multiplied = vector + vectorizedPlustiplicator;
Unsafe.As<double, Vector<double>>(ref currentDst) = multiplied;
}
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand;
}
}
internal static void PlusCore<R>(this ReadOnlySpan<double?> units, double summand, int len, Span<R?> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value + summand).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value + summand).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value + summand).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value + summand).ToUnit<R>() : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value + summand).ToUnit<R>() : null;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void PlusCore<R>(this double summand, ReadOnlySpan<double> units,
int len, Span<R> destination) where R : struct, IMensuraUnit, IEquatable<R> => units.PlusCore(summand, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void PlusCore<R>(this double summand, ReadOnlySpan<double?> units,
int len, Span<R?> destination) where R : struct, IMensuraUnit, IEquatable<R> => units.PlusCore(summand, len, destination);
// === PlusCore === SIMD
internal static void PlusCore(this ReadOnlySpan<double> srcDouble, double summand, int len, Span<double> dstDouble)
{
var vectorizedPlustiplicator = new Vector<double>(summand);
int vectorSize = Vector<double>.Count;
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
int simdEnd = len & ~(vectorSize - 1);
for (; i < simdEnd; i += vectorSize)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
var vector = Unsafe.As<double, Vector<double>>(ref currentSrc);
var multiplied = vector + vectorizedPlustiplicator;
Unsafe.As<double, Vector<double>>(ref currentDst) = multiplied;
}
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand;
}
}
internal static void PlusCore(this ReadOnlySpan<double?> units, double summand, int len, Span<double?> destination)
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Обрабатываем конвейером по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
var u0 = Unsafe.Add(ref srcRef, i);
var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2);
var u3 = Unsafe.Add(ref srcRef, i + 3);
// Получаем ref-ссылки на ячейки назначения (zero-cost адресация)
ref var d0 = ref Unsafe.Add(ref dstRef, i);
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? u0.Value + summand : null;
d1 = u1.HasValue ? u1.Value + summand : null;
d2 = u2.HasValue ? u2.Value + summand : null;
d3 = u3.HasValue ? u3.Value + summand : null;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
for (; i < len; i++)
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? unit.Value + summand : null;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void PlusCore(this double summand,
ReadOnlySpan<double> units, int len, Span<double> destination) => units.PlusCore(summand, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void PlusCore(this double summand,
ReadOnlySpan<double?> units, int len, Span<double?> destination) => units.PlusCore(summand, len, destination);
// === ReadOnlySpan
internal static void Plus<T>(this ReadOnlySpan<double> units, T summand, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.PlusCore(summand.ToDouble(), len, destination);
}
internal static void Plus<T>(this ReadOnlySpan<double?> units, T summand, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.PlusCore(summand.ToDouble(), len, destination);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Plus<T>(this T summand, ReadOnlySpan<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Plus<T>(this T summand, ReadOnlySpan<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand, destination);
// === Array ===
internal static T[] Plus<T>(this double[] units, T summand)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T[len];
Plus(units, summand, result);
return result;
}
internal static T?[] Plus<T>(this double?[] units, T summand)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new T?[len];
Plus(units, summand, result);
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static T[] Plus<T>(this T summand, double[] units)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static T?[] Plus<T>(this T summand, double?[] units)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
// === List<T> ===
internal static List<T> Plus<T>(this List<double> units, T summand)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
var resultArray = new T[len];
Plus(CollectionsMarshal.AsSpan(units), summand, resultArray);
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Plus<T>(this List<double?> units, T summand)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Plus(CollectionsMarshal.AsSpan(units), summand, resultArray);
return resultArray.WrapAsList<T, T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<T> Plus<T>(this T summand, List<double> units)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<T?> Plus<T>(this T summand, List<double?> units)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
// === ICollection<T> ===
internal static void Plus<T>(this ICollection<double> units, T summand, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double[] array) { array.PlusCore(summand.ToDouble(), array.Length, destination); return; }
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = (item + summand.ToDouble()).ToUnit<T>();
}
internal static void Plus<T>(this ICollection<double?> units, T summand, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double?[] array) { array.PlusCore(summand.ToDouble(), array.Length, destination); return; }
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value + summand.ToDouble()).ToUnit<T>() : null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Plus<T>(this T summand, ICollection<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Plus<T>(this T summand, ICollection<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
// === IReadOnlyCollection<T> ===
internal static void Plus<T>(this IReadOnlyCollection<double> units, T summand, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double[] array) { array.PlusCore(summand.ToDouble(), array.Length, destination); return; }
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = (item + summand.ToDouble()).ToUnit<T>();
}
internal static void Plus<T>(this IReadOnlyCollection<double?> units, T summand, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
int count = units.Count;
if (count == 0) return;
if (destination.Length < count)
throw new ArgumentException("Destination too short");
if (units is double?[] array) { array.PlusCore(summand.ToDouble(), array.Length, destination); return; }
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value + summand.ToDouble()).ToUnit<T>() : null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Plus<T>(this T summand, IReadOnlyCollection<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Plus<T>(this T summand, IReadOnlyCollection<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
// === IEnumerable<T> + yeild ===
internal static IEnumerable<T> PlusIterator<T>(this IEnumerable<double> units, double summand)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return (item + summand).ToUnit<T>();
}
internal static IEnumerable<T?> PlusNullableIterator<T>(this IEnumerable<double?> units, double summand)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return item.HasValue
? (item.Value + summand).ToUnit<T>() : null;
}
// === IEnumerable<T> ===
internal static IEnumerable<T> Plus<T>(this IEnumerable<double> units, T summand)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double[] array) return array.Plus(summand);
if (units is List<double> list) return list.Plus(summand);
if (units is ICollection<double> col)
{
var arr = col.ToArray();
arr.PlusCore(summand.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
if (units is IReadOnlyCollection<double> roc)
{
var arr = roc.ToArray();
arr.PlusCore(summand.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return PlusIterator<T>(units, summand.ToDouble());
}
internal static IEnumerable<T?> Plus<T>(this IEnumerable<double?> units, T summand)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double?[] array) return array.Plus(summand);
if (units is List<double?> list) return list.Plus(summand);
if (units is ICollection<double?> col)
{
var arr = col.ToArray();
arr.PlusCore(summand.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
if (units is IReadOnlyCollection<double?> roc)
{
var arr = roc.ToArray();
arr.PlusCore(summand.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return PlusNullableIterator<T>(units, summand.ToDouble());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static IEnumerable<T> Plus<T>(this T summand, IEnumerable<double> units)
where T : struct, IMensuraUnit, IEquatable<T> => Plus(units, summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static IEnumerable<T?> Plus<T>(this T summand, IEnumerable<double?> units)
where T : struct, IMensuraUnit, IEquatable<T> => Plus(units, summand);
}

View File

@@ -209,7 +209,7 @@ internal static partial class CollectionsPowExtensions
var resultArray = new R[count];
Pow(CollectionsMarshal.AsSpan(units), power, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Pow<T, R>(this List<T?> units, int power)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -221,7 +221,7 @@ internal static partial class CollectionsPowExtensions
var resultArray = new R?[count];
Pow(CollectionsMarshal.AsSpan(units), power, resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
// === ICollection<Length> ===
@@ -521,7 +521,7 @@ internal static partial class CollectionsPowExtensions
var result = new R[len];
CollectionsMarshal.AsSpan(units).Pow(power, result);
return result.WrapAsList();
return result.WrapAsList<R, R>();
}
internal static List<R?> Pow<T, R>(this List<T?> units, double power)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -533,7 +533,7 @@ internal static partial class CollectionsPowExtensions
var result = new R?[len];
CollectionsMarshal.AsSpan(units).Pow(power, result);
return result.WrapAsList();
return result.WrapAsList<R, R>();
}
// === ICollection<Length> ===

View File

@@ -165,7 +165,7 @@ internal static partial class CollectionsSqrtExtensions
var resultArray = new R[len];
Sqrt(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Sqrt<T, R>(this List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -177,7 +177,7 @@ internal static partial class CollectionsSqrtExtensions
var resultArray = new R?[len];
Sqrt(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList();
return resultArray.WrapAsList<R, R>();
}
// === ICollection<Length> ===

File diff suppressed because it is too large Load Diff

View File

@@ -187,131 +187,255 @@ public readonly partial record struct XXXXXXXX : IMensuraUnit<XXXXXXXX>, IEquata
public static XXXXXXXX[] operator +(XXXXXXXX[] T1, XXXXXXXX T2) => T1.Plus(T2._Value);
public static XXXXXXXX?[] operator +(XXXXXXXX?[] T1, XXXXXXXX T2) => T1.Plus(T2._Value);
public static XXXXXXXX[] operator +(XXXXXXXX T1, XXXXXXXX[] T2) => T1._Value.Plus(T2);
public static XXXXXXXX?[] operator +(XXXXXXXX T1, XXXXXXXX?[] T2) => T1._Value.Plus(T2);
public static XXXXXXXX[] operator +(XXXXXXXX[] T1, XXXXXXXX? T2) => T1.Plus(T2.Protected());
public static XXXXXXXX?[] operator +(XXXXXXXX?[] T1, XXXXXXXX? T2) => T1.Plus(T2.Protected());
public static XXXXXXXX[] operator +(XXXXXXXX? T1, XXXXXXXX[] T2) => T1.Protected().Plus(T2);
public static XXXXXXXX?[] operator +(XXXXXXXX? T1, XXXXXXXX?[] T2) => T1.Protected().Plus(T2);
public static XXXXXXXX[] operator -(XXXXXXXX[] T1, XXXXXXXX T2) => T1.Minus(T2._Value);
public static XXXXXXXX?[] operator -(XXXXXXXX?[] T1, XXXXXXXX T2) => T1.Minus(T2._Value);
public static XXXXXXXX[] operator -(XXXXXXXX T1, XXXXXXXX[] T2) => T1._Value.Minus(T2);
public static XXXXXXXX?[] operator -(XXXXXXXX T1, XXXXXXXX?[] T2) => T1._Value.Minus(T2);
public static XXXXXXXX[] operator -(XXXXXXXX[] T1, XXXXXXXX? T2) => T1.Minus(T2.Protected());
public static XXXXXXXX?[] operator -(XXXXXXXX?[] T1, XXXXXXXX? T2) => T1.Minus(T2.Protected());
public static XXXXXXXX[] operator -(XXXXXXXX? T1, XXXXXXXX[] T2) => T1.Protected().Minus(T2);
public static XXXXXXXX?[] operator -(XXXXXXXX? T1, XXXXXXXX?[] T2) => T1.Protected().Minus(T2);
public static double[] operator /(XXXXXXXX T1, XXXXXXXX[] T2) => T1.Div(T2);
public static double?[] operator /(XXXXXXXX T1, XXXXXXXX?[] T2) => T1.Div(T2);
public static double[] operator /(XXXXXXXX[] T1, XXXXXXXX T2) => T1.Div(T2);
public static double?[] operator /(XXXXXXXX?[] T1, XXXXXXXX T2) => T1.Div(T2);
public static double[] operator /(XXXXXXXX? T1, XXXXXXXX[] T2) => T1.ProtectedU().Div(T2);
public static double?[] operator /(XXXXXXXX? T1, XXXXXXXX?[] T2) => T1.ProtectedU().Div(T2);
public static double[] operator /(XXXXXXXX[] T1, XXXXXXXX? T2) => T1.Div(T2.ProtectedU());
public static double?[] operator /(XXXXXXXX?[] T1, XXXXXXXX? T2) => T1.Div(T2.ProtectedU());
// double
public static XXXXXXXX operator *(XXXXXXXX T1, double[] T2) => new(T1._Value * T2);
public static XXXXXXXX operator *(double[] T1, XXXXXXXX T2) => new(T1 * T2._Value);
public static XXXXXXXX operator /(XXXXXXXX T1, double[] T2) => new(T1._Value / T2);
public static double operator /(XXXXXXXX T1, XXXXXXXX[] T2) => T1._Value / T2._Value;
public static double operator /(XXXXXXXX[] T1, XXXXXXXX T2) => T1._Value / T2._Value;
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// sbyte
public static XXXXXXXX operator *(XXXXXXXX T1, sbyte T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, sbyte? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(sbyte T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(sbyte? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, sbyte T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, sbyte? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, sbyte[] T2) => T1.Mul(T2.ToDouble());
public static XXXXXXXX?[] operator *(XXXXXXXX T1, sbyte?[] T2) => T1.Mul(T2.ToDouble());
public static XXXXXXXX[] operator *(XXXXXXXX? T1, sbyte[] T2) => T1.ProtectedU().Mul(T2.ToDouble());
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, sbyte?[] T2) => T1.ProtectedU().Mul(T2.ToDouble());
public static XXXXXXXX[] operator *(sbyte[] T1, XXXXXXXX T2) => T1.ToDouble().Mul(T2);
public static XXXXXXXX?[] operator *(sbyte?[] T1, XXXXXXXX T2) => T1.ToDouble().Mul(T2);
public static XXXXXXXX[] operator *(sbyte[] T1, XXXXXXXX? T2) => T1.ToDouble().Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(sbyte?[] T1, XXXXXXXX? T2) => T1.ToDouble().Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, sbyte[] T2) => T1.Div(T2.ToDouble());
public static XXXXXXXX?[] operator /(XXXXXXXX T1, sbyte?[] T2) => T1.Div(T2.ToDouble());
public static XXXXXXXX[] operator /(XXXXXXXX? T1, sbyte[] T2) => T1.ProtectedU().Div(T2.ToDouble());
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, sbyte?[] T2) => T1.ProtectedU().Div(T2.ToDouble());
// short
public static XXXXXXXX operator *(XXXXXXXX T1, short T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, short? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(short T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(short? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, short T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, short? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// int
public static XXXXXXXX operator *(XXXXXXXX T1, int T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, int? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(int T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(int? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, int T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, int? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// long
public static XXXXXXXX operator *(XXXXXXXX T1, long T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, long? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(long T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(long? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, long T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, long? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// byte
public static XXXXXXXX operator *(XXXXXXXX T1, byte T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, byte? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(byte T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(byte? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, byte T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, byte? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// ushort
public static XXXXXXXX operator *(XXXXXXXX T1, ushort T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, ushort? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(ushort T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(ushort? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, ushort T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, ushort? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// uint
public static XXXXXXXX operator *(XXXXXXXX T1, uint T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, uint? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(uint T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(uint? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, uint T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, uint? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// ulong
public static XXXXXXXX operator *(XXXXXXXX T1, ulong T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, ulong? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(ulong T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(ulong? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, ulong T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, ulong? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// nint
public static XXXXXXXX operator *(XXXXXXXX T1, nint T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, nint? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(nint T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(nint? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, nint T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, nint? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// nuint
public static XXXXXXXX operator *(XXXXXXXX T1, nuint T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, nuint? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(nuint T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(nuint? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, nuint T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, nuint? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// float
public static XXXXXXXX operator *(XXXXXXXX T1, float T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, float? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(float T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(float? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, float T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, float? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// decimal
public static XXXXXXXX operator *(XXXXXXXX T1, decimal T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, decimal? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(decimal T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(decimal? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, decimal T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, decimal? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
#if NET7_0_OR_GREATER
// Int128
public static XXXXXXXX operator *(XXXXXXXX T1, Int128 T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, Int128? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(Int128 T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(Int128? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, Int128 T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, Int128? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
// UInt128
public static XXXXXXXX operator *(XXXXXXXX T1, UInt128 T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(XXXXXXXX T1, UInt128? T2) => T1 * T2.ToDouble();
public static XXXXXXXX operator *(UInt128 T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator *(UInt128? T1, XXXXXXXX T2) => T1.ToDouble() * T2;
public static XXXXXXXX operator /(XXXXXXXX T1, UInt128 T2) => T1 / T2.ToDouble();
public static XXXXXXXX operator /(XXXXXXXX T1, UInt128? T2) => T1 / T2.ToDouble();
public static XXXXXXXX[] operator *(XXXXXXXX T1, double[] T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX T1, double?[] T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX?[] operator *(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX T2) => T1.Mul(T2);
public static XXXXXXXX[] operator *(double[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX?[] operator *(double?[] T1, XXXXXXXX? T2) => T1.Mul(T2.ProtectedU());
public static XXXXXXXX[] operator /(XXXXXXXX T1, double[] T2) => T1.Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX T1, double?[] T2) => T1.Div(T2);
public static XXXXXXXX[] operator /(XXXXXXXX? T1, double[] T2) => T1.ProtectedU().Div(T2);
public static XXXXXXXX?[] operator /(XXXXXXXX? T1, double?[] T2) => T1.ProtectedU().Div(T2);
#endif
}
public static class XXXXXXXXExtensions
{
public static double Protected(this XXXXXXXX? unit) => unit is null ? 0d : unit.Value._Value;
internal static double Protected(this XXXXXXXX? unit) => unit is null ? 0d : unit.Value._Value;
internal static XXXXXXXX ProtectedU(this XXXXXXXX? unit) => unit is null ? XXXXXXXX.Zero : unit.Value;
@@ -383,71 +507,6 @@ public static class XXXXXXXXExtensions
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this ReadOnlySpan<XXXXXXXX> units,
double subtrahend, Span<XXXXXXXX> destination) => units.Minus<XXXXXXXX>(subtrahend, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this ReadOnlySpan<XXXXXXXX?> units,
double subtrahend, Span<XXXXXXXX?> destination) => units.Minus<XXXXXXXX>(subtrahend, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend,
ReadOnlySpan<XXXXXXXX> units, Span<XXXXXXXX> destination) => minuend.Minus<XXXXXXXX>(units, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend,
ReadOnlySpan<XXXXXXXX?> units, Span<XXXXXXXX?> destination) => minuend.Minus<XXXXXXXX>(units, destination);
// === Array ===
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static XXXXXXXX[] Minus(
this XXXXXXXX[] units, double subtrahend) => units.Minus<XXXXXXXX>(subtrahend);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX?[] Minus(
this XXXXXXXX?[] units, double subtrahend) => units.Minus<XXXXXXXX>(subtrahend);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX[] Minus(
this double minuend, XXXXXXXX[] units) => minuend.Minus<XXXXXXXX>(units);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX?[] Minus(
this double minuend, XXXXXXXX?[] units) => minuend.Minus<XXXXXXXX>(units);
// === List<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<XXXXXXXX> Minus(
this List<XXXXXXXX> units, double subtrahend) => units.Minus<XXXXXXXX>(subtrahend);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<XXXXXXXX?> Minus(
this List<XXXXXXXX?> units, double subtrahend) => units.Minus<XXXXXXXX>(subtrahend);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<XXXXXXXX> Minus(
this double minuend, List<XXXXXXXX> units) => minuend.Minus<XXXXXXXX>(units);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<XXXXXXXX?> Minus(
this double minuend, List<XXXXXXXX?> units) => minuend.Minus<XXXXXXXX>(units);
// === ICollection<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this ICollection<XXXXXXXX> units,
double subtrahend, Span<XXXXXXXX> destination) => units.Minus<XXXXXXXX>(subtrahend, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this ICollection<XXXXXXXX?> units,
double subtrahend, Span<XXXXXXXX?> destination) => units.Minus<XXXXXXXX>(subtrahend, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend,
ICollection<XXXXXXXX> units, Span<XXXXXXXX> destination) => minuend.Minus<XXXXXXXX>(units, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend,
ICollection<XXXXXXXX?> units, Span<XXXXXXXX?> destination) => minuend.Minus<XXXXXXXX>(units, destination);
// === IReadOnlyCollection<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Minus(this IReadOnlyCollection<XXXXXXXX> units,
double subtrahend, Span<XXXXXXXX> destination) => units.Minus<XXXXXXXX>(subtrahend, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Minus(this IReadOnlyCollection<XXXXXXXX?> units,
double subtrahend, Span<XXXXXXXX?> destination) => units.Minus<XXXXXXXX>(subtrahend, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend,
IReadOnlyCollection<XXXXXXXX> units, Span<XXXXXXXX> destination) => minuend.Minus<XXXXXXXX>(units, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend,
IReadOnlyCollection<XXXXXXXX?> units, Span<XXXXXXXX?> destination) => minuend.Minus<XXXXXXXX>(units, destination);
// === IEnumerable<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<XXXXXXXX> Minus(
this IEnumerable<XXXXXXXX> units, double subtrahend) => units.Minus<XXXXXXXX>(subtrahend);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<XXXXXXXX?> Minus(
this IEnumerable<XXXXXXXX?> units, double subtrahend) => units.Minus<XXXXXXXX>(subtrahend);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<XXXXXXXX> Minus(
this double minuend, IEnumerable<XXXXXXXX> units) => minuend.Minus<XXXXXXXX>(units);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<XXXXXXXX?> Minus(
this double minuend, IEnumerable<XXXXXXXX?> units) => minuend.Minus<XXXXXXXX>(units);
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Mul(this ReadOnlySpan<XXXXXXXX> units,
double multiplicator, Span<XXXXXXXX> destination) => units.Mul<XXXXXXXX>(multiplicator, destination);
@@ -513,71 +572,6 @@ public static class XXXXXXXXExtensions
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this ReadOnlySpan<XXXXXXXX> units,
double summand, Span<XXXXXXXX> destination) => units.Plus<XXXXXXXX>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this ReadOnlySpan<XXXXXXXX?> units,
double summand, Span<XXXXXXXX?> destination) => units.Plus<XXXXXXXX>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand,
ReadOnlySpan<XXXXXXXX> units, Span<XXXXXXXX> destination) => units.Plus<XXXXXXXX>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand,
ReadOnlySpan<XXXXXXXX?> units, Span<XXXXXXXX?> destination) => units.Plus<XXXXXXXX>(summand, destination);
// === Array ===
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static XXXXXXXX[] Plus(
this XXXXXXXX[] units, double summand) => units.Plus<XXXXXXXX>(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX?[] Plus(
this XXXXXXXX?[] units, double summand) => units.Plus<XXXXXXXX>(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX[] Plus(
this double summand, XXXXXXXX[] units) => units.Plus<XXXXXXXX>(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX?[] Plus(
this double summand, XXXXXXXX?[] units) => units.Plus<XXXXXXXX>(summand);
// === List<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<XXXXXXXX> Plus(
this List<XXXXXXXX> units, double summand) => units.Plus<XXXXXXXX>(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<XXXXXXXX?> Plus(
this List<XXXXXXXX?> units, double summand) => units.Plus<XXXXXXXX>(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<XXXXXXXX> Plus(
this double summand, List<XXXXXXXX> units) => units.Plus<XXXXXXXX>(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<XXXXXXXX?> Plus(
this double summand, List<XXXXXXXX?> units) => units.Plus<XXXXXXXX>(summand);
// === ICollection<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this ICollection<XXXXXXXX> units,
double summand, Span<XXXXXXXX> destination) => units.Plus<XXXXXXXX>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this ICollection<XXXXXXXX?> units,
double summand, Span<XXXXXXXX?> destination) => units.Plus<XXXXXXXX>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand,
ICollection<XXXXXXXX> units, Span<XXXXXXXX> destination) => units.Plus<XXXXXXXX>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand,
ICollection<XXXXXXXX?> units, Span<XXXXXXXX?> destination) => units.Plus<XXXXXXXX>(summand, destination);
// === IReadOnlyCollection<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Plus(this IReadOnlyCollection<XXXXXXXX> units,
double summand, Span<XXXXXXXX> destination) => units.Plus<XXXXXXXX>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Plus(this IReadOnlyCollection<XXXXXXXX?> units,
double summand, Span<XXXXXXXX?> destination) => units.Plus<XXXXXXXX>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand,
IReadOnlyCollection<XXXXXXXX> units, Span<XXXXXXXX> destination) => units.Plus<XXXXXXXX>(summand, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand,
IReadOnlyCollection<XXXXXXXX?> units, Span<XXXXXXXX?> destination) => units.Plus<XXXXXXXX>(summand, destination);
// === IEnumerable<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<XXXXXXXX> Plus(
this IEnumerable<XXXXXXXX> units, double summand) => units.Plus<XXXXXXXX>(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<XXXXXXXX?> Plus(
this IEnumerable<XXXXXXXX?> units, double summand) => units.Plus<XXXXXXXX>(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<XXXXXXXX> Plus(
this double summand, IEnumerable<XXXXXXXX> units) => units.Plus<XXXXXXXX>(summand);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<XXXXXXXX?> Plus(
this double summand, IEnumerable<XXXXXXXX?> units) => units.Plus<XXXXXXXX>(summand);
// Sum Average Max Min (не nullable) ==========================================