// This function is not well-tested. It may be wildly inaccurate. /// <summary> /// Returns the tangent of the specified angle. /// </summary> /// <param name="x">An angle, measured in radians.</param> /// <returns></returns> public static Fix64 Tan(Fix64 x) { var clampedPi = x.RawValue % _PI; var flip = false; if (clampedPi < 0) { clampedPi = -clampedPi; flip = true; } if (clampedPi > PI_OVER_2) { flip = !flip; clampedPi = PI_OVER_2 - (clampedPi - PI_OVER_2); } var clamped = new Fix64(clampedPi); // Find the two closest values in the LUT and perform linear interpolation var rawIndex = Fix64.FastMultiply(clamped, LutInterval); var roundedIndex = Round(rawIndex); var indexError = Fix64.FastSubtract(rawIndex, roundedIndex); var nearestValue = new Fix64(TanLut[(int)roundedIndex]); var secondNearestValue = new Fix64(TanLut[(int)roundedIndex + Sign(indexError)]); var delta = Fix64.FastMultiply(indexError, FastAbs(Fix64.FastSubtract(nearestValue, secondNearestValue))).RawValue; var interpolatedValue = nearestValue.RawValue + delta; var finalValue = flip ? -interpolatedValue : interpolatedValue; return(new Fix64(finalValue)); }
// The relative error is less than 1E-10 for x in [-2PI, 2PI], and less than 1E-7 in the worst case. /// <summary> /// Returns the sine of the specified angle. /// </summary> /// <param name="x">An angle, measured in radians.</param> /// <returns></returns> public static Fix64 Sin(Fix64 x) { var clampedL = ClampSinValue(x.RawValue, out var flipHorizontal, out var flipVertical); var clamped = new Fix64(clampedL); // Find the two closest values in the LUT and perform linear interpolation // This is what kills the performance of this function on x86 - x64 is fine though var rawIndex = Fix64.FastMultiply(clamped, LutInterval); var roundedIndex = Round(rawIndex); var indexError = Fix64.FastSubtract(rawIndex, roundedIndex); var nearestValue = new Fix64(SinLut[flipHorizontal ? SinLut.Length - 1 - (int)roundedIndex : (int)roundedIndex]); var secondNearestValue = new Fix64(SinLut[flipHorizontal ? SinLut.Length - 1 - (int)roundedIndex - Sign(indexError) : (int)roundedIndex + Sign(indexError)]); var delta = Fix64.FastMultiply(indexError, FastAbs(Fix64.FastSubtract(nearestValue, secondNearestValue))).RawValue; var interpolatedValue = nearestValue.RawValue + (flipHorizontal ? -delta : delta); var finalValue = flipVertical ? -interpolatedValue : interpolatedValue; return(new Fix64(finalValue)); }