< Summary

Information
Class: FixedMathSharp.WideWeightedAverage
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Wide/WideWeightedAverage.cs
Line coverage
100%
Covered lines: 107
Uncovered lines: 0
Coverable lines: 107
Total lines: 188
Line coverage: 100%
Branch coverage
100%
Covered branches: 16
Total branches: 16
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetAverage(...)100%22100%
TryGet(...)100%44100%
TryGet(...)100%44100%
GetComponent(...)100%11100%
GetComponent(...)100%11100%
ValidateInputs(...)100%66100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Wide/WideWeightedAverage.cs

#LineLine coverage
 1//=======================================================================
 2// WideWeightedAverage.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9
 10namespace FixedMathSharp;
 11
 12/// <summary>
 13/// Provides methods for computing the weighted average of two-dimensional and
 14/// three-dimensional vectors using wide arithmetic to avoid overflow and maintain precision.
 15/// </summary>
 16internal static class WideWeightedAverage
 17{
 18    // A maximum-length span needs at most 159 signed bits for weighted
 19    // component products and 95 for the total Q32.32 weight.
 20
 21    internal static Vector2d GetAverage(ReadOnlySpan<Vector2d> values)
 22    {
 10223        Signed192 totalX = default;
 10224        Signed192 totalY = default;
 61625        for (int i = 0; i < values.Length; i++)
 26        {
 20627            totalX = WideArithmetic.AddSigned192(
 20628                totalX,
 20629                Signed192.Raw(values[i].X));
 20630            totalY = WideArithmetic.AddSigned192(
 20631                totalY,
 20632                Signed192.Raw(values[i].Y));
 33        }
 34
 10235        Signed576 denominator = Signed576.ExtendValue(
 10236            Signed320.ExtendValue(
 10237                Signed192.Signed(values.Length)));
 10238        return new Vector2d(
 10239            GetComponent(totalX, denominator),
 10240            GetComponent(totalY, denominator));
 41    }
 42
 43    internal static bool TryGet(
 44        ReadOnlySpan<Vector2d> values,
 45        ReadOnlySpan<Fixed64> weights,
 46        out Vector2d average)
 47    {
 348        Signed192 totalWeight = default;
 349        Signed320 weightedX = default;
 350        Signed320 weightedY = default;
 1651        for (int i = 0; i < values.Length; i++)
 52        {
 553            Signed192 weight = Signed192.Raw(weights[i]);
 554            totalWeight = WideArithmetic.AddSigned192(
 555                totalWeight,
 556                weight);
 557            weightedX = WideArithmetic.AddSigned320(
 558                weightedX,
 559                WideArithmetic.MultiplySigned192(
 560                    Signed192.Raw(values[i].X),
 561                    weight));
 562            weightedY = WideArithmetic.AddSigned320(
 563                weightedY,
 564                WideArithmetic.MultiplySigned192(
 565                    Signed192.Raw(values[i].Y),
 566                    weight));
 67        }
 68
 369        if (totalWeight.Sign == 0)
 70        {
 171            average = default;
 172            return false;
 73        }
 74
 275        Signed576 denominator = Signed576.ExtendValue(
 276            Signed320.ExtendValue(totalWeight));
 277        Fixed64 x = GetComponent(
 278                weightedX,
 279                denominator);
 280        Fixed64 y = GetComponent(
 281                weightedY,
 282                denominator);
 283        average = new Vector2d(x, y);
 284        return true;
 85    }
 86
 87    internal static bool TryGet(
 88        ReadOnlySpan<Vector3d> values,
 89        ReadOnlySpan<Fixed64> weights,
 90        out Vector3d average)
 91    {
 17792        Signed192 totalWeight = default;
 17793        Signed320 weightedX = default;
 17794        Signed320 weightedY = default;
 17795        Signed320 weightedZ = default;
 105896        for (int i = 0; i < values.Length; i++)
 97        {
 35298            Signed192 weight = Signed192.Raw(weights[i]);
 35299            totalWeight = WideArithmetic.AddSigned192(
 352100                totalWeight,
 352101                weight);
 352102            weightedX = WideArithmetic.AddSigned320(
 352103                weightedX,
 352104                WideArithmetic.MultiplySigned192(
 352105                    Signed192.Raw(values[i].X),
 352106                    weight));
 352107            weightedY = WideArithmetic.AddSigned320(
 352108                weightedY,
 352109                WideArithmetic.MultiplySigned192(
 352110                    Signed192.Raw(values[i].Y),
 352111                    weight));
 352112            weightedZ = WideArithmetic.AddSigned320(
 352113                weightedZ,
 352114                WideArithmetic.MultiplySigned192(
 352115                    Signed192.Raw(values[i].Z),
 352116                    weight));
 117        }
 118
 177119        if (totalWeight.Sign == 0)
 120        {
 1121            average = default;
 1122            return false;
 123        }
 124
 176125        Signed576 denominator = Signed576.ExtendValue(
 176126            Signed320.ExtendValue(totalWeight));
 176127        Fixed64 x = GetComponent(
 176128                weightedX,
 176129                denominator);
 176130        Fixed64 y = GetComponent(
 176131                weightedY,
 176132                denominator);
 176133        Fixed64 z = GetComponent(
 176134                weightedZ,
 176135                denominator);
 176136        average = new Vector3d(x, y, z);
 176137        return true;
 138    }
 139
 140    private static Fixed64 GetComponent(
 141        Signed320 numerator,
 142        Signed576 denominator)
 143    {
 144        // A non-negative weighted average is bounded by its representable
 145        // inputs, so only the generic ratio helper's representable result is
 146        // reachable here.
 532147        Fixed64.TryGetSignedRawRatio(
 532148            Signed576.ExtendValue(numerator),
 532149            denominator,
 532150            out Fixed64 component);
 532151        return component;
 152    }
 153
 154    private static Fixed64 GetComponent(
 155        Signed192 numerator,
 156        Signed576 denominator)
 157    {
 158        // An arithmetic mean is bounded by its representable inputs.
 204159        Fixed64.TryGetSignedRawRatio(
 204160            Signed576.ExtendValue(
 204161                Signed320.ExtendValue(numerator)),
 204162            denominator,
 204163            out Fixed64 component);
 204164        return component;
 165    }
 166
 167    internal static void ValidateInputs(
 168        int valueCount,
 169        ReadOnlySpan<Fixed64> weights)
 170    {
 184171        if (valueCount != weights.Length)
 172        {
 2173            throw new ArgumentException(
 2174                "Values and weights must have the same length.",
 2175                nameof(weights));
 176        }
 177
 1078178        for (int i = 0; i < weights.Length; i++)
 179        {
 359180            if (weights[i] < Fixed64.Zero)
 181            {
 2182                throw new ArgumentOutOfRangeException(
 2183                    nameof(weights),
 2184                    "Weights cannot be negative.");
 185            }
 186        }
 180187    }
 188}