Skip to content

Commit e62579c

Browse files
committed
Implemented Cos() and Tan()
1 parent b0416b2 commit e62579c

File tree

4 files changed

+25916
-12
lines changed

4 files changed

+25916
-12
lines changed

Fix64.cs

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)