diff --git a/QWERTYkez.Mensura/Extensions/CastExtensions.cs b/QWERTYkez.Mensura/Extensions/CastExtensions.cs index d154eac..e0edffd 100644 --- a/QWERTYkez.Mensura/Extensions/CastExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CastExtensions.cs @@ -29,14 +29,18 @@ internal static partial class CastExtensions mimic.Size = count; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static List WrapAsList(this T[] array) + internal static List WrapAsList(this T[] array) + where T : struct, IMensuraUnit, IEquatable + where R : struct, IMensuraUnit, IEquatable { // Создаём пустой список с нулевой ёмкостью - var list = new List(0); + var list = new List(0); // Получаем внутреннюю структуру списка - ref var mimic = ref Unsafe.As, ListLayoutMimic>(ref list); + ref var mimic = ref Unsafe.As, ListLayoutMimic>(ref list); // Подменяем массив и устанавливаем размер mimic.Items = array; @@ -47,13 +51,96 @@ internal static partial class CastExtensions } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static List WrapAsList(this T[] array) + internal static List WrapAsList(this T?[] array) where T : struct, IMensuraUnit, IEquatable where R : struct, IMensuraUnit, IEquatable { - return Unsafe.As(ref array).WrapAsList(); + // Создаём пустой список с нулевой ёмкостью + var list = new List(0); + + // Получаем внутреннюю структуру списка + ref var mimic = ref Unsafe.As, ListLayoutMimic>(ref list); + + // Подменяем массив и устанавливаем размер + mimic.Items = array; + mimic.Size = array.Length; + mimic.Version = 1; // любое ненулевое значение для консистенции + + return list; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List WrapAsList(this T[] array) + where T : struct, IMensuraUnit, IEquatable + { + // Создаём пустой список с нулевой ёмкостью + var list = new List(0); + + // Получаем внутреннюю структуру списка + ref var mimic = ref Unsafe.As, ListLayoutMimic>(ref list); + + // Подменяем массив и устанавливаем размер + mimic.Items = array; + mimic.Size = array.Length; + mimic.Version = 1; // любое ненулевое значение для консистенции + + return list; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List WrapAsList(this T?[] array) + where T : struct, IMensuraUnit, IEquatable + { + // Создаём пустой список с нулевой ёмкостью + var list = new List(0); + + // Получаем внутреннюю структуру списка + ref var mimic = ref Unsafe.As, ListLayoutMimic>(ref list); + + // Подменяем массив и устанавливаем размер + mimic.Items = array; + mimic.Size = array.Length; + mimic.Version = 1; // любое ненулевое значение для консистенции + + return list; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List WrapAsList(this double[] array) + { + // Создаём пустой список с нулевой ёмкостью + var list = new List(0); + + // Получаем внутреннюю структуру списка + ref var mimic = ref Unsafe.As, ListLayoutMimic>(ref list); + + // Подменяем массив и устанавливаем размер + mimic.Items = array; + mimic.Size = array.Length; + mimic.Version = 1; // любое ненулевое значение для консистенции + + return list; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List WrapAsList(this double?[] array) + { + // Создаём пустой список с нулевой ёмкостью + var list = new List(0); + + // Получаем внутреннюю структуру списка + ref var mimic = ref Unsafe.As, ListLayoutMimic>(ref list); + + // Подменяем массив и устанавливаем размер + mimic.Items = array; + mimic.Size = array.Length; + mimic.Version = 1; // любое ненулевое значение для консистенции + + return list; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static List ReCast(this List list) where T : struct, IMensuraUnit, IEquatable @@ -70,6 +157,20 @@ internal static partial class CastExtensions return Unsafe.As, List>(ref list); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List ReCast(this List list) + where T : struct, IMensuraUnit, IEquatable + { + return Unsafe.As, List>(ref list); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List ReCast(this List list) + where T : struct, IMensuraUnit, IEquatable + { + return Unsafe.As, List>(ref list); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static R[] ReCast(this T[] array) where T : struct, IMensuraUnit, IEquatable diff --git a/QWERTYkez.Mensura/Extensions/CollectionsDivideExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsDivideExtensions.cs index 8a468bd..d3a7b1b 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsDivideExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsDivideExtensions.cs @@ -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(); } internal static List Div(this List units, double divisor) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Div(this double dividend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Div(this double dividend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } // === ICollection === @@ -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(); } internal static List Div(this List units, double divisor) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Div(this double dividend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Div(this double dividend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } // === ICollection === @@ -931,14 +931,13 @@ internal static partial class CollectionsDivideExtensions // === DivideCore === SIMD - internal static void DivCore(this ReadOnlySpan dividends, T unit, int len, Span destination) - where T : struct, IMensuraUnit, IEquatable + internal static void DivCore(this ReadOnlySpan dividends, double unit, int len, Span destination) where R : struct, IMensuraUnit, IEquatable { Span dstDouble = MemoryMarshal.Cast(destination); // Вместо деления в цикле, умножаем на обратное число (invDivisor) - double invDivisor = 1.0 / unit.ToDouble(); + double invDivisor = 1.0 / unit; var vectorizedInvDivisor = new Vector(invDivisor); int vectorSize = Vector.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(this ReadOnlySpan dividends, T unit, int len, Span destination) - where T : struct, IMensuraUnit, IEquatable + internal static void DivCore(this ReadOnlySpan dividends, double unit, int len, Span destination) where R : struct, IMensuraUnit, IEquatable { // Получаем прямые неуправляемые 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() : null; } } //SIMD - internal static void DivCore(this T unit, ReadOnlySpan divisors, int len, Span destination) - where T : struct, IMensuraUnit, IEquatable + internal static void DivCore(this double unit, ReadOnlySpan divisors, int len, Span destination) where R : struct, IMensuraUnit, IEquatable { - var dUnit = unit.ToDouble(); Span dstDouble = MemoryMarshal.Cast(destination); - var vectorizedDividend = new Vector(dUnit); + var vectorizedDividend = new Vector(unit); int vectorSize = Vector.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(this T unit, ReadOnlySpan divisors, int len, Span destination) - where T : struct, IMensuraUnit, IEquatable + internal static void DivCore(this double unit, ReadOnlySpan divisors, int len, Span destination) where R : struct, IMensuraUnit, IEquatable { - 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() : null; - d1 = u1.HasValue ? (dUnit / u1.Value).ToUnit() : null; - d2 = u2.HasValue ? (dUnit / u2.Value).ToUnit() : null; - d3 = u3.HasValue ? (dUnit / u3.Value).ToUnit() : null; + d0 = u0.HasValue ? (unit / u0.Value).ToUnit() : null; + d1 = u1.HasValue ? (unit / u1.Value).ToUnit() : null; + d2 = u2.HasValue ? (unit / u2.Value).ToUnit() : null; + d3 = u3.HasValue ? (unit / u3.Value).ToUnit() : 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() : null; + dst = div.HasValue ? (unit / div.Value).ToUnit() : 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(this ReadOnlySpan units, T divisor, Span destination) where T : struct, IMensuraUnit, IEquatable @@ -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(this T dividend, ReadOnlySpan units, Span destination) where T : struct, IMensuraUnit, IEquatable @@ -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(this T dividend, ReadOnlySpan units, Span destination) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Div(this List units, T divisor) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Div(this T dividend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Div(this T dividend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } // === ICollection === @@ -1512,33 +1506,33 @@ internal static partial class CollectionsDivideExtensions } // === IEnumerable + yeild === - static IEnumerable DivideIterator(IEnumerable units, T divisor) + static IEnumerable DivideIterator(IEnumerable units, double divisor) where T : struct, IMensuraUnit, IEquatable { - double invDivisor = 1.0 / divisor.ToDouble(); + double invDivisor = 1.0 / divisor; foreach (var item in units) yield return (item * invDivisor).ToUnit(); } - static IEnumerable DivideNullableIterator(IEnumerable units, T divisor) + static IEnumerable DivideNullableIterator(IEnumerable units, double divisor) where T : struct, IMensuraUnit, IEquatable { - double invDivisor = 1.0 / divisor.ToDouble(); + double invDivisor = 1.0 / divisor; foreach (var item in units) yield return item.HasValue ? (item.Value * invDivisor).ToUnit() : null; } - static IEnumerable DivideIterator(T dividend, IEnumerable units) + static IEnumerable DivideIterator(double dividend, IEnumerable units) where T : struct, IMensuraUnit, IEquatable { foreach (var item in units) - yield return (dividend.ToDouble() / item).ToUnit(); + yield return (dividend / item).ToUnit(); } - static IEnumerable DivideNullableIterator(T dividend, IEnumerable units) + static IEnumerable DivideNullableIterator(double dividend, IEnumerable units) where T : struct, IMensuraUnit, IEquatable { foreach (var item in units) yield return item.HasValue - ? (dividend.ToDouble() / item.Value).ToUnit() : null; + ? (dividend / item.Value).ToUnit() : null; } // === IEnumerable === @@ -1560,7 +1554,7 @@ internal static partial class CollectionsDivideExtensions arr.DivCore(divisor.ToDouble(), arr.Length, arr); return arr.ReCast(); } - return DivideIterator(units, divisor); + return DivideIterator(units, divisor.ToDouble()); } internal static IEnumerable Div(this IEnumerable units, T divisor) where T : struct, IMensuraUnit, IEquatable @@ -1580,7 +1574,7 @@ internal static partial class CollectionsDivideExtensions arr.DivCore(divisor.ToDouble(), arr.Length, arr); return arr.ReCast(); } - return DivideNullableIterator(units, divisor); + return DivideNullableIterator(units, divisor.ToDouble()); } internal static IEnumerable Div(this T dividend, IEnumerable units) where T : struct, IMensuraUnit, IEquatable @@ -1600,7 +1594,7 @@ internal static partial class CollectionsDivideExtensions dividend.ToDouble().DivCore(arr, arr.Length, arr); return arr.ReCast(); } - return DivideIterator(dividend, units); + return DivideIterator(dividend.ToDouble(), units); } internal static IEnumerable Div(this T dividend, IEnumerable units) where T : struct, IMensuraUnit, IEquatable @@ -1620,6 +1614,556 @@ internal static partial class CollectionsDivideExtensions dividend.ToDouble().DivCore(arr, arr.Length, arr); return arr.ReCast(); } + return DivideNullableIterator(dividend.ToDouble(), units); + } + + + + + + + + + + // === DivideCore === SIMD + internal static void DivideCore(this ReadOnlySpan units, double divisor, int len, Span dstDouble) + where T : struct, IMensuraUnit, IEquatable + { + ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); + + // Вместо деления в цикле, умножаем на обратное число (invDivisor) + double invDivisor = 1.0 / divisor; + var vectorizedInvDivisor = new Vector(invDivisor); + + int vectorSize = Vector.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>(ref currentSrc); + var multiplied = vector * vectorizedInvDivisor; + + Unsafe.As>(ref currentDst) = multiplied; + } + + // Хвост + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * invDivisor; + } + } + internal static void DivideCore(this ReadOnlySpan units, double divisor, int len, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + // Получаем прямые неуправляемые 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(this double dividend, ReadOnlySpan units, int len, Span dstDouble) + where T : struct, IMensuraUnit, IEquatable + { + ReadOnlySpan srcDouble = MemoryMarshal.Cast(units); + + var vectorizedDividend = new Vector(dividend); + int vectorSize = Vector.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>(ref currentSrc); + + // Векторное деление: константа делится на покомпонентные элементы массива + var divided = Vector.Divide(vectorizedDividend, vector); + + Unsafe.As>(ref currentDst) = divided; + } + + // Хвост + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = dividend / Unsafe.Add(ref srcRef, i); + } + } + internal static void DivideCore(this double dividend, ReadOnlySpan units, int len, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + // Получаем прямые неуправляемые 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(this ReadOnlySpan units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this ReadOnlySpan units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T dividend, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T dividend, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T[] units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T?[] units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T dividend, T[] units) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T dividend, T?[] units) + where T : struct, IMensuraUnit, IEquatable + { + 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 === + internal static List Div(this List units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + 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 Div(this List units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + 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 Div(this T dividend, List units) + where T : struct, IMensuraUnit, IEquatable + { + 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 Div(this T dividend, List units) + where T : struct, IMensuraUnit, IEquatable + { + 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 === + internal static void Div(this ICollection units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(this ICollection units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(this T dividend, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(this T dividend, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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 === + internal static void Div(this IReadOnlyCollection units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(this IReadOnlyCollection units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(this T dividend, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(this T dividend, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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 + yeild === + static IEnumerable DivideIterator(IEnumerable units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + double invDivisor = 1.0 / divisor.ToDouble(); + foreach (var item in units) + yield return item.ToDouble() * invDivisor; + } + static IEnumerable DivideNullableIterator(IEnumerable units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + double invDivisor = 1.0 / divisor.ToDouble(); + foreach (var item in units) + yield return item.HasValue ? item.Value.ToDouble() * invDivisor : null; + } + static IEnumerable DivideIterator(T dividend, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable + { + var div = dividend.ToDouble(); + foreach (var item in units) + yield return div / item.ToDouble(); + } + static IEnumerable DivideNullableIterator(T dividend, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable + { + var div = dividend.ToDouble(); + foreach (var item in units) + yield return item.HasValue ? div / item.Value.ToDouble() : null; + } + + // === IEnumerable === + internal static IEnumerable Div(this IEnumerable units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is T[] array) return array.Div(divisor); + if (units is List list) return list.Div(divisor); + if (units is ICollection col) + { + var arr = col.ToArray(); + arr.DivideCore(divisor.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + arr.DivideCore(divisor.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + return DivideIterator(units, divisor); + } + internal static IEnumerable Div(this IEnumerable units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is T?[] array) return array.Div(divisor); + if (units is List list) return list.Div(divisor); + if (units is ICollection col) + { + var arr = col.ToArray(); + arr.DivideCore(divisor.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + arr.DivideCore(divisor.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + return DivideNullableIterator(units, divisor); + } + internal static IEnumerable Div(this T dividend, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is T[] array) return dividend.Div(array); + if (units is List list) return dividend.Div(list); + if (units is ICollection col) + { + var arr = col.ToArray(); + dividend.ToDouble().DivideCore(arr, arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + dividend.ToDouble().DivideCore(arr, arr.Length, arr); + return arr.ReCast(); + } + return DivideIterator(dividend, units); + } + internal static IEnumerable Div(this T dividend, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is T?[] array) return dividend.Div(array); + if (units is List list) return dividend.Div(list); + if (units is ICollection col) + { + var arr = col.ToArray(); + dividend.ToDouble().DivideCore(arr, arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + dividend.ToDouble().DivideCore(arr, arr.Length, arr); + return arr.ReCast(); + } return DivideNullableIterator(dividend, units); } } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Extensions/CollectionsMinusExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsMinusExtensions.cs index 7846612..3f77d73 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsMinusExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsMinusExtensions.cs @@ -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(); } internal static List Minus(this List units, double subtrahend) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Minus(this double minuend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Minus(this double minuend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } // === ICollection === @@ -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(); } internal static List Minus(this List units, double subtrahend) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Minus(this double minuend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } internal static List Minus(this double minuend, List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } // === ICollection === @@ -905,4 +905,689 @@ internal static partial class CollectionsMinusExtensions } return MinusNullableIterator(minuend, units); } + + + + + + + + + + // === MinusCore === SIMD + internal static void MinusCore(this ReadOnlySpan srcDouble, double subtrahend, int len, Span destination) + where R : struct, IMensuraUnit, IEquatable + { + Span dstDouble = MemoryMarshal.Cast(destination); + + var vectorizedSubtrahend = new Vector(subtrahend); + int vectorSize = Vector.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>(ref currentSrc); + var subtracted = vector - vectorizedSubtrahend; + + Unsafe.As>(ref currentDst) = subtracted; + } + + // Хвост + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend; + } + } + internal static void MinusCore(this ReadOnlySpan units, double subtrahend, int len, Span destination) + where R : struct, IMensuraUnit, IEquatable + { + // Получаем прямые неуправляемые 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() : null; + d1 = u1.HasValue ? (u1.Value - subtrahend).ToUnit() : null; + d2 = u2.HasValue ? (u2.Value - subtrahend).ToUnit() : null; + d3 = u3.HasValue ? (u3.Value - subtrahend).ToUnit() : 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() : null; + } + } + //SIMD + internal static void MinusCore(this double minuend, ReadOnlySpan srcDouble, int len, Span destination) + where R : struct, IMensuraUnit, IEquatable + { + Span dstDouble = MemoryMarshal.Cast(destination); + + var vectorizedMinuend = new Vector(minuend); + int vectorSize = Vector.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>(ref currentSrc); + + // Векторное вычитание: константа уменьшается на покомпонентные элементы массива + var subtracted = vectorizedMinuend - vector; + + Unsafe.As>(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 units, int len, Span destination) + where R : struct, IMensuraUnit, IEquatable + { + // Получаем прямые неуправляемые 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() : null; + d1 = u1.HasValue ? (minuend - u1.Value).ToUnit() : null; + d2 = u2.HasValue ? (minuend - u2.Value).ToUnit() : null; + d3 = u3.HasValue ? (minuend - u3.Value).ToUnit() : 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() : null; + } + } + + + // === DivideCore === SIMD + internal static void MinusCore(this ReadOnlySpan srcDouble, double subtrahend, int len, Span dstDouble) + { + var vectorizedSubtrahend = new Vector(subtrahend); + int vectorSize = Vector.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>(ref currentSrc); + var subtracted = vector - vectorizedSubtrahend; + + Unsafe.As>(ref currentDst) = subtracted; + } + + // Хвост + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend; + } + } + internal static void MinusCore(this ReadOnlySpan units, double subtrahend, int len, Span 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 srcDouble, int len, Span dstDouble) + { + var vectorizedMinuend = new Vector(minuend); + int vectorSize = Vector.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>(ref currentSrc); + + // Векторное вычитание: константа уменьшается на покомпонентные элементы массива + var subtracted = vectorizedMinuend - vector; + + Unsafe.As>(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 units, int len, Span 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(this ReadOnlySpan units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this ReadOnlySpan units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T dividend, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T dividend, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this double[] units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + 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(this double?[] units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T dividend, double[] units) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T dividend, double?[] units) + where T : struct, IMensuraUnit, IEquatable + { + 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 === + internal static List Minus(this List units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + 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(); + } + internal static List Minus(this List units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + 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(); + } + internal static List Minus(this T dividend, List units) + where T : struct, IMensuraUnit, IEquatable + { + 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(); + } + internal static List Minus(this T dividend, List units) + where T : struct, IMensuraUnit, IEquatable + { + 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(); + } + + // === ICollection === + internal static void Minus(this ICollection units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(); + } + internal static void Minus(this ICollection units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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() : null; + } + internal static void Minus(this T dividend, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (dividend.ToDouble() / item).ToUnit(); + } + internal static void Minus(this T dividend, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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() : null; + } + + // === IReadOnlyCollection === + internal static void Minus(this IReadOnlyCollection units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(); + } + internal static void Minus(this IReadOnlyCollection units, T divisor, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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() : null; + } + internal static void Minus(this T dividend, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; } + + int i = 0; + foreach (var item in units) + destination[i++] = (dividend.ToDouble() / item).ToUnit(); + } + internal static void Minus(this T dividend, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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() : null; + } + + // === IEnumerable + yeild === + static IEnumerable MinusideIterator(IEnumerable units, double divisor) + where T : struct, IMensuraUnit, IEquatable + { + double invMinusisor = 1.0 / divisor; + foreach (var item in units) + yield return (item * invMinusisor).ToUnit(); + } + static IEnumerable MinusideNullableIterator(IEnumerable units, double divisor) + where T : struct, IMensuraUnit, IEquatable + { + double invMinusisor = 1.0 / divisor; + foreach (var item in units) + yield return item.HasValue + ? (item.Value * invMinusisor).ToUnit() : null; + } + static IEnumerable MinusideIterator(double dividend, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable + { + foreach (var item in units) + yield return (dividend / item).ToUnit(); + } + static IEnumerable MinusideNullableIterator(double dividend, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable + { + foreach (var item in units) + yield return item.HasValue + ? (dividend / item.Value).ToUnit() : null; + } + + // === IEnumerable === + internal static IEnumerable Minus(this IEnumerable units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is double[] array) return array.Minus(divisor); + if (units is List list) return list.Minus(divisor); + if (units is ICollection col) + { + var arr = col.ToArray(); + arr.MinusCore(divisor.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + arr.MinusCore(divisor.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + return MinusideIterator(units, divisor.ToDouble()); + } + internal static IEnumerable Minus(this IEnumerable units, T divisor) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is double?[] array) return array.Minus(divisor); + if (units is List list) return list.Minus(divisor); + if (units is ICollection col) + { + var arr = col.ToArray(); + arr.MinusCore(divisor.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + arr.MinusCore(divisor.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + return MinusideNullableIterator(units, divisor.ToDouble()); + } + internal static IEnumerable Minus(this T dividend, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is double[] array) return dividend.Minus(array); + if (units is List list) return dividend.Minus(list); + if (units is ICollection col) + { + var arr = col.ToArray(); + dividend.ToDouble().MinusCore(arr, arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + dividend.ToDouble().MinusCore(arr, arr.Length, arr); + return arr.ReCast(); + } + return MinusideIterator(dividend.ToDouble(), units); + } + internal static IEnumerable Minus(this T dividend, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is double?[] array) return dividend.Minus(array); + if (units is List list) return dividend.Minus(list); + if (units is ICollection col) + { + var arr = col.ToArray(); + dividend.ToDouble().MinusCore(arr, arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + dividend.ToDouble().MinusCore(arr, arr.Length, arr); + return arr.ReCast(); + } + return MinusideNullableIterator(dividend.ToDouble(), units); + } } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Extensions/CollectionsMultiplyExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsMultiplyExtensions.cs index ee03102..6bce3ee 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsMultiplyExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsMultiplyExtensions.cs @@ -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(); } internal static List Mul(this List units, double multiplicator) where T : struct, IMensuraUnit, IEquatable @@ -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(); } [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(); } internal static List Mul(this List units, double multiplicator) where T : struct, IMensuraUnit, IEquatable @@ -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(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -574,4 +574,412 @@ internal static partial class CollectionsMultiplyExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static IEnumerable Mul(this double multiplicator, IEnumerable units) where T : struct, IMensuraUnit, IEquatable => Mul(units, multiplicator); + + + + + + + + + + // === MultiplyCore === SIMD + internal static void MultiplyCore(this ReadOnlySpan srcDouble, double multiplicator, int len, Span destination) + where R : struct, IMensuraUnit, IEquatable + { + Span dstDouble = MemoryMarshal.Cast(destination); + + var vectorizedMultiplicator = new Vector(multiplicator); + int vectorSize = Vector.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>(ref currentSrc); + var multiplied = vector * vectorizedMultiplicator; + + Unsafe.As>(ref currentDst) = multiplied; + } + + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator; + } + } + internal static void MultiplyCore(this ReadOnlySpan units, double multiplicator, int len, Span destination) + where R : struct, IMensuraUnit, IEquatable + { + // Получаем прямые неуправляемые 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() : null; + d1 = u1.HasValue ? (u1.Value * multiplicator).ToUnit() : null; + d2 = u2.HasValue ? (u2.Value * multiplicator).ToUnit() : null; + d3 = u3.HasValue ? (u3.Value * multiplicator).ToUnit() : 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() : null; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore(this double multiplicator, ReadOnlySpan units, + int len, Span destination) where R : struct, IMensuraUnit, IEquatable => units.MultiplyCore(multiplicator, len, destination); + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore(this double multiplicator, ReadOnlySpan units, + int len, Span destination) where R : struct, IMensuraUnit, IEquatable => units.MultiplyCore(multiplicator, len, destination); + + + // === MultiplyCore === SIMD + internal static void MultiplyCore(this ReadOnlySpan srcDouble, double multiplicator, int len, Span dstDouble) + { + var vectorizedMultiplicator = new Vector(multiplicator); + int vectorSize = Vector.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>(ref currentSrc); + var multiplied = vector * vectorizedMultiplicator; + + Unsafe.As>(ref currentDst) = multiplied; + } + + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator; + } + } + internal static void MultiplyCore(this ReadOnlySpan units, double multiplicator, int len, Span 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 units, int len, Span destination) => units.MultiplyCore(multiplicator, len, destination); + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore(this double multiplicator, + ReadOnlySpan units, int len, Span destination) => units.MultiplyCore(multiplicator, len, destination); + + + + + + // === ReadOnlySpan + internal static void Mul(this ReadOnlySpan units, T multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this ReadOnlySpan units, T multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T multiplicator, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator, destination); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Mul(this T multiplicator, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator, destination); + + // === Array === + internal static T[] Mul(this double[] units, T multiplicator) + where T : struct, IMensuraUnit, IEquatable + { + 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(this double?[] units, T multiplicator) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T multiplicator, double[] units) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static T?[] Mul(this T multiplicator, double?[] units) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator); + + // === List === + internal static List Mul(this List units, T multiplicator) + where T : struct, IMensuraUnit, IEquatable + { + 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(); + } + internal static List Mul(this List units, T multiplicator) + where T : struct, IMensuraUnit, IEquatable + { + 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(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List Mul(this T multiplicator, List units) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List Mul(this T multiplicator, List units) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator); + + // === ICollection === + internal static void Mul(this ICollection units, T multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(); + } + internal static void Mul(this ICollection units, T multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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() : null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Mul(this T multiplicator, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator, destination); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Mul(this T multiplicator, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator, destination); + + // === IReadOnlyCollection === + internal static void Mul(this IReadOnlyCollection units, T multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(); + } + internal static void Mul(this IReadOnlyCollection units, T multiplicator, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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() : null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Mul(this T multiplicator, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator, destination); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Mul(this T multiplicator, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Mul(multiplicator, destination); + + // === IEnumerable + yeild === + internal static IEnumerable MultiplyIterator(this IEnumerable units, double multiplicator) + where T : struct, IMensuraUnit, IEquatable + { + foreach (var item in units) + yield return (item * multiplicator).ToUnit(); + } + internal static IEnumerable MultiplyNullableIterator(this IEnumerable units, double multiplicator) + where T : struct, IMensuraUnit, IEquatable + { + foreach (var item in units) + yield return item.HasValue + ? (item.Value * multiplicator).ToUnit() : null; + } + + // === IEnumerable === + internal static IEnumerable Mul(this IEnumerable units, T multiplicator) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is double[] array) return array.Mul(multiplicator); + if (units is List list) return list.Mul(multiplicator); + if (units is ICollection col) + { + var arr = col.ToArray(); + arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + return MultiplyIterator(units, multiplicator.ToDouble()); + } + internal static IEnumerable Mul(this IEnumerable units, T multiplicator) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is double?[] array) return array.Mul(multiplicator); + if (units is List list) return list.Mul(multiplicator); + if (units is ICollection col) + { + var arr = col.ToArray(); + arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + return MultiplyNullableIterator(units, multiplicator.ToDouble()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static IEnumerable Mul(this T multiplicator, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable => Mul(units, multiplicator); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static IEnumerable Mul(this T multiplicator, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable => Mul(units, multiplicator); } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Extensions/CollectionsPlusExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsPlusExtensions.cs index 3a59114..b5e3325 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsPlusExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsPlusExtensions.cs @@ -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(); } internal static List Plus(this List units, double summand) where T : struct, IMensuraUnit, IEquatable @@ -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(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -332,7 +332,7 @@ internal static partial class CollectionsPlusExtensions // === ReadOnlySpan - internal static void Plus(this ReadOnlySpan units, double multiplicator, Span destination) + internal static void Plus(this ReadOnlySpan units, double summand, Span destination) where T : struct, IMensuraUnit, IEquatable { 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(this ReadOnlySpan units, double multiplicator, Span destination) + internal static void Plus(this ReadOnlySpan units, double summand, Span destination) where T : struct, IMensuraUnit, IEquatable { 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(this double multiplicator, ReadOnlySpan units, Span destination) - where T : struct, IMensuraUnit, IEquatable => units.Plus(multiplicator, destination); + internal static void Plus(this double summand, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Plus(this double multiplicator, ReadOnlySpan units, Span destination) - where T : struct, IMensuraUnit, IEquatable => units.Plus(multiplicator, destination); + internal static void Plus(this double summand, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); // === Array === internal static T[] Plus(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(); } internal static List Plus(this List units, double summand) where T : struct, IMensuraUnit, IEquatable @@ -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(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -575,4 +575,416 @@ internal static partial class CollectionsPlusExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static IEnumerable Plus(this double summand, IEnumerable units) where T : struct, IMensuraUnit, IEquatable => Plus(units, summand); + + + + + + + + + + // === PlusCore === SIMD + internal static void PlusCore(this ReadOnlySpan srcDouble, double summand, int len, Span destination) + where R : struct, IMensuraUnit, IEquatable + { + Span dstDouble = MemoryMarshal.Cast(destination); + + var vectorizedPlustiplicator = new Vector(summand); + int vectorSize = Vector.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>(ref currentSrc); + var multiplied = vector + vectorizedPlustiplicator; + + Unsafe.As>(ref currentDst) = multiplied; + } + + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand; + } + } + internal static void PlusCore(this ReadOnlySpan units, double summand, int len, Span destination) + where R : struct, IMensuraUnit, IEquatable + { + // Получаем прямые неуправляемые 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() : null; + d1 = u1.HasValue ? (u1.Value + summand).ToUnit() : null; + d2 = u2.HasValue ? (u2.Value + summand).ToUnit() : null; + d3 = u3.HasValue ? (u3.Value + summand).ToUnit() : 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() : null; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void PlusCore(this double summand, ReadOnlySpan units, + int len, Span destination) where R : struct, IMensuraUnit, IEquatable => units.PlusCore(summand, len, destination); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void PlusCore(this double summand, ReadOnlySpan units, + int len, Span destination) where R : struct, IMensuraUnit, IEquatable => units.PlusCore(summand, len, destination); + + + // === PlusCore === SIMD + internal static void PlusCore(this ReadOnlySpan srcDouble, double summand, int len, Span dstDouble) + { + var vectorizedPlustiplicator = new Vector(summand); + int vectorSize = Vector.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>(ref currentSrc); + var multiplied = vector + vectorizedPlustiplicator; + + Unsafe.As>(ref currentDst) = multiplied; + } + + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand; + } + } + internal static void PlusCore(this ReadOnlySpan units, double summand, int len, Span 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 units, int len, Span destination) => units.PlusCore(summand, len, destination); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void PlusCore(this double summand, + ReadOnlySpan units, int len, Span destination) => units.PlusCore(summand, len, destination); + + + + + + // === ReadOnlySpan + internal static void Plus(this ReadOnlySpan units, T summand, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this ReadOnlySpan units, T summand, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T summand, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Plus(this T summand, ReadOnlySpan units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); + + // === Array === + internal static T[] Plus(this double[] units, T summand) + where T : struct, IMensuraUnit, IEquatable + { + 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(this double?[] units, T summand) + where T : struct, IMensuraUnit, IEquatable + { + 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(this T summand, double[] units) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static T?[] Plus(this T summand, double?[] units) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand); + + // === List === + internal static List Plus(this List units, T summand) + where T : struct, IMensuraUnit, IEquatable + { + 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(); + } + internal static List Plus(this List units, T summand) + where T : struct, IMensuraUnit, IEquatable + { + 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(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List Plus(this T summand, List units) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static List Plus(this T summand, List units) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand); + + // === ICollection === + internal static void Plus(this ICollection units, T summand, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(); + } + internal static void Plus(this ICollection units, T summand, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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() : null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Plus(this T summand, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Plus(this T summand, ICollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); + + // === IReadOnlyCollection === + internal static void Plus(this IReadOnlyCollection units, T summand, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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(); + } + internal static void Plus(this IReadOnlyCollection units, T summand, Span destination) + where T : struct, IMensuraUnit, IEquatable + { + 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 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() : null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Plus(this T summand, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Plus(this T summand, IReadOnlyCollection units, Span destination) + where T : struct, IMensuraUnit, IEquatable => units.Plus(summand, destination); + + // === IEnumerable + yeild === + internal static IEnumerable PlusIterator(this IEnumerable units, double summand) + where T : struct, IMensuraUnit, IEquatable + { + foreach (var item in units) + yield return (item + summand).ToUnit(); + } + internal static IEnumerable PlusNullableIterator(this IEnumerable units, double summand) + where T : struct, IMensuraUnit, IEquatable + { + foreach (var item in units) + yield return item.HasValue + ? (item.Value + summand).ToUnit() : null; + } + + // === IEnumerable === + internal static IEnumerable Plus(this IEnumerable units, T summand) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is double[] array) return array.Plus(summand); + if (units is List list) return list.Plus(summand); + if (units is ICollection col) + { + var arr = col.ToArray(); + arr.PlusCore(summand.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + arr.PlusCore(summand.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + return PlusIterator(units, summand.ToDouble()); + } + internal static IEnumerable Plus(this IEnumerable units, T summand) + where T : struct, IMensuraUnit, IEquatable + { + if (units is null) return null!; + if (units is double?[] array) return array.Plus(summand); + if (units is List list) return list.Plus(summand); + if (units is ICollection col) + { + var arr = col.ToArray(); + arr.PlusCore(summand.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + if (units is IReadOnlyCollection roc) + { + var arr = roc.ToArray(); + arr.PlusCore(summand.ToDouble(), arr.Length, arr); + return arr.ReCast(); + } + return PlusNullableIterator(units, summand.ToDouble()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static IEnumerable Plus(this T summand, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable => Plus(units, summand); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static IEnumerable Plus(this T summand, IEnumerable units) + where T : struct, IMensuraUnit, IEquatable => Plus(units, summand); } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Extensions/CollectionsPowExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsPowExtensions.cs index fdee8ae..08eaf84 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsPowExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsPowExtensions.cs @@ -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(); } internal static List Pow(this List units, int power) where T : struct, IMensuraUnit, IEquatable @@ -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(); } // === ICollection === @@ -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(); } internal static List Pow(this List units, double power) where T : struct, IMensuraUnit, IEquatable @@ -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(); } // === ICollection === diff --git a/QWERTYkez.Mensura/Extensions/CollectionsSqrtExtensions.cs b/QWERTYkez.Mensura/Extensions/CollectionsSqrtExtensions.cs index 9e453e7..aedebba 100644 --- a/QWERTYkez.Mensura/Extensions/CollectionsSqrtExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/CollectionsSqrtExtensions.cs @@ -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(); } internal static List Sqrt(this List units) where T : struct, IMensuraUnit, IEquatable @@ -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(); } // === ICollection === diff --git a/QWERTYkez.Mensura/Extensions/DoubleExtensions.cs b/QWERTYkez.Mensura/Extensions/DoubleExtensions.cs index 3c77d22..ad46761 100644 --- a/QWERTYkez.Mensura/Extensions/DoubleExtensions.cs +++ b/QWERTYkez.Mensura/Extensions/DoubleExtensions.cs @@ -1556,4 +1556,1502 @@ public static partial class DoubleExtensions return numbers.ToDoubleIterator(); } #endif + + + + // === IEnumerable + yeild === + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return (double?)number; } + +#if NET7_0_OR_GREATER + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return (double?)number; } + internal static IEnumerable ToDoubleIterator(this IEnumerable numbers) + { foreach (var number in numbers) yield return (double?)number; } +#endif + + + + + + + + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref byte? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref sbyte? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref short? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref ushort? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref int? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref uint? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref nint? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref nuint? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref long? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref ulong? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref Half? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref float? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref decimal? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + +#if NET7_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref Int128? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ToDoubleCore(this ReadOnlySpan source, int len, Span destination) + { + if (len <= 0) return; + ref UInt128? srcRef = ref MemoryMarshal.GetReference(source); + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + int i = 0; int unrollEnd = len & ~3; + 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); + Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null; + Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null; + } + for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; } + } +#endif + + + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = item; + } + return destination; + } + public static double?[] ToDouble(this byte?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is byte?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is byte?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is byte?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this sbyte?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is sbyte?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is sbyte?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is sbyte?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this short?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is short?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is short?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is short?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this ushort?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is ushort?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is ushort?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is ushort?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this int?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is int?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is int?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is int?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this uint?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is uint?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is uint?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is uint?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this nint?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is nint?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is nint?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is nint?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this nuint?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is nuint?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is nuint?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is nuint?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this long?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is long?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is long?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is long?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this ulong?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is ulong?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is ulong?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is ulong?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this float?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is float?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is float?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is float?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this decimal?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is decimal?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is decimal?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is decimal?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + +#if NET7_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this Int128?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is Int128?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is Int128?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is Int128?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double?[] ToDouble(this IEnumerable source, int count) + { + if (count == 0) return []; + int i = 0; + double?[] destination = new double?[count]; + ref double? dstRef = ref MemoryMarshal.GetArrayDataReference(destination); + foreach (var item in source) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + return destination; + } + public static double?[] ToDouble(this UInt128?[] numbers) + { + if (numbers is null) return null!; + int len = numbers.Length; + if (len == 0) return []; + + var result = new double?[len]; + numbers.ToDoubleCore(len, result); + return result; + } + public static List ToDouble(this List numbers) + { + if (numbers is null) return null!; + int len = numbers.Count; + if (len == 0) return []; + + var result = new double?[len]; + CollectionsMarshal.AsSpan(numbers).ToDoubleCore(len, result); + return result.WrapAsList(); + } + public static void ToDouble(this ICollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is UInt128?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static void ToDouble(this IReadOnlyCollection numbers, Span destination) + { + if (numbers is null) return; + int count = numbers.Count; + if (count == 0) return; + if (destination.Length < count) + throw new ArgumentException("Destination too short"); + + if (numbers is UInt128?[] array) { array.ToDoubleCore(count, destination); return; } + if (numbers is List list) { CollectionsMarshal.AsSpan(list).ToDoubleCore(count, destination); return; } + + int i = 0; + ref double? dstRef = ref MemoryMarshal.GetReference(destination); + foreach (var item in numbers) + { + if ((uint)i >= (uint)count) break; + Unsafe.Add(ref dstRef, i++) = (double?)item; + } + } + public static IEnumerable ToDouble(this IEnumerable numbers) + { + if (numbers is null) return null!; + if (numbers is UInt128?[] array) return array.ToDouble(); + if (numbers is List list) return list.ToDouble(); + if (numbers is ICollection col) return col.ToDouble(col.Count); + if (numbers is IReadOnlyCollection roc) return roc.ToDouble(roc.Count); + return numbers.ToDoubleIterator(); + } +#endif } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs b/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs index 3b36555..7ce0671 100644 --- a/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs +++ b/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs @@ -187,131 +187,255 @@ public readonly partial record struct XXXXXXXX : IMensuraUnit, 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 units, - double subtrahend, Span destination) => units.Minus(subtrahend, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this ReadOnlySpan units, - double subtrahend, Span destination) => units.Minus(subtrahend, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend, - ReadOnlySpan units, Span destination) => minuend.Minus(units, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend, - ReadOnlySpan units, Span destination) => minuend.Minus(units, destination); - - // === Array === - [MethodImpl(MethodImplOptions.AggressiveInlining)]public static XXXXXXXX[] Minus( - this XXXXXXXX[] units, double subtrahend) => units.Minus(subtrahend); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX?[] Minus( - this XXXXXXXX?[] units, double subtrahend) => units.Minus(subtrahend); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX[] Minus( - this double minuend, XXXXXXXX[] units) => minuend.Minus(units); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX?[] Minus( - this double minuend, XXXXXXXX?[] units) => minuend.Minus(units); - - // === List === - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Minus( - this List units, double subtrahend) => units.Minus(subtrahend); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Minus( - this List units, double subtrahend) => units.Minus(subtrahend); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Minus( - this double minuend, List units) => minuend.Minus(units); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Minus( - this double minuend, List units) => minuend.Minus(units); - - // === ICollection === - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this ICollection units, - double subtrahend, Span destination) => units.Minus(subtrahend, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this ICollection units, - double subtrahend, Span destination) => units.Minus(subtrahend, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend, - ICollection units, Span destination) => minuend.Minus(units, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend, - ICollection units, Span destination) => minuend.Minus(units, destination); - - // === IReadOnlyCollection === - [MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Minus(this IReadOnlyCollection units, - double subtrahend, Span destination) => units.Minus(subtrahend, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Minus(this IReadOnlyCollection units, - double subtrahend, Span destination) => units.Minus(subtrahend, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend, - IReadOnlyCollection units, Span destination) => minuend.Minus(units, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Minus(this double minuend, - IReadOnlyCollection units, Span destination) => minuend.Minus(units, destination); - - // === IEnumerable === - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Minus( - this IEnumerable units, double subtrahend) => units.Minus(subtrahend); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Minus( - this IEnumerable units, double subtrahend) => units.Minus(subtrahend); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Minus( - this double minuend, IEnumerable units) => minuend.Minus(units); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Minus( - this double minuend, IEnumerable units) => minuend.Minus(units); - - - - - - // === ReadOnlySpan [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Mul(this ReadOnlySpan units, double multiplicator, Span destination) => units.Mul(multiplicator, destination); @@ -513,71 +572,6 @@ public static class XXXXXXXXExtensions - // === ReadOnlySpan - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this ReadOnlySpan units, - double summand, Span destination) => units.Plus(summand, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this ReadOnlySpan units, - double summand, Span destination) => units.Plus(summand, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand, - ReadOnlySpan units, Span destination) => units.Plus(summand, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand, - ReadOnlySpan units, Span destination) => units.Plus(summand, destination); - - // === Array === - [MethodImpl(MethodImplOptions.AggressiveInlining)]public static XXXXXXXX[] Plus( - this XXXXXXXX[] units, double summand) => units.Plus(summand); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX?[] Plus( - this XXXXXXXX?[] units, double summand) => units.Plus(summand); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX[] Plus( - this double summand, XXXXXXXX[] units) => units.Plus(summand); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static XXXXXXXX?[] Plus( - this double summand, XXXXXXXX?[] units) => units.Plus(summand); - - // === List === - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Plus( - this List units, double summand) => units.Plus(summand); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Plus( - this List units, double summand) => units.Plus(summand); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Plus( - this double summand, List units) => units.Plus(summand); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Plus( - this double summand, List units) => units.Plus(summand); - - // === ICollection === - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this ICollection units, - double summand, Span destination) => units.Plus(summand, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this ICollection units, - double summand, Span destination) => units.Plus(summand, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand, - ICollection units, Span destination) => units.Plus(summand, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand, - ICollection units, Span destination) => units.Plus(summand, destination); - - // === IReadOnlyCollection === - [MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Plus(this IReadOnlyCollection units, - double summand, Span destination) => units.Plus(summand, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Plus(this IReadOnlyCollection units, - double summand, Span destination) => units.Plus(summand, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand, - IReadOnlyCollection units, Span destination) => units.Plus(summand, destination); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Plus(this double summand, - IReadOnlyCollection units, Span destination) => units.Plus(summand, destination); - - // === IEnumerable === - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Plus( - this IEnumerable units, double summand) => units.Plus(summand); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Plus( - this IEnumerable units, double summand) => units.Plus(summand); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Plus( - this double summand, IEnumerable units) => units.Plus(summand); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable Plus( - this double summand, IEnumerable units) => units.Plus(summand); - - - - - - // Sum Average Max Min (не nullable) ==========================================