Pow2 Pow3 Sqrt2 Sqrt3

This commit is contained in:
melekhin
2026-06-11 09:10:45 +07:00
parent 4c0a5890bc
commit 343996ef46
11 changed files with 1004 additions and 67 deletions

View File

@@ -23,7 +23,7 @@ internal static partial class CastExtensions
{
// Берем адрес управляемого объекта List в памяти
// Объект передается по ref-ссылке, преобразуется в указатель
ref var mimic = ref Unsafe.As<List<T>, ListLayoutMimic<T>>(ref list);
ref var mimic = ref Unsafe.As<List<T>, Mimics<T>>(ref list);
// Меняем приватный размер напрямую в памяти объекта!
mimic.Size = count;
@@ -40,7 +40,7 @@ internal static partial class CastExtensions
var list = new List<R>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<R>, ListLayoutMimic<T>>(ref list);
ref var mimic = ref Unsafe.As<List<R>, Mimics<T>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
@@ -59,7 +59,7 @@ internal static partial class CastExtensions
var list = new List<R?>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<R?>, ListLayoutMimic<T?>>(ref list);
ref var mimic = ref Unsafe.As<List<R?>, Mimics<T?>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
@@ -77,7 +77,7 @@ internal static partial class CastExtensions
var list = new List<double>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<double>, ListLayoutMimic<T>>(ref list);
ref var mimic = ref Unsafe.As<List<double>, Mimics<T>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
@@ -95,7 +95,7 @@ internal static partial class CastExtensions
var list = new List<double?>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<double?>, ListLayoutMimic<T?>>(ref list);
ref var mimic = ref Unsafe.As<List<double?>, Mimics<T?>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
@@ -112,7 +112,7 @@ internal static partial class CastExtensions
var list = new List<double>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<double>, ListLayoutMimic<double>>(ref list);
ref var mimic = ref Unsafe.As<List<double>, Mimics<double>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;
@@ -129,7 +129,7 @@ internal static partial class CastExtensions
var list = new List<double?>(0);
// Получаем внутреннюю структуру списка
ref var mimic = ref Unsafe.As<List<double?>, ListLayoutMimic<double?>>(ref list);
ref var mimic = ref Unsafe.As<List<double?>, Mimics<double?>>(ref list);
// Подменяем массив и устанавливаем размер
mimic.Items = array;

View File

@@ -0,0 +1,309 @@
namespace QWERTYkez.Mensura.Extensions;
internal static partial class CollectionsPow2Extensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double QuickPow2(this double base_Value) => base_Value * base_Value;
// === ВТОРАЯ СТЕПЕНЬ ==========================================
// === Pow2Core2 === SIMD
internal static void Pow2Core2<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
// Делаем реинтерпретацию памяти без выделений и копирований
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units[..len]);
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination[..len]);
int i = 0;
// Используем SIMD. Vector<double> автоматически выберет AVX2 (4 элемента) или AVX-512 (8 элементов)
if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
{
ref double srcStart = ref MemoryMarshal.GetReference(srcDouble);
ref double dstStart = ref MemoryMarshal.GetReference(dstDouble);
int limit = len - Vector<double>.Count;
for (; i <= limit; i += Vector<double>.Count)
{
ref double srcCurrent = ref Unsafe.Add(ref srcStart, i);
ref double dstCurrent = ref Unsafe.Add(ref dstStart, i);
// Загружаем вектор, умножаем сам на себя (квадрат) и сохраняем
Vector<double> v = Unsafe.As<double, Vector<double>>(ref srcCurrent);
Unsafe.As<double, Vector<double>>(ref dstCurrent) = v * v;
}
}
// Добираем остаток элементов, если длина не кратна размеру вектора
for (; i < len; i++)
{
double val = srcDouble[i];
dstDouble[i] = val * val;
}
}
internal static void Pow2Core2<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
// 1. Получаем низкоуровневые ссылки на первый элемент каждого Span
ref T? srcRef = ref MemoryMarshal.GetReference(units);
ref R? dstRef = ref MemoryMarshal.GetReference(destination);
// 2. Делаем каст самих ref-ссылок в наш мимик. Компилятор это пропускает.
ref NullableDoubleMimic srcStart = ref Unsafe.As<T?, NullableDoubleMimic>(ref srcRef);
ref NullableDoubleMimic dstStart = ref Unsafe.As<R?, NullableDoubleMimic>(ref dstRef);
int i = 0;
int limit = len - 4;
// Loop Unrolling (Развёртка)
for (; i <= limit; i += 4)
{
ref var s0 = ref Unsafe.Add(ref srcStart, i);
ref var s1 = ref Unsafe.Add(ref srcStart, i + 1);
ref var s2 = ref Unsafe.Add(ref srcStart, i + 2);
ref var s3 = ref Unsafe.Add(ref srcStart, i + 3);
ref var d0 = ref Unsafe.Add(ref dstStart, i);
ref var d1 = ref Unsafe.Add(ref dstStart, i + 1);
ref var d2 = ref Unsafe.Add(ref dstStart, i + 2);
ref var d3 = ref Unsafe.Add(ref dstStart, i + 3);
d0.Value = s0.Value * s0.Value;
d0.HasValue = s0.HasValue;
d1.Value = s1.Value * s1.Value;
d1.HasValue = s1.HasValue;
d2.Value = s2.Value * s2.Value;
d2.HasValue = s2.HasValue;
d3.Value = s3.Value * s3.Value;
d3.HasValue = s3.HasValue;
}
// Добираем остатки
for (; i < len; i++)
{
ref var s = ref Unsafe.Add(ref srcStart, i);
ref var d = ref Unsafe.Add(ref dstStart, i);
d.Value = s.Value * s.Value;
d.HasValue = s.HasValue;
}
}
// === ReadOnlySpan
internal static void Pow2<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
int len = units.Length;
if (len == 0) return;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.Pow2Core2(len, destination);
}
internal static void Pow2<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
int len = units.Length;
if (len == 0) return;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.Pow2Core2(len, destination);
}
// === Array ===
internal static R[] Pow2<T, R>(this T[] units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new R[len];
Pow2(units, result);
return result;
}
internal static R?[] Pow2<T, R>(this T?[] units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new R?[len];
Pow2(units, result);
return result;
}
// === List<Length> ===
internal static List<R> Pow2<T, R>(this List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
Pow2(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Pow2<T, R>(this List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
Pow2(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
}
// === ICollection<Length> ===
internal static void Pow2<T, R>(this ICollection<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Pow2(destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.ToDouble().QuickPow2().ToUnit<R>();
}
internal static void Pow2<T, R>(this ICollection<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Pow2(destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? item.Value.ToDouble().QuickPow2().ToUnit<R>() : null;
}
// === IReadOnlyCollection<Length> ===
internal static void Pow2<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Pow2(destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.ToDouble().QuickPow2().ToUnit<R>();
}
internal static void Pow2<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Pow2(destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? item.Value.ToDouble().QuickPow2().ToUnit<R>() : null;
}
// === IEnumerable<T, R> + yeild ===
static IEnumerable<R> Pow2Iterator<T, R>(IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return (item.ToDouble().QuickPow2()).ToUnit<R>();
}
static IEnumerable<R?> Pow2NullableIterator<T, R>(IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return item.HasValue
? item.Value.ToDouble().QuickPow2().ToUnit<R>() : null;
}
// === IEnumerable<Length> ===
internal static IEnumerable<R> Pow2<T, R>(this IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units is T[] array) return array.Pow2<T, R>();
if (units is List<T> list) return list.Pow2<T, R>();
if (units is ICollection<T> col)
{
var arr = col.ToArray();
arr.Pow2Core2(arr.Length, arr);
return arr.ReCast<T, R>();
}
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Pow2(arr);
return arr.ReCast<T, R>();
}
else return Pow2Iterator<T, R>(units);
}
internal static IEnumerable<R?> Pow2<T, R>(this IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units is T?[] array) return array.Pow2<T, R>();
if (units is List<T?> list) return list.Pow2<T, R>();
if (units is ICollection<T?> col)
{
var arr = col.ToArray();
arr.Pow2(arr);
return arr.ReCast<T, R>();
}
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Pow2(arr);
return arr.ReCast<T, R>();
}
else return Pow2NullableIterator<T, R>(units);
}
}

View File

@@ -0,0 +1,312 @@
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace QWERTYkez.Mensura.Extensions;
internal static partial class CollectionsPow3Extensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double QuickPow3(this double base_Value) => base_Value * base_Value * base_Value;
// === ТРЕТЬЯ СТЕПЕНЬ ==========================================
// === PowCore3 === SIMD
internal static void PowCore3<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
// Делаем реинтерпретацию памяти без выделений и копирований
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units[..len]);
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination[..len]);
int i = 0;
// Используем SIMD. Vector<double> автоматически выберет AVX2 (4 элемента) или AVX-512 (8 элементов)
if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
{
ref double srcStart = ref MemoryMarshal.GetReference(srcDouble);
ref double dstStart = ref MemoryMarshal.GetReference(dstDouble);
int limit = len - Vector<double>.Count;
for (; i <= limit; i += Vector<double>.Count)
{
ref double srcCurrent = ref Unsafe.Add(ref srcStart, i);
ref double dstCurrent = ref Unsafe.Add(ref dstStart, i);
// Загружаем вектор, умножаем сам на себя (квадрат) и сохраняем
Vector<double> v = Unsafe.As<double, Vector<double>>(ref srcCurrent);
Unsafe.As<double, Vector<double>>(ref dstCurrent) = v * v * v;
}
}
// Добираем остаток элементов, если длина не кратна размеру вектора
for (; i < len; i++)
{
double val = srcDouble[i];
dstDouble[i] = val * val * val;
}
}
internal static void PowCore3<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
// 1. Получаем низкоуровневые ссылки на первый элемент каждого Span
ref T? srcRef = ref MemoryMarshal.GetReference(units);
ref R? dstRef = ref MemoryMarshal.GetReference(destination);
// 2. Делаем каст самих ref-ссылок в наш мимик. Компилятор это пропускает.
ref NullableDoubleMimic srcStart = ref Unsafe.As<T?, NullableDoubleMimic>(ref srcRef);
ref NullableDoubleMimic dstStart = ref Unsafe.As<R?, NullableDoubleMimic>(ref dstRef);
int i = 0;
int limit = len - 4;
// Loop Unrolling (Развёртка)
for (; i <= limit; i += 4)
{
ref var s0 = ref Unsafe.Add(ref srcStart, i);
ref var s1 = ref Unsafe.Add(ref srcStart, i + 1);
ref var s2 = ref Unsafe.Add(ref srcStart, i + 2);
ref var s3 = ref Unsafe.Add(ref srcStart, i + 3);
ref var d0 = ref Unsafe.Add(ref dstStart, i);
ref var d1 = ref Unsafe.Add(ref dstStart, i + 1);
ref var d2 = ref Unsafe.Add(ref dstStart, i + 2);
ref var d3 = ref Unsafe.Add(ref dstStart, i + 3);
d0.Value = s0.Value * s0.Value * s0.Value;
d0.HasValue = s0.HasValue;
d1.Value = s1.Value * s1.Value * s1.Value;
d1.HasValue = s1.HasValue;
d2.Value = s2.Value * s2.Value * s2.Value;
d2.HasValue = s2.HasValue;
d3.Value = s3.Value * s3.Value * s3.Value;
d3.HasValue = s3.HasValue;
}
// Добираем остатки
for (; i < len; i++)
{
ref var s = ref Unsafe.Add(ref srcStart, i);
ref var d = ref Unsafe.Add(ref dstStart, i);
d.Value = s.Value * s.Value * s.Value;
d.HasValue = s.HasValue;
}
}
// === ReadOnlySpan
internal static void Pow3<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
int len = units.Length;
if (len == 0) return;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.PowCore3(len, destination);
}
internal static void Pow3<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
int len = units.Length;
if (len == 0) return;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.PowCore3(len, destination);
}
// === Array ===
internal static R[] Pow3<T, R>(this T[] units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new R[len];
Pow3(units, result);
return result;
}
internal static R?[] Pow3<T, R>(this T?[] units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Length;
if (len == 0) return [];
var result = new R?[len];
Pow3(units, result);
return result;
}
// === List<Length> ===
internal static List<R> Pow3<T, R>(this List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
Pow3(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Pow3<T, R>(this List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
Pow3(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
}
// === ICollection<Length> ===
internal static void Pow3<T, R>(this ICollection<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Pow3(destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.ToDouble().QuickPow3().ToUnit<R>();
}
internal static void Pow3<T, R>(this ICollection<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Pow3(destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? item.Value.ToDouble().QuickPow3().ToUnit<R>() : null;
}
// === IReadOnlyCollection<Length> ===
internal static void Pow3<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Pow3(destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.ToDouble().QuickPow3().ToUnit<R>();
}
internal static void Pow3<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Pow3(destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? item.Value.ToDouble().QuickPow3().ToUnit<R>() : null;
}
// === IEnumerable<T, R> + yeild ===
static IEnumerable<R> PowIterator3<T, R>(IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return (item.ToDouble().QuickPow3()).ToUnit<R>();
}
static IEnumerable<R?> PowNullableIterator3<T, R>(IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return item.HasValue
? item.Value.ToDouble().QuickPow3().ToUnit<R>() : null;
}
// === IEnumerable<Length> ===
internal static IEnumerable<R> Pow3<T, R>(this IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units is T[] array) return array.Pow3<T, R>();
if (units is List<T> list) return list.Pow3<T, R>();
if (units is ICollection<T> col)
{
var arr = col.ToArray();
arr.PowCore3(arr.Length, arr);
return arr.ReCast<T, R>();
}
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Pow3(arr);
return arr.ReCast<T, R>();
}
else return PowIterator3<T, R>(units);
}
internal static IEnumerable<R?> Pow3<T, R>(this IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units is T?[] array) return array.Pow3<T, R>();
if (units is List<T?> list) return list.Pow3<T, R>();
if (units is ICollection<T?> col)
{
var arr = col.ToArray();
arr.Pow3(arr);
return arr.ReCast<T, R>();
}
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Pow3(arr);
return arr.ReCast<T, R>();
}
else return PowNullableIterator3<T, R>(units);
}
}

View File

@@ -3,11 +3,9 @@ using System.Runtime.Intrinsics.X86;
namespace QWERTYkez.Mensura.Extensions;
internal static partial class CollectionsPowExtensions
internal static partial class CollectionsPowNExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static double QuickPow(this double base_Value, int exp)
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double QuickPow(this double base_Value, int exp)
{
switch (exp)
{

View File

@@ -0,0 +1,317 @@
using System.Runtime.Intrinsics.X86;
namespace QWERTYkez.Mensura.Extensions;
internal static partial class CollectionsSqrt3Extensions
{
// === SqrtCore3 === SIMD
internal static unsafe void SqrtCore3<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
int i = 0;
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
// 1. ПУТЬ AVX (x64 Процессоры Intel/AMD) — обрабатываем по 4 элемента double
if (Avx.IsSupported && len >= 4)
{
int simdEnd = len & ~3;
for (; i < simdEnd; i += 4)
{
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
// Получаем указатели через Unsafe.AsPointer
double* pSrc = (double*)Unsafe.AsPointer(ref currentSrc);
double* pDst = (double*)Unsafe.AsPointer(ref currentDst);
// Выровненная загрузка (требует, чтобы pSrc был кратен 32)
var v = Avx.LoadVector256(pSrc);
var sqrtV = Avx.Sqrt(v);
// Выровненное сохранение
Avx.Store(pDst, sqrtV);
}
}
// 2. ПУТЬ VECTOR (ARM64 / Apple Silicon / Старые CPU без AVX)
else if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
{
int vCount = Vector<double>.Count;
int simdEnd = len & ~(vCount - 1);
for (; i < simdEnd; i += vCount)
{
// Используем Span для кроссплатформенного создания вектора
var v = new Vector<double>(srcDouble.Slice(i, vCount));
// Кроссплатформенный аппаратный корень (на ARM превратится в NEON инструкцию)
var sqrtV = Vector.SquareRoot(v);
// Копируем напрямую в целевой Span
sqrtV.CopyTo(dstDouble.Slice(i, vCount));
}
}
// 3. Хвост массива (или обычный расчет, если SIMD на процессоре недоступен)
for (; i < len; i++)
{
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
}
}
internal static void SqrtCore3<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
// Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора
ref var srcRef = ref MemoryMarshal.GetReference(units);
ref var dstRef = ref MemoryMarshal.GetReference(destination);
int i = 0;
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
// 1. ОСНОВНОЙ ЦИКЛ: Конвейерная обработка по 4 элемента за итерацию
for (; i < unrollEnd; i += 4)
{
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-ссылки на целевые ячейки типа R? (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);
// Считаем нативный корень прямо в регистрах и трансформируем тип из T в R по месту
d0 = u0.HasValue ? Math.Sqrt(u0.Value.ToDouble()).ToUnit<R>() : null;
d1 = u1.HasValue ? Math.Sqrt(u1.Value.ToDouble()).ToUnit<R>() : null;
d2 = u2.HasValue ? Math.Sqrt(u2.Value.ToDouble()).ToUnit<R>() : null;
d3 = u3.HasValue ? Math.Sqrt(u3.Value.ToDouble()).ToUnit<R>() : 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 ? Math.Sqrt(unit.Value.ToDouble()).ToUnit<R>() : null;
}
}
// === ReadOnlySpan ===
internal static void Sqrt3<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.SqrtCore3(len, destination);
}
internal static void Sqrt3<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units.IsEmpty) return;
int len = units.Length;
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.SqrtCore3(len, destination);
}
// === Array ===
internal static R[] Sqrt3<T, R>(this T[] units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units.Length == 0) return [];
var result = new R[units.Length];
Sqrt3(units, result);
return result;
}
internal static R?[] Sqrt3<T, R>(this T?[] units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units.Length == 0) return [];
var result = new R?[units.Length];
Sqrt3(units, result);
return result;
}
// === List<Length> ===
internal static List<R> Sqrt3<T, R>(this List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
var resultArray = new R[len];
Sqrt3(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
}
internal static List<R?> Sqrt3<T, R>(this List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
var resultArray = new R?[len];
Sqrt3(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
}
// === ICollection<Length> ===
internal static void Sqrt3<T, R>(this ICollection<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Sqrt3(destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
int i = 0;
foreach (T item in units)
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
}
internal static void Sqrt3<T, R>(this ICollection<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Sqrt3(destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
int i = 0;
foreach (T? item in units)
destination[i++] = item.HasValue
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
}
// === IReadOnlyCollection<Length> ===
internal static void Sqrt3<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Sqrt3(destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
int i = 0;
foreach (T item in units)
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
}
internal static void Sqrt3<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
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.Sqrt3(destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
int i = 0;
foreach (T? item in units)
destination[i++] = item.HasValue
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
}
// === IEnumerable<Length> + yield ===
internal static IEnumerable<R> SqrtIterator3<T, R>(this IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return Math.Sqrt(item.ToDouble()).ToUnit<R>();
}
internal static IEnumerable<R?> SqrtNullableIterator3<T, R>(this IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return item.HasValue
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
}
// === IEnumerable<Length> ===
internal static IEnumerable<R> Sqrt3<T, R>(this IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units is T[] array) return array.Sqrt3<T, R>();
if (units is List<T> list) return list.Sqrt3<T, R>();
if (units is ICollection<T> col)
{
var arr = col.ToArray();
arr.Sqrt3(arr);
return arr.ReCast<T, R>();
}
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Sqrt3(arr);
return arr.ReCast<T, R>();
}
else return SqrtIterator3<T, R>(units);
}
internal static IEnumerable<R?> Sqrt3<T, R>(this IEnumerable<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units is T?[] array) return array.Sqrt3<T, R>();
if (units is List<T?> list) return list.Sqrt3<T, R>();
if (units is ICollection<T?> col)
{
var arr = col.ToArray();
arr.Sqrt3(arr);
return arr.ReCast<T, R>();
}
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Sqrt3(arr);
return arr.ReCast<T, R>();
}
else return SqrtNullableIterator3<T, R>(units);
}
}

View File

@@ -1,9 +0,0 @@
namespace QWERTYkez.Mensura;
[StructLayout(LayoutKind.Sequential)]
internal class ListLayoutMimic<T>
{
public T[] Items = null!;
public int Size;
public int Version;
}

View File

@@ -0,0 +1,16 @@
namespace QWERTYkez.Mensura;
[StructLayout(LayoutKind.Sequential)]
internal class Mimics<T>
{
public T[] Items = null!;
public int Size;
public int Version;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NullableDoubleMimic
{
public double Value;
public byte HasValue;
}

View File

@@ -61,21 +61,21 @@ public static class AreaSqrtExtension
{
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
this ReadOnlySpan<Area> units, Span<Length> destination) => units.Sqrt<Area, Length>(destination);
this ReadOnlySpan<Area> units, Span<Length> destination) => units.Sqrt3<Area, Length>(destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
this ReadOnlySpan<Area?> units, Span<Length?> destination) => units.Sqrt<Area, Length>(destination);
this ReadOnlySpan<Area?> units, Span<Length?> destination) => units.Sqrt3<Area, Length>(destination);
// === Array ===
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static Length[] Sqrt(this Area[] units) => units.Sqrt<Area, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt(this Area?[] units) => units.Sqrt<Area, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static Length[] Sqrt(this Area[] units) => units.Sqrt3<Area, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt(this Area?[] units) => units.Sqrt3<Area, Length>();
// === List<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt(this List<Area> units) => units.Sqrt<Area, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt(this List<Area?> units) => units.Sqrt<Area, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt(this List<Area> units) => units.Sqrt3<Area, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt(this List<Area?> units) => units.Sqrt3<Area, Length>();
// === IEnumerable<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt(this IEnumerable<Area> units) => units.Sqrt<Area, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt(this IEnumerable<Area?> units) => units.Sqrt<Area, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt(this IEnumerable<Area> units) => units.Sqrt3<Area, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt(this IEnumerable<Area?> units) => units.Sqrt3<Area, Length>();
}
internal readonly struct AreaConv

View File

@@ -86,34 +86,30 @@ public readonly partial record struct Length
public static class LengthPowExtension
{
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Pow(
this ReadOnlySpan<Length> units, Span<Area> destination) => units.Pow<Length, Area>(destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Pow(
this ReadOnlySpan<Length?> units, Span<Area?> destination) => units.Pow<Length, Area>(destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Pow(
this ReadOnlySpan<Length> units, Span<Area> destination) => units.Pow2<Length, Area>(destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Pow(
this ReadOnlySpan<Length?> units, Span<Area?> destination) => units.Pow2<Length, Area>(destination);
// === Array ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Area[] Pow(this Length[] units) => units.Pow<Length, Area>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Area?[] Pow(this Length?[] units) => units.Pow<Length, Area>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Area[] Pow(this Length[] units) => units.Pow2<Length, Area>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Area?[] Pow(this Length?[] units) => units.Pow2<Length, Area>();
// === List<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Area> Pow(this List<Length> units) => units.Pow<Length, Area>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Area?> Pow(this List<Length?> units) => units.Pow<Length, Area>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Area> Pow(this List<Length> units) => units.Pow2<Length, Area>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Area?> Pow(this List<Length?> units) => units.Pow2<Length, Area>();
// === IEnumerable<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Area> Pow(this IEnumerable<Length> units) => units.Pow<Length, Area>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Area?> Pow(this IEnumerable<Length?> units) => units.Pow<Length, Area>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Area> Pow(this IEnumerable<Length> units) => units.Pow2<Length, Area>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Area?> Pow(this IEnumerable<Length?> units) => units.Pow2<Length, Area>();
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Pow3(
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Pow3(
this ReadOnlySpan<Length> units, Span<Volume> destination) => units.Pow3<Length, Volume>(destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Pow3(
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Pow3(
this ReadOnlySpan<Length?> units, Span<Volume?> destination) => units.Pow3<Length, Volume>(destination);
// === Array ===

View File

@@ -35,29 +35,6 @@ public readonly partial record struct Voltage
public Voltage AddMegaVolts(double value) => new(_Value + VoltageConv.MegaVolts.To(value));
}
public static class VolumeSqrtExtension
{
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sqrt3(
this ReadOnlySpan<Volume> units, Span<Length> destination) => units.Sqrt3<Volume, Length>(destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sqrt3(
this ReadOnlySpan<Volume?> units, Span<Length?> destination) => units.Sqrt3<Volume, Length>(destination);
// === Array ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length[] Sqrt3(this Volume[] units) => units.Sqrt3<Volume, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt3(this Volume?[] units) => units.Sqrt3<Volume, Length>();
// === List<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt3(this List<Volume> units) => units.Sqrt3<Volume, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt3(this List<Volume?> units) => units.Sqrt3<Volume, Length>();
// === IEnumerable<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt3(this IEnumerable<Volume> units) => units.Sqrt3<Volume, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt3(this IEnumerable<Volume?> units) => units.Sqrt3<Volume, Length>();
}
internal readonly struct VoltageConv
{
private VoltageConv(double multiplicator) => this.Multiplicator = multiplicator;

View File

@@ -35,6 +35,27 @@ public readonly partial record struct Volume
public Volume AddMetersCubic(double value) => new(_Value + VolumeConv.MetersCubic.To(value));
}
public static class VolumeSqrtExtension
{
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt3(
this ReadOnlySpan<Volume> units, Span<Length> destination) => units.Sqrt3<Volume, Length>(destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt3(
this ReadOnlySpan<Volume?> units, Span<Length?> destination) => units.Sqrt3<Volume, Length>(destination);
// === Array ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length[] Sqrt3(this Volume[] units) => units.Sqrt3<Volume, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt3(this Volume?[] units) => units.Sqrt3<Volume, Length>();
// === List<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt3(this List<Volume> units) => units.Sqrt3<Volume, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt3(this List<Volume?> units) => units.Sqrt3<Volume, Length>();
// === IEnumerable<T> ===
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt3(this IEnumerable<Volume> units) => units.Sqrt3<Volume, Length>();
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt3(this IEnumerable<Volume?> units) => units.Sqrt3<Volume, Length>();
}
internal readonly struct VolumeConv
{
private VolumeConv(double multiplicator) => this.Multiplicator = multiplicator;