@@ -429,13 +429,10 @@ public static Fix64 Sqrt(Fix64 x) {
429429
430430 /// <summary>
431431 /// Returns the Sine of x.
432- /// This function has about 9 decimals of accuracy for small values of x.
433- /// It may lose accuracy as the value of x grows.
434- /// Performance: about 25% slower than Math.Sin() in x64, and 200% slower in x86.
432+ /// The relative error is less than 1E-10 for x in [-2PI, 2PI], and less than 1E-7 in the worst case.
435433 /// </summary>
436434 public static Fix64 Sin ( Fix64 x ) {
437- bool flipHorizontal , flipVertical ;
438- var clampedL = ClampSinValue ( x . m_rawValue , out flipHorizontal , out flipVertical ) ;
435+ var clampedL = ClampSinValue ( x . m_rawValue , out var flipHorizontal , out var flipVertical ) ;
439436 var clamped = new Fix64 ( clampedL ) ;
440437
441438 // Find the two closest values in the LUT and perform linear interpolation
@@ -478,12 +475,21 @@ public static Fix64 FastSin(Fix64 x) {
478475 return new Fix64 ( flipVertical ? - nearestValue : nearestValue ) ;
479476 }
480477
481-
482-
483- [ MethodImplAttribute ( MethodImplOptions . AggressiveInlining ) ]
478+
484479 static long ClampSinValue ( long angle , out bool flipHorizontal , out bool flipVertical ) {
485- // Clamp value to 0 - 2*PI using modulo; this is very slow but there's no better way AFAIK
486- var clamped2Pi = angle % PI_TIMES_2 ;
480+ var largePI = 7244019458077122842 ;
481+ // Obtained from ((Fix64)1686629713.065252369824872831112M).m_rawValue
482+ // This is (2^29)*PI, where 29 is the largest N such that (2^N)*PI < MaxValue.
483+ // The idea is that this number contains way more precision than PI_TIMES_2,
484+ // and (((x % (2^29*PI)) % (2^28*PI)) % ... (2^1*PI) = x % (2 * PI)
485+ // In practice this gives us an error of about 1,25e-9 in the worst case scenario (Sin(MaxValue))
486+ // Whereas simply doing x % PI_TIMES_2 is the 2e-3 range.
487+
488+ var clamped2Pi = angle ;
489+ for ( int i = 0 ; i < 29 ; ++ i )
490+ {
491+ clamped2Pi %= ( largePI >> i ) ;
492+ }
487493 if ( angle < 0 ) {
488494 clamped2Pi += PI_TIMES_2 ;
489495 }
@@ -507,7 +513,7 @@ static long ClampSinValue(long angle, out bool flipHorizontal, out bool flipVert
507513
508514 /// <summary>
509515 /// Returns the cosine of x.
510- /// See Sin() for more details .
516+ /// The relative error is less than 1E-10 for x in [-2PI, 2PI], and less than 1E-7 in the worst case .
511517 /// </summary>
512518 public static Fix64 Cos ( Fix64 x ) {
513519 var xl = x . m_rawValue ;
@@ -641,7 +647,8 @@ public int CompareTo(Fix64 other) {
641647 }
642648
643649 public override string ToString ( ) {
644- return ( ( decimal ) this ) . ToString ( ) ;
650+ // Up to 10 decimal places
651+ return ( ( decimal ) this ) . ToString ( "0.##########" ) ;
645652 }
646653
647654 public static Fix64 FromRaw ( long rawValue ) {
0 commit comments