| | | 1 | | //======================================================================= |
| | | 2 | | // FiniteSlabPolynomial.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.Geometry; |
| | | 11 | | |
| | | 12 | | /// <summary> |
| | | 13 | | /// Borrowed polynomial arithmetic for this owner's affine and conic charts. |
| | | 14 | | /// All limb operations remain in the existing wide arithmetic owner. |
| | | 15 | | /// </summary> |
| | | 16 | | internal readonly ref struct FiniteSlabPolynomial |
| | | 17 | | { |
| | | 18 | | internal const int Words = 64; |
| | | 19 | | internal const int AffineWords = 128; |
| | 549888 | 20 | | internal int FieldWords => Values.Length / Signs.Length; |
| | | 21 | | internal readonly Span<ulong> Values; |
| | | 22 | | internal readonly Span<sbyte> Signs; |
| | 153060 | 23 | | internal int Count => Signs.Length; |
| | 132996 | 24 | | internal bool IsZero { get { foreach (sbyte sign in Signs) if (sign != 0) return false; return true; } } |
| | | 25 | | internal FiniteSlabPolynomial(Span<ulong> values, Span<sbyte> signs) |
| | 1440849 | 26 | | { Values = values; Signs = signs; } |
| | | 27 | | internal static FiniteSlabPolynomial At(Span<ulong> values, Span<sbyte> signs, int index, int count) => |
| | 386508 | 28 | | new(values.Slice(index * (values.Length / signs.Length), count * (values.Length / signs.Length)), signs.Slice(in |
| | 117203 | 29 | | internal FiniteSlabPolynomial Slice(int index, int count) => At(Values, Signs, index, count); |
| | 698718 | 30 | | internal void Clear() { Values.Clear(); Signs.Clear(); } |
| | | 31 | | internal void Set(Signed576 value, int index = 0) |
| | | 32 | | { |
| | 60743 | 33 | | Span<ulong> slot = Values.Slice(index * FieldWords, FieldWords); |
| | 121486 | 34 | | WideArithmetic.GetMagnitude(value, slot); Signs[index] = (sbyte)value.Sign; |
| | 60743 | 35 | | } |
| | | 36 | | internal void Set(Signed832 value, int index = 0) |
| | | 37 | | { |
| | 85346 | 38 | | Span<ulong> slot = Values.Slice(index * FieldWords, FieldWords); |
| | 170692 | 39 | | WideArithmetic.GetMagnitude(value, slot); Signs[index] = (sbyte)value.Sign; |
| | 85346 | 40 | | } |
| | 23923 | 41 | | internal void Set(Signed320 value, int index = 0) => Set(Signed576.ExtendValue(value), index); |
| | 13198 | 42 | | internal void Set(int value, int index = 0) => Set(Signed320.ExtendValue(Signed192.Signed(value)), index); |
| | | 43 | | internal void Copy(FiniteSlabPolynomial source) |
| | | 44 | | { |
| | 25689 | 45 | | Clear(); |
| | 25689 | 46 | | if (FieldWords == source.FieldWords) |
| | | 47 | | { |
| | 51374 | 48 | | source.Values.CopyTo(Values); source.Signs.CopyTo(Signs); |
| | | 49 | | } |
| | 2 | 50 | | else Add(source); |
| | 2 | 51 | | } |
| | | 52 | | internal void Add(FiniteSlabPolynomial source, int multiplier = 1, int offset = 0) => |
| | 286876 | 53 | | WideFiniteAxisIntersection.AddFiniteAxisPolynomial(source.Values, source.Signs, |
| | 286876 | 54 | | Values, Signs, multiplier, offset); |
| | | 55 | | internal void Multiply(FiniteSlabPolynomial left, FiniteSlabPolynomial right) |
| | | 56 | | { |
| | 135658 | 57 | | Span<ulong> product = FieldWords == Words ? stackalloc ulong[Words] : stackalloc ulong[AffineWords]; |
| | 135658 | 58 | | WideFiniteAxisIntersection.MultiplyFiniteAxisPolynomials(left.Values, left.Signs, |
| | 135658 | 59 | | right.Values, right.Signs, Values, Signs, product); |
| | 135658 | 60 | | } |
| | | 61 | | internal void Scale(FiniteSlabPolynomial source, Signed576 factor) |
| | | 62 | | { |
| | 97388 | 63 | | if (factor.IsZero) { Clear(); return; } |
| | | 64 | | // Polynomial coefficients are integers; these units are literal 1, |
| | | 65 | | // rather than the Q32.32 value retained by Signed576.One. |
| | 33893 | 66 | | if ((factor.Word0 == 1UL && factor.Equals(Signed576.ExtendValue(Signed192.Signed(1)))) |
| | 33893 | 67 | | || (factor.Word0 == ulong.MaxValue && factor.Equals(Signed576.ExtendValue(Signed192.Signed(-1))))) |
| | | 68 | | { |
| | 754 | 69 | | Clear(); Add(source, factor.Sign); |
| | 377 | 70 | | return; |
| | | 71 | | } |
| | | 72 | | // The scalar carrier fills nine words; multiplication supports independent input strides. |
| | 33516 | 73 | | Span<ulong> data = stackalloc ulong[9]; |
| | 33516 | 74 | | Span<sbyte> signs = stackalloc sbyte[1]; |
| | 67032 | 75 | | FiniteSlabPolynomial scalar = new(data, signs); scalar.Set(factor); |
| | 33516 | 76 | | Multiply(source, scalar); |
| | 33516 | 77 | | } |
| | | 78 | | internal void Scale(FiniteSlabPolynomial source, Signed832 factor) |
| | | 79 | | { |
| | 268675 | 80 | | if (factor.IsZero) { Clear(); return; } |
| | 72364 | 81 | | if ((factor.Word0 == 1UL && factor.Equals(Signed832.ExtendValue(Signed192.Signed(1)))) |
| | 72364 | 82 | | || (factor.Word0 == ulong.MaxValue && factor.Equals(Signed832.ExtendValue(Signed192.Signed(-1))))) |
| | | 83 | | { |
| | 52402 | 84 | | Clear(); Add(source, factor.Sign); |
| | 26201 | 85 | | return; |
| | | 86 | | } |
| | | 87 | | // The scalar carrier fills thirteen words, independently of the polynomial bank width. |
| | 46163 | 88 | | Span<ulong> data = stackalloc ulong[13]; |
| | 46163 | 89 | | Span<sbyte> signs = stackalloc sbyte[1]; |
| | 92326 | 90 | | FiniteSlabPolynomial scalar = new(data, signs); scalar.Set(factor); |
| | 46163 | 91 | | Multiply(source, scalar); |
| | 46163 | 92 | | } |
| | 44685 | 93 | | internal void Scale(FiniteSlabPolynomial source, Signed320 factor) => Scale(source, Signed576.ExtendValue(factor)); |
| | | 94 | | internal static int Sign(scoped ref FiniteAxisValueRoot root, scoped FiniteSlabPolynomial query) |
| | | 95 | | { |
| | 50879 | 96 | | int degree = query.Count - 1; |
| | 371807 | 97 | | while (degree > 0 && query.Signs[degree] == 0) degree--; |
| | 89672 | 98 | | if (degree == 0) return query.Signs[0]; |
| | | 99 | | // A common positive scale cannot change a sign. Strip it from a |
| | | 100 | | // scratch copy, never from a retained coordinate/denominator ratio; |
| | | 101 | | // otherwise exact-zero queries pay a needlessly large equality bound. |
| | 24172 | 102 | | Span<ulong> values = stackalloc ulong[query.Values.Length]; query.Values.CopyTo(values); |
| | 12086 | 103 | | WideFiniteAxisIntersection.NormalizeFiniteAxisPolynomialPowerOfTwo(values, query.Signs); |
| | 12086 | 104 | | return WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, values, query.Signs); |
| | | 105 | | } |
| | | 106 | | } |