@@ -29,7 +29,7 @@ public partial struct Fix64 : IEquatable<Fix64>, IComparable<Fix64> {
2929 public static readonly Fix64 PiInv = ( Fix64 ) 0.3183098861837906715377675267M ;
3030 public static readonly Fix64 PiOver2Inv = ( Fix64 ) 0.6366197723675813430755350535M ;
3131
32- static readonly Fix64 SinInterval = ( Fix64 ) ( SIN_LUT_SIZE - 1 ) / PiOver2 ;
32+ static readonly Fix64 LutInterval = ( Fix64 ) ( LUT_SIZE - 1 ) / PiOver2 ;
3333 const long MAX_VALUE = long . MaxValue ;
3434 const long MIN_VALUE = long . MinValue ;
3535 const int NUM_BITS = 64 ;
@@ -38,7 +38,7 @@ public partial struct Fix64 : IEquatable<Fix64>, IComparable<Fix64> {
3838 const long PI_TIMES_2 = 0x6487ED511 ;
3939 const long PI = 0x3243F6A88 ;
4040 const long PI_OVER_2 = 0x1921FB544 ;
41- const int SIN_LUT_SIZE = ( int ) ( PI_OVER_2 >> 15 ) ;
41+ const int LUT_SIZE = ( int ) ( PI_OVER_2 >> 15 ) ;
4242
4343 /// <summary>
4444 /// Returns a number indicating the sign of a Fix64 number.
@@ -441,7 +441,7 @@ public static Fix64 Sin(Fix64 x) {
441441
442442 // Find the two closest values in the LUT and perform linear interpolation
443443 // This is what kills the performance of this function on x86 - x64 is fine though
444- var rawIndex = FastMul ( clamped , SinInterval ) ;
444+ var rawIndex = FastMul ( clamped , LutInterval ) ;
445445 var roundedIndex = Round ( rawIndex ) ;
446446 var indexError = FastSub ( rawIndex , roundedIndex ) ;
447447
@@ -470,7 +470,7 @@ public static Fix64 FastSin(Fix64 x) {
470470 // Here we use the fact that the SinLut table has a number of entries
471471 // equal to (PI_OVER_2 >> 15) to use the angle to index directly into it
472472 var rawIndex = ( uint ) ( clampedL >> 15 ) ;
473- if ( rawIndex == SIN_LUT_SIZE ) {
473+ if ( rawIndex == LUT_SIZE ) {
474474 -- rawIndex ;
475475 }
476476 var nearestValue = SinLut [ flipHorizontal ?
@@ -504,6 +504,56 @@ static long ClampSinValue(long angle, out bool flipHorizontal, out bool flipVert
504504 return clampedPiOver2 ;
505505 }
506506
507+ /// <summary>
508+ /// Returns the cosine of x.
509+ /// See Sin() for more details.
510+ /// </summary>
511+ public static Fix64 Cos ( Fix64 x ) {
512+ var xl = x . m_rawValue ;
513+ var rawAngle = xl + ( xl > 0 ? - PI - PI_OVER_2 : PI_OVER_2 ) ;
514+ return Sin ( new Fix64 ( rawAngle ) ) ;
515+ }
516+
517+ /// <summary>
518+ /// Returns a rough approximation of the cosine of x.
519+ /// See FastSin for more details.
520+ /// </summary>
521+ public static Fix64 FastCos ( Fix64 x ) {
522+ var xl = x . m_rawValue ;
523+ var rawAngle = xl + ( xl > 0 ? - PI - PI_OVER_2 : PI_OVER_2 ) ;
524+ return FastSin ( new Fix64 ( rawAngle ) ) ;
525+ }
526+
527+ public static Fix64 Tan ( Fix64 x ) {
528+ var clampedPi = x . m_rawValue % PI ;
529+ var flip = false ;
530+ if ( clampedPi < 0 ) {
531+ clampedPi = - clampedPi ;
532+ flip = true ;
533+ }
534+ if ( clampedPi > PI_OVER_2 ) {
535+ flip = ! flip ;
536+ clampedPi = PI_OVER_2 - ( clampedPi - PI_OVER_2 ) ;
537+ }
538+
539+ var clamped = new Fix64 ( clampedPi ) ;
540+
541+ // Find the two closest values in the LUT and perform linear interpolation
542+ var rawIndex = FastMul ( clamped , LutInterval ) ;
543+ var roundedIndex = Round ( rawIndex ) ;
544+ var indexError = FastSub ( rawIndex , roundedIndex ) ;
545+
546+ var nearestValue = new Fix64 ( TanLut [ ( int ) roundedIndex ] ) ;
547+ var secondNearestValue = new Fix64 ( TanLut [ ( int ) roundedIndex + Sign ( indexError ) ] ) ;
548+
549+ var delta = FastMul ( indexError , FastAbs ( FastSub ( nearestValue , secondNearestValue ) ) ) . m_rawValue ;
550+ var interpolatedValue = nearestValue . m_rawValue + delta ;
551+ var finalValue = flip ? - interpolatedValue : interpolatedValue ;
552+ return new Fix64 ( finalValue ) ;
553+ }
554+
555+
556+
507557 public static explicit operator Fix64 ( long value ) {
508558 return new Fix64 ( value * ONE ) ;
509559 }
@@ -560,8 +610,8 @@ internal static void GenerateSinLut() {
560610 partial struct Fix64 {
561611 public static readonly long[] SinLut = new[] {" ) ;
562612 int lineCounter = 0 ;
563- for ( int i = 0 ; i < SIN_LUT_SIZE ; ++ i ) {
564- var angle = i * Math . PI * 0.5 / ( SIN_LUT_SIZE - 1 ) ;
613+ for ( int i = 0 ; i < LUT_SIZE ; ++ i ) {
614+ var angle = i * Math . PI * 0.5 / ( LUT_SIZE - 1 ) ;
565615 if ( lineCounter ++ % 8 == 0 ) {
566616 writer . WriteLine ( ) ;
567617 writer . Write ( " " ) ;
@@ -578,6 +628,34 @@ partial struct Fix64 {
578628 }
579629 }
580630
631+ internal static void GenerateTanLut ( ) {
632+ using ( var writer = new StreamWriter ( "Fix64TanLut.cs" ) ) {
633+ writer . Write (
634+ @"namespace FixMath.NET {
635+ partial struct Fix64 {
636+ public static readonly long[] TanLut = new[] {" ) ;
637+ int lineCounter = 0 ;
638+ for ( int i = 0 ; i < LUT_SIZE ; ++ i ) {
639+ var angle = i * Math . PI * 0.5 / ( LUT_SIZE - 1 ) ;
640+ if ( lineCounter ++ % 8 == 0 ) {
641+ writer . WriteLine ( ) ;
642+ writer . Write ( " " ) ;
643+ }
644+ var tan = Math . Tan ( angle ) ;
645+ if ( tan > ( double ) MaxValue || tan < 0.0 ) {
646+ tan = ( double ) MaxValue ;
647+ }
648+ var rawValue = ( ( ( decimal ) tan > ( decimal ) MaxValue || tan < 0.0 ) ? MaxValue : ( Fix64 ) tan ) . m_rawValue ;
649+ writer . Write ( string . Format ( "0x{0:X}L, " , rawValue ) ) ;
650+ }
651+ writer . Write (
652+ @"
653+ };
654+ }
655+ }" ) ;
656+ }
657+ }
658+
581659 /// <summary>
582660 /// The underlying integer representation
583661 /// </summary>
0 commit comments