From 7ebbeb785530fd0040899ea631c0f1471b865d6e Mon Sep 17 00:00:00 2001 From: Fantom TM Date: Fri, 29 May 2026 01:33:38 +0700 Subject: [PATCH] XXXXX --- .../UnitOperatorsGenerator.cs | 2041 ++++++++++++++--- QWERTYkez.Mensura/Extensions.cs | 490 ++-- QWERTYkez.Mensura/Units/Length.cs | 1070 --------- QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs | 1681 ++++++++++++++ QWERTYkez.Mensura/Units/XXXXXXXX.Ref.cs | 74 + QWERTYkez.Mensura/globals.cs | 3 +- 6 files changed, 3724 insertions(+), 1635 deletions(-) create mode 100644 QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs create mode 100644 QWERTYkez.Mensura/Units/XXXXXXXX.Ref.cs diff --git a/QWERTYkez.Mensura.Generator/UnitOperatorsGenerator.cs b/QWERTYkez.Mensura.Generator/UnitOperatorsGenerator.cs index bddb0ae..e424168 100644 --- a/QWERTYkez.Mensura.Generator/UnitOperatorsGenerator.cs +++ b/QWERTYkez.Mensura.Generator/UnitOperatorsGenerator.cs @@ -2,396 +2,1783 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; using System.Text; namespace QWERTYkez.Mensura.Generator; -[Generator(LanguageNames.CSharp)] +[Generator] public class UnitOperatorsGenerator : IIncrementalGenerator { + private const string AttributeName = "UnitOperatorsGenerator"; + public void Initialize(IncrementalGeneratorInitializationContext context) { - // Регистрируем сам атрибут для использования в коде + // Генерируем атрибут context.RegisterPostInitializationOutput(ctx => { - ctx.AddSource("UnitOperatorsGeneratorAttribute.g.cs", - SourceText.From(@"namespace QWERTYkez.Mensura + string attributeSource = @" +namespace QWERTYkez.Mensura { - [System.AttributeUsage(System.AttributeTargets.Struct | System.AttributeTargets.RecordStruct, AllowMultiple = false)] + [System.AttributeUsage(System.AttributeTargets.Struct, AllowMultiple = false)] public sealed class UnitOperatorsGeneratorAttribute : System.Attribute { } -}", Encoding.UTF8)); +}"; + ctx.AddSource("UnitOperatorsGeneratorAttribute.g.cs", SourceText.From(attributeSource, Encoding.UTF8)); }); - // Находим все record struct с атрибутом - var unitStructs = context.SyntaxProvider + // Ищем все readonly partial record struct с атрибутом + var structsProvider = context.SyntaxProvider .CreateSyntaxProvider( - predicate: static (node, _) => IsCandidate(node), - transform: static (ctx, _) => GetUnitInfo(ctx)) - .Where(info => info != null) + predicate: static (node, _) => IsTargetStruct(node), + transform: static (ctx, _) => GetStructInfo(ctx)) + .Where(info => info.HasValue) .Select((info, _) => info!.Value) .Collect(); - context.RegisterSourceOutput(unitStructs, Execute); + context.RegisterSourceOutput(structsProvider, (spc, structs) => + { + foreach (var structInfo in structs) + { + string generatedCode = GeneratePartial(structInfo); + spc.AddSource($"{structInfo.TypeName}.Generated.g.cs", SourceText.From(generatedCode, Encoding.UTF8)); + } + }); } - private static bool IsCandidate(SyntaxNode node) + private static bool IsTargetStruct(SyntaxNode node) { - return node is RecordDeclarationSyntax record && - record.Modifiers.Any(SyntaxKind.ReadOnlyKeyword) && - record.Modifiers.Any(SyntaxKind.PartialKeyword) && - record.Keyword.IsKind(SyntaxKind.RecordKeyword) && - record.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword); + if (node is not RecordDeclarationSyntax record) + return false; + + // Должен быть record struct с модификаторами readonly и partial + if (!record.Modifiers.Any(SyntaxKind.ReadOnlyKeyword) || + !record.Modifiers.Any(SyntaxKind.PartialKeyword) || + !record.Keyword.IsKind(SyntaxKind.RecordKeyword) || + !record.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword)) + return false; + + // Проверяем наличие атрибута [UnitOperatorsGenerator] + foreach (var attrList in record.AttributeLists) + foreach (var attr in attrList.Attributes) + { + string name = attr.Name.ToString(); + if (name == AttributeName || name == AttributeName + "Attribute") + return true; + } + return false; } - private static UnitInfo? GetUnitInfo(GeneratorSyntaxContext context) + private static StructInfo? GetStructInfo(GeneratorSyntaxContext context) { var record = (RecordDeclarationSyntax)context.Node; var semanticModel = context.SemanticModel; - if (semanticModel.GetDeclaredSymbol(record) is not INamedTypeSymbol typeSymbol) return null; + if (semanticModel.GetDeclaredSymbol(record) is not INamedTypeSymbol typeSymbol) + return null; - // Проверяем наличие атрибута [UnitOperatorsGenerator] - bool hasAttribute = typeSymbol.GetAttributes() - .Any(attr => attr.AttributeClass?.Name == "UnitOperatorsGeneratorAttribute"); - if (!hasAttribute) return null; + string namespaceName = typeSymbol.ContainingNamespace?.ToString(); + if (string.IsNullOrEmpty(namespaceName)) + return null; - string ns = typeSymbol.ContainingNamespace?.ToString(); - if (string.IsNullOrEmpty(ns)) return null; - - string typeName = typeSymbol.Name; - - // Собираем имена уже существующих членов, чтобы не генерировать дубликаты - var existingMemberNames = new HashSet( - typeSymbol.GetMembers() - .Where(m => m.Kind == SymbolKind.Method || m.Kind == SymbolKind.Property || m.Kind == SymbolKind.Field) - .Select(m => m.Name)); - - var existingOperatorNames = new HashSet( - typeSymbol.GetMembers() - .Where(m => m is IMethodSymbol method && method.MethodKind == MethodKind.UserDefinedOperator) - .Select(m => m.Name)); - - return new UnitInfo(ns, typeName, existingMemberNames, existingOperatorNames); + return new StructInfo(namespaceName, typeSymbol.Name); } - private static void Execute(SourceProductionContext context, ImmutableArray units) + private static string GeneratePartial(StructInfo info) { - // Группируем по полному имени типа, чтобы избежать дублирования hintName - var distinctUnits = units - .GroupBy(u => $"{u.Namespace}.{u.TypeName}") - .Select(g => g.First()) - .ToImmutableArray(); + string typeName = info.TypeName; + string ns = info.Namespace; - foreach (var unit in distinctUnits) - { - string code = GenerateFullCode(unit); - string hintName = $"{unit.Namespace}.{unit.TypeName}.Generated.cs" - .Replace('<', '_') - .Replace('>', '_') - .Replace('[', '_') - .Replace(']', '_') - .Replace(' ', '_'); - context.AddSource(hintName, SourceText.From(code, Encoding.UTF8)); - } + // Здесь должен быть полный код из вашего файла XXXXXXXXXXXX.cs + // с заменой XXXXXXXXXXXXXX на {typeName}. Для краткости приведён скелет. + // Вы должны скопировать сюда всё содержимое вашего второго файла, + // заменив XXXXXXXXXXXXXX на {typeName}. + string skeleton = @" +using System.Globalization; +using System.Runtime.Serialization; + +namespace QWERTYkez.Mensura.Units; + +[JsonConverter(typeof({typeName}Converter))] +public readonly partial record struct {typeName} +{ + [JsonInclude, DataMember, JsonPropertyName(""v"")] // для JSON / EF на случай сбоев, если пробелма с _Value + internal double Value { get => _Value; init => _Value = value; } + internal readonly double _Value; + internal {typeName}(double value) => _Value = value; + + public override int GetHashCode() => _Value.GetHashCode(); + public int CompareTo({typeName}? other) => _Value.CompareTo(other is null ? 0d : other.Value._Value); + public int CompareTo({typeName} other) => _Value.CompareTo(other._Value); + + public bool Equals({typeName}? other) => _Value.Equals(other?._Value); + + + [JsonIgnore, IgnoreDataMember] public bool IsPositive => _Value >= 0; + [JsonIgnore, IgnoreDataMember] public bool IsGreaterThanZero => _Value > 0; + [JsonIgnore, IgnoreDataMember] public bool IsNegative => _Value < 0; + [JsonIgnore, IgnoreDataMember] public bool IsZero => _Value == 0; + + + public static {typeName} Zero { get; } = new(0d); + public static {typeName} Min { get; } = new(double.MinValue); + public static {typeName} Max { get; } = new(double.MaxValue); + public static {typeName} NegativeInfinity { get; } = new(double.NegativeInfinity); + public static {typeName} PositiveInfinity { get; } = new(double.PositiveInfinity); + + + public static bool operator ==({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) == (T2 is null ? 0d : T2.Value._Value); + public static bool operator !=({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) != (T2 is null ? 0d : T2.Value._Value); + + public static bool operator <({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) < (T2 is null ? 0d : T2.Value._Value); + public static bool operator <=({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) <= (T2 is null ? 0d : T2.Value._Value); + public static bool operator >({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) > (T2 is null ? 0d : T2.Value._Value); + public static bool operator >=({typeName}? T1, {typeName}? T2) => (T1 is null ? 0d : T1.Value._Value) >= (T2 is null ? 0d : T2.Value._Value); + + + public static {typeName} operator +({typeName} T2) => new(+T2._Value); + public static {typeName} operator +({typeName} T1, {typeName} T2) => new(T1._Value + T2._Value); + public static {typeName} operator -({typeName} T2) => new(-T2._Value); + public static {typeName} operator -({typeName} T1, {typeName} T2) => new(T1._Value - T2._Value); + + + // double + public static {typeName} operator *({typeName} T1, double T2) => new(T1._Value * T2); + public static {typeName} operator *({typeName} T1, double? T2) => T1 * (T2 ?? 0d); + public static {typeName} operator *(double T1, {typeName} T2) => new(T1 * T2._Value); + public static {typeName} operator *(double? T1, {typeName} T2) => (T1 ?? 0d) * T2; + public static {typeName} operator /({typeName} T1, double T2) => new(T1._Value / T2); + public static {typeName} operator /({typeName} T1, double? T2) => T1 / (T2 ?? 0d); + public static double operator /({typeName} T1, {typeName} T2) => T1._Value / T2._Value; + + // sbyte + public static {typeName} operator *({typeName} T1, sbyte T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, sbyte? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(sbyte T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(sbyte? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, sbyte T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, sbyte? T2) => T1 / T2.ToDouble(); + + // short + public static {typeName} operator *({typeName} T1, short T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, short? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(short T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(short? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, short T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, short? T2) => T1 / T2.ToDouble(); + + // int + public static {typeName} operator *({typeName} T1, int T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, int? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(int T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(int? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, int T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, int? T2) => T1 / T2.ToDouble(); + + // long + public static {typeName} operator *({typeName} T1, long T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, long? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(long T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(long? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, long T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, long? T2) => T1 / T2.ToDouble(); + + // byte + public static {typeName} operator *({typeName} T1, byte T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, byte? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(byte T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(byte? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, byte T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, byte? T2) => T1 / T2.ToDouble(); + + // ushort + public static {typeName} operator *({typeName} T1, ushort T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, ushort? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(ushort T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(ushort? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, ushort T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, ushort? T2) => T1 / T2.ToDouble(); + + // uint + public static {typeName} operator *({typeName} T1, uint T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, uint? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(uint T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(uint? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, uint T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, uint? T2) => T1 / T2.ToDouble(); + + // ulong + public static {typeName} operator *({typeName} T1, ulong T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, ulong? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(ulong T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(ulong? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, ulong T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, ulong? T2) => T1 / T2.ToDouble(); + + // nint + public static {typeName} operator *({typeName} T1, nint T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, nint? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(nint T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(nint? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, nint T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, nint? T2) => T1 / T2.ToDouble(); + + // nuint + public static {typeName} operator *({typeName} T1, nuint T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, nuint? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(nuint T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(nuint? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, nuint T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, nuint? T2) => T1 / T2.ToDouble(); + + // float + public static {typeName} operator *({typeName} T1, float T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, float? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(float T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(float? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, float T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, float? T2) => T1 / T2.ToDouble(); + + // decimal + public static {typeName} operator *({typeName} T1, decimal T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, decimal? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(decimal T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(decimal? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, decimal T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, decimal? T2) => T1 / T2.ToDouble(); + +#if NET7_0_OR_GREATER + // Int128 + public static {typeName} operator *({typeName} T1, Int128 T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, Int128? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(Int128 T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(Int128? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, Int128 T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, Int128? T2) => T1 / T2.ToDouble(); + + // UInt128 + public static {typeName} operator *({typeName} T1, UInt128 T2) => T1 * T2.ToDouble(); + public static {typeName} operator *({typeName} T1, UInt128? T2) => T1 * T2.ToDouble(); + public static {typeName} operator *(UInt128 T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator *(UInt128? T1, {typeName} T2) => T1.ToDouble() * T2; + public static {typeName} operator /({typeName} T1, UInt128 T2) => T1 / T2.ToDouble(); + public static {typeName} operator /({typeName} T1, UInt128? T2) => T1 / T2.ToDouble(); +#endif + + public static explicit operator {typeName}(double val) => new(val); + public static explicit operator double({typeName} unit) => unit._Value; + + public {typeName} Abs() => new(Math.Abs(_Value)); + + /// C^2 = this^2 + B^2 C = (this^2 + B^2).Sqrt(2) + public {typeName} HypFromLeg({typeName} B) => new(Math.Sqrt(_Value * _Value + B._Value * B._Value)); + + /// C^2 = this^2 + B^2 C = (this^2 + B^2).Sqrt(2) + public {typeName} HypFromLeg({typeName}? B) + { + double b = B is null ? 0d : B.Value._Value; + return new(Math.Sqrt(_Value * _Value + b * b)); } - private static string GenerateFullCode(UnitInfo info) + /// C^2 = this^2 + B^2 B = (C^2 - this^2).Sqrt(2) + public {typeName} LegFromHyp({typeName} C) => new(Math.Sqrt(C._Value * C._Value - _Value * _Value)); + + /// C^2 = this^2 + B^2 B = (C^2 - this^2).Sqrt(2) + public {typeName} LegFromHyp({typeName}? C) { - string t = info.TypeName; - var sb = new StringBuilder(); - sb.AppendLine("// "); - sb.AppendLine("using System.Globalization;"); - sb.AppendLine("using System.Runtime.Serialization;"); - sb.AppendLine("using System.Numerics;"); - sb.AppendLine(); - sb.AppendLine($"namespace {info.Namespace};"); - sb.AppendLine(); - sb.AppendLine($"[System.Text.Json.Serialization.JsonConverter(typeof({t}Converter))]"); - sb.AppendLine($"public readonly partial record struct {t}"); - sb.AppendLine("{"); - // 1. Поле и конструктор - sb.AppendLine($" [System.Text.Json.Serialization.JsonInclude, DataMember, System.Text.Json.Serialization.JsonPropertyName(\"v\")]"); - sb.AppendLine($" internal double Value {{ get => _Value; init => _Value = value; }}"); - sb.AppendLine($" internal readonly double _Value;"); - sb.AppendLine($" internal {t}(double value) => _Value = value;"); - sb.AppendLine(); - // 2. Базовые методы - if (!info.ExistingMemberNames.Contains("GetHashCode")) - sb.AppendLine($" public override int GetHashCode() => _Value.GetHashCode();"); - if (!info.ExistingMemberNames.Contains("CompareTo")) + double c = C is null ? 0d : C.Value._Value; + return new(Math.Sqrt(c * c - _Value * _Value)); + } + + /// this^2 = A^2 + B^2 B = (this^2 - A^2).Sqrt(2) + public {typeName} LegFromLeg({typeName} A) => new(Math.Sqrt(_Value * _Value - A._Value * A._Value)); + + /// this^2 = A^2 + B^2 B = (this^2 - A^2).Sqrt(2) + public {typeName} LegFromLeg({typeName}? A) + { + double a = A is null ? 0d : A.Value._Value; + return new(Math.Sqrt(_Value * _Value - a * a)); + } +} + +public static class {typeName}Extension +{ + internal static double ToDouble(this {typeName}? unit) => unit is null ? 0d : unit.Value._Value; + + public static {typeName} MetricSum(this IEnumerable<{typeName}> units) => new() { Value = units?.Sum(m => m._Value) ?? 0d }; + public static {typeName} MetricAverage(this IEnumerable<{typeName}> units) => new() { Value = units?.Average(m => m._Value) ?? double.NaN }; + public static {typeName} MetricMax(this IEnumerable<{typeName}> units) => new() { Value = units?.Max(m => m._Value) ?? double.MinValue }; + public static {typeName} MetricMin(this IEnumerable<{typeName}> units) => new() { Value = units?.Min(m => m._Value) ?? double.MaxValue }; + + public static {typeName} MetricSum(this IEnumerable<{typeName}?> units) => new() { Value = units?.Sum(m => m.ToDouble()) ?? 0d }; + public static {typeName} MetricAverage(this IEnumerable<{typeName}?> units) => new() { Value = units?.Average(m => m.ToDouble()) ?? double.NaN }; + public static {typeName} MetricMax(this IEnumerable<{typeName}?> units) => new() { Value = units?.Max(m => m.ToDouble()) ?? double.MinValue }; + public static {typeName} MetricMin(this IEnumerable<{typeName}?> units) => new() { Value = units?.Min(m => m.ToDouble()) ?? double.MaxValue }; + + + internal static void MultiplyCore(ReadOnlySpan<{typeName}> source, double value, Span<{typeName}> destination) + { + int len = source.Length; + ReadOnlySpan srcDouble = MemoryMarshal.Cast<{typeName}, double>(source); + Span dstDouble = MemoryMarshal.Cast<{typeName}, double>(destination); + + var vectorizedValue = new Vector(value); + int vectorSize = Vector.Count; + int i = 0; + + ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); + ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); + + int SIMDEnd = len - (len % vectorSize); + for (; i < SIMDEnd; i += vectorSize) { - sb.AppendLine($" public int CompareTo({t}? other) => _Value.CompareTo(other is null ? 0d : other._Value);"); - sb.AppendLine($" public int CompareTo({t} other) => _Value.CompareTo(other._Value);"); + ref double currentSrc = ref Unsafe.Add(ref srcRef, i); + ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); + var vector = new Vector(srcWindow); + var multiplied = vector * vectorizedValue; + ref double currentDst = ref Unsafe.Add(ref dstRef, i); + Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); + multiplied.CopyTo(dstWindow); } - if (!info.ExistingMemberNames.Contains("Equals")) - sb.AppendLine($" public bool Equals({t}? other) => _Value.Equals(other?._Value);"); - sb.AppendLine(); - // 3. Свойства IsPositive и т.д. - if (!info.ExistingMemberNames.Contains("IsPositive")) - sb.AppendLine($" [System.Text.Json.Serialization.JsonIgnore, IgnoreDataMember] public bool IsPositive => _Value >= 0;"); - if (!info.ExistingMemberNames.Contains("IsGreaterThanZero")) - sb.AppendLine($" [System.Text.Json.Serialization.JsonIgnore, IgnoreDataMember] public bool IsGreaterThanZero => _Value > 0;"); - if (!info.ExistingMemberNames.Contains("IsNegative")) - sb.AppendLine($" [System.Text.Json.Serialization.JsonIgnore, IgnoreDataMember] public bool IsNegative => _Value < 0;"); - if (!info.ExistingMemberNames.Contains("IsZero")) - sb.AppendLine($" [System.Text.Json.Serialization.JsonIgnore, IgnoreDataMember] public bool IsZero => _Value == 0;"); - sb.AppendLine(); - // 4. Статические свойства - if (!info.ExistingMemberNames.Contains("Zero")) - sb.AppendLine($" public static {t} Zero => new(0d);"); - if (!info.ExistingMemberNames.Contains("Min")) - sb.AppendLine($" public static {t} Min => new(double.MinValue);"); - if (!info.ExistingMemberNames.Contains("Max")) - sb.AppendLine($" public static {t} Max => new(double.MaxValue);"); - if (!info.ExistingMemberNames.Contains("NegativeInfinity")) - sb.AppendLine($" public static {t} NegativeInfinity => new(double.NegativeInfinity);"); - if (!info.ExistingMemberNames.Contains("PositiveInfinity")) - sb.AppendLine($" public static {t} PositiveInfinity => new(double.PositiveInfinity);"); - sb.AppendLine(); - // 5. Операторы сравнения (с поддержкой null) - if (!info.ExistingOperatorNames.Contains("op_Equality")) - sb.AppendLine($" public static bool operator ==({t}? left, {t}? right) => (left is null ? 0d : left._Value) == (right is null ? 0d : right._Value);"); - if (!info.ExistingOperatorNames.Contains("op_Inequality")) - sb.AppendLine($" public static bool operator !=({t}? left, {t}? right) => (left is null ? 0d : left._Value) != (right is null ? 0d : right._Value);"); - if (!info.ExistingOperatorNames.Contains("op_LessThan")) - sb.AppendLine($" public static bool operator <({t}? left, {t}? right) => (left is null ? 0d : left._Value) < (right is null ? 0d : right._Value);"); - if (!info.ExistingOperatorNames.Contains("op_LessThanOrEqual")) - sb.AppendLine($" public static bool operator <=({t}? left, {t}? right) => (left is null ? 0d : left._Value) <= (right is null ? 0d : right._Value);"); - if (!info.ExistingOperatorNames.Contains("op_GreaterThan")) - sb.AppendLine($" public static bool operator >({t}? left, {t}? right) => (left is null ? 0d : left._Value) > (right is null ? 0d : right._Value);"); - if (!info.ExistingOperatorNames.Contains("op_GreaterThanOrEqual")) - sb.AppendLine($" public static bool operator >=({t}? left, {t}? right) => (left is null ? 0d : left._Value) >= (right is null ? 0d : right._Value);"); - sb.AppendLine(); - // 6. Унарные операторы - if (!info.ExistingOperatorNames.Contains("op_UnaryPlus")) - sb.AppendLine($" public static {t} operator +({t} x) => x;"); - if (!info.ExistingOperatorNames.Contains("op_UnaryNegation")) - sb.AppendLine($" public static {t} operator -({t} x) => new(-x._Value);"); - sb.AppendLine(); - // 7. Бинарные +, - с тем же типом - if (!info.ExistingOperatorNames.Contains("op_Addition")) - sb.AppendLine($" public static {t} operator +({t} a, {t} b) => new(a._Value + b._Value);"); - if (!info.ExistingOperatorNames.Contains("op_Subtraction")) - sb.AppendLine($" public static {t} operator -({t} a, {t} b) => new(a._Value - b._Value);"); - sb.AppendLine(); - // 8. Умножение на числа (все числовые типы) - var numericTypes = new[] { "double", "double?", "byte", "byte?", "sbyte", "sbyte?", - "short", "short?", "ushort", "ushort?", "int", "int?", "uint", "uint?", - "long", "long?", "ulong", "ulong?", "float", "float?", "decimal", "decimal?" }; - if (!info.ExistingOperatorNames.Contains("op_Multiply")) + + for (; i < len; i++) { - foreach (var nt in numericTypes) + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * value; + } + } + internal static void DivideCore(ReadOnlySpan<{typeName}> source, double divisor, Span<{typeName}> destination) + { + // 1. Проверка на ноль + if (divisor == 0d || double.IsNaN(divisor)) + throw new DivideByZeroException(""Делитель не может быть равен нулю.""); + + int len = source.Length; + ReadOnlySpan srcDouble = MemoryMarshal.Cast<{typeName}, double>(source); + Span dstDouble = MemoryMarshal.Cast<{typeName}, double>(destination); + + var vectorizedValue = new Vector(divisor); + int vectorSize = Vector.Count; + int i = 0; + + ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); + ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); + + int SIMDEnd = len - (len % vectorSize); + for (; i < SIMDEnd; i += vectorSize) + { + ref double currentSrc = ref Unsafe.Add(ref srcRef, i); + ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); + var vector = new Vector(srcWindow); + var multiplied = vector / vectorizedValue; + ref double currentDst = ref Unsafe.Add(ref dstRef, i); + Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); + multiplied.CopyTo(dstWindow); + } + + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) / divisor; + } + } + internal static void DivideCore(double dividend, ReadOnlySpan<{typeName}> source, Span<{typeName}> destination) + { + int len = source.Length; + ReadOnlySpan srcDouble = MemoryMarshal.Cast<{typeName}, double>(source); + Span dstDouble = MemoryMarshal.Cast<{typeName}, double>(destination); + + var vectorizedValue = new Vector(dividend); + var zeroVector = Vector.Zero; // Вектор из нулей для сравнения + int vectorSize = Vector.Count; + int i = 0; + + ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); + ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); + + int SIMDEnd = len - (len % vectorSize); + for (; i < SIMDEnd; i += vectorSize) + { + ref double currentSrc = ref Unsafe.Add(ref srcRef, i); + ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); + var vector = new Vector(srcWindow); + + // БЫСТРАЯ ПРОВЕРКА: Есть ли хотя бы один 0.0 в текущем векторе? + if (Vector.EqualsAny(vector, zeroVector)) { - bool isNullable = nt.EndsWith("?"); - string baseType = isNullable ? nt.TrimEnd('?') : nt; - if (baseType == "decimal") + throw new DivideByZeroException($""Обнаружен делитель, равный нулю, в районе индексов {i}..{i + vectorSize - 1}.""); + } + + var multiplied = vectorizedValue / vector; + ref double currentDst = ref Unsafe.Add(ref dstRef, i); + Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); + multiplied.CopyTo(dstWindow); + } + + // Хвостовой цикл + for (; i < len; i++) + { + double divisor = Unsafe.Add(ref srcRef, i); + if (divisor == 0.0) + { + throw new DivideByZeroException($""Обнаружен делитель, равный нулю, в индексе {i}.""); + } + Unsafe.Add(ref dstRef, i) = dividend / divisor; + } + } + internal static void PlusCore(ReadOnlySpan<{typeName}> source, double summand, Span<{typeName}> destination) + { + int len = source.Length; + ReadOnlySpan srcDouble = MemoryMarshal.Cast<{typeName}, double>(source); + Span dstDouble = MemoryMarshal.Cast<{typeName}, double>(destination); + + var vectorizedValue = 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 - (len % vectorSize); + for (; i < SIMDEnd; i += vectorSize) + { + ref double currentSrc = ref Unsafe.Add(ref srcRef, i); + ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); + var vector = new Vector(srcWindow); + var multiplied = vector + vectorizedValue; + ref double currentDst = ref Unsafe.Add(ref dstRef, i); + Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); + multiplied.CopyTo(dstWindow); + } + + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand; + } + } + internal static void MinusCore(ReadOnlySpan<{typeName}> source, double subtrahend, Span<{typeName}> destination) + { + int len = source.Length; + ReadOnlySpan srcDouble = MemoryMarshal.Cast<{typeName}, double>(source); + Span dstDouble = MemoryMarshal.Cast<{typeName}, double>(destination); + + var vectorizedValue = 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 - (len % vectorSize); + for (; i < SIMDEnd; i += vectorSize) + { + ref double currentSrc = ref Unsafe.Add(ref srcRef, i); + ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); + var vector = new Vector(srcWindow); + var multiplied = vector - vectorizedValue; + ref double currentDst = ref Unsafe.Add(ref dstRef, i); + Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); + multiplied.CopyTo(dstWindow); + } + + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend; + } + } + internal static void MinusCore(double minuend, ReadOnlySpan<{typeName}> source, Span<{typeName}> destination) + { + int len = source.Length; + ReadOnlySpan srcDouble = MemoryMarshal.Cast<{typeName}, double>(source); + Span dstDouble = MemoryMarshal.Cast<{typeName}, double>(destination); + + var vectorizedValue = 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 - (len % vectorSize); + for (; i < SIMDEnd; i += vectorSize) + { + ref double currentSrc = ref Unsafe.Add(ref srcRef, i); + ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); + var vector = new Vector(srcWindow); + var multiplied = vectorizedValue - vector; + ref double currentDst = ref Unsafe.Add(ref dstRef, i); + Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); + multiplied.CopyTo(dstWindow); + } + + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = minuend - Unsafe.Add(ref srcRef, i); + } + } + + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + internal static void PowCore(ReadOnlySpan<{typeName}> source, int power, Span<{typeName}> destination) + { + int len = source.Length; + ReadOnlySpan srcDouble = MemoryMarshal.Cast<{typeName}, double>(source); + Span dstDouble = MemoryMarshal.Cast<{typeName}, double>(destination); + int vectorSize = Vector.Count; + int i = 0; + ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); + ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); + int SIMDEnd = len - (len % vectorSize); + for (; i < SIMDEnd; i += vectorSize) + { + var vector = new Vector(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.Add(ref srcRef, i), vectorSize)); + var resultVector = VectorPow(vector, power); + resultVector.CopyTo(MemoryMarshal.CreateSpan(ref Unsafe.Add(ref dstRef, i), vectorSize)); + } + + // Приватный SIMD-метод быстрого возведения в степень + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static Vector VectorPow(Vector baseVector, int exp) + { + if (exp == 0) return Vector.One; + if (exp == 1) return baseVector; + + if (exp < 0) + { + baseVector = Vector.One / baseVector; + exp = -exp; // Внимание: может переполниться при int.MinValue, но для степеней это редчайший кейс + } + + var result = Vector.One; + var currentBase = baseVector; + + while (exp > 0) + { + if ((exp & 1) == 1) { - string conv = isNullable ? "(double)(b ?? 0m)" : "(double)b"; - sb.AppendLine($" public static {t} operator *({t} a, {nt} b) => new(a._Value * {conv});"); - sb.AppendLine($" public static {t} operator *({nt} a, {t} b) => new({conv} * b._Value);"); - } - else if (isNullable) - { - sb.AppendLine($" public static {t} operator *({t} a, {nt} b) => new(a._Value * (b ?? 0d));"); - sb.AppendLine($" public static {t} operator *({nt} a, {t} b) => new((a ?? 0d) * b._Value);"); - } - else - { - sb.AppendLine($" public static {t} operator *({t} a, {nt} b) => new(a._Value * b);"); - sb.AppendLine($" public static {t} operator *({nt} a, {t} b) => new(a * b._Value);"); + result *= currentBase; } + currentBase *= currentBase; + exp >>= 1; + } + + return result; + } + + for (; i < len; i++) + Unsafe.Add(ref dstRef, i) = Math.Pow(Unsafe.Add(ref srcRef, i), power); + } + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + internal static unsafe void PowCore(ReadOnlySpan<{typeName}> source, double power, Span<{typeName}> destination) + { + int len = source.Length; + if (len == 0) return; + + fixed (double* pSrc = MemoryMarshal.Cast<{typeName}, double>(source)) + fixed (double* pDst = MemoryMarshal.Cast<{typeName}, double>(destination)) + { + double* pCurrentSrc = pSrc; + double* pCurrentDst = pDst; + double* pEnd = pSrc + len; + + while (pCurrentSrc <= pEnd - 4) + { + pCurrentDst[0] = Math.Pow(pCurrentSrc[0], power); + pCurrentDst[1] = Math.Pow(pCurrentSrc[1], power); + pCurrentDst[2] = Math.Pow(pCurrentSrc[2], power); + pCurrentDst[3] = Math.Pow(pCurrentSrc[3], power); + + pCurrentSrc += 4; + pCurrentDst += 4; + } + + while (pCurrentSrc < pEnd) + { + *pCurrentDst = Math.Pow(*pCurrentSrc, power); + + pCurrentSrc++; + pCurrentDst++; } } - // 9. Деление на число - if (!info.ExistingOperatorNames.Contains("op_Division")) + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void SqrtCore(ReadOnlySpan<{typeName}> source, Span<{typeName}> destination) + { + int len = source.Length; + ReadOnlySpan srcDouble = MemoryMarshal.Cast<{typeName}, double>(source); + Span dstDouble = MemoryMarshal.Cast<{typeName}, double>(destination); + + int vectorSize = Vector.Count; + int i = 0; + + ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); + ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); + + int SIMDEnd = len - (len % vectorSize); + for (; i < SIMDEnd; i += vectorSize) { - foreach (var nt in numericTypes) + ref double currentSrc = ref Unsafe.Add(ref srcRef, i); + ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); + var vector = new Vector(srcWindow); + var multiplied = Vector.SquareRoot(vector); + ref double currentDst = ref Unsafe.Add(ref dstRef, i); + Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); + multiplied.CopyTo(dstWindow); + } + + for (; i < len; i++) + { + Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i)); + } + } + + // ========================================== + // === MULTIPLY === + // ========================================== + + public static {typeName}[] Multiply(this {typeName}[] units, double multiplicator) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = new {typeName}[units.Length]; + MultiplyCore(units, multiplicator, result); + return result; + } + public static {typeName}[] Multiply(this double multiplicator, {typeName}[] units) + => units.Multiply(multiplicator); + public static {typeName}?[] Multiply(this {typeName}?[] units, double multiplicator) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = ({typeName}?[])units.Clone(); + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value * multiplicator); + } + return result; + } + public static {typeName}?[] Multiply(this double multiplicator, {typeName}?[] units) + => units.Multiply(multiplicator); + + // === ReadOnlySpan === + public static Span<{typeName}> Multiply(this ReadOnlySpan<{typeName}> units, double multiplicator) + { + if (units.Length == 0) return []; + Span<{typeName}> result = new {typeName}[units.Length]; + MultiplyCore(units, multiplicator, result); + return result; + } + public static Span<{typeName}> Multiply(this double multiplicator, ReadOnlySpan<{typeName}> units) + => units.Multiply(multiplicator); + public static Span<{typeName}?> Multiply(this ReadOnlySpan<{typeName}?> units, double multiplicator) + { + if (units.Length == 0) return []; + Span<{typeName}?> result = new {typeName}?[units.Length]; + units.CopyTo(result); + + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value * multiplicator); + } + return result; + } + public static Span<{typeName}?> Multiply(this double multiplicator, ReadOnlySpan<{typeName}?> units) + => units.Multiply(multiplicator); + + // === List === + public static List<{typeName}> Multiply(this List<{typeName}> units, double multiplicator) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}>(len); + result.SetCountUnsafe(len); + MultiplyCore(CollectionsMarshal.AsSpan(units), multiplicator, CollectionsMarshal.AsSpan(result)); + return result; + } + public static List<{typeName}> Multiply(this double multiplicator, List<{typeName}> units) + => units.Multiply(multiplicator); + public static List<{typeName}?> Multiply(this List<{typeName}?> units, double multiplicator) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}?>(units); + Span<{typeName}?> dstSpan = CollectionsMarshal.AsSpan(result); + for (int i = 0; i < len; i++) + { + ref var item = ref dstSpan[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value * multiplicator); + } + return result; + } + public static List<{typeName}?> Multiply(this double multiplicator, List<{typeName}?> units) + => units.Multiply(multiplicator); + + // === ICollection === + public static Tcoll Multiply(this ICollection<{typeName}> units, double multiplicator) + where Tcoll : class, ICollection<{typeName}>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item._Value * multiplicator)); + return tColl; + } + public static Tcoll Multiply(this double multiplicator, ICollection<{typeName}> units) + where Tcoll : class, ICollection<{typeName}>, new() => Multiply(units, multiplicator); + public static Tcoll Multiply(this ICollection<{typeName}?> units, double multiplicator) + where Tcoll : class, ICollection<{typeName}?>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item.HasValue ? item.Value._Value * multiplicator : 0d)); + return tColl; + } + public static Tcoll Multiply(this double multiplicator, ICollection<{typeName}?> units) + where Tcoll : class, ICollection<{typeName}?>, new() => Multiply(units, multiplicator); + + // === IEnumerable === + public static IEnumerable<{typeName}> Multiply(this IEnumerable<{typeName}> units, double multiplicator) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return new {typeName}(item._Value * multiplicator); + } + public static IEnumerable<{typeName}> Multiply(this double multiplicator, IEnumerable<{typeName}> units) + => units.Multiply(multiplicator); + public static IEnumerable<{typeName}?> Multiply(this IEnumerable<{typeName}?> units, double multiplicator) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return item.HasValue + ? new {typeName}(item.Value._Value * multiplicator) : null; + } + public static IEnumerable<{typeName}?> Multiply(this double multiplicator, IEnumerable<{typeName}?> units) + => units.Multiply(multiplicator); + + // ========================================== + // === DIVIDE === + // ========================================== + + public static {typeName}[] Divide(this {typeName}[] units, double divisor) + { + if (units is null) return null!; + if (units.Length == 0) return []; + if (divisor == 0 || double.IsNaN(divisor)) + throw new ArgumentException(""Делитель не может быть 0 или NaN."", nameof(divisor)); + + var result = new {typeName}[units.Length]; + DivideCore(units, divisor, result); + return result; + } + public static {typeName}[] Divide(this double dividend, {typeName}[] units) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = new {typeName}[units.Length]; + DivideCore(dividend, units, result); // Вызов зеркального ядра (число / массив) + return result; + } + public static {typeName}?[] Divide(this {typeName}?[] units, double divisor) + { + if (units is null) return null!; + if (units.Length == 0) return []; + if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException(""Делитель не может быть 0 или NaN."", nameof(divisor)); + + var result = ({typeName}?[])units.Clone(); + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value / divisor); + } + return result; + } + public static {typeName}?[] Divide(this double dividend, {typeName}?[] units) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = ({typeName}?[])units.Clone(); + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(dividend / item.Value._Value); + } + return result; + } + + // === ReadOnlySpan === + public static Span<{typeName}> Divide(this ReadOnlySpan<{typeName}> units, double divisor) + { + if (units.Length == 0) return []; + if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException(""Делитель не может быть 0 или NaN."", nameof(divisor)); + var result = new {typeName}[units.Length]; + DivideCore(units, divisor, result); + return result; + } + public static Span<{typeName}> Divide(this double dividend, ReadOnlySpan<{typeName}> units) + { + if (units.Length == 0) return []; + var result = new {typeName}[units.Length]; + DivideCore(dividend, units, result); + return result; + } + public static Span<{typeName}?> Divide(this ReadOnlySpan<{typeName}?> units, double divisor) + { + if (units.Length == 0) return []; + if (divisor == 0 || double.IsNaN(divisor)) + throw new ArgumentException(""Делитель не может быть 0 или NaN."", nameof(divisor)); + + Span<{typeName}?> result = new {typeName}?[units.Length]; + units.CopyTo(result); + + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value / divisor); + } + return result; + } + public static Span<{typeName}?> Divide(this double dividend, ReadOnlySpan<{typeName}?> units) + { + if (units.Length == 0) return []; + Span<{typeName}?> result = new {typeName}?[units.Length]; + units.CopyTo(result); + + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(dividend / item.Value._Value); + } + return result; + } + + // === List === + public static List<{typeName}> Divide(this List<{typeName}> units, double divisor) + { + if (units is null) return null!; + if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException(""Делитель не может быть 0 или NaN."", nameof(divisor)); + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}>(len); + result.SetCountUnsafe(len); + DivideCore(CollectionsMarshal.AsSpan(units), divisor, CollectionsMarshal.AsSpan(result)); + return result; + } + public static List<{typeName}> Divide(this double dividend, List<{typeName}> units) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}>(len); + result.SetCountUnsafe(len); + DivideCore(dividend, CollectionsMarshal.AsSpan(units), CollectionsMarshal.AsSpan(result)); + return result; + } + public static List<{typeName}?> Divide(this List<{typeName}?> units, double divisor) + { + if (units is null) return null!; + if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException(""Делитель не может быть 0 или NaN."", nameof(divisor)); + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}?>(units); + Span<{typeName}?> dstSpan = CollectionsMarshal.AsSpan(result); + for (int i = 0; i < len; i++) + { + ref var item = ref dstSpan[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value / divisor); + } + return result; + } + public static List<{typeName}?> Divide(this double dividend, List<{typeName}?> units) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}?>(units); + Span<{typeName}?> dstSpan = CollectionsMarshal.AsSpan(result); + for (int i = 0; i < len; i++) + { + ref var item = ref dstSpan[i]; + if (item.HasValue) item = new {typeName}(dividend / item.Value._Value); + } + return result; + } + + // === ICollection === + public static Tcoll Divide(this ICollection<{typeName}> units, double divisor) + where Tcoll : class, ICollection<{typeName}>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item._Value / divisor)); + return tColl; + } + public static Tcoll Divide(this double dividend, ICollection<{typeName}> units) + where Tcoll : class, ICollection<{typeName}>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(dividend / item._Value)); + return tColl; + } + public static Tcoll Divide(this ICollection<{typeName}?> units, double divisor) + where Tcoll : class, ICollection<{typeName}?>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item.HasValue ? item.Value._Value / divisor : 0d)); + return tColl; + } + public static Tcoll Divide(this double dividend, ICollection<{typeName}?> units) + where Tcoll : class, ICollection<{typeName}?>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item.HasValue ? dividend / item.Value._Value : 0d)); + return tColl; + } + + // === IEnumerable === + public static IEnumerable<{typeName}> Divide(this IEnumerable<{typeName}> units, double divisor) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return new {typeName}(item._Value * divisor); + } + public static IEnumerable<{typeName}> Divide(this double dividend, IEnumerable<{typeName}> units) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return new {typeName}(dividend / item._Value); + } + public static IEnumerable<{typeName}?> Divide(this IEnumerable<{typeName}?> units, double divisor) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return item.HasValue + ? new {typeName}(item.Value._Value * divisor) : null; + } + public static IEnumerable<{typeName}?> Divide(this double dividend, IEnumerable<{typeName}?> units) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return item.HasValue + ? new {typeName}(dividend / item.Value._Value) : null; + } + + // ========================================== + // === PLUS === + // ========================================== + + public static {typeName}[] Plus(this {typeName}[] units, double summand) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = new {typeName}[units.Length]; + PlusCore(units, summand, result); + return result; + } + public static {typeName}[] Plus(this double summand, {typeName}[] units) + => units.Plus(summand); + public static {typeName}?[] Plus(this {typeName}?[] units, double summand) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = ({typeName}?[])units.Clone(); + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value + summand); + } + return result; + } + public static {typeName}?[] Plus(this double summand, {typeName}?[] units) + => units.Plus(summand); + + // === ReadOnlySpan === + public static Span<{typeName}> Plus(this ReadOnlySpan<{typeName}> units, double summand) + { + if (units.Length == 0) return []; + var result = new {typeName}[units.Length]; + PlusCore(units, summand, result); + return result; + } + public static Span<{typeName}> Plus(this double summand, ReadOnlySpan<{typeName}> units) + => units.Plus(summand); + public static Span<{typeName}?> Plus(this ReadOnlySpan<{typeName}?> units, double summand) + { + if (units.Length == 0) return []; + Span<{typeName}?> result = new {typeName}?[units.Length]; + units.CopyTo(result); + + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value + summand); + } + return result; + } + public static Span<{typeName}?> Plus(this double summand, ReadOnlySpan<{typeName}?> units) + => units.Multiply(summand); + + // === List === + public static List<{typeName}> Plus(this List<{typeName}> units, double summand) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}>(len); + result.SetCountUnsafe(len); + PlusCore(CollectionsMarshal.AsSpan(units), summand, CollectionsMarshal.AsSpan(result)); + return result; + } + public static List<{typeName}> Plus(this double summand, List<{typeName}> units) + => units.Plus(summand); + public static List<{typeName}?> Plus(this List<{typeName}?> units, double summand) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}?>(units); + Span<{typeName}?> dstSpan = CollectionsMarshal.AsSpan(result); + for (int i = 0; i < len; i++) + { + ref var item = ref dstSpan[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value + summand); + } + return result; + } + public static List<{typeName}?> Plus(this double summand, List<{typeName}?> units) + => units.Plus(summand); + + // === ICollection === + public static Tcoll Plus(this ICollection<{typeName}> units, double summand) + where Tcoll : class, ICollection<{typeName}>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item._Value + summand)); + return tColl; + } + public static Tcoll Plus(this double summand, ICollection<{typeName}> units) + where Tcoll : class, ICollection<{typeName}>, new() => Plus(units, summand); + public static Tcoll Plus(this ICollection<{typeName}?> units, double summand) + where Tcoll : class, ICollection<{typeName}?>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item.HasValue ? item.Value._Value + summand : 0d)); + return tColl; + } + public static Tcoll Plus(this double summand, ICollection<{typeName}?> units) + where Tcoll : class, ICollection<{typeName}?>, new() => Plus(units, summand); + + // === IEnumerable === + public static IEnumerable<{typeName}> Plus(this IEnumerable<{typeName}> units, double summand) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return new {typeName}(item._Value + summand); + } + public static IEnumerable<{typeName}> Plus(this double summand, IEnumerable<{typeName}> units) + => units.Plus(summand); + public static IEnumerable<{typeName}?> Plus(this IEnumerable<{typeName}?> units, double summand) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return item.HasValue + ? new {typeName}(item.Value._Value + summand) : null; + } + public static IEnumerable<{typeName}?> Plus(this double summand, IEnumerable<{typeName}?> units) + => units.Plus(summand); + + // ========================================== + // === MINUS === + // ========================================== + + public static {typeName}[] Minus(this {typeName}[] units, double subtrahend) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = new {typeName}[units.Length]; + MinusCore(units, subtrahend, result); + return result; + } + public static {typeName}[] Minus(this double minuend, {typeName}[] units) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = new {typeName}[units.Length]; + MinusCore(minuend, units, result); // Вызов зеркального ядра (число - массив) + return result; + } + public static {typeName}?[] Minus(this {typeName}?[] units, double subtrahend) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = ({typeName}?[])units.Clone(); + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value - subtrahend); + } + return result; + } + public static {typeName}?[] Minus(this double minuend, {typeName}?[] units) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = ({typeName}?[])units.Clone(); + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(minuend - item.Value._Value); + } + return result; + } + + // === ReadOnlySpan === + public static Span<{typeName}> Minus(this ReadOnlySpan<{typeName}> units, double subtrahend) + { + if (units.Length == 0) return []; + var result = new {typeName}[units.Length]; + MinusCore(units, subtrahend, result); + return result; + } + public static Span<{typeName}> Minus(this double minuend, ReadOnlySpan<{typeName}> units) + { + if (units.Length == 0) return []; + var result = new {typeName}[units.Length]; + MinusCore(minuend, units, result); + return result; + } + public static Span<{typeName}?> Minus(this ReadOnlySpan<{typeName}?> units, double subtrahend) + { + if (units.Length == 0) return []; + Span<{typeName}?> result = new {typeName}?[units.Length]; + units.CopyTo(result); + + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value - subtrahend); + } + return result; + } + public static Span<{typeName}?> Minus(this double minuend, ReadOnlySpan<{typeName}?> units) + { + if (units.Length == 0) return []; + Span<{typeName}?> result = new {typeName}?[units.Length]; + units.CopyTo(result); + + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(minuend - item.Value._Value); + } + return result; + } + + // === List === + public static List<{typeName}> Minus(this List<{typeName}> units, double subtrahend) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}>(len); + result.SetCountUnsafe(len); + MinusCore(CollectionsMarshal.AsSpan(units), subtrahend, CollectionsMarshal.AsSpan(result)); + return result; + } + public static List<{typeName}> Minus(this double minuend, List<{typeName}> units) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}>(len); + result.SetCountUnsafe(len); + MinusCore(minuend, CollectionsMarshal.AsSpan(units), CollectionsMarshal.AsSpan(result)); + return result; + } + public static List<{typeName}?> Minus(this List<{typeName}?> units, double subtrahend) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}?>(units); + Span<{typeName}?> dstSpan = CollectionsMarshal.AsSpan(result); + for (int i = 0; i < len; i++) + { + ref var item = ref dstSpan[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value - subtrahend); + } + return result; + } + public static List<{typeName}?> Minus(this double minuend, List<{typeName}?> units) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}?>(units); + Span<{typeName}?> dstSpan = CollectionsMarshal.AsSpan(result); + for (int i = 0; i < len; i++) + { + ref var item = ref dstSpan[i]; + if (item.HasValue) item = new {typeName}(minuend - item.Value._Value); + } + return result; + } + + // === ICollection === + public static Tcoll Minus(this ICollection<{typeName}> units, double subtrahend) + where Tcoll : class, ICollection<{typeName}>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item._Value - subtrahend)); + return tColl; + } + public static Tcoll Minus(this double minuend, ICollection<{typeName}> units) + where Tcoll : class, ICollection<{typeName}>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(minuend - item._Value)); + return tColl; + } + public static Tcoll Minus(this ICollection<{typeName}?> units, double subtrahend) + where Tcoll : class, ICollection<{typeName}?>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item.HasValue ? item.Value._Value - subtrahend : 0d)); + return tColl; + } + public static Tcoll Minus(this double minuend, ICollection<{typeName}?> units) + where Tcoll : class, ICollection<{typeName}?>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item.HasValue ? minuend - item.Value._Value : 0d)); + return tColl; + } + + // === IEnumerable === + public static IEnumerable<{typeName}> Minus(this IEnumerable<{typeName}> units, double subtrahend) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return new {typeName}(item._Value - subtrahend); + } + public static IEnumerable<{typeName}> Minus(this double minuend, IEnumerable<{typeName}> units) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return new {typeName}(minuend - item._Value); + } + public static IEnumerable<{typeName}?> Minus(this IEnumerable<{typeName}?> units, double subtrahend) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return item.HasValue + ? new {typeName}(item.Value._Value - subtrahend) : null; + } + public static IEnumerable<{typeName}?> Minus(this double minuend, IEnumerable<{typeName}?> units) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return item.HasValue + ? new {typeName}(minuend - item.Value._Value) : null; + } + + // ========================================== + // ЦЕЛАЯ СТЕПЕНЬ (int power) + // ========================================== + + public static {typeName}[] Pow(this {typeName}[] units, int power) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = new {typeName}[units.Length]; + PowCore(units, power, result); + return result; + } + public static {typeName}?[] Pow(this {typeName}?[] units, int power) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = ({typeName}?[])units.Clone(); + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) { - bool isNullable = nt.EndsWith("?"); - string baseType = isNullable ? nt.TrimEnd('?') : nt; - if (baseType == "decimal") - { - string conv = isNullable ? "(double)(b ?? 0m)" : "(double)b"; - sb.AppendLine($" public static {t} operator /({t} a, {nt} b) => new(a._Value / {conv});"); - } - else if (isNullable) - { - sb.AppendLine($" public static {t} operator /({t} a, {nt} b) => new(a._Value / (b ?? 0d));"); - } - else - { - sb.AppendLine($" public static {t} operator /({t} a, {nt} b) => new(a._Value / b);"); - } + // Используем тот же быстрый QuickPow, что и в ядре, чтобы не вызывать тяжелый Math.Pow + item = new {typeName}(item.Value._Value.QuickPow(power)); } } - // 10. Деление двух метрик (возвращает double) - if (!info.ExistingOperatorNames.Contains("op_Division")) - sb.AppendLine($" public static double operator /({t} a, {t} b) => a._Value / b._Value;"); - sb.AppendLine(); - // 11. Методы SetArray / SetList - GenerateArrayAndListMethods(sb, t); - sb.AppendLine("}"); - // 12. Конвертер JSON - GenerateJsonConverter(sb, t); - return sb.ToString(); + return result; } - private static void GenerateArrayAndListMethods(StringBuilder sb, string t) + // === ReadOnlySpan === + public static Span<{typeName}> Pow(this ReadOnlySpan<{typeName}> units, int power) { - // SetArray - sb.AppendLine($@" /// With Multiply - public {t}[] SetArray(IEnumerable nums) - {{ - if (nums is not null) - {{ - var result = new {t}[nums.Count()]; - int i = 0; - foreach (var num in nums) - result[i++] = new(_Value * num); - return result; - }} - return []; - }} - /// With Multiply - public {t}[] SetArray(IEnumerable nums) - {{ - if (nums is not null) - {{ - var result = new {t}[nums.Count()]; - int i = 0; - foreach (var num in nums) - result[i++] = new((num ?? 0d) * _Value); - return result; - }} - return []; - }} - /// With Multiply - public {t}[] SetArray(IEnumerable nums) where N : INumber - {{ - if (nums is not null) - {{ - var result = new {t}[nums.Count()]; - int i = 0; - foreach (var num in nums) - result[i++] = new(num.ToDouble() * _Value); - return result; - }} - return []; - }} - /// With Multiply - public {t}[] SetArray(IEnumerable nums) where N : struct, INumber - {{ - if (nums is not null) - {{ - var result = new {t}[nums.Count()]; - int i = 0; - foreach (var num in nums) - result[i++] = new(num.ToDouble() * _Value); - return result; - }} - return []; - }}"); - // SetList - sb.AppendLine($@" - /// With Multiply - public List<{t}> SetList(IEnumerable nums) - {{ - if (nums is not null) - {{ - var result = new List<{t}>(nums.Count()); - foreach (var num in nums) - result.Add(new(_Value * num)); - return result; - }} - return []; - }} - /// With Multiply - public List<{t}> SetList(IEnumerable nums) - {{ - if (nums is not null) - {{ - var result = new List<{t}>(nums.Count()); - foreach (var num in nums) - result.Add(new((num ?? 0d) * _Value)); - return result; - }} - return []; - }} - /// With Multiply - public List<{t}> SetList(IEnumerable nums) where N : INumber - {{ - if (nums is not null) - {{ - var result = new List<{t}>(nums.Count()); - foreach (var num in nums) - result.Add(new(_Value * num.ToDouble())); - return result; - }} - return []; - }} - /// With Multiply - public List<{t}> SetList(IEnumerable nums) where N : struct, INumber - {{ - if (nums is not null) - {{ - var result = new List<{t}>(nums.Count()); - foreach (var num in nums) - result.Add(new(_Value * num.ToDouble())); - return result; - }} - return []; - }}"); + if (units.Length == 0) return []; + var result = new {typeName}[units.Length]; + PowCore(units, power, result); + return result; + } + public static Span<{typeName}?> Pow(this ReadOnlySpan<{typeName}?> units, int power) + { + int len = units.Length; + if (len == 0) return []; + Span<{typeName}?> result = new {typeName}?[units.Length]; + units.CopyTo(result); + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value.QuickPow(power)); + } + return result; } - private static void GenerateJsonConverter(StringBuilder sb, string t) + // === List === + public static List<{typeName}> Pow(this List<{typeName}> units, int power) { - sb.AppendLine($@" -public class {t}Converter : System.Text.Json.Serialization.JsonConverter<{t}> -{{ + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}>(len); + result.SetCountUnsafe(len); + PowCore(CollectionsMarshal.AsSpan(units), power, CollectionsMarshal.AsSpan(result)); + return result; + } + public static List<{typeName}?> Pow(this List<{typeName}?> units, int power) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}?>(units); + Span<{typeName}?> dstSpan = CollectionsMarshal.AsSpan(result); + for (int i = 0; i < len; i++) + { + ref var item = ref dstSpan[i]; + if (item.HasValue) item = new {typeName}(item.Value._Value.QuickPow(power)); + } + return result; + } + + // === ICollection === + public static Tcoll Pow(this ICollection<{typeName}> units, int power) + where Tcoll : class, ICollection<{typeName}>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item._Value.QuickPow(power))); + return tColl; + } + public static Tcoll Pow(this ICollection<{typeName}?> units, int power) + where Tcoll : class, ICollection<{typeName}?>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item.HasValue ? item.Value._Value.QuickPow(power) : 0d)); + return tColl; + } + + // === IEnumerable === + public static IEnumerable<{typeName}> Pow(this IEnumerable<{typeName}> units, int power) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return new {typeName}(item._Value.QuickPow(power)); + } + public static IEnumerable<{typeName}?> Pow(this IEnumerable<{typeName}?> units, int power) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return item.HasValue + ? new {typeName}(item.Value._Value.QuickPow(power)) : null; + } + + // ========================================== + // ДРОБНАЯ СТЕПЕНЬ (double power) + // ========================================== + + public static {typeName}[] Pow(this {typeName}[] units, double power) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = new {typeName}[units.Length]; + PowCore(units, power, result); + return result; + } + public static {typeName}?[] Pow(this {typeName}?[] units, double power) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = ({typeName}?[])units.Clone(); + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) + { + item = new {typeName}(Math.Pow(item.Value._Value, power)); + } + } + return result; + } + + // === ReadOnlySpan === + public static Span<{typeName}> Pow(this ReadOnlySpan<{typeName}> units, double power) + { + if (units.Length == 0) return []; + var result = new {typeName}[units.Length]; + PowCore(units, power, result); + return result; + } + public static Span<{typeName}?> Pow(this ReadOnlySpan<{typeName}?> units, double power) + { + int len = units.Length; + if (len == 0) return []; + Span<{typeName}?> result = new {typeName}?[units.Length]; + units.CopyTo(result); + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(Math.Pow(item.Value._Value, power)); + } + return result; + } + + // === List === + public static List<{typeName}> Pow(this List<{typeName}> units, double power) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}>(len); + result.SetCountUnsafe(len); + PowCore(CollectionsMarshal.AsSpan(units), power, CollectionsMarshal.AsSpan(result)); + return result; + } + public static List<{typeName}?> Pow(this List<{typeName}?> units, double power) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}?>(units); + Span<{typeName}?> dstSpan = CollectionsMarshal.AsSpan(result); + for (int i = 0; i < len; i++) + { + ref var item = ref dstSpan[i]; + if (item.HasValue) item = new {typeName}(Math.Pow(item.Value._Value, power)); + } + return result; + } + + // === ICollection === + public static Tcoll Pow(this ICollection<{typeName}> units, double power) + where Tcoll : class, ICollection<{typeName}>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(Math.Pow(item._Value, power))); + return tColl; + } + public static Tcoll Pow(this ICollection<{typeName}?> units, double power) + where Tcoll : class, ICollection<{typeName}?>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item.HasValue ? Math.Pow(item.Value._Value, power) : 0d)); + return tColl; + } + + // === IEnumerable === + public static IEnumerable<{typeName}> Pow(this IEnumerable<{typeName}> units, double power) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return new {typeName}(Math.Pow(item._Value, power)); + } + public static IEnumerable<{typeName}?> Pow(this IEnumerable<{typeName}?> units, double power) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return item.HasValue + ? new {typeName}(Math.Pow(item.Value._Value, power)) : null; + } + + + // ========================================== + // КВАДРАТНЫЙ КОРЕНЬ (Sqrt) + // ========================================== + + public static {typeName}[] Sqrt(this {typeName}[] units) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = new {typeName}[units.Length]; + SqrtCore(units, result); + return result; + } + public static {typeName}?[] Sqrt(this {typeName}?[] units) + { + if (units is null) return null!; + if (units.Length == 0) return []; + + var result = ({typeName}?[])units.Clone(); + int len = result.Length; + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) + { + item = new {typeName}(Math.Sqrt(item.Value._Value)); + } + } + return result; + } + + // === ReadOnlySpan === + public static Span<{typeName}> Sqrt(this ReadOnlySpan<{typeName}> units) + { + if (units.Length == 0) return []; + var result = new {typeName}[units.Length]; + SqrtCore(units, result); + return result; + } + public static Span<{typeName}?> Sqrt(this ReadOnlySpan<{typeName}?> units) + { + int len = units.Length; + if (len == 0) return []; + Span<{typeName}?> result = new {typeName}?[units.Length]; + units.CopyTo(result); + for (int i = 0; i < len; i++) + { + ref var item = ref result[i]; + if (item.HasValue) item = new {typeName}(Math.Sqrt(item.Value._Value)); + } + return result; + } + + // === List === + public static List<{typeName}> Sqrt(this List<{typeName}> units) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}>(len); + result.SetCountUnsafe(len); + SqrtCore(CollectionsMarshal.AsSpan(units), CollectionsMarshal.AsSpan(result)); + return result; + } + public static List<{typeName}?> Sqrt(this List<{typeName}?> units) + { + if (units is null) return null!; + int len = units.Count; + if (len == 0) return []; + + var result = new List<{typeName}?>(units); + Span<{typeName}?> dstSpan = CollectionsMarshal.AsSpan(result); + for (int i = 0; i < len; i++) + { + ref var item = ref dstSpan[i]; + if (item.HasValue) item = new {typeName}(Math.Sqrt(item.Value._Value)); + } + return result; + } + + // === ICollection === + public static Tcoll Pow(this ICollection<{typeName}> units) + where Tcoll : class, ICollection<{typeName}>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(Math.Sqrt(item._Value))); + return tColl; + } + public static Tcoll Pow(this ICollection<{typeName}?> units) + where Tcoll : class, ICollection<{typeName}?>, new() + { + ArgumentNullException.ThrowIfNull(units); + var tColl = new Tcoll(); + if (tColl is List<{typeName}> list) + list.Capacity = units.Count; + foreach (var item in units) + tColl.Add(new {typeName}(item.HasValue ? Math.Sqrt(item.Value._Value) : 0d)); + return tColl; + } + + // === IEnumerable === + public static IEnumerable<{typeName}> Pow(this IEnumerable<{typeName}> units) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return new {typeName}(Math.Sqrt(item._Value)); + } + public static IEnumerable<{typeName}?> Pow(this IEnumerable<{typeName}?> units) + { + ArgumentNullException.ThrowIfNull(units); + foreach (var item in units) + yield return item.HasValue + ? new {typeName}(Math.Sqrt(item.Value._Value)) : null; + } +} + +public class {typeName}Converter : JsonConverter<{typeName}> +{ + // Используем инвариантную культуру, чтобы разделителем всегда была точка (10.5, а не 10,5) private static readonly CultureInfo Culture = CultureInfo.InvariantCulture; - public override {t} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - {{ + public override {typeName} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { double doubleValue; + if (reader.TokenType == JsonTokenType.String) - {{ - if (!double.TryParse(reader.GetString(), Culture, out doubleValue)) - throw new JsonException($""Не удалось преобразовать строковое значение в double для метрики {t}.""); - }} + { + // Безопасно парсим double из строки с поддержкой точки как разделителя + if (!double.TryParse(reader.GetString(), NumberStyles.Float, Culture, out doubleValue)) + { + throw new JsonException($""Не удалось преобразовать строковое значение в double для метрики {nameof({typeName})}.""); + } + } else - {{ + { + // Прямое быстрое чтение числа из JSON doubleValue = reader.GetDouble(); - }} + } + return new(doubleValue); - }} - - public override void Write(Utf8JsonWriter writer, {t} value, JsonSerializerOptions options) - {{ - writer.WriteNumberValue(value._Value); - }} - - public override void WriteAsPropertyName(Utf8JsonWriter writer, {t} value, JsonSerializerOptions options) - {{ - writer.WritePropertyName(value._Value.ToString(""R"", Culture)); - }} - - public override {t} ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - {{ - string propertyName = reader.GetString()!; - if (!double.TryParse(propertyName, Culture, out double doubleValue)) - throw new JsonException($""Невалидное числовое значение в ключе свойства JSON: '{{propertyName}}' для метрики {t}.""); - return new(doubleValue); - }} -}}"); } - private readonly struct UnitInfo(string ns, string typeName, HashSet existingMemberNames, HashSet existingOperatorNames) + public override void Write(Utf8JsonWriter writer, {typeName} value, JsonSerializerOptions options) + { + // Записываем число напрямую в байтовый буфер без выделения памяти под строки + writer.WriteNumberValue(value._Value); + } + + public override void WriteAsPropertyName(Utf8JsonWriter writer, {typeName} value, JsonSerializerOptions options) + { + // Ключи JSON-объектов всегда должны быть строками. + // Форматируем double в строку с точкой, чтобы другие сервисы экосистемы прочитали её корректно. + // Формат ""R"" (Round-trip) гарантирует, что число не потеряет точность при обратном парсинге. + writer.WritePropertyName(value._Value.ToString(""R"", Culture)); + } + + public override {typeName} ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + string propertyName = reader.GetString()!; + + if (!double.TryParse(propertyName, NumberStyles.Float, Culture, out double doubleValue)) + { + throw new JsonException($""Невалидное числовое значение в ключе свойства JSON: '{propertyName}' для метрики {nameof({typeName})}.""); + } + + return new(doubleValue); + } +} +"; + return skeleton.Replace("{typeName}", typeName).Replace("{ns}", ns); + } + + private readonly struct StructInfo(string ns, string name) { public string Namespace { get; } = ns; - public string TypeName { get; } = typeName; - public HashSet ExistingMemberNames { get; } = existingMemberNames; - public HashSet ExistingOperatorNames { get; } = existingOperatorNames; + public string TypeName { get; } = name; } } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Extensions.cs b/QWERTYkez.Mensura/Extensions.cs index 03cce00..05f2870 100644 --- a/QWERTYkez.Mensura/Extensions.cs +++ b/QWERTYkez.Mensura/Extensions.cs @@ -48,268 +48,284 @@ public static partial class Extensions mimic.Size = count; } - - - - - - - - internal static U Protect(this U? metric) where U : class, IMetric, new() => metric ?? new(); - internal static C Protect(this C? collection) - where C : IMetricCollection, new() where U : class, IMetric, new() => collection ?? new(); - - - public static C MetricSelect(this C? collection, Func? selector) - where C : IMetricCollection, new() where U : class, IMetric, new() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static double QuickPow(this double baseValue, int exp) { - var source = (collection ??= new()); - var nColl = (C)source.CreateByInstanceU(source.Count); - if (selector is not null) + switch (exp) { - for (int i = 0; i < nColl.Count; i++) - nColl[i] = selector(source[i]); - return nColl; + case 0: return 1.0; + case 1: return baseValue; + case 2: return baseValue * baseValue; + case 3: return baseValue * baseValue * baseValue; + case 4: { double x2 = baseValue * baseValue; return x2 * x2; } + case -1: return 1.0 / baseValue; + case -2: return 1.0 / (baseValue * baseValue); + default: return Math.Pow(baseValue, exp); } - return new(); - } - public static IEnumerable MetricSelect(this IMetricCollection collection, Func selector) - where U : class, IMetric, new() - { - if (collection is not null) - { - if (selector is not null) - return collection.Select(selector); - return collection.Select(u => double.NaN); - } - else return []; } - public static IMetricCollection MetricSelect(this IMetricCollection? collection, Func? selector) - where Ux : class, IMetric, new() where Uz : class, IMetric, new() - { - if (collection is not null && selector is not null) - { - var destCollection = collection.CreateByInstance(collection.Count); - for (int i = 0; i < collection.Count; i++) - destCollection[i] = selector(collection[i]); - return destCollection; - } - return null!; - } - public static MetricCollection MetricSelect(this MetricCollection? collection, Func? selector) - where Ux : class, IMetric, new() where Uz : class, IMetric, new() - { - if (collection is not null && selector is not null) - { - var destCollection = collection.CreateByInstance(collection.Count()); - for (int i = 0; i < collection.Count(); i++) - destCollection[i] = selector(collection[i]); - return destCollection; - } - return null!; - } - public static MetricArray MetricSelect(this MetricArray? collection, Func? selector) - where Ux : class, IMetric, new() where Uz : class, IMetric, new() - { - var coll = collection?.ToArray(); - if (coll is not null && selector is not null) - { - var destCollection = new MetricArray(coll.Length); - for (int i = 0; i < coll.Length; i++) - destCollection[i] = selector(coll[i]); - return destCollection; - } - return null!; - } - public static MetricList MetricSelect(this MetricList? collection, Func? selector) - where Ux : class, IMetric, new() where Uz : class, IMetric, new() - { - if (collection is not null && selector is not null) - { - var destCollection = new MetricList(collection.Count); - for (int i = 0; i < collection.Count; i++) - destCollection[i] = selector(collection[i]); - return destCollection; - } - return null!; - } - public static MetricObservableCollection MetricSelect(this MetricObservableCollection? collection, Func? selector) - where Ux : class, IMetric, new() where Uz : class, IMetric, new() - { - if (collection is not null && selector is not null) - { - var destCollection = new MetricObservableCollection(collection.Count); - for (int i = 0; i < collection.Count; i++) - destCollection[i] = selector(collection[i]); - return destCollection; - } - return null!; - } - - - public static double[] MetricSelect(this MetricArray collection, Func selector) - where U : class, IMetric, new() - { - var coll = collection ?? []; - var arr = new double[coll.Length]; - if (selector is not null) - for (int i = 0; i < arr.Length; i++) - arr[i] = selector(coll[i]); - return arr; - } - public static List MetricSelect(this MetricList collection, Func selector) - where U : class, IMetric, new() - { - var coll = collection ?? []; - var list = new List(coll.Count); - if (selector is not null) - for (int i = 0; i < list.Count; i++) - list[i] = selector(coll[i]); - return list; - } - public static ObservableCollection MetricSelect(this MetricObservableCollection collection, Func selector) - where U : class, IMetric, new() - { - var coll = collection ?? []; - var list = new List(coll.Count); - if (selector is not null) - for (int i = 0; i < list.Count; i++) - list[i] = selector(coll[i]); - return new(list); - } - internal static C ForEachC(this C? collection, Func? Set) - where C : IMetricCollection, new() where U : class, IMetric, new() - { - var nColl = (C)(collection ??= new()).CreateByInstanceU(collection.Count); - if (Set is not null) - for (int i = 0; i < nColl.Count; i++) - nColl[i] = Set(nColl[i]); - return nColl; - } - internal static double ProtectValue(this IMetric? metric) => metric is null ? 0d : metric.Value; - - public static U Min(this U? T1, U? T2) where U : class, IMetric, new() => (T1.ProtectValue() < T2.ProtectValue() ? T1 : T2).Protect(); - public static U Min(this U T1, IEnumerable units) where U : class, IMetric, new() => (T1 ?? new()).Min((units ?? []).MaxBy(u => u.ProtectValue())); - - public static U Max(this U? T1, U? T2) where U : class, IMetric, new() => (T1.ProtectValue() > T2.ProtectValue() ? T1 : T2).Protect(); - public static U Max(this U T1, IEnumerable units) where U : class, IMetric, new() => (T1 ?? new()).Max((units ?? []).MaxBy(u => u.ProtectValue())); - - - //internal static double ToDouble(this double number) => number; - //internal static double ToDouble(this double? number) => number ?? 0d; - //internal static double ToDouble(this N number) where N : INumber => Convert.ToDouble(number); - //internal static double ToDouble(this N? number) where N : struct, INumber => number is not null ? Convert.ToDouble(number) : 0d; - - - internal static IEnumerable MetricSelect(this double[] nums, Func selector) where U : class, IMetric, new() => nums.Select(selector); - internal static IEnumerable MetricSelect(this double?[] nums, Func selector) where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); - internal static IEnumerable MetricSelect(this N[] nums, Func selector) where N : INumber where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); - internal static IEnumerable MetricSelect(this N?[] nums, Func selector) where N : struct, INumber where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); - - - internal static IEnumerable MetricSelect(this IEnumerable nums, Func selector) where U : class, IMetric, new() => nums.Select(selector); - internal static IEnumerable MetricSelect(this IEnumerable nums, Func selector) where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); - internal static IEnumerable MetricSelect(this IEnumerable nums, Func selector) where N : INumber where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); - internal static IEnumerable MetricSelect(this IEnumerable nums, Func selector) where N : struct, INumber where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); - public static U Clone(this U? metric) where U : class, IMetric, new() => new() { Value = metric.ProtectValue() }; - public static U Abs(this U? metric) where U : class, IMetric, new() => new() { Value = Math.Abs(metric.ProtectValue()) }; - - /// C^2 = A^2 + B^2 - /// C = (A^2 + B^2).Sqrt(2) - public static U Hypotenuse(this U? A, U? B) where U : class, IMetric, new() - { - var a = A.ProtectValue(); - var b = B.ProtectValue(); - return new U() { Value = Math.Sqrt(a * a + b * b) }; - } - /// C^2 = A^2 + B^2 - /// B = (C^2 - A^2).Sqrt(2) - public static U KatetFromHyp(this U? A, U? C) where U : class, IMetric, new() - { - var a = A.ProtectValue(); - var c = C.ProtectValue(); - return new U() { Value = Math.Sqrt(c * c - a * a) }; - } - /// C^2 = A^2 + B^2 - /// B = (C^2 - A^2).Sqrt(2) - public static U KatetFromKatet(this U? C, U? A) where U : class, IMetric, new() - { - var a = A.ProtectValue(); - var c = C.ProtectValue(); - return new U() { Value = Math.Sqrt(c * c - a * a) }; - } - - public static Area Pow(this Length? metric, double? val = 2) => new() { Value = Math.Pow(metric.ProtectValue(), val ?? 2) }; - public static Length Sqrt(this Area? metric) => new() { Value = Math.Sqrt(metric.ProtectValue()) }; + //internal static U Protect(this U? metric) where U : class, IMetric, new() => metric ?? new(); + //internal static C Protect(this C? collection) + // where C : IMetricCollection, new() where U : class, IMetric, new() => collection ?? new(); - public static U MetricSum(this IEnumerable args) where U : IMetric, new() => new() { Value = args?.Where(t => t is not null).Sum(m => m.ProtectValue()) ?? 0d }; - public static U MetricAverage(this IEnumerable args) where U : IMetric, new() => new() { Value = args?.Average(m => m.ProtectValue()) ?? double.NaN }; - public static U MetricMax(this IEnumerable args) where U : IMetric, new() => new() { Value = args.Max(m => m.ProtectValue()) }; - public static U MetricMin(this IEnumerable args) where U : IMetric, new() => new() { Value = args.Min(m => m.ProtectValue()) }; + //public static C MetricSelect(this C? collection, Func? selector) + // where C : IMetricCollection, new() where U : class, IMetric, new() + //{ + // var source = (collection ??= new()); + // var nColl = (C)source.CreateByInstanceU(source.Count); + // if (selector is not null) + // { + // for (int i = 0; i < nColl.Count; i++) + // nColl[i] = selector(source[i]); + // return nColl; + // } + // return new(); + //} + //public static IEnumerable MetricSelect(this IMetricCollection collection, Func selector) + // where U : class, IMetric, new() + //{ + // if (collection is not null) + // { + // if (selector is not null) + // return collection.Select(selector); + // return collection.Select(u => double.NaN); + // } + // else return []; + //} - public static C MetricSum(this IEnumerable> collections) - where C : MetricCollection, ICreateByCapacity, new() where U : class, IMetric, new() - { - var cArr = collections.ToArray(); - C accumulator = (C)cArr.FirstOrDefault(new C()); - for (int i = 1; i < cArr.Length; i++) - accumulator = accumulator.FuncByPairOrOneToMany(cArr[i], (a, b) => a + b, out C _); - return accumulator; - } - public static C MetricAverage(this IEnumerable> collections) - where C : MetricCollection, ICreateByCapacity, new() where U : class, IMetric, new() - => collections.MetricSum() / collections.Count(); + + //public static IMetricCollection MetricSelect(this IMetricCollection? collection, Func? selector) + // where Ux : class, IMetric, new() where Uz : class, IMetric, new() + //{ + // if (collection is not null && selector is not null) + // { + // var destCollection = collection.CreateByInstance(collection.Count); + // for (int i = 0; i < collection.Count; i++) + // destCollection[i] = selector(collection[i]); + // return destCollection; + // } + // return null!; + //} + //public static MetricCollection MetricSelect(this MetricCollection? collection, Func? selector) + // where Ux : class, IMetric, new() where Uz : class, IMetric, new() + //{ + // if (collection is not null && selector is not null) + // { + // var destCollection = collection.CreateByInstance(collection.Count()); + // for (int i = 0; i < collection.Count(); i++) + // destCollection[i] = selector(collection[i]); + // return destCollection; + // } + // return null!; + //} + //public static MetricArray MetricSelect(this MetricArray? collection, Func? selector) + // where Ux : class, IMetric, new() where Uz : class, IMetric, new() + //{ + // var coll = collection?.ToArray(); + // if (coll is not null && selector is not null) + // { + // var destCollection = new MetricArray(coll.Length); + // for (int i = 0; i < coll.Length; i++) + // destCollection[i] = selector(coll[i]); + // return destCollection; + // } + // return null!; + //} + //public static MetricList MetricSelect(this MetricList? collection, Func? selector) + // where Ux : class, IMetric, new() where Uz : class, IMetric, new() + //{ + // if (collection is not null && selector is not null) + // { + // var destCollection = new MetricList(collection.Count); + // for (int i = 0; i < collection.Count; i++) + // destCollection[i] = selector(collection[i]); + // return destCollection; + // } + // return null!; + //} + //public static MetricObservableCollection MetricSelect(this MetricObservableCollection? collection, Func? selector) + // where Ux : class, IMetric, new() where Uz : class, IMetric, new() + //{ + // if (collection is not null && selector is not null) + // { + // var destCollection = new MetricObservableCollection(collection.Count); + // for (int i = 0; i < collection.Count; i++) + // destCollection[i] = selector(collection[i]); + // return destCollection; + // } + // return null!; + //} + + + //public static double[] MetricSelect(this MetricArray collection, Func selector) + // where U : class, IMetric, new() + //{ + // var coll = collection ?? []; + // var arr = new double[coll.Length]; + // if (selector is not null) + // for (int i = 0; i < arr.Length; i++) + // arr[i] = selector(coll[i]); + // return arr; + //} + //public static List MetricSelect(this MetricList collection, Func selector) + // where U : class, IMetric, new() + //{ + // var coll = collection ?? []; + // var list = new List(coll.Count); + // if (selector is not null) + // for (int i = 0; i < list.Count; i++) + // list[i] = selector(coll[i]); + // return list; + //} + //public static ObservableCollection MetricSelect(this MetricObservableCollection collection, Func selector) + // where U : class, IMetric, new() + //{ + // var coll = collection ?? []; + // var list = new List(coll.Count); + // if (selector is not null) + // for (int i = 0; i < list.Count; i++) + // list[i] = selector(coll[i]); + // return new(list); + //} + //internal static C ForEachC(this C? collection, Func? Set) + // where C : IMetricCollection, new() where U : class, IMetric, new() + //{ + // var nColl = (C)(collection ??= new()).CreateByInstanceU(collection.Count); + // if (Set is not null) + // for (int i = 0; i < nColl.Count; i++) + // nColl[i] = Set(nColl[i]); + // return nColl; + //} + //internal static double ProtectValue(this IMetric? metric) => metric is null ? 0d : metric.Value; + + //public static U Min(this U? T1, U? T2) where U : class, IMetric, new() => (T1.ProtectValue() < T2.ProtectValue() ? T1 : T2).Protect(); + //public static U Min(this U T1, IEnumerable units) where U : class, IMetric, new() => (T1 ?? new()).Min((units ?? []).MaxBy(u => u.ProtectValue())); + + //public static U Max(this U? T1, U? T2) where U : class, IMetric, new() => (T1.ProtectValue() > T2.ProtectValue() ? T1 : T2).Protect(); + //public static U Max(this U T1, IEnumerable units) where U : class, IMetric, new() => (T1 ?? new()).Max((units ?? []).MaxBy(u => u.ProtectValue())); + + + ////internal static double ToDouble(this double number) => number; + ////internal static double ToDouble(this double? number) => number ?? 0d; + ////internal static double ToDouble(this N number) where N : INumber => Convert.ToDouble(number); + ////internal static double ToDouble(this N? number) where N : struct, INumber => number is not null ? Convert.ToDouble(number) : 0d; + + + //internal static IEnumerable MetricSelect(this double[] nums, Func selector) where U : class, IMetric, new() => nums.Select(selector); + //internal static IEnumerable MetricSelect(this double?[] nums, Func selector) where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); + //internal static IEnumerable MetricSelect(this N[] nums, Func selector) where N : INumber where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); + //internal static IEnumerable MetricSelect(this N?[] nums, Func selector) where N : struct, INumber where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); + + + //internal static IEnumerable MetricSelect(this IEnumerable nums, Func selector) where U : class, IMetric, new() => nums.Select(selector); + //internal static IEnumerable MetricSelect(this IEnumerable nums, Func selector) where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); + //internal static IEnumerable MetricSelect(this IEnumerable nums, Func selector) where N : INumber where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); + //internal static IEnumerable MetricSelect(this IEnumerable nums, Func selector) where N : struct, INumber where U : class, IMetric, new() => nums.Select(num => selector(num.ToDouble())); - public static U MetricSumBy(this IEnumerable source, Func selector) - where U : class, IMetric, new() - { - if (source is null) return new(); - if (selector is null) throw new ArgumentNullException("selector is null"); - return new() { Value = source.Select(selector).Where(t => t is not null).Sum(t => t.ProtectValue()) }; - } - public static U MetricAverageBy(this IEnumerable source, Func selector) - where U : class, IMetric, new() - { - if (source is null) return new(); - if (selector is null) throw new ArgumentNullException("selector is null"); + //public static U Clone(this U? metric) where U : class, IMetric, new() => new() { Value = metric.ProtectValue() }; + //public static U Abs(this U? metric) where U : class, IMetric, new() => new() { Value = Math.Abs(metric.ProtectValue()) }; - return new() { Value = source.Select(selector).Average(t => t.ProtectValue()) }; - } + ///// C^2 = A^2 + B^2 + ///// C = (A^2 + B^2).Sqrt(2) + //public static U Hypotenuse(this U? A, U? B) where U : class, IMetric, new() + //{ + // var a = A.ProtectValue(); + // var b = B.ProtectValue(); + // return new U() { Value = Math.Sqrt(a * a + b * b) }; + //} + ///// C^2 = A^2 + B^2 + ///// B = (C^2 - A^2).Sqrt(2) + //public static U KatetFromHyp(this U? A, U? C) where U : class, IMetric, new() + //{ + // var a = A.ProtectValue(); + // var c = C.ProtectValue(); + // return new U() { Value = Math.Sqrt(c * c - a * a) }; + //} + ///// C^2 = A^2 + B^2 + ///// B = (C^2 - A^2).Sqrt(2) + //public static U KatetFromKatet(this U? C, U? A) where U : class, IMetric, new() + //{ + // var a = A.ProtectValue(); + // var c = C.ProtectValue(); + // return new U() { Value = Math.Sqrt(c * c - a * a) }; + //} + + //public static Area Pow(this Length? metric, double? val = 2) => new() { Value = Math.Pow(metric.ProtectValue(), val ?? 2) }; + //public static Length Sqrt(this Area? metric) => new() { Value = Math.Sqrt(metric.ProtectValue()) }; - public static C MetricSumBy(this IEnumerable source, Func> selector) - where C : MetricCollection, ICreateByCapacity, new() where U : class, IMetric, new() - { - if (source is null) return new(); - if (selector is null) throw new ArgumentNullException("selector is null"); - - return source.Select(selector).MetricSum(); - } - public static C MetricAverageBy(this IEnumerable source, Func> selector) - where C : MetricCollection, ICreateByCapacity, new() where U : class, IMetric, new() - { - if (source is null) return new(); - if (selector is null) throw new ArgumentNullException("selector is null"); - - return source.Select(selector).MetricAverage(); - } + //public static U MetricSum(this IEnumerable args) where U : IMetric, new() => new() { Value = args?.Where(t => t is not null).Sum(m => m.ProtectValue()) ?? 0d }; + //public static U MetricAverage(this IEnumerable args) where U : IMetric, new() => new() { Value = args?.Average(m => m.ProtectValue()) ?? double.NaN }; + //public static U MetricMax(this IEnumerable args) where U : IMetric, new() => new() { Value = args.Max(m => m.ProtectValue()) }; + //public static U MetricMin(this IEnumerable args) where U : IMetric, new() => new() { Value = args.Min(m => m.ProtectValue()) }; - public static MetricArray ToMetricArray(this IEnumerable source) where U : class, IMetric, new() => new(source); - public static MetricList ToMetricList(this IEnumerable source) where U : class, IMetric, new() => new(source); + //public static C MetricSum(this IEnumerable> collections) + // where C : MetricCollection, ICreateByCapacity, new() where U : class, IMetric, new() + //{ + // var cArr = collections.ToArray(); + // C accumulator = (C)cArr.FirstOrDefault(new C()); + // for (int i = 1; i < cArr.Length; i++) + // accumulator = accumulator.FuncByPairOrOneToMany(cArr[i], (a, b) => a + b, out C _); + // return accumulator; + //} + //public static C MetricAverage(this IEnumerable> collections) + // where C : MetricCollection, ICreateByCapacity, new() where U : class, IMetric, new() + // => collections.MetricSum() / collections.Count(); + + + + //public static U MetricSumBy(this IEnumerable source, Func selector) + // where U : class, IMetric, new() + //{ + // if (source is null) return new(); + // if (selector is null) throw new ArgumentNullException("selector is null"); + + // return new() { Value = source.Select(selector).Where(t => t is not null).Sum(t => t.ProtectValue()) }; + //} + //public static U MetricAverageBy(this IEnumerable source, Func selector) + // where U : class, IMetric, new() + //{ + // if (source is null) return new(); + // if (selector is null) throw new ArgumentNullException("selector is null"); + + // return new() { Value = source.Select(selector).Average(t => t.ProtectValue()) }; + //} + + + //public static C MetricSumBy(this IEnumerable source, Func> selector) + // where C : MetricCollection, ICreateByCapacity, new() where U : class, IMetric, new() + //{ + // if (source is null) return new(); + // if (selector is null) throw new ArgumentNullException("selector is null"); + + // return source.Select(selector).MetricSum(); + //} + //public static C MetricAverageBy(this IEnumerable source, Func> selector) + // where C : MetricCollection, ICreateByCapacity, new() where U : class, IMetric, new() + //{ + // if (source is null) return new(); + // if (selector is null) throw new ArgumentNullException("selector is null"); + + // return source.Select(selector).MetricAverage(); + //} + + + + //public static MetricArray ToMetricArray(this IEnumerable source) where U : class, IMetric, new() => new(source); + //public static MetricList ToMetricList(this IEnumerable source) where U : class, IMetric, new() => new(source); } \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/Length.cs b/QWERTYkez.Mensura/Units/Length.cs index d662fe1..6ebea66 100644 --- a/QWERTYkez.Mensura/Units/Length.cs +++ b/QWERTYkez.Mensura/Units/Length.cs @@ -3,7 +3,6 @@ /// /// Base value is MilliMeters /// - [UnitOperatorsGenerator, DebuggerDisplay("mm = {_MilliMeters.ToString(\"0.###\")}, m = {Meters.ToString(\"0.###\")}")] public readonly partial record struct Length { @@ -58,1077 +57,8 @@ public readonly partial record struct Length public Length AddDeciMeters(double value) => new(_Value + LengthConv.DeciMeters.To(value)); public Length AddMeters(double value) => new(_Value + LengthConv.Meters.To(value)); public Length AddKiloMeters(double value) => new(_Value + LengthConv.KiloMeters.To(value)); - - - - - - - public static explicit operator Length(double val) => new(val); - public static explicit operator double(Length unit) => unit._Value; - - public Length Abs() => new(Math.Abs(_Value)); - - /// C^2 = this^2 + B^2 C = (this^2 + B^2).Sqrt(2) - public Length HypFromLeg(Length B) => new(Math.Sqrt(_Value * _Value + B._Value * B._Value)); - - /// C^2 = this^2 + B^2 C = (this^2 + B^2).Sqrt(2) - public Length HypFromLeg(Length? B) - { - double b = B is null ? 0d : B.Value._Value; - return new(Math.Sqrt(_Value * _Value + b * b)); - } - - /// C^2 = this^2 + B^2 B = (C^2 - this^2).Sqrt(2) - public Length LegFromHyp(Length C) => new(Math.Sqrt(C._Value * C._Value - _Value * _Value)); - - /// C^2 = this^2 + B^2 B = (C^2 - this^2).Sqrt(2) - public Length LegFromHyp(Length? C) - { - double c = C is null ? 0d : C.Value._Value; - return new(Math.Sqrt(c * c - _Value * _Value)); - } - - /// this^2 = A^2 + B^2 B = (this^2 - A^2).Sqrt(2) - public Length LegFromLeg(Length A) => new(Math.Sqrt(_Value * _Value - A._Value * A._Value)); - - /// this^2 = A^2 + B^2 B = (this^2 - A^2).Sqrt(2) - public Length LegFromLeg(Length? A) - { - double a = A is null ? 0d : A.Value._Value; - return new(Math.Sqrt(_Value * _Value - a * a)); - } } -public static class LengthExtension -{ - internal static double ToDouble(this Length? unit) => unit is null ? 0d : unit.Value._Value; - - public static Length MetricSum(this IEnumerable units) => new() { Value = units?.Sum(m => m._Value) ?? 0d }; - public static Length MetricAverage(this IEnumerable units) => new() { Value = units?.Average(m => m._Value) ?? double.NaN }; - public static Length MetricMax(this IEnumerable units) => new() { Value = units?.Max(m => m._Value) ?? double.MinValue }; - public static Length MetricMin(this IEnumerable units) => new() { Value = units?.Min(m => m._Value) ?? double.MaxValue }; - - public static Length MetricSum(this IEnumerable units) => new() { Value = units?.Sum(m => m.ToDouble()) ?? 0d }; - public static Length MetricAverage(this IEnumerable units) => new() { Value = units?.Average(m => m.ToDouble()) ?? double.NaN }; - public static Length MetricMax(this IEnumerable units) => new() { Value = units?.Max(m => m.ToDouble()) ?? double.MinValue }; - public static Length MetricMin(this IEnumerable units) => new() { Value = units?.Min(m => m.ToDouble()) ?? double.MaxValue }; - - - internal static void MultiplyCore(ReadOnlySpan source, double value, Span destination) - { - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - - var vectorizedValue = new Vector(value); - int vectorSize = Vector.Count; - int i = 0; - - ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); - ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); - - int SIMDEnd = len - (len % vectorSize); - for (; i < SIMDEnd; i += vectorSize) - { - ref double currentSrc = ref Unsafe.Add(ref srcRef, i); - ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); - var vector = new Vector(srcWindow); - var multiplied = vector * vectorizedValue; - ref double currentDst = ref Unsafe.Add(ref dstRef, i); - Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); - multiplied.CopyTo(dstWindow); - } - - for (; i < len; i++) - { - Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * value; - } - } - internal static void DivideCore(ReadOnlySpan source, double divisor, Span destination) - { - // 1. Проверка на ноль - if (divisor == 0d || double.IsNaN(divisor)) - throw new DivideByZeroException("Делитель не может быть равен нулю."); - - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - - var vectorizedValue = new Vector(divisor); - int vectorSize = Vector.Count; - int i = 0; - - ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); - ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); - - int SIMDEnd = len - (len % vectorSize); - for (; i < SIMDEnd; i += vectorSize) - { - ref double currentSrc = ref Unsafe.Add(ref srcRef, i); - ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); - var vector = new Vector(srcWindow); - var multiplied = vector / vectorizedValue; - ref double currentDst = ref Unsafe.Add(ref dstRef, i); - Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); - multiplied.CopyTo(dstWindow); - } - - for (; i < len; i++) - { - Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) / divisor; - } - } - internal static void DivideCore(double dividend, ReadOnlySpan source, Span destination) - { - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - - var vectorizedValue = new Vector(dividend); - var zeroVector = Vector.Zero; // Вектор из нулей для сравнения - int vectorSize = Vector.Count; - int i = 0; - - ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); - ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); - - int SIMDEnd = len - (len % vectorSize); - for (; i < SIMDEnd; i += vectorSize) - { - ref double currentSrc = ref Unsafe.Add(ref srcRef, i); - ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); - var vector = new Vector(srcWindow); - - // БЫСТРАЯ ПРОВЕРКА: Есть ли хотя бы один 0.0 в текущем векторе? - if (Vector.EqualsAny(vector, zeroVector)) - { - throw new DivideByZeroException($"Обнаружен делитель, равный нулю, в районе индексов {i}..{i + vectorSize - 1}."); - } - - var multiplied = vectorizedValue / vector; - ref double currentDst = ref Unsafe.Add(ref dstRef, i); - Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); - multiplied.CopyTo(dstWindow); - } - - // Хвостовой цикл - for (; i < len; i++) - { - double divisor = Unsafe.Add(ref srcRef, i); - if (divisor == 0.0) - { - throw new DivideByZeroException($"Обнаружен делитель, равный нулю, в индексе {i}."); - } - Unsafe.Add(ref dstRef, i) = dividend / divisor; - } - } - internal static void PlusCore(ReadOnlySpan source, double summand, Span destination) - { - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - - var vectorizedValue = 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 - (len % vectorSize); - for (; i < SIMDEnd; i += vectorSize) - { - ref double currentSrc = ref Unsafe.Add(ref srcRef, i); - ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); - var vector = new Vector(srcWindow); - var multiplied = vector + vectorizedValue; - ref double currentDst = ref Unsafe.Add(ref dstRef, i); - Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); - multiplied.CopyTo(dstWindow); - } - - for (; i < len; i++) - { - Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand; - } - } - internal static void MinusCore(ReadOnlySpan source, double subtrahend, Span destination) - { - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - - var vectorizedValue = 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 - (len % vectorSize); - for (; i < SIMDEnd; i += vectorSize) - { - ref double currentSrc = ref Unsafe.Add(ref srcRef, i); - ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); - var vector = new Vector(srcWindow); - var multiplied = vector - vectorizedValue; - ref double currentDst = ref Unsafe.Add(ref dstRef, i); - Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); - multiplied.CopyTo(dstWindow); - } - - for (; i < len; i++) - { - Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend; - } - } - internal static void MinusCore(double minuend, ReadOnlySpan source, Span destination) - { - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - - var vectorizedValue = 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 - (len % vectorSize); - for (; i < SIMDEnd; i += vectorSize) - { - ref double currentSrc = ref Unsafe.Add(ref srcRef, i); - ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); - var vector = new Vector(srcWindow); - var multiplied = vectorizedValue - vector; - ref double currentDst = ref Unsafe.Add(ref dstRef, i); - Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); - multiplied.CopyTo(dstWindow); - } - - for (; i < len; i++) - { - Unsafe.Add(ref dstRef, i) = minuend - Unsafe.Add(ref srcRef, i); - } - } - - [MethodImpl(MethodImplOptions.AggressiveOptimization)] - internal static void PowCore(ReadOnlySpan source, int power, Span destination) - { - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - int vectorSize = Vector.Count; - int i = 0; - ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); - ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); - int SIMDEnd = len - (len % vectorSize); - for (; i < SIMDEnd; i += vectorSize) - { - var vector = new Vector(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.Add(ref srcRef, i), vectorSize)); - var resultVector = VectorPow(vector, power); - resultVector.CopyTo(MemoryMarshal.CreateSpan(ref Unsafe.Add(ref dstRef, i), vectorSize)); - } - - // Приватный SIMD-метод быстрого возведения в степень - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static Vector VectorPow(Vector baseVector, int exp) - { - if (exp == 0) return Vector.One; - if (exp == 1) return baseVector; - - if (exp < 0) - { - baseVector = Vector.One / baseVector; - exp = -exp; // Внимание: может переполниться при int.MinValue, но для степеней это редчайший кейс - } - - var result = Vector.One; - var currentBase = baseVector; - - while (exp > 0) - { - if ((exp & 1) == 1) - { - result *= currentBase; - } - currentBase *= currentBase; - exp >>= 1; - } - - return result; - } - - for (; i < len; i++) - Unsafe.Add(ref dstRef, i) = Math.Pow(Unsafe.Add(ref srcRef, i), power); - } - [MethodImpl(MethodImplOptions.AggressiveOptimization)] - internal static unsafe void PowCore(ReadOnlySpan source, double power, Span destination) - { - int len = source.Length; - if (len == 0) return; - - fixed (double* pSrc = MemoryMarshal.Cast(source)) - fixed (double* pDst = MemoryMarshal.Cast(destination)) - { - double* pCurrentSrc = pSrc; - double* pCurrentDst = pDst; - double* pEnd = pSrc + len; - - while (pCurrentSrc <= pEnd - 4) - { - pCurrentDst[0] = Math.Pow(pCurrentSrc[0], power); - pCurrentDst[1] = Math.Pow(pCurrentSrc[1], power); - pCurrentDst[2] = Math.Pow(pCurrentSrc[2], power); - pCurrentDst[3] = Math.Pow(pCurrentSrc[3], power); - - pCurrentSrc += 4; - pCurrentDst += 4; - } - - while (pCurrentSrc < pEnd) - { - *pCurrentDst = Math.Pow(*pCurrentSrc, power); - - pCurrentSrc++; - pCurrentDst++; - } - } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static double QuickPow(double baseValue, int exp) - { - // Разворачиваем самые частые степени в прямое умножение вообще без циклов и if! - switch (exp) - { - case 0: return 1.0; - case 1: return baseValue; - case 2: return baseValue * baseValue; - case 3: return baseValue * baseValue * baseValue; - case 4: { double x2 = baseValue * baseValue; return x2 * x2; } - } - - // Если степень отрицательная - if (exp < 0) - { - baseValue = 1.0 / baseValue; - if (exp == int.MinValue) return (1.0 / baseValue) * QuickPow(baseValue, int.MaxValue); - exp = -exp; - } - - // Тяжелая артиллерия для редких больших степеней - if (exp > 32) return Math.Pow(baseValue, exp); - - // Стандартный бинарный алгоритм для средних степеней (от 5 до 32) - double result = 1.0; - double currentBase = baseValue; - while (exp > 0) - { - if ((exp & 1) == 1) result *= currentBase; - currentBase *= currentBase; - exp >>= 1; - } - return result; - } - internal static void SqrtCore(ReadOnlySpan source, Span destination) - { - int len = source.Length; - ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); - Span dstDouble = MemoryMarshal.Cast(destination); - - int vectorSize = Vector.Count; - int i = 0; - - ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); - ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); - - int SIMDEnd = len - (len % vectorSize); - for (; i < SIMDEnd; i += vectorSize) - { - ref double currentSrc = ref Unsafe.Add(ref srcRef, i); - ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); - var vector = new Vector(srcWindow); - var multiplied = Vector.SquareRoot(vector); - ref double currentDst = ref Unsafe.Add(ref dstRef, i); - Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); - multiplied.CopyTo(dstWindow); - } - - for (; i < len; i++) - { - Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i)); - } - } - - - // ========================================== - // === MULTIPLY === - // ========================================== - - public static Length[] Multiply(this Length[] units, double multiplicator) - { - if (units is null) return null!; - if (units.Length == 0) return []; - - var result = new Length[units.Length]; - MultiplyCore(units, multiplicator, result); - return result; - } - public static Length[] Multiply(this double multiplicator, Length[] units) - => units.Multiply(multiplicator); - - public static Length?[] Multiply(this Length?[] units, double multiplicator) - { - if (units is null) return []; - if (units.Length == 0) return []; - - var result = (Length?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(item.Value._Value * multiplicator); - } - return result; - } - public static Length?[] Multiply(this double multiplicator, Length?[] units) - => units.Multiply(multiplicator); - - // === ReadOnlySpan === - public static Span Multiply(this ReadOnlySpan units, double multiplicator) - { - if (units.Length == 0) return []; - Span result = new Length[units.Length]; - LengthExtension.MultiplyCore(units, multiplicator, result); - return result; - } - public static Span Multiply(this double multiplicator, ReadOnlySpan units) - => units.Multiply(multiplicator); - public static Span Multiply(this ReadOnlySpan units, double multiplicator) - { - if (units.Length == 0) return []; - Span result = new Length?[units.Length]; - units.CopyTo(result); - - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(item.Value._Value * multiplicator); - } - return result; - } - public static Span Multiply(this double multiplicator, ReadOnlySpan units) - => units.Multiply(multiplicator); - - // === List === - public static List Multiply(this List units, double multiplicator) - { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - - var result = new List(len); - result.SetCountUnsafe(len); - LengthExtension.MultiplyCore(CollectionsMarshal.AsSpan(units), multiplicator, CollectionsMarshal.AsSpan(result)); - return result; - } - public static List Multiply(this double multiplicator, List units) - => units.Multiply(multiplicator); - public static List Multiply(this List units, double multiplicator) - { - if (units is null) return []; - int len = units.Count; - if (len == 0) return []; - - var result = new List(units); - Span dstSpan = CollectionsMarshal.AsSpan(result); - for (int i = 0; i < len; i++) - { - ref var item = ref dstSpan[i]; - if (item.HasValue) item = new Length(item.Value._Value * multiplicator); - } - return result; - } - public static List Multiply(this double multiplicator, List units) - => units.Multiply(multiplicator); - - // ========================================== - // === DIVIDE === - // ========================================== - - public static Length[] Divide(this Length[] units, double divisor) - { - if (units is null) return null!; - if (units.Length == 0) return []; - if (divisor == 0 || double.IsNaN(divisor)) - throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); - - var result = new Length[units.Length]; - DivideCore(units, divisor, result); - return result; - } - public static Length[] Divide(this double dividend, Length[] units) - { - if (units is null) return null!; - if (units.Length == 0) return []; - - var result = new Length[units.Length]; - DivideCore(dividend, units, result); // Вызов зеркального ядра (число / массив) - return result; - } - public static Length?[] Divide(this Length?[] units, double divisor) - { - if (units is null) return []; - if (units.Length == 0) return []; - if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); - - var result = (Length?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(item.Value._Value / divisor); - } - return result; - } - public static Length?[] Divide(this double dividend, Length?[] units) - { - if (units is null) return []; - if (units.Length == 0) return []; - - var result = (Length?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(dividend / item.Value._Value); - } - return result; - } - - // === ReadOnlySpan === - public static Span Divide(this ReadOnlySpan units, double divisor) - { - if (units.Length == 0) return []; - if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); - var result = new Length[units.Length]; - LengthExtension.DivideCore(units, divisor, result); - return result; - } - public static Span Divide(this double dividend, ReadOnlySpan units) - { - if (units.Length == 0) return []; - var result = new Length[units.Length]; - LengthExtension.DivideCore(dividend, units, result); - return result; - } - public static Span Divide(this ReadOnlySpan units, double divisor) - { - if (units.Length == 0) return []; - if (divisor == 0 || double.IsNaN(divisor)) - throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); - - Span result = new Length?[units.Length]; - units.CopyTo(result); - - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(item.Value._Value / divisor); - } - return result; - } - public static Span Divide(this double dividend, ReadOnlySpan units) - { - if (units.Length == 0) return []; - Span result = new Length?[units.Length]; - units.CopyTo(result); - - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(dividend / item.Value._Value); - } - return result; - } - - // === List === - public static List Divide(this List units, double divisor) - { - if (units is null) return null!; - if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); - int len = units.Count; - if (len == 0) return []; - - var result = new List(len); - result.SetCountUnsafe(len); - LengthExtension.DivideCore(CollectionsMarshal.AsSpan(units), divisor, CollectionsMarshal.AsSpan(result)); - return result; - } - public static List Divide(this double dividend, List units) - { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - - var result = new List(len); - result.SetCountUnsafe(len); - LengthExtension.DivideCore(dividend, CollectionsMarshal.AsSpan(units), CollectionsMarshal.AsSpan(result)); - return result; - } - public static List Divide(this List units, double divisor) - { - if (units is null) return []; - if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); - int len = units.Count; - if (len == 0) return []; - - var result = new List(units); - Span dstSpan = CollectionsMarshal.AsSpan(result); - for (int i = 0; i < len; i++) - { - ref var item = ref dstSpan[i]; - if (item.HasValue) item = new Length(item.Value._Value / divisor); - } - return result; - } - public static List Divide(this double dividend, List units) - { - if (units is null) return []; - int len = units.Count; - if (len == 0) return []; - - var result = new List(units); - Span dstSpan = CollectionsMarshal.AsSpan(result); - for (int i = 0; i < len; i++) - { - ref var item = ref dstSpan[i]; - if (item.HasValue) item = new Length(dividend / item.Value._Value); - } - return result; - } - - // ========================================== - // === PLUS === - // ========================================== - - public static Length[] Plus(this Length[] units, double summand) - { - if (units is null) return null!; - if (units.Length == 0) return []; - - var result = new Length[units.Length]; - PlusCore(units, summand, result); - return result; - } - public static Length[] Plus(this double summand, Length[] units) - => units.Plus(summand); - public static Length?[] Plus(this Length?[] units, double summand) - { - if (units is null) return []; - if (units.Length == 0) return []; - - var result = (Length?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(item.Value._Value + summand); - } - return result; - } - public static Length?[] Plus(this double summand, Length?[] units) - => units.Plus(summand); - - // === ReadOnlySpan === - public static Span Plus(this ReadOnlySpan units, double summand) - { - if (units.Length == 0) return []; - var result = new Length[units.Length]; - LengthExtension.PlusCore(units, summand, result); - return result; - } - public static Span Plus(this double summand, ReadOnlySpan units) - => units.Plus(summand); - - // === List === - public static List Plus(this List units, double summand) - { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - - var result = new List(len); - result.SetCountUnsafe(len); - LengthExtension.PlusCore(CollectionsMarshal.AsSpan(units), summand, CollectionsMarshal.AsSpan(result)); - return result; - } - public static List Plus(this double summand, List units) - => units.Plus(summand); - public static List Plus(this List units, double summand) - { - if (units is null) return []; - int len = units.Count; - if (len == 0) return []; - - var result = new List(units); - Span dstSpan = CollectionsMarshal.AsSpan(result); - for (int i = 0; i < len; i++) - { - ref var item = ref dstSpan[i]; - if (item.HasValue) item = new Length(item.Value._Value + summand); - } - return result; - } - public static List Plus(this double summand, List units) - => units.Plus(summand); - - // ========================================== - // === MINUS === - // ========================================== - - public static Length[] Minus(this Length[] units, double subtrahend) - { - if (units is null) return null!; - if (units.Length == 0) return []; - - var result = new Length[units.Length]; - MinusCore(units, subtrahend, result); - return result; - } - public static Length[] Minus(this double minuend, Length[] units) - { - if (units is null) return null!; - if (units.Length == 0) return []; - - var result = new Length[units.Length]; - MinusCore(minuend, units, result); // Вызов зеркального ядра (число - массив) - return result; - } - public static Length?[] Minus(this Length?[] units, double subtrahend) - { - if (units is null) return []; - if (units.Length == 0) return []; - - var result = (Length?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(item.Value._Value - subtrahend); - } - return result; - } - public static Length?[] Minus(this double minuend, Length?[] units) - { - if (units is null) return []; - if (units.Length == 0) return []; - - var result = (Length?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(minuend - item.Value._Value); - } - return result; - } - - // === ReadOnlySpan === - public static Span Minus(this ReadOnlySpan units, double subtrahend) - { - if (units.Length == 0) return []; - var result = new Length[units.Length]; - LengthExtension.MinusCore(units, subtrahend, result); - return result; - } - public static Span Minus(this double minuend, ReadOnlySpan units) - { - if (units.Length == 0) return []; - var result = new Length[units.Length]; - LengthExtension.MinusCore(minuend, units, result); - return result; - } - - // === List === - public static List Minus(this List units, double subtrahend) - { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - - var result = new List(len); - result.SetCountUnsafe(len); - LengthExtension.MinusCore(CollectionsMarshal.AsSpan(units), subtrahend, CollectionsMarshal.AsSpan(result)); - return result; - } - public static List Minus(this double minuend, List units) - { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - - var result = new List(len); - result.SetCountUnsafe(len); - LengthExtension.MinusCore(minuend, CollectionsMarshal.AsSpan(units), CollectionsMarshal.AsSpan(result)); - return result; - } - public static List Minus(this List units, double subtrahend) - { - if (units is null) return []; - int len = units.Count; - if (len == 0) return []; - - var result = new List(units); - Span dstSpan = CollectionsMarshal.AsSpan(result); - for (int i = 0; i < len; i++) - { - ref var item = ref dstSpan[i]; - if (item.HasValue) item = new Length(item.Value._Value - subtrahend); - } - return result; - } - public static List Minus(this double minuend, List units) - { - if (units is null) return []; - int len = units.Count; - if (len == 0) return []; - - var result = new List(units); - Span dstSpan = CollectionsMarshal.AsSpan(result); - for (int i = 0; i < len; i++) - { - ref var item = ref dstSpan[i]; - if (item.HasValue) item = new Length(minuend - item.Value._Value); - } - return result; - } - - // ========================================== - // ЦЕЛАЯ СТЕПЕНЬ (int power) - // ========================================== - - public static Length[] Pow(this Length[] units, int power) - { - if (units is null) return null!; - if (units.Length == 0) return []; - - var result = new Length[units.Length]; - LengthExtension.PowCore(units, power, result); - return result; - } - public static Length?[] Pow(this Length?[] units, int power) - { - if (units is null) return []; - if (units.Length == 0) return []; - - var result = (Length?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) - { - // Используем тот же быстрый QuickPow, что и в ядре, чтобы не вызывать тяжелый Math.Pow - item = new Length(QuickPow(item.Value._Value, power)); - } - } - return result; - } - - // === ReadOnlySpan === - public static Span Pow(this ReadOnlySpan units, int power) - { - if (units.Length == 0) return []; - var result = new Length[units.Length]; - LengthExtension.PowCore(units, power, result); - return result; - } - - // === List === - public static List Pow(this List units, int power) - { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - - var result = new List(len); - result.SetCountUnsafe(len); - LengthExtension.PowCore(CollectionsMarshal.AsSpan(units), power, CollectionsMarshal.AsSpan(result)); - return result; - } - public static List Pow(this List units, int power) - { - if (units is null) return []; - int len = units.Count; - if (len == 0) return []; - - var result = new List(units); - Span dstSpan = CollectionsMarshal.AsSpan(result); - for (int i = 0; i < len; i++) - { - ref var item = ref dstSpan[i]; - if (item.HasValue) item = new Length(QuickPow(item.Value._Value, power)); - } - return result; - } - - - // ========================================== - // ДРОБНАЯ СТЕПЕНЬ (double power) - // ========================================== - - public static Length[] Pow(this Length[] units, double power) - { - if (units is null) return null!; - if (units.Length == 0) return []; - - var result = new Length[units.Length]; - LengthExtension.PowCore(units, power, result); - return result; - } - public static Length?[] Pow(this Length?[] units, double power) - { - if (units is null) return []; - if (units.Length == 0) return []; - - var result = (Length?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) - { - item = new Length(Math.Pow(item.Value._Value, power)); - } - } - return result; - } - - // === ReadOnlySpan === - public static Span Pow(this ReadOnlySpan units, double power) - { - if (units.Length == 0) return []; - var result = new Length[units.Length]; - LengthExtension.PowCore(units, power, result); - return result; - } - public static Span Pow(this ReadOnlySpan units, double power) - { - int len = units.Length; - if (len == 0) return []; - Span result = new Length?[units.Length]; - units.CopyTo(result); - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) item = new Length(Math.Pow(item.Value._Value, power)); - } - return result; - } - - // === List === - public static List Pow(this List units, double power) - { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - - var result = new List(len); - result.SetCountUnsafe(len); - LengthExtension.PowCore(CollectionsMarshal.AsSpan(units), power, CollectionsMarshal.AsSpan(result)); - return result; - } - public static List Pow(this List units, double power) - { - if (units is null) return []; - int len = units.Count; - if (len == 0) return []; - - var result = new List(units); - Span dstSpan = CollectionsMarshal.AsSpan(result); - for (int i = 0; i < len; i++) - { - ref var item = ref dstSpan[i]; - if (item.HasValue) item = new Length(Math.Pow(item.Value._Value, power)); - } - return result; - } - - - // ========================================== - // КВАДРАТНЫЙ КОРЕНЬ (Sqrt) - // ========================================== - - public static Length[] Sqrt(this Length[] units) - { - if (units is null) return null!; - if (units.Length == 0) return []; - - var result = new Length[units.Length]; - LengthExtension.SqrtCore(units, result); - return result; - } - public static Length?[] Sqrt(this Length?[] units) - { - if (units is null) return []; - if (units.Length == 0) return []; - - var result = (Length?[])units.Clone(); - int len = result.Length; - for (int i = 0; i < len; i++) - { - ref var item = ref result[i]; - if (item.HasValue) - { - item = new Length(Math.Sqrt(item.Value._Value)); - } - } - return result; - } - - // === ReadOnlySpan === - public static Span Sqrt(this ReadOnlySpan units) - { - if (units.Length == 0) return []; - var result = new Length[units.Length]; - LengthExtension.SqrtCore(units, result); - return result; - } - - // === List === - public static List Sqrt(this List units) - { - if (units is null) return null!; - int len = units.Count; - if (len == 0) return []; - - var result = new List(len); - result.SetCountUnsafe(len); - LengthExtension.SqrtCore(CollectionsMarshal.AsSpan(units), CollectionsMarshal.AsSpan(result)); - return result; - } - public static List Sqrt(this List units) - { - if (units is null) return []; - int len = units.Count; - if (len == 0) return []; - - var result = new List(units); - Span dstSpan = CollectionsMarshal.AsSpan(result); - for (int i = 0; i < len; i++) - { - ref var item = ref dstSpan[i]; - if (item.HasValue) item = new Length(Math.Sqrt(item.Value._Value)); - } - return result; - } -} internal readonly struct LengthConv { diff --git a/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs b/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs new file mode 100644 index 0000000..e53c1c1 --- /dev/null +++ b/QWERTYkez.Mensura/Units/XXXXXXXX.Gen.cs @@ -0,0 +1,1681 @@ +//using System.Globalization; +//using System.Runtime.Serialization; + +//namespace QWERTYkez.Mensura.Units; + +//[JsonConverter(typeof(XXXXXXXXXXXXXXConverter))] +//public readonly partial record struct XXXXXXXXXXXXXX +//{ +// [JsonInclude, DataMember, JsonPropertyName("v")] // для JSON / EF на случай сбоев, если пробелма с _Value +// internal double Value { get => _Value; init => _Value = value; } +// internal readonly double _Value; +// internal XXXXXXXXXXXXXX(double value) => _Value = value; + +// public override int GetHashCode() => _Value.GetHashCode(); +// public int CompareTo(XXXXXXXXXXXXXX? other) => _Value.CompareTo(other is null ? 0d : other.Value._Value); +// public int CompareTo(XXXXXXXXXXXXXX other) => _Value.CompareTo(other._Value); + +// public bool Equals(XXXXXXXXXXXXXX? other) => _Value.Equals(other?._Value); + + +// [JsonIgnore, IgnoreDataMember] public bool IsPositive => _Value >= 0; +// [JsonIgnore, IgnoreDataMember] public bool IsGreaterThanZero => _Value > 0; +// [JsonIgnore, IgnoreDataMember] public bool IsNegative => _Value < 0; +// [JsonIgnore, IgnoreDataMember] public bool IsZero => _Value == 0; + + +// public static XXXXXXXXXXXXXX Zero { get; } = new(0d); +// public static XXXXXXXXXXXXXX Min { get; } = new(double.MinValue); +// public static XXXXXXXXXXXXXX Max { get; } = new(double.MaxValue); +// public static XXXXXXXXXXXXXX NegativeInfinity { get; } = new(double.NegativeInfinity); +// public static XXXXXXXXXXXXXX PositiveInfinity { get; } = new(double.PositiveInfinity); + + +// public static bool operator ==(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) == (T2 is null ? 0d : T2.Value._Value); +// public static bool operator !=(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) != (T2 is null ? 0d : T2.Value._Value); + +// public static bool operator <(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) < (T2 is null ? 0d : T2.Value._Value); +// public static bool operator <=(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) <= (T2 is null ? 0d : T2.Value._Value); +// public static bool operator >(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) > (T2 is null ? 0d : T2.Value._Value); +// public static bool operator >=(XXXXXXXXXXXXXX? T1, XXXXXXXXXXXXXX? T2) => (T1 is null ? 0d : T1.Value._Value) >= (T2 is null ? 0d : T2.Value._Value); + + +// public static XXXXXXXXXXXXXX operator +(XXXXXXXXXXXXXX T2) => new(+T2._Value); +// public static XXXXXXXXXXXXXX operator +(XXXXXXXXXXXXXX T1, XXXXXXXXXXXXXX T2) => new(T1._Value + T2._Value); +// public static XXXXXXXXXXXXXX operator -(XXXXXXXXXXXXXX T2) => new(-T2._Value); +// public static XXXXXXXXXXXXXX operator -(XXXXXXXXXXXXXX T1, XXXXXXXXXXXXXX T2) => new(T1._Value - T2._Value); + + +// // double +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, double T2) => new(T1._Value * T2); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, double? T2) => T1 * (T2 ?? 0d); +// public static XXXXXXXXXXXXXX operator *(double T1, XXXXXXXXXXXXXX T2) => new(T1 * T2._Value); +// public static XXXXXXXXXXXXXX operator *(double? T1, XXXXXXXXXXXXXX T2) => (T1 ?? 0d) * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, double T2) => new(T1._Value / T2); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, double? T2) => T1 / (T2 ?? 0d); +// public static double operator /(XXXXXXXXXXXXXX T1, XXXXXXXXXXXXXX T2) => T1._Value / T2._Value; + +// // sbyte +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, sbyte T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, sbyte? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(sbyte T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(sbyte? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, sbyte T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, sbyte? T2) => T1 / T2.ToDouble(); + +// // short +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, short T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, short? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(short T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(short? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, short T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, short? T2) => T1 / T2.ToDouble(); + +// // int +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, int T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, int? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(int T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(int? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, int T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, int? T2) => T1 / T2.ToDouble(); + +// // long +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, long T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, long? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(long T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(long? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, long T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, long? T2) => T1 / T2.ToDouble(); + +// // byte +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, byte T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, byte? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(byte T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(byte? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, byte T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, byte? T2) => T1 / T2.ToDouble(); + +// // ushort +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, ushort T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, ushort? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(ushort T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(ushort? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, ushort T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, ushort? T2) => T1 / T2.ToDouble(); + +// // uint +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, uint T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, uint? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(uint T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(uint? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, uint T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, uint? T2) => T1 / T2.ToDouble(); + +// // ulong +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, ulong T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, ulong? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(ulong T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(ulong? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, ulong T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, ulong? T2) => T1 / T2.ToDouble(); + +// // nint +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, nint T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, nint? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(nint T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(nint? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, nint T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, nint? T2) => T1 / T2.ToDouble(); + +// // nuint +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, nuint T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, nuint? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(nuint T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(nuint? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, nuint T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, nuint? T2) => T1 / T2.ToDouble(); + +// // float +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, float T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, float? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(float T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(float? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, float T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, float? T2) => T1 / T2.ToDouble(); + +// // decimal +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, decimal T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, decimal? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(decimal T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(decimal? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, decimal T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, decimal? T2) => T1 / T2.ToDouble(); + +//#if NET7_0_OR_GREATER +// // Int128 +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, Int128 T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, Int128? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(Int128 T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(Int128? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, Int128 T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, Int128? T2) => T1 / T2.ToDouble(); + +// // UInt128 +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, UInt128 T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(XXXXXXXXXXXXXX T1, UInt128? T2) => T1 * T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator *(UInt128 T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator *(UInt128? T1, XXXXXXXXXXXXXX T2) => T1.ToDouble() * T2; +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, UInt128 T2) => T1 / T2.ToDouble(); +// public static XXXXXXXXXXXXXX operator /(XXXXXXXXXXXXXX T1, UInt128? T2) => T1 / T2.ToDouble(); +//#endif + +// public static explicit operator XXXXXXXXXXXXXX(double val) => new(val); +// public static explicit operator double(XXXXXXXXXXXXXX unit) => unit._Value; + +// public XXXXXXXXXXXXXX Abs() => new(Math.Abs(_Value)); + +// /// C^2 = this^2 + B^2 C = (this^2 + B^2).Sqrt(2) +// public XXXXXXXXXXXXXX HypFromLeg(XXXXXXXXXXXXXX B) => new(Math.Sqrt(_Value * _Value + B._Value * B._Value)); + +// /// C^2 = this^2 + B^2 C = (this^2 + B^2).Sqrt(2) +// public XXXXXXXXXXXXXX HypFromLeg(XXXXXXXXXXXXXX? B) +// { +// double b = B is null ? 0d : B.Value._Value; +// return new(Math.Sqrt(_Value * _Value + b * b)); +// } + +// /// C^2 = this^2 + B^2 B = (C^2 - this^2).Sqrt(2) +// public XXXXXXXXXXXXXX LegFromHyp(XXXXXXXXXXXXXX C) => new(Math.Sqrt(C._Value * C._Value - _Value * _Value)); + +// /// C^2 = this^2 + B^2 B = (C^2 - this^2).Sqrt(2) +// public XXXXXXXXXXXXXX LegFromHyp(XXXXXXXXXXXXXX? C) +// { +// double c = C is null ? 0d : C.Value._Value; +// return new(Math.Sqrt(c * c - _Value * _Value)); +// } + +// /// this^2 = A^2 + B^2 B = (this^2 - A^2).Sqrt(2) +// public XXXXXXXXXXXXXX LegFromLeg(XXXXXXXXXXXXXX A) => new(Math.Sqrt(_Value * _Value - A._Value * A._Value)); + +// /// this^2 = A^2 + B^2 B = (this^2 - A^2).Sqrt(2) +// public XXXXXXXXXXXXXX LegFromLeg(XXXXXXXXXXXXXX? A) +// { +// double a = A is null ? 0d : A.Value._Value; +// return new(Math.Sqrt(_Value * _Value - a * a)); +// } +//} + +//public static class XXXXXXXXXXXXXXExtension +//{ +// internal static double ToDouble(this XXXXXXXXXXXXXX? unit) => unit is null ? 0d : unit.Value._Value; + +// public static XXXXXXXXXXXXXX MetricSum(this IEnumerable units) => new() { Value = units?.Sum(m => m._Value) ?? 0d }; +// public static XXXXXXXXXXXXXX MetricAverage(this IEnumerable units) => new() { Value = units?.Average(m => m._Value) ?? double.NaN }; +// public static XXXXXXXXXXXXXX MetricMax(this IEnumerable units) => new() { Value = units?.Max(m => m._Value) ?? double.MinValue }; +// public static XXXXXXXXXXXXXX MetricMin(this IEnumerable units) => new() { Value = units?.Min(m => m._Value) ?? double.MaxValue }; + +// public static XXXXXXXXXXXXXX MetricSum(this IEnumerable units) => new() { Value = units?.Sum(m => m.ToDouble()) ?? 0d }; +// public static XXXXXXXXXXXXXX MetricAverage(this IEnumerable units) => new() { Value = units?.Average(m => m.ToDouble()) ?? double.NaN }; +// public static XXXXXXXXXXXXXX MetricMax(this IEnumerable units) => new() { Value = units?.Max(m => m.ToDouble()) ?? double.MinValue }; +// public static XXXXXXXXXXXXXX MetricMin(this IEnumerable units) => new() { Value = units?.Min(m => m.ToDouble()) ?? double.MaxValue }; + + +// internal static void MultiplyCore(ReadOnlySpan source, double value, Span destination) +// { +// int len = source.Length; +// ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); +// Span dstDouble = MemoryMarshal.Cast(destination); + +// var vectorizedValue = new Vector(value); +// int vectorSize = Vector.Count; +// int i = 0; + +// ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); +// ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); + +// int SIMDEnd = len - (len % vectorSize); +// for (; i < SIMDEnd; i += vectorSize) +// { +// ref double currentSrc = ref Unsafe.Add(ref srcRef, i); +// ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); +// var vector = new Vector(srcWindow); +// var multiplied = vector * vectorizedValue; +// ref double currentDst = ref Unsafe.Add(ref dstRef, i); +// Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); +// multiplied.CopyTo(dstWindow); +// } + +// for (; i < len; i++) +// { +// Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * value; +// } +// } +// internal static void DivideCore(ReadOnlySpan source, double divisor, Span destination) +// { +// // 1. Проверка на ноль +// if (divisor == 0d || double.IsNaN(divisor)) +// throw new DivideByZeroException("Делитель не может быть равен нулю."); + +// int len = source.Length; +// ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); +// Span dstDouble = MemoryMarshal.Cast(destination); + +// var vectorizedValue = new Vector(divisor); +// int vectorSize = Vector.Count; +// int i = 0; + +// ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); +// ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); + +// int SIMDEnd = len - (len % vectorSize); +// for (; i < SIMDEnd; i += vectorSize) +// { +// ref double currentSrc = ref Unsafe.Add(ref srcRef, i); +// ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); +// var vector = new Vector(srcWindow); +// var multiplied = vector / vectorizedValue; +// ref double currentDst = ref Unsafe.Add(ref dstRef, i); +// Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); +// multiplied.CopyTo(dstWindow); +// } + +// for (; i < len; i++) +// { +// Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) / divisor; +// } +// } +// internal static void DivideCore(double dividend, ReadOnlySpan source, Span destination) +// { +// int len = source.Length; +// ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); +// Span dstDouble = MemoryMarshal.Cast(destination); + +// var vectorizedValue = new Vector(dividend); +// var zeroVector = Vector.Zero; // Вектор из нулей для сравнения +// int vectorSize = Vector.Count; +// int i = 0; + +// ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); +// ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); + +// int SIMDEnd = len - (len % vectorSize); +// for (; i < SIMDEnd; i += vectorSize) +// { +// ref double currentSrc = ref Unsafe.Add(ref srcRef, i); +// ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); +// var vector = new Vector(srcWindow); + +// // БЫСТРАЯ ПРОВЕРКА: Есть ли хотя бы один 0.0 в текущем векторе? +// if (Vector.EqualsAny(vector, zeroVector)) +// { +// throw new DivideByZeroException($"Обнаружен делитель, равный нулю, в районе индексов {i}..{i + vectorSize - 1}."); +// } + +// var multiplied = vectorizedValue / vector; +// ref double currentDst = ref Unsafe.Add(ref dstRef, i); +// Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); +// multiplied.CopyTo(dstWindow); +// } + +// // Хвостовой цикл +// for (; i < len; i++) +// { +// double divisor = Unsafe.Add(ref srcRef, i); +// if (divisor == 0.0) +// { +// throw new DivideByZeroException($"Обнаружен делитель, равный нулю, в индексе {i}."); +// } +// Unsafe.Add(ref dstRef, i) = dividend / divisor; +// } +// } +// internal static void PlusCore(ReadOnlySpan source, double summand, Span destination) +// { +// int len = source.Length; +// ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); +// Span dstDouble = MemoryMarshal.Cast(destination); + +// var vectorizedValue = 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 - (len % vectorSize); +// for (; i < SIMDEnd; i += vectorSize) +// { +// ref double currentSrc = ref Unsafe.Add(ref srcRef, i); +// ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); +// var vector = new Vector(srcWindow); +// var multiplied = vector + vectorizedValue; +// ref double currentDst = ref Unsafe.Add(ref dstRef, i); +// Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); +// multiplied.CopyTo(dstWindow); +// } + +// for (; i < len; i++) +// { +// Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) + summand; +// } +// } +// internal static void MinusCore(ReadOnlySpan source, double subtrahend, Span destination) +// { +// int len = source.Length; +// ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); +// Span dstDouble = MemoryMarshal.Cast(destination); + +// var vectorizedValue = 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 - (len % vectorSize); +// for (; i < SIMDEnd; i += vectorSize) +// { +// ref double currentSrc = ref Unsafe.Add(ref srcRef, i); +// ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); +// var vector = new Vector(srcWindow); +// var multiplied = vector - vectorizedValue; +// ref double currentDst = ref Unsafe.Add(ref dstRef, i); +// Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); +// multiplied.CopyTo(dstWindow); +// } + +// for (; i < len; i++) +// { +// Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) - subtrahend; +// } +// } +// internal static void MinusCore(double minuend, ReadOnlySpan source, Span destination) +// { +// int len = source.Length; +// ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); +// Span dstDouble = MemoryMarshal.Cast(destination); + +// var vectorizedValue = 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 - (len % vectorSize); +// for (; i < SIMDEnd; i += vectorSize) +// { +// ref double currentSrc = ref Unsafe.Add(ref srcRef, i); +// ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); +// var vector = new Vector(srcWindow); +// var multiplied = vectorizedValue - vector; +// ref double currentDst = ref Unsafe.Add(ref dstRef, i); +// Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); +// multiplied.CopyTo(dstWindow); +// } + +// for (; i < len; i++) +// { +// Unsafe.Add(ref dstRef, i) = minuend - Unsafe.Add(ref srcRef, i); +// } +// } + +// [MethodImpl(MethodImplOptions.AggressiveOptimization)] +// internal static void PowCore(ReadOnlySpan source, int power, Span destination) +// { +// int len = source.Length; +// ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); +// Span dstDouble = MemoryMarshal.Cast(destination); +// int vectorSize = Vector.Count; +// int i = 0; +// ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); +// ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); +// int SIMDEnd = len - (len % vectorSize); +// for (; i < SIMDEnd; i += vectorSize) +// { +// var vector = new Vector(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.Add(ref srcRef, i), vectorSize)); +// var resultVector = VectorPow(vector, power); +// resultVector.CopyTo(MemoryMarshal.CreateSpan(ref Unsafe.Add(ref dstRef, i), vectorSize)); +// } + +// // Приватный SIMD-метод быстрого возведения в степень +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// static Vector VectorPow(Vector baseVector, int exp) +// { +// if (exp == 0) return Vector.One; +// if (exp == 1) return baseVector; + +// if (exp < 0) +// { +// baseVector = Vector.One / baseVector; +// exp = -exp; // Внимание: может переполниться при int.MinValue, но для степеней это редчайший кейс +// } + +// var result = Vector.One; +// var currentBase = baseVector; + +// while (exp > 0) +// { +// if ((exp & 1) == 1) +// { +// result *= currentBase; +// } +// currentBase *= currentBase; +// exp >>= 1; +// } + +// return result; +// } + +// for (; i < len; i++) +// Unsafe.Add(ref dstRef, i) = Math.Pow(Unsafe.Add(ref srcRef, i), power); +// } +// [MethodImpl(MethodImplOptions.AggressiveOptimization)] +// internal static unsafe void PowCore(ReadOnlySpan source, double power, Span destination) +// { +// int len = source.Length; +// if (len == 0) return; + +// fixed (double* pSrc = MemoryMarshal.Cast(source)) +// fixed (double* pDst = MemoryMarshal.Cast(destination)) +// { +// double* pCurrentSrc = pSrc; +// double* pCurrentDst = pDst; +// double* pEnd = pSrc + len; + +// while (pCurrentSrc <= pEnd - 4) +// { +// pCurrentDst[0] = Math.Pow(pCurrentSrc[0], power); +// pCurrentDst[1] = Math.Pow(pCurrentSrc[1], power); +// pCurrentDst[2] = Math.Pow(pCurrentSrc[2], power); +// pCurrentDst[3] = Math.Pow(pCurrentSrc[3], power); + +// pCurrentSrc += 4; +// pCurrentDst += 4; +// } + +// while (pCurrentSrc < pEnd) +// { +// *pCurrentDst = Math.Pow(*pCurrentSrc, power); + +// pCurrentSrc++; +// pCurrentDst++; +// } +// } +// } +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// internal static void SqrtCore(ReadOnlySpan source, Span destination) +// { +// int len = source.Length; +// ReadOnlySpan srcDouble = MemoryMarshal.Cast(source); +// Span dstDouble = MemoryMarshal.Cast(destination); + +// int vectorSize = Vector.Count; +// int i = 0; + +// ref double srcRef = ref MemoryMarshal.GetReference(srcDouble); +// ref double dstRef = ref MemoryMarshal.GetReference(dstDouble); + +// int SIMDEnd = len - (len % vectorSize); +// for (; i < SIMDEnd; i += vectorSize) +// { +// ref double currentSrc = ref Unsafe.Add(ref srcRef, i); +// ReadOnlySpan srcWindow = MemoryMarshal.CreateReadOnlySpan(ref currentSrc, vectorSize); +// var vector = new Vector(srcWindow); +// var multiplied = Vector.SquareRoot(vector); +// ref double currentDst = ref Unsafe.Add(ref dstRef, i); +// Span dstWindow = MemoryMarshal.CreateSpan(ref currentDst, vectorSize); +// multiplied.CopyTo(dstWindow); +// } + +// for (; i < len; i++) +// { +// Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i)); +// } +// } + +// // ========================================== +// // === MULTIPLY === +// // ========================================== + +// public static XXXXXXXXXXXXXX[] Multiply(this XXXXXXXXXXXXXX[] units, double multiplicator) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = new XXXXXXXXXXXXXX[units.Length]; +// MultiplyCore(units, multiplicator, result); +// return result; +// } +// public static XXXXXXXXXXXXXX[] Multiply(this double multiplicator, XXXXXXXXXXXXXX[] units) +// => units.Multiply(multiplicator); +// public static XXXXXXXXXXXXXX?[] Multiply(this XXXXXXXXXXXXXX?[] units, double multiplicator) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = (XXXXXXXXXXXXXX?[])units.Clone(); +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value * multiplicator); +// } +// return result; +// } +// public static XXXXXXXXXXXXXX?[] Multiply(this double multiplicator, XXXXXXXXXXXXXX?[] units) +// => units.Multiply(multiplicator); + +// // === ReadOnlySpan === +// public static Span Multiply(this ReadOnlySpan units, double multiplicator) +// { +// if (units.Length == 0) return []; +// Span result = new XXXXXXXXXXXXXX[units.Length]; +// MultiplyCore(units, multiplicator, result); +// return result; +// } +// public static Span Multiply(this double multiplicator, ReadOnlySpan units) +// => units.Multiply(multiplicator); +// public static Span Multiply(this ReadOnlySpan units, double multiplicator) +// { +// if (units.Length == 0) return []; +// Span result = new XXXXXXXXXXXXXX?[units.Length]; +// units.CopyTo(result); + +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value * multiplicator); +// } +// return result; +// } +// public static Span Multiply(this double multiplicator, ReadOnlySpan units) +// => units.Multiply(multiplicator); + +// // === List === +// public static List Multiply(this List units, double multiplicator) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(len); +// result.SetCountUnsafe(len); +// MultiplyCore(CollectionsMarshal.AsSpan(units), multiplicator, CollectionsMarshal.AsSpan(result)); +// return result; +// } +// public static List Multiply(this double multiplicator, List units) +// => units.Multiply(multiplicator); +// public static List Multiply(this List units, double multiplicator) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(units); +// Span dstSpan = CollectionsMarshal.AsSpan(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref dstSpan[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value * multiplicator); +// } +// return result; +// } +// public static List Multiply(this double multiplicator, List units) +// => units.Multiply(multiplicator); + +// // === ICollection === +// public static Tcoll Multiply(this ICollection units, double multiplicator) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item._Value * multiplicator)); +// return tColl; +// } +// public static Tcoll Multiply(this double multiplicator, ICollection units) +// where Tcoll : class, ICollection, new() => Multiply(units, multiplicator); +// public static Tcoll Multiply(this ICollection units, double multiplicator) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item.HasValue ? item.Value._Value * multiplicator : 0d)); +// return tColl; +// } +// public static Tcoll Multiply(this double multiplicator, ICollection units) +// where Tcoll : class, ICollection, new() => Multiply(units, multiplicator); + +// // === IEnumerable === +// public static IEnumerable Multiply(this IEnumerable units, double multiplicator) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return new XXXXXXXXXXXXXX(item._Value * multiplicator); +// } +// public static IEnumerable Multiply(this double multiplicator, IEnumerable units) +// => units.Multiply(multiplicator); +// public static IEnumerable Multiply(this IEnumerable units, double multiplicator) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return item.HasValue +// ? new XXXXXXXXXXXXXX(item.Value._Value * multiplicator) : null; +// } +// public static IEnumerable Multiply(this double multiplicator, IEnumerable units) +// => units.Multiply(multiplicator); + +// // ========================================== +// // === DIVIDE === +// // ========================================== + +// public static XXXXXXXXXXXXXX[] Divide(this XXXXXXXXXXXXXX[] units, double divisor) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; +// if (divisor == 0 || double.IsNaN(divisor)) +// throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); + +// var result = new XXXXXXXXXXXXXX[units.Length]; +// DivideCore(units, divisor, result); +// return result; +// } +// public static XXXXXXXXXXXXXX[] Divide(this double dividend, XXXXXXXXXXXXXX[] units) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = new XXXXXXXXXXXXXX[units.Length]; +// DivideCore(dividend, units, result); // Вызов зеркального ядра (число / массив) +// return result; +// } +// public static XXXXXXXXXXXXXX?[] Divide(this XXXXXXXXXXXXXX?[] units, double divisor) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; +// if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); + +// var result = (XXXXXXXXXXXXXX?[])units.Clone(); +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value / divisor); +// } +// return result; +// } +// public static XXXXXXXXXXXXXX?[] Divide(this double dividend, XXXXXXXXXXXXXX?[] units) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = (XXXXXXXXXXXXXX?[])units.Clone(); +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(dividend / item.Value._Value); +// } +// return result; +// } + +// // === ReadOnlySpan === +// public static Span Divide(this ReadOnlySpan units, double divisor) +// { +// if (units.Length == 0) return []; +// if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); +// var result = new XXXXXXXXXXXXXX[units.Length]; +// DivideCore(units, divisor, result); +// return result; +// } +// public static Span Divide(this double dividend, ReadOnlySpan units) +// { +// if (units.Length == 0) return []; +// var result = new XXXXXXXXXXXXXX[units.Length]; +// DivideCore(dividend, units, result); +// return result; +// } +// public static Span Divide(this ReadOnlySpan units, double divisor) +// { +// if (units.Length == 0) return []; +// if (divisor == 0 || double.IsNaN(divisor)) +// throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); + +// Span result = new XXXXXXXXXXXXXX?[units.Length]; +// units.CopyTo(result); + +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value / divisor); +// } +// return result; +// } +// public static Span Divide(this double dividend, ReadOnlySpan units) +// { +// if (units.Length == 0) return []; +// Span result = new XXXXXXXXXXXXXX?[units.Length]; +// units.CopyTo(result); + +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(dividend / item.Value._Value); +// } +// return result; +// } + +// // === List === +// public static List Divide(this List units, double divisor) +// { +// if (units is null) return null!; +// if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(len); +// result.SetCountUnsafe(len); +// DivideCore(CollectionsMarshal.AsSpan(units), divisor, CollectionsMarshal.AsSpan(result)); +// return result; +// } +// public static List Divide(this double dividend, List units) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(len); +// result.SetCountUnsafe(len); +// DivideCore(dividend, CollectionsMarshal.AsSpan(units), CollectionsMarshal.AsSpan(result)); +// return result; +// } +// public static List Divide(this List units, double divisor) +// { +// if (units is null) return null!; +// if (divisor == 0 || double.IsNaN(divisor)) throw new ArgumentException("Делитель не может быть 0 или NaN.", nameof(divisor)); +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(units); +// Span dstSpan = CollectionsMarshal.AsSpan(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref dstSpan[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value / divisor); +// } +// return result; +// } +// public static List Divide(this double dividend, List units) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(units); +// Span dstSpan = CollectionsMarshal.AsSpan(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref dstSpan[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(dividend / item.Value._Value); +// } +// return result; +// } + +// // === ICollection === +// public static Tcoll Divide(this ICollection units, double divisor) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item._Value / divisor)); +// return tColl; +// } +// public static Tcoll Divide(this double dividend, ICollection units) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(dividend / item._Value)); +// return tColl; +// } +// public static Tcoll Divide(this ICollection units, double divisor) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item.HasValue ? item.Value._Value / divisor : 0d)); +// return tColl; +// } +// public static Tcoll Divide(this double dividend, ICollection units) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item.HasValue ? dividend / item.Value._Value : 0d)); +// return tColl; +// } + +// // === IEnumerable === +// public static IEnumerable Divide(this IEnumerable units, double divisor) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return new XXXXXXXXXXXXXX(item._Value * divisor); +// } +// public static IEnumerable Divide(this double dividend, IEnumerable units) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return new XXXXXXXXXXXXXX(dividend / item._Value); +// } +// public static IEnumerable Divide(this IEnumerable units, double divisor) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return item.HasValue +// ? new XXXXXXXXXXXXXX(item.Value._Value * divisor) : null; +// } +// public static IEnumerable Divide(this double dividend, IEnumerable units) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return item.HasValue +// ? new XXXXXXXXXXXXXX(dividend / item.Value._Value) : null; +// } + +// // ========================================== +// // === PLUS === +// // ========================================== + +// public static XXXXXXXXXXXXXX[] Plus(this XXXXXXXXXXXXXX[] units, double summand) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = new XXXXXXXXXXXXXX[units.Length]; +// PlusCore(units, summand, result); +// return result; +// } +// public static XXXXXXXXXXXXXX[] Plus(this double summand, XXXXXXXXXXXXXX[] units) +// => units.Plus(summand); +// public static XXXXXXXXXXXXXX?[] Plus(this XXXXXXXXXXXXXX?[] units, double summand) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = (XXXXXXXXXXXXXX?[])units.Clone(); +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value + summand); +// } +// return result; +// } +// public static XXXXXXXXXXXXXX?[] Plus(this double summand, XXXXXXXXXXXXXX?[] units) +// => units.Plus(summand); + +// // === ReadOnlySpan === +// public static Span Plus(this ReadOnlySpan units, double summand) +// { +// if (units.Length == 0) return []; +// var result = new XXXXXXXXXXXXXX[units.Length]; +// PlusCore(units, summand, result); +// return result; +// } +// public static Span Plus(this double summand, ReadOnlySpan units) +// => units.Plus(summand); +// public static Span Plus(this ReadOnlySpan units, double summand) +// { +// if (units.Length == 0) return []; +// Span result = new XXXXXXXXXXXXXX?[units.Length]; +// units.CopyTo(result); + +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value + summand); +// } +// return result; +// } +// public static Span Plus(this double summand, ReadOnlySpan units) +// => units.Multiply(summand); + +// // === List === +// public static List Plus(this List units, double summand) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(len); +// result.SetCountUnsafe(len); +// PlusCore(CollectionsMarshal.AsSpan(units), summand, CollectionsMarshal.AsSpan(result)); +// return result; +// } +// public static List Plus(this double summand, List units) +// => units.Plus(summand); +// public static List Plus(this List units, double summand) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(units); +// Span dstSpan = CollectionsMarshal.AsSpan(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref dstSpan[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value + summand); +// } +// return result; +// } +// public static List Plus(this double summand, List units) +// => units.Plus(summand); + +// // === ICollection === +// public static Tcoll Plus(this ICollection units, double summand) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item._Value + summand)); +// return tColl; +// } +// public static Tcoll Plus(this double summand, ICollection units) +// where Tcoll : class, ICollection, new() => Plus(units, summand); +// public static Tcoll Plus(this ICollection units, double summand) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item.HasValue ? item.Value._Value + summand : 0d)); +// return tColl; +// } +// public static Tcoll Plus(this double summand, ICollection units) +// where Tcoll : class, ICollection, new() => Plus(units, summand); + +// // === IEnumerable === +// public static IEnumerable Plus(this IEnumerable units, double summand) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return new XXXXXXXXXXXXXX(item._Value + summand); +// } +// public static IEnumerable Plus(this double summand, IEnumerable units) +// => units.Plus(summand); +// public static IEnumerable Plus(this IEnumerable units, double summand) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return item.HasValue +// ? new XXXXXXXXXXXXXX(item.Value._Value + summand) : null; +// } +// public static IEnumerable Plus(this double summand, IEnumerable units) +// => units.Plus(summand); + +// // ========================================== +// // === MINUS === +// // ========================================== + +// public static XXXXXXXXXXXXXX[] Minus(this XXXXXXXXXXXXXX[] units, double subtrahend) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = new XXXXXXXXXXXXXX[units.Length]; +// MinusCore(units, subtrahend, result); +// return result; +// } +// public static XXXXXXXXXXXXXX[] Minus(this double minuend, XXXXXXXXXXXXXX[] units) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = new XXXXXXXXXXXXXX[units.Length]; +// MinusCore(minuend, units, result); // Вызов зеркального ядра (число - массив) +// return result; +// } +// public static XXXXXXXXXXXXXX?[] Minus(this XXXXXXXXXXXXXX?[] units, double subtrahend) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = (XXXXXXXXXXXXXX?[])units.Clone(); +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value - subtrahend); +// } +// return result; +// } +// public static XXXXXXXXXXXXXX?[] Minus(this double minuend, XXXXXXXXXXXXXX?[] units) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = (XXXXXXXXXXXXXX?[])units.Clone(); +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(minuend - item.Value._Value); +// } +// return result; +// } + +// // === ReadOnlySpan === +// public static Span Minus(this ReadOnlySpan units, double subtrahend) +// { +// if (units.Length == 0) return []; +// var result = new XXXXXXXXXXXXXX[units.Length]; +// MinusCore(units, subtrahend, result); +// return result; +// } +// public static Span Minus(this double minuend, ReadOnlySpan units) +// { +// if (units.Length == 0) return []; +// var result = new XXXXXXXXXXXXXX[units.Length]; +// MinusCore(minuend, units, result); +// return result; +// } +// public static Span Minus(this ReadOnlySpan units, double subtrahend) +// { +// if (units.Length == 0) return []; +// Span result = new XXXXXXXXXXXXXX?[units.Length]; +// units.CopyTo(result); + +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value - subtrahend); +// } +// return result; +// } +// public static Span Minus(this double minuend, ReadOnlySpan units) +// { +// if (units.Length == 0) return []; +// Span result = new XXXXXXXXXXXXXX?[units.Length]; +// units.CopyTo(result); + +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(minuend - item.Value._Value); +// } +// return result; +// } + +// // === List === +// public static List Minus(this List units, double subtrahend) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(len); +// result.SetCountUnsafe(len); +// MinusCore(CollectionsMarshal.AsSpan(units), subtrahend, CollectionsMarshal.AsSpan(result)); +// return result; +// } +// public static List Minus(this double minuend, List units) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(len); +// result.SetCountUnsafe(len); +// MinusCore(minuend, CollectionsMarshal.AsSpan(units), CollectionsMarshal.AsSpan(result)); +// return result; +// } +// public static List Minus(this List units, double subtrahend) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(units); +// Span dstSpan = CollectionsMarshal.AsSpan(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref dstSpan[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value - subtrahend); +// } +// return result; +// } +// public static List Minus(this double minuend, List units) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(units); +// Span dstSpan = CollectionsMarshal.AsSpan(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref dstSpan[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(minuend - item.Value._Value); +// } +// return result; +// } + +// // === ICollection === +// public static Tcoll Minus(this ICollection units, double subtrahend) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item._Value - subtrahend)); +// return tColl; +// } +// public static Tcoll Minus(this double minuend, ICollection units) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(minuend - item._Value)); +// return tColl; +// } +// public static Tcoll Minus(this ICollection units, double subtrahend) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item.HasValue ? item.Value._Value - subtrahend : 0d)); +// return tColl; +// } +// public static Tcoll Minus(this double minuend, ICollection units) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item.HasValue ? minuend - item.Value._Value : 0d)); +// return tColl; +// } + +// // === IEnumerable === +// public static IEnumerable Minus(this IEnumerable units, double subtrahend) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return new XXXXXXXXXXXXXX(item._Value - subtrahend); +// } +// public static IEnumerable Minus(this double minuend, IEnumerable units) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return new XXXXXXXXXXXXXX(minuend - item._Value); +// } +// public static IEnumerable Minus(this IEnumerable units, double subtrahend) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return item.HasValue +// ? new XXXXXXXXXXXXXX(item.Value._Value - subtrahend) : null; +// } +// public static IEnumerable Minus(this double minuend, IEnumerable units) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return item.HasValue +// ? new XXXXXXXXXXXXXX(minuend - item.Value._Value) : null; +// } + +// // ========================================== +// // ЦЕЛАЯ СТЕПЕНЬ (int power) +// // ========================================== + +// public static XXXXXXXXXXXXXX[] Pow(this XXXXXXXXXXXXXX[] units, int power) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = new XXXXXXXXXXXXXX[units.Length]; +// PowCore(units, power, result); +// return result; +// } +// public static XXXXXXXXXXXXXX?[] Pow(this XXXXXXXXXXXXXX?[] units, int power) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = (XXXXXXXXXXXXXX?[])units.Clone(); +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) +// { +// // Используем тот же быстрый QuickPow, что и в ядре, чтобы не вызывать тяжелый Math.Pow +// item = new XXXXXXXXXXXXXX(item.Value._Value.QuickPow(power)); +// } +// } +// return result; +// } + +// // === ReadOnlySpan === +// public static Span Pow(this ReadOnlySpan units, int power) +// { +// if (units.Length == 0) return []; +// var result = new XXXXXXXXXXXXXX[units.Length]; +// PowCore(units, power, result); +// return result; +// } +// public static Span Pow(this ReadOnlySpan units, int power) +// { +// int len = units.Length; +// if (len == 0) return []; +// Span result = new XXXXXXXXXXXXXX?[units.Length]; +// units.CopyTo(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value.QuickPow(power)); +// } +// return result; +// } + +// // === List === +// public static List Pow(this List units, int power) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(len); +// result.SetCountUnsafe(len); +// PowCore(CollectionsMarshal.AsSpan(units), power, CollectionsMarshal.AsSpan(result)); +// return result; +// } +// public static List Pow(this List units, int power) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(units); +// Span dstSpan = CollectionsMarshal.AsSpan(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref dstSpan[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(item.Value._Value.QuickPow(power)); +// } +// return result; +// } + +// // === ICollection === +// public static Tcoll Pow(this ICollection units, int power) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item._Value.QuickPow(power))); +// return tColl; +// } +// public static Tcoll Pow(this ICollection units, int power) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item.HasValue ? item.Value._Value.QuickPow(power) : 0d)); +// return tColl; +// } + +// // === IEnumerable === +// public static IEnumerable Pow(this IEnumerable units, int power) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return new XXXXXXXXXXXXXX(item._Value.QuickPow(power)); +// } +// public static IEnumerable Pow(this IEnumerable units, int power) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return item.HasValue +// ? new XXXXXXXXXXXXXX(item.Value._Value.QuickPow(power)) : null; +// } + +// // ========================================== +// // ДРОБНАЯ СТЕПЕНЬ (double power) +// // ========================================== + +// public static XXXXXXXXXXXXXX[] Pow(this XXXXXXXXXXXXXX[] units, double power) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = new XXXXXXXXXXXXXX[units.Length]; +// PowCore(units, power, result); +// return result; +// } +// public static XXXXXXXXXXXXXX?[] Pow(this XXXXXXXXXXXXXX?[] units, double power) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = (XXXXXXXXXXXXXX?[])units.Clone(); +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) +// { +// item = new XXXXXXXXXXXXXX(Math.Pow(item.Value._Value, power)); +// } +// } +// return result; +// } + +// // === ReadOnlySpan === +// public static Span Pow(this ReadOnlySpan units, double power) +// { +// if (units.Length == 0) return []; +// var result = new XXXXXXXXXXXXXX[units.Length]; +// PowCore(units, power, result); +// return result; +// } +// public static Span Pow(this ReadOnlySpan units, double power) +// { +// int len = units.Length; +// if (len == 0) return []; +// Span result = new XXXXXXXXXXXXXX?[units.Length]; +// units.CopyTo(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(Math.Pow(item.Value._Value, power)); +// } +// return result; +// } + +// // === List === +// public static List Pow(this List units, double power) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(len); +// result.SetCountUnsafe(len); +// PowCore(CollectionsMarshal.AsSpan(units), power, CollectionsMarshal.AsSpan(result)); +// return result; +// } +// public static List Pow(this List units, double power) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(units); +// Span dstSpan = CollectionsMarshal.AsSpan(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref dstSpan[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(Math.Pow(item.Value._Value, power)); +// } +// return result; +// } + +// // === ICollection === +// public static Tcoll Pow(this ICollection units, double power) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(Math.Pow(item._Value, power))); +// return tColl; +// } +// public static Tcoll Pow(this ICollection units, double power) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item.HasValue ? Math.Pow(item.Value._Value, power) : 0d)); +// return tColl; +// } + +// // === IEnumerable === +// public static IEnumerable Pow(this IEnumerable units, double power) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return new XXXXXXXXXXXXXX(Math.Pow(item._Value, power)); +// } +// public static IEnumerable Pow(this IEnumerable units, double power) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return item.HasValue +// ? new XXXXXXXXXXXXXX(Math.Pow(item.Value._Value, power)) : null; +// } + + +// // ========================================== +// // КВАДРАТНЫЙ КОРЕНЬ (Sqrt) +// // ========================================== + +// public static XXXXXXXXXXXXXX[] Sqrt(this XXXXXXXXXXXXXX[] units) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = new XXXXXXXXXXXXXX[units.Length]; +// SqrtCore(units, result); +// return result; +// } +// public static XXXXXXXXXXXXXX?[] Sqrt(this XXXXXXXXXXXXXX?[] units) +// { +// if (units is null) return null!; +// if (units.Length == 0) return []; + +// var result = (XXXXXXXXXXXXXX?[])units.Clone(); +// int len = result.Length; +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) +// { +// item = new XXXXXXXXXXXXXX(Math.Sqrt(item.Value._Value)); +// } +// } +// return result; +// } + +// // === ReadOnlySpan === +// public static Span Sqrt(this ReadOnlySpan units) +// { +// if (units.Length == 0) return []; +// var result = new XXXXXXXXXXXXXX[units.Length]; +// SqrtCore(units, result); +// return result; +// } +// public static Span Sqrt(this ReadOnlySpan units) +// { +// int len = units.Length; +// if (len == 0) return []; +// Span result = new XXXXXXXXXXXXXX?[units.Length]; +// units.CopyTo(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref result[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(Math.Sqrt(item.Value._Value)); +// } +// return result; +// } + +// // === List === +// public static List Sqrt(this List units) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(len); +// result.SetCountUnsafe(len); +// SqrtCore(CollectionsMarshal.AsSpan(units), CollectionsMarshal.AsSpan(result)); +// return result; +// } +// public static List Sqrt(this List units) +// { +// if (units is null) return null!; +// int len = units.Count; +// if (len == 0) return []; + +// var result = new List(units); +// Span dstSpan = CollectionsMarshal.AsSpan(result); +// for (int i = 0; i < len; i++) +// { +// ref var item = ref dstSpan[i]; +// if (item.HasValue) item = new XXXXXXXXXXXXXX(Math.Sqrt(item.Value._Value)); +// } +// return result; +// } + +// // === ICollection === +// public static Tcoll Pow(this ICollection units) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(Math.Sqrt(item._Value))); +// return tColl; +// } +// public static Tcoll Pow(this ICollection units) +// where Tcoll : class, ICollection, new() +// { +// ArgumentNullException.ThrowIfNull(units); +// var tColl = new Tcoll(); +// if (tColl is List list) +// list.Capacity = units.Count; +// foreach (var item in units) +// tColl.Add(new XXXXXXXXXXXXXX(item.HasValue ? Math.Sqrt(item.Value._Value) : 0d)); +// return tColl; +// } + +// // === IEnumerable === +// public static IEnumerable Pow(this IEnumerable units) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return new XXXXXXXXXXXXXX(Math.Sqrt(item._Value)); +// } +// public static IEnumerable Pow(this IEnumerable units) +// { +// ArgumentNullException.ThrowIfNull(units); +// foreach (var item in units) +// yield return item.HasValue +// ? new XXXXXXXXXXXXXX(Math.Sqrt(item.Value._Value)) : null; +// } +//} + +//public class XXXXXXXXXXXXXXConverter : JsonConverter +//{ +// // Используем инвариантную культуру, чтобы разделителем всегда была точка (10.5, а не 10,5) +// private static readonly CultureInfo Culture = CultureInfo.InvariantCulture; + +// public override XXXXXXXXXXXXXX Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) +// { +// double doubleValue; + +// if (reader.TokenType == JsonTokenType.String) +// { +// // Безопасно парсим double из строки с поддержкой точки как разделителя +// if (!double.TryParse(reader.GetString(), NumberStyles.Float, Culture, out doubleValue)) +// { +// throw new JsonException($"Не удалось преобразовать строковое значение в double для метрики {nameof(XXXXXXXXXXXXXX)}."); +// } +// } +// else +// { +// // Прямое быстрое чтение числа из JSON +// doubleValue = reader.GetDouble(); +// } + +// return new(doubleValue); +// } + +// public override void Write(Utf8JsonWriter writer, XXXXXXXXXXXXXX value, JsonSerializerOptions options) +// { +// // Записываем число напрямую в байтовый буфер без выделения памяти под строки +// writer.WriteNumberValue(value._Value); +// } + +// public override void WriteAsPropertyName(Utf8JsonWriter writer, XXXXXXXXXXXXXX value, JsonSerializerOptions options) +// { +// // Ключи JSON-объектов всегда должны быть строками. +// // Форматируем double в строку с точкой, чтобы другие сервисы экосистемы прочитали её корректно. +// // Формат "R" (Round-trip) гарантирует, что число не потеряет точность при обратном парсинге. +// writer.WritePropertyName(value._Value.ToString("R", Culture)); +// } + +// public override XXXXXXXXXXXXXX ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) +// { +// string propertyName = reader.GetString()!; + +// if (!double.TryParse(propertyName, NumberStyles.Float, Culture, out double doubleValue)) +// { +// throw new JsonException($"Невалидное числовое значение в ключе свойства JSON: '{propertyName}' для метрики {nameof(XXXXXXXXXXXXXX)}."); +// } + +// return new(doubleValue); +// } +//} \ No newline at end of file diff --git a/QWERTYkez.Mensura/Units/XXXXXXXX.Ref.cs b/QWERTYkez.Mensura/Units/XXXXXXXX.Ref.cs new file mode 100644 index 0000000..1962d5d --- /dev/null +++ b/QWERTYkez.Mensura/Units/XXXXXXXX.Ref.cs @@ -0,0 +1,74 @@ +//namespace QWERTYkez.Mensura.Units; + +///// +///// Base value is MilliMeters +///// +//[UnitOperatorsGenerator, DebuggerDisplay("mm = {_MilliMeters.ToString(\"0.###\")}, m = {Meters.ToString(\"0.###\")}")] +//public readonly partial record struct XXXXXXXXXXXXXX +//{ +// public static XXXXXXXXXXXXXX MilliMeter { get; } = new(1); +//#pragma warning disable IDE1006 // _Подчеркивание для обозначения того, что это базовая единица +// [NotMapped, JsonIgnore] public double _MilliMeters { get => _Value; init => _Value = value; } +//#pragma warning restore IDE1006 + + +// public static XXXXXXXXXXXXXX CentiMeter { get; } = new(XXXXXXXXXXXXXXConv.CentiMeters.To(1)); +// [NotMapped, JsonIgnore] public double CentiMeters +// { +// get => XXXXXXXXXXXXXXConv.CentiMeters.From(_Value); +// init +// { +// XXXXXXXXXXXXXX aaa = new(); +// XXXXXXXXXXXXXX bbb = new(); + +// if (aaa != bbb || aaa == bbb) +// { + +// } + +// _Value = XXXXXXXXXXXXXXConv.CentiMeters.To(value); +// } +// } + +// public static XXXXXXXXXXXXXX DeciMeter { get; } = new(XXXXXXXXXXXXXXConv.DeciMeters.To(1)); +// [NotMapped, JsonIgnore] public double DeciMeters +// { +// get => XXXXXXXXXXXXXXConv.DeciMeters.From(_Value); +// init => _Value = XXXXXXXXXXXXXXConv.DeciMeters.To(value); +// } + +// public static XXXXXXXXXXXXXX Meter { get; } = new(XXXXXXXXXXXXXXConv.Meters.To(1)); +// [NotMapped, JsonIgnore] public double Meters +// { +// get => XXXXXXXXXXXXXXConv.Meters.From(_Value); +// init => _Value = XXXXXXXXXXXXXXConv.Meters.To(value); +// } + +// public static XXXXXXXXXXXXXX KiloMeter { get; } = new(XXXXXXXXXXXXXXConv.KiloMeters.To(1)); +// [NotMapped, JsonIgnore] public double KiloMeters +// { +// get => XXXXXXXXXXXXXXConv.KiloMeters.From(_Value); +// init => _Value = XXXXXXXXXXXXXXConv.KiloMeters.To(value); +// } + + +// public XXXXXXXXXXXXXX AddMilliMeters(double value) => new(_Value + value); +// public XXXXXXXXXXXXXX AddCentiMeters(double value) => new(_Value + XXXXXXXXXXXXXXConv.CentiMeters.To(value)); +// public XXXXXXXXXXXXXX AddDeciMeters(double value) => new(_Value + XXXXXXXXXXXXXXConv.DeciMeters.To(value)); +// public XXXXXXXXXXXXXX AddMeters(double value) => new(_Value + XXXXXXXXXXXXXXConv.Meters.To(value)); +// public XXXXXXXXXXXXXX AddKiloMeters(double value) => new(_Value + XXXXXXXXXXXXXXConv.KiloMeters.To(value)); +//} + + +//internal readonly struct XXXXXXXXXXXXXXConv +//{ +// private XXXXXXXXXXXXXXConv(double multiplicator) => this.Multiplicator = multiplicator; +// public double To(double value) => value * Multiplicator; +// public double From(double value) => value / Multiplicator; +// public double Multiplicator { get; init; } +// public static XXXXXXXXXXXXXXConv MilliMeters { get; } = new(1); +// public static XXXXXXXXXXXXXXConv CentiMeters { get; } = new(10); +// public static XXXXXXXXXXXXXXConv DeciMeters { get; } = new(100); +// public static XXXXXXXXXXXXXXConv Meters { get; } = new(1000); +// public static XXXXXXXXXXXXXXConv KiloMeters { get; } = new(1000000); +//} \ No newline at end of file diff --git a/QWERTYkez.Mensura/globals.cs b/QWERTYkez.Mensura/globals.cs index a077678..5ee6156 100644 --- a/QWERTYkez.Mensura/globals.cs +++ b/QWERTYkez.Mensura/globals.cs @@ -9,4 +9,5 @@ global using System.Numerics; global using System.Runtime.CompilerServices; global using System.Runtime.InteropServices; global using System.Text.Json; -global using System.Text.Json.Serialization; \ No newline at end of file +global using System.Text.Json.Serialization; +global using QWERTYkez.Mensura; \ No newline at end of file