| | | 1 | | //======================================================================= |
| | | 2 | | // WideArithmetic.Comparison.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 | | |
| | | 8 | | using System; |
| | | 9 | | |
| | | 10 | | namespace FixedMathSharp; |
| | | 11 | | |
| | | 12 | | /// <content> |
| | | 13 | | /// Comparison helpers for wide fixed-point arithmetic, including normalized |
| | | 14 | | /// depth rounding and comparisons against wide intermediate representations. |
| | | 15 | | /// </content> |
| | | 16 | | internal static partial class WideArithmetic |
| | | 17 | | { |
| | | 18 | | #region Normalized Depth Comparison |
| | | 19 | | |
| | | 20 | | /// <summary> |
| | | 21 | | /// Rounds a nonnegative depth represented as |
| | | 22 | | /// <c>overlap / (commonDenominator * sqrt(squaredAxisLength))</c> |
| | | 23 | | /// to the nearest raw Q32.32 value with ties to even. |
| | | 24 | | /// </summary> |
| | | 25 | | /// <remarks> |
| | | 26 | | /// Squared axis lengths at least <c>(2^31)^2</c> use a constant-time floor |
| | | 27 | | /// root approximation whose error is less than one raw result unit, then |
| | | 28 | | /// one exact midpoint correction. Smaller nonzero axes use an exact binary |
| | | 29 | | /// search over the representable nonnegative raw domain. Both paths apply |
| | | 30 | | /// exact clamping classification and nearest-even midpoint admission. |
| | | 31 | | /// </remarks> |
| | | 32 | | internal static Fixed64 GetRoundedNonNegativeNormalizedDepth( |
| | | 33 | | Signed576 overlap, |
| | | 34 | | Signed576 squaredAxisLength, |
| | | 35 | | Signed320 commonDenominator, |
| | | 36 | | out bool isClamped) |
| | | 37 | | { |
| | 563 | 38 | | Signed192 maximumTwiceRaw = AddSigned192( |
| | 563 | 39 | | Signed192.Signed(long.MaxValue), |
| | 563 | 40 | | Signed192.Signed(long.MaxValue)); |
| | 563 | 41 | | if (CompareNormalizedDepthToTwiceRaw( |
| | 563 | 42 | | overlap, |
| | 563 | 43 | | squaredAxisLength, |
| | 563 | 44 | | commonDenominator, |
| | 563 | 45 | | maximumTwiceRaw) > 0) |
| | | 46 | | { |
| | 11 | 47 | | isClamped = true; |
| | 11 | 48 | | return Fixed64.MaxValue; |
| | | 49 | | } |
| | | 50 | | |
| | 552 | 51 | | Signed576 approximationThreshold = Signed576.ExtendValue( |
| | 552 | 52 | | Signed320.ExtendValue(Signed192.Signed(1L << 62))); |
| | 552 | 53 | | if (CompareNonNegative( |
| | 552 | 54 | | squaredAxisLength, |
| | 552 | 55 | | approximationThreshold) < 0) |
| | | 56 | | { |
| | 50 | 57 | | long low = 0L; |
| | 50 | 58 | | long high = long.MaxValue; |
| | 3200 | 59 | | while (low < high) |
| | | 60 | | { |
| | 3150 | 61 | | long candidate = (long)( |
| | 3150 | 62 | | ((ulong)low + (ulong)high + 1UL) >> 1); |
| | 3150 | 63 | | Signed192 candidateLowerMidpoint = SubtractSigned192( |
| | 3150 | 64 | | AddSigned192( |
| | 3150 | 65 | | Signed192.Signed(candidate), |
| | 3150 | 66 | | Signed192.Signed(candidate)), |
| | 3150 | 67 | | Signed192.Signed(1L)); |
| | 3150 | 68 | | int candidateComparison = CompareNormalizedDepthToTwiceRaw( |
| | 3150 | 69 | | overlap, |
| | 3150 | 70 | | squaredAxisLength, |
| | 3150 | 71 | | commonDenominator, |
| | 3150 | 72 | | candidateLowerMidpoint); |
| | 3150 | 73 | | bool roundsAtLeastCandidate = candidateComparison > 0 |
| | 3150 | 74 | | || (candidateComparison == 0 |
| | 3150 | 75 | | && (candidate & 1L) == 0L); |
| | 3150 | 76 | | if (roundsAtLeastCandidate) |
| | 1200 | 77 | | low = candidate; |
| | | 78 | | else |
| | 1950 | 79 | | high = candidate - 1L; |
| | | 80 | | } |
| | | 81 | | |
| | 50 | 82 | | isClamped = false; |
| | 50 | 83 | | return Fixed64.FromRaw(low); |
| | | 84 | | } |
| | | 85 | | |
| | 502 | 86 | | Signed320 scaledAxisLength = |
| | 502 | 87 | | GetFloorSquareRootScaledByFixed64(squaredAxisLength); |
| | 502 | 88 | | Signed576 scaledDenominator = MultiplySigned320( |
| | 502 | 89 | | scaledAxisLength, |
| | 502 | 90 | | commonDenominator); |
| | 502 | 91 | | if (!Fixed64.TryGetSignedRawRatio( |
| | 502 | 92 | | Signed832.ExtendValue(overlap), |
| | 502 | 93 | | Signed832.ExtendValue(scaledDenominator), |
| | 502 | 94 | | FixedMath.SHIFT_AMOUNT_I, |
| | 502 | 95 | | out Fixed64 depth)) |
| | | 96 | | { |
| | | 97 | | // The floor root can place a representable exact result one raw |
| | | 98 | | // unit above the scalar domain. The exact midpoint correction |
| | | 99 | | // below distinguishes MaxValue from MaxValue - one raw unit. |
| | 1 | 100 | | depth = Fixed64.MaxValue; |
| | | 101 | | } |
| | 502 | 102 | | isClamped = false; |
| | 502 | 103 | | if (depth == Fixed64.Zero) |
| | 11 | 104 | | return depth; |
| | | 105 | | |
| | 491 | 106 | | Signed192 lowerMidpoint = SubtractSigned192( |
| | 491 | 107 | | AddSigned192( |
| | 491 | 108 | | Signed192.Signed(depth.m_rawValue), |
| | 491 | 109 | | Signed192.Signed(depth.m_rawValue)), |
| | 491 | 110 | | Signed192.Signed(1L)); |
| | 491 | 111 | | int comparison = CompareNormalizedDepthToTwiceRaw( |
| | 491 | 112 | | overlap, |
| | 491 | 113 | | squaredAxisLength, |
| | 491 | 114 | | commonDenominator, |
| | 491 | 115 | | lowerMidpoint); |
| | 491 | 116 | | if (comparison < (depth.m_rawValue & 1L)) |
| | | 117 | | { |
| | 34 | 118 | | depth = Fixed64.FromRaw(depth.m_rawValue - 1L); |
| | | 119 | | } |
| | | 120 | | |
| | 491 | 121 | | return depth; |
| | | 122 | | } |
| | | 123 | | |
| | | 124 | | /// <summary> |
| | | 125 | | /// Compares nonnegative depths represented as |
| | | 126 | | /// <c>overlap / (commonDenominator * sqrt(squaredAxisLength))</c>. |
| | | 127 | | /// </summary> |
| | | 128 | | internal static int CompareNonNegativeNormalizedDepths( |
| | | 129 | | Signed576 leftOverlap, |
| | | 130 | | Signed576 leftSquaredAxisLength, |
| | | 131 | | Signed320 leftCommonDenominator, |
| | | 132 | | Signed576 rightOverlap, |
| | | 133 | | Signed576 rightSquaredAxisLength, |
| | | 134 | | Signed320 rightCommonDenominator) |
| | | 135 | | { |
| | 13908 | 136 | | Span<ulong> leftOverlapWords = stackalloc ulong[9]; |
| | 13908 | 137 | | Span<ulong> rightOverlapWords = stackalloc ulong[9]; |
| | 13908 | 138 | | Span<ulong> leftAxisWords = stackalloc ulong[9]; |
| | 13908 | 139 | | Span<ulong> rightAxisWords = stackalloc ulong[9]; |
| | 13908 | 140 | | GetMagnitude(leftOverlap, leftOverlapWords); |
| | 13908 | 141 | | GetMagnitude(rightOverlap, rightOverlapWords); |
| | 13908 | 142 | | GetMagnitude(leftSquaredAxisLength, leftAxisWords); |
| | 13908 | 143 | | GetMagnitude(rightSquaredAxisLength, rightAxisWords); |
| | | 144 | | |
| | 13908 | 145 | | if (leftCommonDenominator.Equals(rightCommonDenominator)) |
| | | 146 | | { |
| | 13907 | 147 | | return CompareSignedNormalizedMagnitudes( |
| | 13907 | 148 | | leftOverlapWords, |
| | 13907 | 149 | | leftOverlap.Sign, |
| | 13907 | 150 | | leftAxisWords, |
| | 13907 | 151 | | rightOverlapWords, |
| | 13907 | 152 | | rightOverlap.Sign, |
| | 13907 | 153 | | rightAxisWords); |
| | | 154 | | } |
| | | 155 | | |
| | 1 | 156 | | Span<ulong> leftCommonWords = stackalloc ulong[5]; |
| | 1 | 157 | | Span<ulong> rightCommonWords = stackalloc ulong[5]; |
| | 1 | 158 | | GetMagnitude( |
| | 1 | 159 | | leftCommonDenominator, |
| | 1 | 160 | | out leftCommonWords[4], |
| | 1 | 161 | | out leftCommonWords[3], |
| | 1 | 162 | | out leftCommonWords[2], |
| | 1 | 163 | | out leftCommonWords[1], |
| | 1 | 164 | | out leftCommonWords[0]); |
| | 1 | 165 | | GetMagnitude( |
| | 1 | 166 | | rightCommonDenominator, |
| | 1 | 167 | | out rightCommonWords[4], |
| | 1 | 168 | | out rightCommonWords[3], |
| | 1 | 169 | | out rightCommonWords[2], |
| | 1 | 170 | | out rightCommonWords[1], |
| | 1 | 171 | | out rightCommonWords[0]); |
| | | 172 | | |
| | 1 | 173 | | Span<ulong> leftOverlapSquared = stackalloc ulong[18]; |
| | 1 | 174 | | Span<ulong> rightOverlapSquared = stackalloc ulong[18]; |
| | 1 | 175 | | Span<ulong> leftCommonSquared = stackalloc ulong[10]; |
| | 1 | 176 | | Span<ulong> rightCommonSquared = stackalloc ulong[10]; |
| | 1 | 177 | | MultiplyMagnitudes( |
| | 1 | 178 | | leftOverlapWords, |
| | 1 | 179 | | leftOverlapWords, |
| | 1 | 180 | | leftOverlapSquared); |
| | 1 | 181 | | MultiplyMagnitudes( |
| | 1 | 182 | | rightOverlapWords, |
| | 1 | 183 | | rightOverlapWords, |
| | 1 | 184 | | rightOverlapSquared); |
| | 1 | 185 | | MultiplyMagnitudes( |
| | 1 | 186 | | leftCommonWords, |
| | 1 | 187 | | leftCommonWords, |
| | 1 | 188 | | leftCommonSquared); |
| | 1 | 189 | | MultiplyMagnitudes( |
| | 1 | 190 | | rightCommonWords, |
| | 1 | 191 | | rightCommonWords, |
| | 1 | 192 | | rightCommonSquared); |
| | | 193 | | |
| | 1 | 194 | | Span<ulong> leftScaledOnce = stackalloc ulong[28]; |
| | 1 | 195 | | Span<ulong> rightScaledOnce = stackalloc ulong[28]; |
| | 1 | 196 | | Span<ulong> leftScaled = stackalloc ulong[40]; |
| | 1 | 197 | | Span<ulong> rightScaled = stackalloc ulong[40]; |
| | 1 | 198 | | MultiplyMagnitudes( |
| | 1 | 199 | | leftOverlapSquared, |
| | 1 | 200 | | rightCommonSquared, |
| | 1 | 201 | | leftScaledOnce); |
| | 1 | 202 | | MultiplyMagnitudes( |
| | 1 | 203 | | rightOverlapSquared, |
| | 1 | 204 | | leftCommonSquared, |
| | 1 | 205 | | rightScaledOnce); |
| | 1 | 206 | | MultiplyMagnitudes( |
| | 1 | 207 | | leftScaledOnce, |
| | 1 | 208 | | rightAxisWords, |
| | 1 | 209 | | leftScaled); |
| | 1 | 210 | | MultiplyMagnitudes( |
| | 1 | 211 | | rightScaledOnce, |
| | 1 | 212 | | leftAxisWords, |
| | 1 | 213 | | rightScaled); |
| | 1 | 214 | | return CompareMagnitudeEqualLength(leftScaled, rightScaled); |
| | | 215 | | } |
| | | 216 | | |
| | | 217 | | private static int CompareNormalizedDepthToTwiceRaw( |
| | | 218 | | Signed576 overlap, |
| | | 219 | | Signed576 squaredAxisLength, |
| | | 220 | | Signed320 commonDenominator, |
| | | 221 | | Signed192 twiceRaw) |
| | | 222 | | { |
| | 4204 | 223 | | Span<ulong> overlapWords = stackalloc ulong[9]; |
| | 4204 | 224 | | Span<ulong> axisWords = stackalloc ulong[9]; |
| | 4204 | 225 | | Span<ulong> commonWords = stackalloc ulong[5]; |
| | 4204 | 226 | | Span<ulong> twiceRawWords = stackalloc ulong[3]; |
| | 4204 | 227 | | GetMagnitude(overlap, overlapWords); |
| | 4204 | 228 | | GetMagnitude(squaredAxisLength, axisWords); |
| | 4204 | 229 | | GetMagnitude( |
| | 4204 | 230 | | commonDenominator, |
| | 4204 | 231 | | out commonWords[4], |
| | 4204 | 232 | | out commonWords[3], |
| | 4204 | 233 | | out commonWords[2], |
| | 4204 | 234 | | out commonWords[1], |
| | 4204 | 235 | | out commonWords[0]); |
| | 4204 | 236 | | GetMagnitude( |
| | 4204 | 237 | | twiceRaw, |
| | 4204 | 238 | | out twiceRawWords[2], |
| | 4204 | 239 | | out twiceRawWords[1], |
| | 4204 | 240 | | out twiceRawWords[0]); |
| | | 241 | | |
| | 4204 | 242 | | Span<ulong> left = stackalloc ulong[25]; |
| | 4204 | 243 | | MultiplyMagnitudes(overlapWords, overlapWords, left); |
| | 4204 | 244 | | ShiftLeftMagnitude(left, 2); |
| | | 245 | | |
| | 4204 | 246 | | Span<ulong> commonSquared = stackalloc ulong[10]; |
| | 4204 | 247 | | Span<ulong> twiceRawSquared = stackalloc ulong[6]; |
| | 4204 | 248 | | Span<ulong> thresholdSquared = stackalloc ulong[16]; |
| | 4204 | 249 | | Span<ulong> right = stackalloc ulong[25]; |
| | 4204 | 250 | | MultiplyMagnitudes(commonWords, commonWords, commonSquared); |
| | 4204 | 251 | | MultiplyMagnitudes( |
| | 4204 | 252 | | twiceRawWords, |
| | 4204 | 253 | | twiceRawWords, |
| | 4204 | 254 | | twiceRawSquared); |
| | 4204 | 255 | | MultiplyMagnitudes( |
| | 4204 | 256 | | commonSquared, |
| | 4204 | 257 | | twiceRawSquared, |
| | 4204 | 258 | | thresholdSquared); |
| | 4204 | 259 | | MultiplyMagnitudes(thresholdSquared, axisWords, right); |
| | 4204 | 260 | | return CompareMagnitudeEqualLength(left, right); |
| | | 261 | | } |
| | | 262 | | |
| | | 263 | | #endregion |
| | | 264 | | |
| | | 265 | | #region Scaled-Frame Normalized Depth Comparison |
| | | 266 | | |
| | | 267 | | /// <summary>Compares exact scaled-frame depths without narrowing their squared axes.</summary> |
| | | 268 | | internal static int CompareNonNegativeNormalizedDepths( |
| | | 269 | | Signed832 leftOverlap, Signed832 leftSquaredAxisLength, Signed576 leftCommonDenominator, |
| | | 270 | | Signed832 rightOverlap, Signed832 rightSquaredAxisLength, Signed576 rightCommonDenominator) |
| | | 271 | | { |
| | 14864 | 272 | | Span<ulong> leftN = stackalloc ulong[13], rightN = stackalloc ulong[13]; |
| | 14864 | 273 | | Span<ulong> leftAxis = stackalloc ulong[13], rightAxis = stackalloc ulong[13]; |
| | 14864 | 274 | | GetMagnitude(leftOverlap, leftN); GetMagnitude(rightOverlap, rightN); |
| | 14864 | 275 | | GetMagnitude(leftSquaredAxisLength, leftAxis); GetMagnitude(rightSquaredAxisLength, rightAxis); |
| | 7432 | 276 | | if (leftCommonDenominator.Equals(rightCommonDenominator)) |
| | 7427 | 277 | | return CompareSignedNormalizedMagnitudes(leftN, leftOverlap.Sign, leftAxis, |
| | 7427 | 278 | | rightN, rightOverlap.Sign, rightAxis); |
| | | 279 | | |
| | 10 | 280 | | Span<ulong> leftD = stackalloc ulong[9], rightD = stackalloc ulong[9]; |
| | 10 | 281 | | GetMagnitude(leftCommonDenominator, leftD); GetMagnitude(rightCommonDenominator, rightD); |
| | 10 | 282 | | Span<ulong> leftSquared = stackalloc ulong[26], rightSquared = stackalloc ulong[26]; |
| | 10 | 283 | | Span<ulong> leftDSquared = stackalloc ulong[18], rightDSquared = stackalloc ulong[18]; |
| | 10 | 284 | | MultiplyMagnitudes(leftN, leftN, leftSquared); MultiplyMagnitudes(rightN, rightN, rightSquared); |
| | 10 | 285 | | MultiplyMagnitudes(leftD, leftD, leftDSquared); MultiplyMagnitudes(rightD, rightD, rightDSquared); |
| | 10 | 286 | | Span<ulong> leftOnce = stackalloc ulong[44], rightOnce = stackalloc ulong[44]; |
| | 10 | 287 | | Span<ulong> left = stackalloc ulong[57], right = stackalloc ulong[57]; |
| | 5 | 288 | | MultiplyMagnitudes(leftSquared, rightDSquared, leftOnce); |
| | 5 | 289 | | MultiplyMagnitudes(rightSquared, leftDSquared, rightOnce); |
| | 10 | 290 | | MultiplyMagnitudes(leftOnce, rightAxis, left); MultiplyMagnitudes(rightOnce, leftAxis, right); |
| | 5 | 291 | | return CompareMagnitudeEqualLength(left, right); |
| | | 292 | | } |
| | | 293 | | |
| | | 294 | | /// <summary>Rounds a scaled-frame normalized depth once, with the same nearest-even contract as rigid SAT.</summary |
| | | 295 | | internal static Fixed64 GetRoundedNonNegativeNormalizedDepth(Signed832 overlap, |
| | | 296 | | Signed832 squaredAxisLength, Signed576 commonDenominator, out bool isClamped) |
| | | 297 | | { |
| | 126 | 298 | | Signed192 maximumTwice = AddSigned192(Signed192.Signed(long.MaxValue), Signed192.Signed(long.MaxValue)); |
| | 126 | 299 | | if (CompareNormalizedDepthToTwiceRaw(overlap, squaredAxisLength, commonDenominator, maximumTwice) > 0) |
| | 6 | 300 | | { isClamped = true; return Fixed64.MaxValue; } |
| | 123 | 301 | | isClamped = false; |
| | | 302 | | // The scaled floor root has less than one raw-unit quotient error for |
| | | 303 | | // axes >= 2^62; exact midpoint admission corrects its final rounding. |
| | 123 | 304 | | if (SubtractSigned832(squaredAxisLength, Signed832.ExtendValue(Signed192.Signed(1L << 62))).Sign >= 0) |
| | | 305 | | { |
| | 119 | 306 | | Signed576 root = GetFloorSquareRootOfProduct(squaredAxisLength, new Signed192(0UL, 1UL, 0UL)); |
| | 119 | 307 | | Signed832 denominator = MultiplySigned576ToSigned832(root, commonDenominator); |
| | 119 | 308 | | if (!Fixed64.TryGetSignedRawRatio(overlap, denominator, FixedMath.SHIFT_AMOUNT_I, out Fixed64 result)) |
| | 1 | 309 | | result = Fixed64.MaxValue; |
| | 128 | 310 | | if (result == Fixed64.Zero) return result; |
| | 110 | 311 | | Signed192 midpoint = SubtractSigned192(AddSigned192(Signed192.Signed(result.m_rawValue), |
| | 110 | 312 | | Signed192.Signed(result.m_rawValue)), Signed192.Signed(1)); |
| | 110 | 313 | | if (CompareNormalizedDepthToTwiceRaw(overlap, squaredAxisLength, commonDenominator, midpoint) |
| | 111 | 314 | | < (result.m_rawValue & 1L)) result = Fixed64.FromRaw(result.m_rawValue - 1); |
| | 110 | 315 | | return result; |
| | | 316 | | } |
| | 8 | 317 | | long low = 0, high = long.MaxValue; |
| | 256 | 318 | | while (low < high) |
| | | 319 | | { |
| | 252 | 320 | | long candidate = (long)(((ulong)low + (ulong)high + 1UL) >> 1); |
| | 252 | 321 | | Signed192 midpoint = SubtractSigned192(AddSigned192(Signed192.Signed(candidate), |
| | 252 | 322 | | Signed192.Signed(candidate)), Signed192.Signed(1)); |
| | 252 | 323 | | int comparison = CompareNormalizedDepthToTwiceRaw(overlap, squaredAxisLength, commonDenominator, midpoint); |
| | 256 | 324 | | if (comparison > 0 || (comparison == 0 && (candidate & 1L) == 0)) low = candidate; |
| | 248 | 325 | | else high = candidate - 1; |
| | | 326 | | } |
| | 4 | 327 | | return Fixed64.FromRaw(low); |
| | | 328 | | } |
| | | 329 | | |
| | | 330 | | private static int CompareNormalizedDepthToTwiceRaw(Signed832 overlap, |
| | | 331 | | Signed832 squaredAxisLength, Signed576 commonDenominator, Signed192 twiceRaw) |
| | | 332 | | { |
| | 1464 | 333 | | Span<ulong> n = stackalloc ulong[13], axis = stackalloc ulong[13], d = stackalloc ulong[9]; |
| | 488 | 334 | | Span<ulong> raw = stackalloc ulong[3]; |
| | 1464 | 335 | | GetMagnitude(overlap, n); GetMagnitude(squaredAxisLength, axis); GetMagnitude(commonDenominator, d); |
| | 488 | 336 | | GetMagnitude(twiceRaw, out raw[2], out raw[1], out raw[0]); |
| | 976 | 337 | | Span<ulong> left = stackalloc ulong[37], right = stackalloc ulong[37]; |
| | 976 | 338 | | Span<ulong> dSquared = stackalloc ulong[18], rawSquared = stackalloc ulong[6]; |
| | 488 | 339 | | Span<ulong> threshold = stackalloc ulong[24]; |
| | 976 | 340 | | MultiplyMagnitudes(n, n, left); ShiftLeftMagnitude(left, 2); |
| | 976 | 341 | | MultiplyMagnitudes(d, d, dSquared); MultiplyMagnitudes(raw, raw, rawSquared); |
| | 976 | 342 | | MultiplyMagnitudes(dSquared, rawSquared, threshold); MultiplyMagnitudes(threshold, axis, right); |
| | 488 | 343 | | return CompareMagnitudeEqualLength(left, right); |
| | | 344 | | } |
| | | 345 | | |
| | | 346 | | #endregion |
| | | 347 | | |
| | | 348 | | #region Normalized Magnitude Comparison |
| | | 349 | | |
| | | 350 | | /// <summary> |
| | | 351 | | /// Compares signed ratios of the form |
| | | 352 | | /// <c>numerator / sqrt(squaredAxisLength)</c>. |
| | | 353 | | /// </summary> |
| | | 354 | | internal static int CompareSignedNormalizedMagnitudes( |
| | | 355 | | ReadOnlySpan<ulong> leftNumerator, |
| | | 356 | | int leftSign, |
| | | 357 | | ReadOnlySpan<ulong> leftSquaredAxisLength, |
| | | 358 | | ReadOnlySpan<ulong> rightNumerator, |
| | | 359 | | int rightSign, |
| | | 360 | | ReadOnlySpan<ulong> rightSquaredAxisLength) |
| | | 361 | | { |
| | | 362 | | // Padding carries no value; size exact products from the active limbs. |
| | 89686 | 363 | | leftNumerator = leftNumerator[..GetActiveMagnitudeLength(leftNumerator)]; |
| | 89686 | 364 | | rightNumerator = rightNumerator[..GetActiveMagnitudeLength(rightNumerator)]; |
| | 89686 | 365 | | leftSquaredAxisLength = leftSquaredAxisLength[..GetActiveMagnitudeLength(leftSquaredAxisLength)]; |
| | 89686 | 366 | | rightSquaredAxisLength = rightSquaredAxisLength[..GetActiveMagnitudeLength(rightSquaredAxisLength)]; |
| | 89686 | 367 | | leftSign = leftSign == 0 || IsZeroMagnitude(leftNumerator) |
| | 89686 | 368 | | ? 0 |
| | 89686 | 369 | | : leftSign; |
| | 89686 | 370 | | rightSign = rightSign == 0 || IsZeroMagnitude(rightNumerator) |
| | 89686 | 371 | | ? 0 |
| | 89686 | 372 | | : rightSign; |
| | 89686 | 373 | | if (leftSign != rightSign) |
| | 9696 | 374 | | return leftSign.CompareTo(rightSign); |
| | 79990 | 375 | | if (leftSign == 0) |
| | 192 | 376 | | return 0; |
| | | 377 | | |
| | 79798 | 378 | | int wordCount = Math.Max( |
| | 79798 | 379 | | Math.Max(leftNumerator.Length, rightNumerator.Length), |
| | 79798 | 380 | | Math.Max( |
| | 79798 | 381 | | leftSquaredAxisLength.Length, |
| | 79798 | 382 | | rightSquaredAxisLength.Length)); |
| | 79798 | 383 | | int productWordCount = wordCount * 3; |
| | 79798 | 384 | | Span<ulong> products = |
| | 79798 | 385 | | stackalloc ulong[productWordCount * 2]; |
| | 79798 | 386 | | Span<ulong> square = stackalloc ulong[wordCount * 2]; |
| | 79798 | 387 | | Span<ulong> paddedNumerator = stackalloc ulong[wordCount]; |
| | 79798 | 388 | | Span<ulong> paddedAxis = stackalloc ulong[wordCount]; |
| | | 389 | | |
| | 79798 | 390 | | paddedNumerator.Clear(); |
| | 79798 | 391 | | leftNumerator.CopyTo(paddedNumerator); |
| | 79798 | 392 | | MultiplyMagnitudes( |
| | 79798 | 393 | | paddedNumerator, |
| | 79798 | 394 | | paddedNumerator, |
| | 79798 | 395 | | square); |
| | 79798 | 396 | | paddedAxis.Clear(); |
| | 79798 | 397 | | rightSquaredAxisLength.CopyTo(paddedAxis); |
| | 79798 | 398 | | MultiplyMagnitudes( |
| | 79798 | 399 | | square, |
| | 79798 | 400 | | paddedAxis, |
| | 79798 | 401 | | products.Slice(0, productWordCount)); |
| | | 402 | | |
| | 79798 | 403 | | paddedNumerator.Clear(); |
| | 79798 | 404 | | rightNumerator.CopyTo(paddedNumerator); |
| | 79798 | 405 | | MultiplyMagnitudes( |
| | 79798 | 406 | | paddedNumerator, |
| | 79798 | 407 | | paddedNumerator, |
| | 79798 | 408 | | square); |
| | 79798 | 409 | | paddedAxis.Clear(); |
| | 79798 | 410 | | leftSquaredAxisLength.CopyTo(paddedAxis); |
| | 79798 | 411 | | MultiplyMagnitudes( |
| | 79798 | 412 | | square, |
| | 79798 | 413 | | paddedAxis, |
| | 79798 | 414 | | products.Slice( |
| | 79798 | 415 | | productWordCount, |
| | 79798 | 416 | | productWordCount)); |
| | | 417 | | |
| | 79798 | 418 | | int comparison = CompareMagnitudeEqualLength( |
| | 79798 | 419 | | products.Slice(0, productWordCount), |
| | 79798 | 420 | | products.Slice(productWordCount, productWordCount)); |
| | 79798 | 421 | | return leftSign > 0 ? comparison : -comparison; |
| | | 422 | | } |
| | | 423 | | |
| | | 424 | | /// <summary> |
| | | 425 | | /// Gets the exact sign of |
| | | 426 | | /// <c>rational + coefficient * sqrt(squaredRadicand)</c>. |
| | | 427 | | /// </summary> |
| | | 428 | | internal static int GetSignedMagnitudeAndSquareRootSign( |
| | | 429 | | ReadOnlySpan<ulong> rational, |
| | | 430 | | int rationalSign, |
| | | 431 | | ReadOnlySpan<ulong> coefficient, |
| | | 432 | | int coefficientSign, |
| | | 433 | | ReadOnlySpan<ulong> squaredRadicand) |
| | | 434 | | { |
| | | 435 | | // Retain every significant limb while avoiding padded-width products. |
| | 6086 | 436 | | rational = rational[..GetActiveMagnitudeLength(rational)]; |
| | 6086 | 437 | | coefficient = coefficient[..GetActiveMagnitudeLength(coefficient)]; |
| | 6086 | 438 | | squaredRadicand = squaredRadicand[..GetActiveMagnitudeLength(squaredRadicand)]; |
| | 6086 | 439 | | rationalSign = rationalSign == 0 || IsZeroMagnitude(rational) |
| | 6086 | 440 | | ? 0 |
| | 6086 | 441 | | : rationalSign; |
| | 6086 | 442 | | coefficientSign = |
| | 6086 | 443 | | coefficientSign == 0 |
| | 6086 | 444 | | || IsZeroMagnitude(coefficient) |
| | 6086 | 445 | | || IsZeroMagnitude(squaredRadicand) |
| | 6086 | 446 | | ? 0 |
| | 6086 | 447 | | : coefficientSign; |
| | 6086 | 448 | | if (rationalSign == 0) |
| | 318 | 449 | | return coefficientSign; |
| | 5768 | 450 | | if (coefficientSign == 0 || rationalSign == coefficientSign) |
| | 3957 | 451 | | return rationalSign; |
| | | 452 | | |
| | 1811 | 453 | | int wordCount = Math.Max( |
| | 1811 | 454 | | Math.Max(rational.Length, coefficient.Length), |
| | 1811 | 455 | | squaredRadicand.Length); |
| | 1811 | 456 | | int productWordCount = wordCount * 3; |
| | 1811 | 457 | | Span<ulong> products = |
| | 1811 | 458 | | stackalloc ulong[productWordCount * 2]; |
| | 1811 | 459 | | products.Clear(); |
| | 1811 | 460 | | Span<ulong> padded = stackalloc ulong[wordCount]; |
| | 1811 | 461 | | Span<ulong> square = stackalloc ulong[wordCount * 2]; |
| | | 462 | | |
| | 1811 | 463 | | padded.Clear(); |
| | 1811 | 464 | | rational.CopyTo(padded); |
| | 1811 | 465 | | MultiplyMagnitudes(padded, padded, square); |
| | 1811 | 466 | | square.CopyTo(products); |
| | | 467 | | |
| | 1811 | 468 | | padded.Clear(); |
| | 1811 | 469 | | coefficient.CopyTo(padded); |
| | 1811 | 470 | | MultiplyMagnitudes(padded, padded, square); |
| | 1811 | 471 | | padded.Clear(); |
| | 1811 | 472 | | squaredRadicand.CopyTo(padded); |
| | 1811 | 473 | | MultiplyMagnitudes( |
| | 1811 | 474 | | square, |
| | 1811 | 475 | | padded, |
| | 1811 | 476 | | products.Slice( |
| | 1811 | 477 | | productWordCount, |
| | 1811 | 478 | | productWordCount)); |
| | | 479 | | |
| | 1811 | 480 | | int comparison = CompareMagnitudeEqualLength( |
| | 1811 | 481 | | products.Slice(0, productWordCount), |
| | 1811 | 482 | | products.Slice(productWordCount, productWordCount)); |
| | 1811 | 483 | | if (comparison == 0) |
| | 271 | 484 | | return 0; |
| | 1540 | 485 | | return comparison > 0 |
| | 1540 | 486 | | ? rationalSign |
| | 1540 | 487 | | : coefficientSign; |
| | | 488 | | } |
| | | 489 | | |
| | | 490 | | #endregion |
| | | 491 | | |
| | | 492 | | #region Radial Projection Comparison |
| | | 493 | | |
| | | 494 | | private const int RadialProjectionWordCount = 96; |
| | | 495 | | |
| | | 496 | | /// <summary> |
| | | 497 | | /// Compares two nonnegative radial projection depths without materializing |
| | | 498 | | /// either radical. |
| | | 499 | | /// </summary> |
| | | 500 | | /// <remarks> |
| | | 501 | | /// Each depth has the form |
| | | 502 | | /// (rational + common * sqrt(radicandNumerator / radicandDenominator)) / |
| | | 503 | | /// (common * sqrt(axisSquared)). The comparison squares the nonnegative |
| | | 504 | | /// depths and reduces the result to at most two radicals on either side. |
| | | 505 | | /// </remarks> |
| | | 506 | | internal static int CompareRadialProjectionDepths( |
| | | 507 | | Signed576 leftRational, |
| | | 508 | | Signed832 leftRadicandNumerator, |
| | | 509 | | Signed576 leftRadicandDenominator, |
| | | 510 | | Signed576 leftAxisSquared, |
| | | 511 | | Signed576 rightRational, |
| | | 512 | | Signed832 rightRadicandNumerator, |
| | | 513 | | Signed576 rightRadicandDenominator, |
| | | 514 | | Signed576 rightAxisSquared, |
| | | 515 | | Signed192 common) |
| | | 516 | | { |
| | 678 | 517 | | Signed320 radialCoefficient = Signed320.ExtendValue(common); |
| | 678 | 518 | | return CompareRadialProjectionDepths( |
| | 678 | 519 | | Signed704.ExtendValue(leftRational), |
| | 678 | 520 | | radialCoefficient, |
| | 678 | 521 | | leftRadicandNumerator, |
| | 678 | 522 | | leftRadicandDenominator, |
| | 678 | 523 | | leftAxisSquared, |
| | 678 | 524 | | Signed704.ExtendValue(rightRational), |
| | 678 | 525 | | radialCoefficient, |
| | 678 | 526 | | rightRadicandNumerator, |
| | 678 | 527 | | rightRadicandDenominator, |
| | 678 | 528 | | rightAxisSquared); |
| | | 529 | | } |
| | | 530 | | |
| | | 531 | | /// <summary> |
| | | 532 | | /// Compares two nonnegative radial projection depths without materializing |
| | | 533 | | /// either radical. |
| | | 534 | | /// </summary> |
| | | 535 | | /// <remarks> |
| | | 536 | | /// Each depth has the form |
| | | 537 | | /// (rational + radialCoefficient * |
| | | 538 | | /// sqrt(radicandNumerator / radicandDenominator)) / |
| | | 539 | | /// sqrt(axisSquared). Any shared positive denominator has already been |
| | | 540 | | /// omitted because it cannot change the ordering. |
| | | 541 | | /// </remarks> |
| | | 542 | | internal static int CompareRadialProjectionDepths( |
| | | 543 | | Signed704 leftRational, |
| | | 544 | | Signed320 leftRadialCoefficient, |
| | | 545 | | Signed832 leftRadicandNumerator, |
| | | 546 | | Signed576 leftRadicandDenominator, |
| | | 547 | | Signed576 leftAxisSquared, |
| | | 548 | | Signed704 rightRational, |
| | | 549 | | Signed320 rightRadialCoefficient, |
| | | 550 | | Signed832 rightRadicandNumerator, |
| | | 551 | | Signed576 rightRadicandDenominator, |
| | | 552 | | Signed576 rightAxisSquared) |
| | | 553 | | { |
| | 1184 | 554 | | Span<ulong> leftBase = |
| | 1184 | 555 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 1184 | 556 | | Span<ulong> rightBase = |
| | 1184 | 557 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 1184 | 558 | | BuildSquaredRadialDepthNumerator( |
| | 1184 | 559 | | leftRational, |
| | 1184 | 560 | | leftRadialCoefficient, |
| | 1184 | 561 | | leftRadicandNumerator, |
| | 1184 | 562 | | leftRadicandDenominator, |
| | 1184 | 563 | | rightAxisSquared, |
| | 1184 | 564 | | rightRadicandDenominator, |
| | 1184 | 565 | | leftBase); |
| | 1184 | 566 | | BuildSquaredRadialDepthNumerator( |
| | 1184 | 567 | | rightRational, |
| | 1184 | 568 | | rightRadialCoefficient, |
| | 1184 | 569 | | rightRadicandNumerator, |
| | 1184 | 570 | | rightRadicandDenominator, |
| | 1184 | 571 | | leftAxisSquared, |
| | 1184 | 572 | | leftRadicandDenominator, |
| | 1184 | 573 | | rightBase); |
| | | 574 | | |
| | 1184 | 575 | | int baseComparison = CompareMagnitudeEqualLength( |
| | 1184 | 576 | | leftBase, |
| | 1184 | 577 | | rightBase); |
| | 1184 | 578 | | Span<ulong> baseMagnitude = |
| | 1184 | 579 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 1184 | 580 | | if (baseComparison >= 0) |
| | | 581 | | { |
| | 918 | 582 | | SubtractEqualMagnitudes( |
| | 918 | 583 | | leftBase, |
| | 918 | 584 | | rightBase, |
| | 918 | 585 | | baseMagnitude); |
| | | 586 | | } |
| | | 587 | | else |
| | | 588 | | { |
| | 266 | 589 | | SubtractEqualMagnitudes( |
| | 266 | 590 | | rightBase, |
| | 266 | 591 | | leftBase, |
| | 266 | 592 | | baseMagnitude); |
| | | 593 | | } |
| | | 594 | | |
| | 1184 | 595 | | Span<ulong> baseRadicand = |
| | 1184 | 596 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 1184 | 597 | | MultiplyMagnitudes( |
| | 1184 | 598 | | baseMagnitude, |
| | 1184 | 599 | | baseMagnitude, |
| | 1184 | 600 | | baseRadicand); |
| | 1184 | 601 | | Span<ulong> leftRadicand = |
| | 1184 | 602 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 1184 | 603 | | BuildRadialDepthCrossRadicand( |
| | 1184 | 604 | | leftRadialCoefficient, |
| | 1184 | 605 | | rightAxisSquared, |
| | 1184 | 606 | | rightRadicandDenominator, |
| | 1184 | 607 | | leftRational, |
| | 1184 | 608 | | leftRadicandNumerator, |
| | 1184 | 609 | | leftRadicandDenominator, |
| | 1184 | 610 | | leftRadicand); |
| | 1184 | 611 | | Span<ulong> rightRadicand = |
| | 1184 | 612 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 1184 | 613 | | BuildRadialDepthCrossRadicand( |
| | 1184 | 614 | | rightRadialCoefficient, |
| | 1184 | 615 | | leftAxisSquared, |
| | 1184 | 616 | | leftRadicandDenominator, |
| | 1184 | 617 | | rightRational, |
| | 1184 | 618 | | rightRadicandNumerator, |
| | 1184 | 619 | | rightRadicandDenominator, |
| | 1184 | 620 | | rightRadicand); |
| | | 621 | | |
| | 1184 | 622 | | int baseSign = IsZeroMagnitude(baseRadicand) |
| | 1184 | 623 | | ? 0 |
| | 1184 | 624 | | : baseComparison; |
| | 1184 | 625 | | int leftSign = IsZeroMagnitude(leftRadicand) |
| | 1184 | 626 | | ? 0 |
| | 1184 | 627 | | : leftRational.Sign; |
| | 1184 | 628 | | int rightSign = IsZeroMagnitude(rightRadicand) |
| | 1184 | 629 | | ? 0 |
| | 1184 | 630 | | : -rightRational.Sign; |
| | 1184 | 631 | | int positiveCount = |
| | 1184 | 632 | | (baseSign > 0 ? 1 : 0) |
| | 1184 | 633 | | + (leftSign > 0 ? 1 : 0) |
| | 1184 | 634 | | + (rightSign > 0 ? 1 : 0); |
| | 1184 | 635 | | int negativeCount = |
| | 1184 | 636 | | (baseSign < 0 ? 1 : 0) |
| | 1184 | 637 | | + (leftSign < 0 ? 1 : 0) |
| | 1184 | 638 | | + (rightSign < 0 ? 1 : 0); |
| | 1184 | 639 | | if (positiveCount == 0) |
| | 147 | 640 | | return negativeCount == 0 ? 0 : -1; |
| | 1037 | 641 | | if (negativeCount == 0) |
| | 177 | 642 | | return 1; |
| | | 643 | | |
| | 860 | 644 | | Span<ulong> positiveFirst = |
| | 860 | 645 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 860 | 646 | | Span<ulong> positiveSecond = |
| | 860 | 647 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 860 | 648 | | Span<ulong> negativeFirst = |
| | 860 | 649 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 860 | 650 | | Span<ulong> negativeSecond = |
| | 860 | 651 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 860 | 652 | | positiveFirst.Clear(); |
| | 860 | 653 | | positiveSecond.Clear(); |
| | 860 | 654 | | negativeFirst.Clear(); |
| | 860 | 655 | | negativeSecond.Clear(); |
| | 860 | 656 | | int positiveIndex = 0; |
| | 860 | 657 | | int negativeIndex = 0; |
| | 860 | 658 | | AddSignedRadicand( |
| | 860 | 659 | | baseRadicand, |
| | 860 | 660 | | baseSign, |
| | 860 | 661 | | positiveFirst, |
| | 860 | 662 | | positiveSecond, |
| | 860 | 663 | | negativeFirst, |
| | 860 | 664 | | negativeSecond, |
| | 860 | 665 | | ref positiveIndex, |
| | 860 | 666 | | ref negativeIndex); |
| | 860 | 667 | | AddSignedRadicand( |
| | 860 | 668 | | leftRadicand, |
| | 860 | 669 | | leftSign, |
| | 860 | 670 | | positiveFirst, |
| | 860 | 671 | | positiveSecond, |
| | 860 | 672 | | negativeFirst, |
| | 860 | 673 | | negativeSecond, |
| | 860 | 674 | | ref positiveIndex, |
| | 860 | 675 | | ref negativeIndex); |
| | 860 | 676 | | AddSignedRadicand( |
| | 860 | 677 | | rightRadicand, |
| | 860 | 678 | | rightSign, |
| | 860 | 679 | | positiveFirst, |
| | 860 | 680 | | positiveSecond, |
| | 860 | 681 | | negativeFirst, |
| | 860 | 682 | | negativeSecond, |
| | 860 | 683 | | ref positiveIndex, |
| | 860 | 684 | | ref negativeIndex); |
| | 860 | 685 | | return CompareNonNegativeRadicalPairs( |
| | 860 | 686 | | positiveFirst, |
| | 860 | 687 | | positiveSecond, |
| | 860 | 688 | | negativeFirst, |
| | 860 | 689 | | negativeSecond); |
| | | 690 | | } |
| | | 691 | | |
| | | 692 | | private static void AddSignedRadicand( |
| | | 693 | | ReadOnlySpan<ulong> radicand, |
| | | 694 | | int sign, |
| | | 695 | | Span<ulong> positiveFirst, |
| | | 696 | | Span<ulong> positiveSecond, |
| | | 697 | | Span<ulong> negativeFirst, |
| | | 698 | | Span<ulong> negativeSecond, |
| | | 699 | | ref int positiveIndex, |
| | | 700 | | ref int negativeIndex) |
| | | 701 | | { |
| | 2580 | 702 | | if (sign == 0) |
| | 447 | 703 | | return; |
| | | 704 | | |
| | 2133 | 705 | | if (sign > 0) |
| | | 706 | | { |
| | 1024 | 707 | | radicand.CopyTo( |
| | 1024 | 708 | | positiveIndex++ == 0 |
| | 1024 | 709 | | ? positiveFirst |
| | 1024 | 710 | | : positiveSecond); |
| | 1024 | 711 | | return; |
| | | 712 | | } |
| | | 713 | | |
| | 1109 | 714 | | radicand.CopyTo( |
| | 1109 | 715 | | negativeIndex++ == 0 |
| | 1109 | 716 | | ? negativeFirst |
| | 1109 | 717 | | : negativeSecond); |
| | 1109 | 718 | | } |
| | | 719 | | |
| | | 720 | | private static void BuildSquaredRadialDepthNumerator( |
| | | 721 | | Signed704 rational, |
| | | 722 | | Signed320 radialCoefficient, |
| | | 723 | | Signed832 radicandNumerator, |
| | | 724 | | Signed576 radicandDenominator, |
| | | 725 | | Signed576 otherAxisSquared, |
| | | 726 | | Signed576 otherRadicandDenominator, |
| | | 727 | | Span<ulong> result) |
| | | 728 | | { |
| | 2368 | 729 | | result.Clear(); |
| | 2368 | 730 | | Span<ulong> rationalWords = stackalloc ulong[11]; |
| | 2368 | 731 | | Span<ulong> radialCoefficientWords = stackalloc ulong[5]; |
| | 2368 | 732 | | Span<ulong> numeratorWords = stackalloc ulong[13]; |
| | 2368 | 733 | | Span<ulong> denominatorWords = stackalloc ulong[9]; |
| | 2368 | 734 | | Span<ulong> axisWords = stackalloc ulong[9]; |
| | 2368 | 735 | | Span<ulong> otherDenominatorWords = stackalloc ulong[9]; |
| | 2368 | 736 | | GetMagnitude(rational, rationalWords); |
| | 2368 | 737 | | GetMagnitude( |
| | 2368 | 738 | | radialCoefficient, |
| | 2368 | 739 | | out radialCoefficientWords[4], |
| | 2368 | 740 | | out radialCoefficientWords[3], |
| | 2368 | 741 | | out radialCoefficientWords[2], |
| | 2368 | 742 | | out radialCoefficientWords[1], |
| | 2368 | 743 | | out radialCoefficientWords[0]); |
| | 2368 | 744 | | GetMagnitude(radicandNumerator, numeratorWords); |
| | 2368 | 745 | | GetMagnitude(radicandDenominator, denominatorWords); |
| | 2368 | 746 | | GetMagnitude(otherAxisSquared, axisWords); |
| | 2368 | 747 | | GetMagnitude( |
| | 2368 | 748 | | otherRadicandDenominator, |
| | 2368 | 749 | | otherDenominatorWords); |
| | | 750 | | |
| | 2368 | 751 | | Span<ulong> rationalSquared = stackalloc ulong[22]; |
| | 2368 | 752 | | Span<ulong> rationalTerm = stackalloc ulong[31]; |
| | 2368 | 753 | | MultiplyMagnitudes( |
| | 2368 | 754 | | rationalWords, |
| | 2368 | 755 | | rationalWords, |
| | 2368 | 756 | | rationalSquared); |
| | 2368 | 757 | | MultiplyMagnitudes( |
| | 2368 | 758 | | rationalSquared, |
| | 2368 | 759 | | denominatorWords, |
| | 2368 | 760 | | rationalTerm); |
| | | 761 | | |
| | 2368 | 762 | | Span<ulong> coefficientSquared = stackalloc ulong[10]; |
| | 2368 | 763 | | Span<ulong> radialTerm = stackalloc ulong[23]; |
| | 2368 | 764 | | MultiplyMagnitudes( |
| | 2368 | 765 | | radialCoefficientWords, |
| | 2368 | 766 | | radialCoefficientWords, |
| | 2368 | 767 | | coefficientSquared); |
| | 2368 | 768 | | MultiplyMagnitudes( |
| | 2368 | 769 | | coefficientSquared, |
| | 2368 | 770 | | numeratorWords, |
| | 2368 | 771 | | radialTerm); |
| | | 772 | | |
| | 2368 | 773 | | Span<ulong> numerator = stackalloc ulong[32]; |
| | 2368 | 774 | | numerator.Clear(); |
| | 2368 | 775 | | AddMagnitudeInto(rationalTerm, numerator); |
| | 2368 | 776 | | AddMagnitudeInto(radialTerm, numerator); |
| | 2368 | 777 | | Span<ulong> axisScaled = stackalloc ulong[41]; |
| | 2368 | 778 | | Span<ulong> fullyScaled = stackalloc ulong[50]; |
| | 2368 | 779 | | MultiplyMagnitudes( |
| | 2368 | 780 | | numerator, |
| | 2368 | 781 | | axisWords, |
| | 2368 | 782 | | axisScaled); |
| | 2368 | 783 | | MultiplyMagnitudes( |
| | 2368 | 784 | | axisScaled, |
| | 2368 | 785 | | otherDenominatorWords, |
| | 2368 | 786 | | fullyScaled); |
| | 2368 | 787 | | fullyScaled.CopyTo(result); |
| | 2368 | 788 | | } |
| | | 789 | | |
| | | 790 | | private static void BuildRadialDepthCrossRadicand( |
| | | 791 | | Signed320 radialCoefficient, |
| | | 792 | | Signed576 otherAxisSquared, |
| | | 793 | | Signed576 otherRadicandDenominator, |
| | | 794 | | Signed704 rational, |
| | | 795 | | Signed832 radicandNumerator, |
| | | 796 | | Signed576 radicandDenominator, |
| | | 797 | | Span<ulong> result) |
| | | 798 | | { |
| | 2368 | 799 | | if (radialCoefficient.IsZero |
| | 2368 | 800 | | || rational.IsZero |
| | 2368 | 801 | | || radicandNumerator.IsZero) |
| | | 802 | | { |
| | 470 | 803 | | result.Clear(); |
| | 470 | 804 | | return; |
| | | 805 | | } |
| | | 806 | | |
| | 1898 | 807 | | Span<ulong> radialCoefficientWords = stackalloc ulong[5]; |
| | 1898 | 808 | | Span<ulong> axisWords = stackalloc ulong[9]; |
| | 1898 | 809 | | Span<ulong> otherDenominatorWords = stackalloc ulong[9]; |
| | 1898 | 810 | | Span<ulong> rationalWords = stackalloc ulong[11]; |
| | 1898 | 811 | | Span<ulong> numeratorWords = stackalloc ulong[13]; |
| | 1898 | 812 | | Span<ulong> denominatorWords = stackalloc ulong[9]; |
| | 1898 | 813 | | GetMagnitude( |
| | 1898 | 814 | | radialCoefficient, |
| | 1898 | 815 | | out radialCoefficientWords[4], |
| | 1898 | 816 | | out radialCoefficientWords[3], |
| | 1898 | 817 | | out radialCoefficientWords[2], |
| | 1898 | 818 | | out radialCoefficientWords[1], |
| | 1898 | 819 | | out radialCoefficientWords[0]); |
| | 1898 | 820 | | GetMagnitude(otherAxisSquared, axisWords); |
| | 1898 | 821 | | GetMagnitude( |
| | 1898 | 822 | | otherRadicandDenominator, |
| | 1898 | 823 | | otherDenominatorWords); |
| | 1898 | 824 | | GetMagnitude(rational, rationalWords); |
| | 1898 | 825 | | GetMagnitude(radicandNumerator, numeratorWords); |
| | 1898 | 826 | | GetMagnitude(radicandDenominator, denominatorWords); |
| | | 827 | | |
| | 1898 | 828 | | Span<ulong> coefficientAndAxis = stackalloc ulong[14]; |
| | 1898 | 829 | | Span<ulong> withRational = stackalloc ulong[25]; |
| | 1898 | 830 | | Span<ulong> completeCoefficient = stackalloc ulong[34]; |
| | 1898 | 831 | | Span<ulong> coefficientSquared = stackalloc ulong[68]; |
| | 1898 | 832 | | Span<ulong> withNumerator = stackalloc ulong[81]; |
| | 1898 | 833 | | MultiplyMagnitudes( |
| | 1898 | 834 | | radialCoefficientWords, |
| | 1898 | 835 | | axisWords, |
| | 1898 | 836 | | coefficientAndAxis); |
| | 1898 | 837 | | MultiplyMagnitudes( |
| | 1898 | 838 | | coefficientAndAxis, |
| | 1898 | 839 | | rationalWords, |
| | 1898 | 840 | | withRational); |
| | 1898 | 841 | | MultiplyMagnitudes( |
| | 1898 | 842 | | withRational, |
| | 1898 | 843 | | otherDenominatorWords, |
| | 1898 | 844 | | completeCoefficient); |
| | 1898 | 845 | | MultiplyMagnitudes( |
| | 1898 | 846 | | completeCoefficient, |
| | 1898 | 847 | | completeCoefficient, |
| | 1898 | 848 | | coefficientSquared); |
| | 1898 | 849 | | MultiplyMagnitudes( |
| | 1898 | 850 | | coefficientSquared, |
| | 1898 | 851 | | numeratorWords, |
| | 1898 | 852 | | withNumerator); |
| | 1898 | 853 | | MultiplyMagnitudes( |
| | 1898 | 854 | | withNumerator, |
| | 1898 | 855 | | denominatorWords, |
| | 1898 | 856 | | result); |
| | 1898 | 857 | | ShiftLeftMagnitude(result, 2); |
| | 1898 | 858 | | } |
| | | 859 | | |
| | | 860 | | private static int CompareNonNegativeRadicalPairs( |
| | | 861 | | ReadOnlySpan<ulong> leftFirst, |
| | | 862 | | ReadOnlySpan<ulong> leftSecond, |
| | | 863 | | ReadOnlySpan<ulong> rightFirst, |
| | | 864 | | ReadOnlySpan<ulong> rightSecond) |
| | | 865 | | { |
| | 860 | 866 | | Span<ulong> leftBase = |
| | 860 | 867 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 860 | 868 | | Span<ulong> rightBase = |
| | 860 | 869 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 860 | 870 | | AddEqualMagnitudes(leftFirst, leftSecond, leftBase); |
| | 860 | 871 | | AddEqualMagnitudes(rightFirst, rightSecond, rightBase); |
| | 860 | 872 | | int baseComparison = CompareMagnitudeEqualLength( |
| | 860 | 873 | | leftBase, |
| | 860 | 874 | | rightBase); |
| | 860 | 875 | | Span<ulong> baseMagnitude = |
| | 860 | 876 | | stackalloc ulong[RadialProjectionWordCount]; |
| | 860 | 877 | | if (baseComparison >= 0) |
| | | 878 | | { |
| | 607 | 879 | | SubtractEqualMagnitudes( |
| | 607 | 880 | | leftBase, |
| | 607 | 881 | | rightBase, |
| | 607 | 882 | | baseMagnitude); |
| | | 883 | | } |
| | | 884 | | else |
| | | 885 | | { |
| | 253 | 886 | | SubtractEqualMagnitudes( |
| | 253 | 887 | | rightBase, |
| | 253 | 888 | | leftBase, |
| | 253 | 889 | | baseMagnitude); |
| | | 890 | | } |
| | | 891 | | |
| | 860 | 892 | | Span<ulong> leftProduct = |
| | 860 | 893 | | stackalloc ulong[RadialProjectionWordCount * 2]; |
| | 860 | 894 | | Span<ulong> rightProduct = |
| | 860 | 895 | | stackalloc ulong[RadialProjectionWordCount * 2]; |
| | 860 | 896 | | MultiplyMagnitudes(leftFirst, leftSecond, leftProduct); |
| | 860 | 897 | | MultiplyMagnitudes(rightFirst, rightSecond, rightProduct); |
| | 860 | 898 | | if (baseComparison >= 0) |
| | | 899 | | { |
| | 607 | 900 | | return ComparePositiveRadicalPairDifference( |
| | 607 | 901 | | baseMagnitude, |
| | 607 | 902 | | leftProduct, |
| | 607 | 903 | | rightProduct); |
| | | 904 | | } |
| | | 905 | | |
| | 253 | 906 | | return -ComparePositiveRadicalPairDifference( |
| | 253 | 907 | | baseMagnitude, |
| | 253 | 908 | | rightProduct, |
| | 253 | 909 | | leftProduct); |
| | | 910 | | } |
| | | 911 | | |
| | | 912 | | private static int ComparePositiveRadicalPairDifference( |
| | | 913 | | ReadOnlySpan<ulong> positiveBase, |
| | | 914 | | ReadOnlySpan<ulong> sameSideProduct, |
| | | 915 | | ReadOnlySpan<ulong> oppositeSideProduct) |
| | | 916 | | { |
| | 860 | 917 | | Span<ulong> baseSquared = |
| | 860 | 918 | | stackalloc ulong[RadialProjectionWordCount * 2]; |
| | 860 | 919 | | Span<ulong> fourSame = |
| | 860 | 920 | | stackalloc ulong[RadialProjectionWordCount * 2]; |
| | 860 | 921 | | Span<ulong> fourOpposite = |
| | 860 | 922 | | stackalloc ulong[RadialProjectionWordCount * 2]; |
| | 860 | 923 | | MultiplyMagnitudes( |
| | 860 | 924 | | positiveBase, |
| | 860 | 925 | | positiveBase, |
| | 860 | 926 | | baseSquared); |
| | 860 | 927 | | sameSideProduct.CopyTo(fourSame); |
| | 860 | 928 | | oppositeSideProduct.CopyTo(fourOpposite); |
| | 860 | 929 | | ShiftLeftMagnitude(fourSame, 2); |
| | 860 | 930 | | ShiftLeftMagnitude(fourOpposite, 2); |
| | | 931 | | |
| | 860 | 932 | | Span<ulong> knownLeft = |
| | 860 | 933 | | stackalloc ulong[RadialProjectionWordCount * 2]; |
| | 860 | 934 | | AddEqualMagnitudes(baseSquared, fourSame, knownLeft); |
| | 860 | 935 | | int knownComparison = CompareMagnitudeEqualLength( |
| | 860 | 936 | | knownLeft, |
| | 860 | 937 | | fourOpposite); |
| | 860 | 938 | | if (knownComparison > 0) |
| | 574 | 939 | | return 1; |
| | 286 | 940 | | if (knownComparison == 0) |
| | | 941 | | { |
| | | 942 | | // This reducer partitions three signed radical terms. Therefore |
| | | 943 | | // at least one side has a zero product; equality of the known |
| | | 944 | | // squared terms can only occur when the remaining cross term is |
| | | 945 | | // also zero. |
| | 278 | 946 | | return 0; |
| | | 947 | | } |
| | | 948 | | |
| | 8 | 949 | | Span<ulong> remainder = |
| | 8 | 950 | | stackalloc ulong[RadialProjectionWordCount * 2]; |
| | 8 | 951 | | SubtractEqualMagnitudes( |
| | 8 | 952 | | fourOpposite, |
| | 8 | 953 | | knownLeft, |
| | 8 | 954 | | remainder); |
| | 8 | 955 | | Span<ulong> crossSquared = |
| | 8 | 956 | | stackalloc ulong[RadialProjectionWordCount * 4]; |
| | 8 | 957 | | Span<ulong> remainderSquared = |
| | 8 | 958 | | stackalloc ulong[RadialProjectionWordCount * 4]; |
| | 8 | 959 | | MultiplyMagnitudes( |
| | 8 | 960 | | baseSquared, |
| | 8 | 961 | | sameSideProduct, |
| | 8 | 962 | | crossSquared); |
| | 8 | 963 | | ShiftLeftMagnitude(crossSquared, 4); |
| | 8 | 964 | | MultiplyMagnitudes( |
| | 8 | 965 | | remainder, |
| | 8 | 966 | | remainder, |
| | 8 | 967 | | remainderSquared); |
| | 8 | 968 | | return CompareMagnitudeEqualLength( |
| | 8 | 969 | | crossSquared, |
| | 8 | 970 | | remainderSquared); |
| | | 971 | | } |
| | | 972 | | |
| | | 973 | | #endregion |
| | | 974 | | |
| | | 975 | | #region Radical Comparison |
| | | 976 | | |
| | | 977 | | |
| | | 978 | | /// <summary> |
| | | 979 | | /// Compares <c>sqrt(firstNumerator / firstDenominator) + |
| | | 980 | | /// sqrt(secondNumerator / secondDenominator)</c> with a nonnegative ratio. |
| | | 981 | | /// </summary> |
| | | 982 | | internal static int CompareNonNegativeRadicalSumToRatio( |
| | | 983 | | Signed576 firstNumerator, |
| | | 984 | | Signed192 firstDenominator, |
| | | 985 | | Signed576 secondNumerator, |
| | | 986 | | Signed192 secondDenominator, |
| | | 987 | | Signed320 ratioNumerator, |
| | | 988 | | Signed192 ratioDenominator) |
| | | 989 | | { |
| | 729 | 990 | | bool firstZero = firstNumerator.IsZero; |
| | 729 | 991 | | bool secondZero = secondNumerator.IsZero; |
| | 729 | 992 | | if (firstZero && secondZero) |
| | 39 | 993 | | return ratioNumerator.IsZero ? 0 : -1; |
| | 690 | 994 | | if (firstZero) |
| | | 995 | | { |
| | 238 | 996 | | return CompareNonNegativeRadicalToRatio( |
| | 238 | 997 | | secondNumerator, |
| | 238 | 998 | | secondDenominator, |
| | 238 | 999 | | ratioNumerator, |
| | 238 | 1000 | | ratioDenominator); |
| | | 1001 | | } |
| | 452 | 1002 | | if (secondZero) |
| | | 1003 | | { |
| | 165 | 1004 | | return CompareNonNegativeRadicalToRatio( |
| | 165 | 1005 | | firstNumerator, |
| | 165 | 1006 | | firstDenominator, |
| | 165 | 1007 | | ratioNumerator, |
| | 165 | 1008 | | ratioDenominator); |
| | | 1009 | | } |
| | | 1010 | | |
| | 287 | 1011 | | Signed576 ratioSquared = MultiplySigned320(ratioNumerator, ratioNumerator); |
| | 287 | 1012 | | Signed576 denominatorProduct = MultiplySigned320( |
| | 287 | 1013 | | Signed320.ExtendValue(firstDenominator), |
| | 287 | 1014 | | Signed320.ExtendValue(secondDenominator)); |
| | 287 | 1015 | | Signed576 squaredRatioTerm = MultiplyNonNegativeToSigned576( |
| | 287 | 1016 | | ratioSquared, |
| | 287 | 1017 | | denominatorProduct); |
| | 287 | 1018 | | Signed576 radicalSquares = AddSigned576( |
| | 287 | 1019 | | MultiplySigned576(firstNumerator, secondDenominator), |
| | 287 | 1020 | | MultiplySigned576(secondNumerator, firstDenominator)); |
| | 287 | 1021 | | Signed320 ratioDenominatorSquared = MultiplySigned192( |
| | 287 | 1022 | | ratioDenominator, |
| | 287 | 1023 | | ratioDenominator); |
| | 287 | 1024 | | _ = Signed192.TryNarrowSigned( |
| | 287 | 1025 | | Signed576.ExtendValue(ratioDenominatorSquared), |
| | 287 | 1026 | | out Signed192 narrowRatioDenominatorSquared); |
| | 287 | 1027 | | Signed576 radicalSquareTerm = MultiplySigned576( |
| | 287 | 1028 | | radicalSquares, |
| | 287 | 1029 | | narrowRatioDenominatorSquared); |
| | 287 | 1030 | | Signed576 remainder = SubtractSigned576( |
| | 287 | 1031 | | squaredRatioTerm, |
| | 287 | 1032 | | radicalSquareTerm); |
| | 287 | 1033 | | if (remainder.Sign <= 0) |
| | 47 | 1034 | | return 1; |
| | | 1035 | | |
| | 240 | 1036 | | return CompareRadicalCrossTerm( |
| | 240 | 1037 | | firstNumerator, |
| | 240 | 1038 | | firstDenominator, |
| | 240 | 1039 | | secondNumerator, |
| | 240 | 1040 | | secondDenominator, |
| | 240 | 1041 | | ratioDenominator, |
| | 240 | 1042 | | remainder); |
| | | 1043 | | } |
| | | 1044 | | |
| | | 1045 | | /// <summary> |
| | | 1046 | | /// Compares a nonnegative radical with a nonnegative ratio whose |
| | | 1047 | | /// denominators require the full five-word geometry range. |
| | | 1048 | | /// </summary> |
| | | 1049 | | internal static int CompareNonNegativeRadicalToRatio( |
| | | 1050 | | Signed576 numerator, |
| | | 1051 | | Signed320 denominator, |
| | | 1052 | | Signed320 ratioNumerator, |
| | | 1053 | | Signed320 ratioDenominator) |
| | | 1054 | | { |
| | 147 | 1055 | | Span<ulong> numeratorWords = stackalloc ulong[9]; |
| | 147 | 1056 | | Span<ulong> denominatorWords = stackalloc ulong[5]; |
| | 147 | 1057 | | Span<ulong> ratioNumeratorWords = stackalloc ulong[5]; |
| | 147 | 1058 | | Span<ulong> ratioDenominatorWords = stackalloc ulong[5]; |
| | 147 | 1059 | | GetMagnitude(numerator, numeratorWords); |
| | 147 | 1060 | | GetMagnitude( |
| | 147 | 1061 | | denominator, |
| | 147 | 1062 | | out denominatorWords[4], |
| | 147 | 1063 | | out denominatorWords[3], |
| | 147 | 1064 | | out denominatorWords[2], |
| | 147 | 1065 | | out denominatorWords[1], |
| | 147 | 1066 | | out denominatorWords[0]); |
| | 147 | 1067 | | GetMagnitude( |
| | 147 | 1068 | | ratioNumerator, |
| | 147 | 1069 | | out ratioNumeratorWords[4], |
| | 147 | 1070 | | out ratioNumeratorWords[3], |
| | 147 | 1071 | | out ratioNumeratorWords[2], |
| | 147 | 1072 | | out ratioNumeratorWords[1], |
| | 147 | 1073 | | out ratioNumeratorWords[0]); |
| | 147 | 1074 | | GetMagnitude( |
| | 147 | 1075 | | ratioDenominator, |
| | 147 | 1076 | | out ratioDenominatorWords[4], |
| | 147 | 1077 | | out ratioDenominatorWords[3], |
| | 147 | 1078 | | out ratioDenominatorWords[2], |
| | 147 | 1079 | | out ratioDenominatorWords[1], |
| | 147 | 1080 | | out ratioDenominatorWords[0]); |
| | | 1081 | | |
| | 147 | 1082 | | Span<ulong> ratioNumeratorSquared = stackalloc ulong[10]; |
| | 147 | 1083 | | Span<ulong> ratioDenominatorSquared = stackalloc ulong[10]; |
| | 147 | 1084 | | Span<ulong> left = stackalloc ulong[19]; |
| | 147 | 1085 | | Span<ulong> right = stackalloc ulong[19]; |
| | 147 | 1086 | | MultiplyMagnitudes( |
| | 147 | 1087 | | ratioNumeratorWords, |
| | 147 | 1088 | | ratioNumeratorWords, |
| | 147 | 1089 | | ratioNumeratorSquared); |
| | 147 | 1090 | | MultiplyMagnitudes( |
| | 147 | 1091 | | ratioDenominatorWords, |
| | 147 | 1092 | | ratioDenominatorWords, |
| | 147 | 1093 | | ratioDenominatorSquared); |
| | 147 | 1094 | | MultiplyMagnitudes( |
| | 147 | 1095 | | numeratorWords, |
| | 147 | 1096 | | ratioDenominatorSquared, |
| | 147 | 1097 | | left); |
| | 147 | 1098 | | MultiplyMagnitudes( |
| | 147 | 1099 | | ratioNumeratorSquared, |
| | 147 | 1100 | | denominatorWords, |
| | 147 | 1101 | | right); |
| | 147 | 1102 | | return CompareMagnitudeEqualLength(left, right); |
| | | 1103 | | } |
| | | 1104 | | |
| | | 1105 | | /// <summary> |
| | | 1106 | | /// Returns the sign of a signed rational term plus a signed coefficient |
| | | 1107 | | /// multiplied by one nonnegative radical. |
| | | 1108 | | /// </summary> |
| | | 1109 | | internal static int CompareSignedLinearRadicalToZero( |
| | | 1110 | | Signed832 rational, |
| | | 1111 | | Signed704 radicalCoefficient, |
| | | 1112 | | Signed576 radicandNumerator, |
| | | 1113 | | Signed320 radicandDenominator) |
| | | 1114 | | { |
| | 10021 | 1115 | | int rationalSign = rational.Sign; |
| | 10021 | 1116 | | int coefficientSign = radicandNumerator.IsZero |
| | 10021 | 1117 | | ? 0 |
| | 10021 | 1118 | | : radicalCoefficient.Sign; |
| | 10021 | 1119 | | if (rationalSign == 0) |
| | 1436 | 1120 | | return coefficientSign; |
| | 8585 | 1121 | | if (coefficientSign == 0 || rationalSign == coefficientSign) |
| | 5292 | 1122 | | return rationalSign; |
| | | 1123 | | |
| | 3293 | 1124 | | Span<ulong> rationalWords = stackalloc ulong[13]; |
| | 3293 | 1125 | | Span<ulong> coefficientWords = stackalloc ulong[11]; |
| | 3293 | 1126 | | Span<ulong> numeratorWords = stackalloc ulong[9]; |
| | 3293 | 1127 | | Span<ulong> denominatorWords = stackalloc ulong[5]; |
| | 3293 | 1128 | | GetMagnitude(rational, rationalWords); |
| | 3293 | 1129 | | GetMagnitude(radicalCoefficient, coefficientWords); |
| | 3293 | 1130 | | GetMagnitude(radicandNumerator, numeratorWords); |
| | 3293 | 1131 | | GetMagnitude( |
| | 3293 | 1132 | | radicandDenominator, |
| | 3293 | 1133 | | out denominatorWords[4], |
| | 3293 | 1134 | | out denominatorWords[3], |
| | 3293 | 1135 | | out denominatorWords[2], |
| | 3293 | 1136 | | out denominatorWords[1], |
| | 3293 | 1137 | | out denominatorWords[0]); |
| | | 1138 | | |
| | 3293 | 1139 | | Span<ulong> rationalSquared = stackalloc ulong[26]; |
| | 3293 | 1140 | | Span<ulong> coefficientSquared = stackalloc ulong[22]; |
| | 3293 | 1141 | | Span<ulong> rationalScaled = stackalloc ulong[31]; |
| | 3293 | 1142 | | Span<ulong> coefficientScaled = stackalloc ulong[31]; |
| | 3293 | 1143 | | MultiplyMagnitudes( |
| | 3293 | 1144 | | rationalWords, |
| | 3293 | 1145 | | rationalWords, |
| | 3293 | 1146 | | rationalSquared); |
| | 3293 | 1147 | | MultiplyMagnitudes( |
| | 3293 | 1148 | | coefficientWords, |
| | 3293 | 1149 | | coefficientWords, |
| | 3293 | 1150 | | coefficientSquared); |
| | 3293 | 1151 | | MultiplyMagnitudes( |
| | 3293 | 1152 | | rationalSquared, |
| | 3293 | 1153 | | denominatorWords, |
| | 3293 | 1154 | | rationalScaled); |
| | 3293 | 1155 | | MultiplyMagnitudes( |
| | 3293 | 1156 | | coefficientSquared, |
| | 3293 | 1157 | | numeratorWords, |
| | 3293 | 1158 | | coefficientScaled); |
| | 3293 | 1159 | | int comparison = CompareMagnitudeEqualLength( |
| | 3293 | 1160 | | rationalScaled, |
| | 3293 | 1161 | | coefficientScaled); |
| | 3293 | 1162 | | return comparison == 0 |
| | 3293 | 1163 | | ? 0 |
| | 3293 | 1164 | | : comparison > 0 |
| | 3293 | 1165 | | ? rationalSign |
| | 3293 | 1166 | | : coefficientSign; |
| | | 1167 | | } |
| | | 1168 | | |
| | | 1169 | | private static int CompareNonNegativeRadicalToRatio( |
| | | 1170 | | Signed576 numerator, |
| | | 1171 | | Signed192 denominator, |
| | | 1172 | | Signed320 ratioNumerator, |
| | | 1173 | | Signed192 ratioDenominator) |
| | | 1174 | | { |
| | 403 | 1175 | | Signed320 ratioDenominatorSquared = MultiplySigned192( |
| | 403 | 1176 | | ratioDenominator, |
| | 403 | 1177 | | ratioDenominator); |
| | 403 | 1178 | | _ = Signed192.TryNarrowSigned( |
| | 403 | 1179 | | Signed576.ExtendValue(ratioDenominatorSquared), |
| | 403 | 1180 | | out Signed192 narrowRatioDenominatorSquared); |
| | 403 | 1181 | | Signed576 left = MultiplySigned576( |
| | 403 | 1182 | | numerator, |
| | 403 | 1183 | | narrowRatioDenominatorSquared); |
| | 403 | 1184 | | Signed576 right = MultiplySigned576( |
| | 403 | 1185 | | MultiplySigned320(ratioNumerator, ratioNumerator), |
| | 403 | 1186 | | denominator); |
| | 403 | 1187 | | return CompareNonNegative(left, right); |
| | | 1188 | | } |
| | | 1189 | | |
| | | 1190 | | private static int CompareRadicalCrossTerm( |
| | | 1191 | | Signed576 firstNumerator, |
| | | 1192 | | Signed192 firstDenominator, |
| | | 1193 | | Signed576 secondNumerator, |
| | | 1194 | | Signed192 secondDenominator, |
| | | 1195 | | Signed192 ratioDenominator, |
| | | 1196 | | Signed576 remainder) |
| | | 1197 | | { |
| | 240 | 1198 | | Span<ulong> firstNumeratorWords = stackalloc ulong[9]; |
| | 240 | 1199 | | Span<ulong> secondNumeratorWords = stackalloc ulong[9]; |
| | 240 | 1200 | | Span<ulong> firstDenominatorWords = stackalloc ulong[3]; |
| | 240 | 1201 | | Span<ulong> secondDenominatorWords = stackalloc ulong[3]; |
| | 240 | 1202 | | Span<ulong> ratioDenominatorWords = stackalloc ulong[3]; |
| | 240 | 1203 | | Span<ulong> remainderWords = stackalloc ulong[9]; |
| | 240 | 1204 | | GetMagnitude(firstNumerator, firstNumeratorWords); |
| | 240 | 1205 | | GetMagnitude(secondNumerator, secondNumeratorWords); |
| | 240 | 1206 | | GetMagnitude( |
| | 240 | 1207 | | firstDenominator, |
| | 240 | 1208 | | out firstDenominatorWords[2], |
| | 240 | 1209 | | out firstDenominatorWords[1], |
| | 240 | 1210 | | out firstDenominatorWords[0]); |
| | 240 | 1211 | | GetMagnitude( |
| | 240 | 1212 | | secondDenominator, |
| | 240 | 1213 | | out secondDenominatorWords[2], |
| | 240 | 1214 | | out secondDenominatorWords[1], |
| | 240 | 1215 | | out secondDenominatorWords[0]); |
| | 240 | 1216 | | GetMagnitude( |
| | 240 | 1217 | | ratioDenominator, |
| | 240 | 1218 | | out ratioDenominatorWords[2], |
| | 240 | 1219 | | out ratioDenominatorWords[1], |
| | 240 | 1220 | | out ratioDenominatorWords[0]); |
| | 240 | 1221 | | GetMagnitude(remainder, remainderWords); |
| | | 1222 | | |
| | 240 | 1223 | | Span<ulong> numeratorProduct = stackalloc ulong[18]; |
| | 240 | 1224 | | Span<ulong> ratioSquared = stackalloc ulong[6]; |
| | 240 | 1225 | | Span<ulong> ratioFourth = stackalloc ulong[12]; |
| | 240 | 1226 | | Span<ulong> denominatorProduct = stackalloc ulong[6]; |
| | 240 | 1227 | | Span<ulong> numeratorAndRatio = stackalloc ulong[30]; |
| | 240 | 1228 | | Span<ulong> left = stackalloc ulong[36]; |
| | 240 | 1229 | | Span<ulong> right = stackalloc ulong[36]; |
| | 240 | 1230 | | MultiplyMagnitudes( |
| | 240 | 1231 | | firstNumeratorWords, |
| | 240 | 1232 | | secondNumeratorWords, |
| | 240 | 1233 | | numeratorProduct); |
| | 240 | 1234 | | MultiplyMagnitudes( |
| | 240 | 1235 | | ratioDenominatorWords, |
| | 240 | 1236 | | ratioDenominatorWords, |
| | 240 | 1237 | | ratioSquared); |
| | 240 | 1238 | | MultiplyMagnitudes(ratioSquared, ratioSquared, ratioFourth); |
| | 240 | 1239 | | MultiplyMagnitudes( |
| | 240 | 1240 | | firstDenominatorWords, |
| | 240 | 1241 | | secondDenominatorWords, |
| | 240 | 1242 | | denominatorProduct); |
| | 240 | 1243 | | MultiplyMagnitudes( |
| | 240 | 1244 | | numeratorProduct, |
| | 240 | 1245 | | ratioFourth, |
| | 240 | 1246 | | numeratorAndRatio); |
| | 240 | 1247 | | MultiplyMagnitudes( |
| | 240 | 1248 | | numeratorAndRatio, |
| | 240 | 1249 | | denominatorProduct, |
| | 240 | 1250 | | left); |
| | 240 | 1251 | | ShiftLeftMagnitude(left, 2); |
| | 240 | 1252 | | MultiplyMagnitudes(remainderWords, remainderWords, right); |
| | | 1253 | | |
| | 240 | 1254 | | int comparison = CompareMagnitudeEqualLength(left, right); |
| | 240 | 1255 | | return comparison == 0 ? 0 : comparison > 0 ? 1 : -1; |
| | | 1256 | | } |
| | | 1257 | | |
| | | 1258 | | #endregion |
| | | 1259 | | } |