< Summary

Information
Class: FixedMathSharp.EnclosedQ96Coefficient
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Scalars/EnclosedQ96Coefficient.cs
Line coverage
100%
Covered lines: 52
Uncovered lines: 0
Coverable lines: 52
Total lines: 114
Line coverage: 100%
Branch coverage
100%
Covered branches: 44
Total branches: 44
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%22100%
get_Value()100%22100%
Equals(...)100%44100%
TryMultiplyRaw(...)100%1818100%
TryMultiplyFull(...)100%1818100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Scalars/EnclosedQ96Coefficient.cs

#LineLine coverage
 1//=======================================================================
 2// EnclosedQ96Coefficient.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.Runtime.CompilerServices;
 9
 10namespace FixedMathSharp;
 11
 12/// <summary>
 13/// Retains a signed Q96 coefficient and its absolute error bound in integer
 14/// Q96 units. Geometry preparation normalizes its sign and widths once;
 15/// multiplying certifies only unique, representable half-even results.
 16/// </summary>
 17internal readonly struct EnclosedQ96Coefficient
 18{
 19    private readonly Signed192 _magnitude;
 20    private readonly uint _errorUnits;
 21    private readonly sbyte _sign;
 22    private readonly bool _fits, _coarse;
 23
 24    internal EnclosedQ96Coefficient(Signed192 value, uint errorUnits)
 25    {
 192726        WideArithmetic.GetMagnitude(value, out ulong high, out ulong middle, out ulong low);
 192727        _magnitude = new Signed192(high, middle, low);
 192728        _sign = (sbyte)value.Sign;
 192729        _errorUnits = errorUnits;
 192730        _fits = high == 0;
 192731        _coarse = _fits && (middle >> 36) == 0;
 192732    }
 33
 192134    internal Signed192 Value => _sign < 0 ? WideArithmetic.Negate(_magnitude) : _magnitude;
 35
 36    internal bool Equals(EnclosedQ96Coefficient other) =>
 637        _sign == other._sign && _errorUnits == other._errorUnits && _magnitude.Equals(other._magnitude);
 38
 39    /// <summary>
 40    /// Returns raw Q32.32 bits on success; returns false/zero for uncertain
 41    /// rounding, a nonzero product whose coefficient magnitude is at least
 42    /// 2^128, or scalar overflow.
 43    /// The default coefficient is zero, including its zero error bound.
 44    /// </summary>
 45    // Keep scalar construction at materialization, outside inlined certificate outputs.
 46    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 47    internal bool TryMultiplyRaw(Fixed64 value, out long result)
 48    {
 192149        result = default;
 192150        if (_sign == 0 || value.m_rawValue == 0)
 16551            return true;
 175652        if (!_fits)
 24053            return false;
 54
 151655        ulong magnitude = Fixed64.AbsToUInt64(value.m_rawValue);
 151656        bool negative = (_sign < 0) != (value.m_rawValue < 0);
 151657        if (_coarse && magnitude < (1UL << 58))
 58        {
 59            // Q60 needs one product. Discarding 36 bits plus any uint error
 60            // loses <2 Q60 units; these widths also prove scalar range safety.
 79961            ulong mantissa = (_magnitude.Middle << 28) | (_magnitude.Low >> 36);
 88762            if (mantissa == 0) return true;
 71163            Fixed64.Multiply64To128(mantissa, magnitude, out ulong upper, out ulong lower);
 71164            ulong fraction = lower & ((1UL << 60) - 1);
 65            const ulong half = 1UL << 59;
 71166            ulong distance = fraction < half ? half - fraction : fraction - half;
 71167            if (distance > 2 * magnitude)
 68            {
 69                // The certificate excludes half ties and proves magnitude <=2^62.
 43770                long raw = (long)((upper << 4) | (lower >> 60)) + (fraction > half ? 1L : 0L);
 43771                result = negative ? -raw : raw;
 43772                return true;
 73            }
 74        }
 99175        return TryMultiplyFull(_magnitude.Middle, _magnitude.Low, magnitude, negative, _errorUnits, out result);
 76    }
 77
 78    private static bool TryMultiplyFull(ulong coefficientMiddle, ulong coefficientLow,
 79        ulong magnitude, bool negative, uint errorUnits, out long result)
 80    {
 99181        result = default;
 99182        Fixed64.Multiply64To128(coefficientLow, magnitude, out ulong lowHigh, out ulong low);
 99183        Fixed64.Multiply64To128(coefficientMiddle, magnitude, out ulong highHigh, out ulong highLow);
 99184        ulong middle = unchecked(lowHigh + highLow);
 99185        ulong high = highHigh + (middle < lowHigh ? 1UL : 0UL);
 99186        if ((high >> 32) != 0)
 5687            return false;
 88
 93589        if (errorUnits != 0)
 90        {
 91            // The radius is below 2^95 because |valueRaw| <= 2^63 and
 92            // errorUnits < 2^32. Only the nearest half-integer can change rounding.
 73993            Fixed64.Multiply64To128(magnitude, errorUnits, out ulong errorHigh, out ulong errorLow);
 73994            ulong fractionHigh = (uint)middle;
 95            const ulong half = 1UL << 31;
 73996            bool belowHalf = fractionHigh < half;
 73997            ulong distanceHigh = belowHalf
 73998                ? half - fractionHigh - (low != 0 ? 1UL : 0UL)
 73999                : fractionHigh - half;
 739100            ulong distanceLow = belowHalf ? unchecked(0UL - low) : low;
 739101            if (distanceHigh < errorHigh || (distanceHigh == errorHigh && distanceLow <= errorLow))
 190102                return false;
 103        }
 104
 745105        ulong quotient = (high << 32) | (middle >> 32);
 745106        bool guard = (middle & (1UL << 31)) != 0;
 745107        bool sticky = low != 0 || (middle & ((1UL << 31) - 1)) != 0;
 745108        Fixed64 rounded = Fixed64.RoundAndApplySign(quotient, guard, sticky, negative, out bool representable);
 745109        if (!representable)
 20110            return false;
 725111        result = rounded.m_rawValue;
 725112        return true;
 113    }
 114}