TrueSync
Fix64.cs
1 using System;
2 using System.IO;
3 using UnityEngine;
4 
5 namespace TrueSync {
6 
10  [Serializable]
11  public partial struct FP : IEquatable<FP>, IComparable<FP>, ISerializationCallbackReceiver {
12 
13  private long m_rawValue;
14 
15  [SerializeField]
16  private string _serializedValue;
17 
18  const long MAX_VALUE = long.MaxValue;
19  const long MIN_VALUE = long.MinValue;
20  const int NUM_BITS = 64;
21  const int FRACTIONAL_PLACES = 32;
22  const long ONE = 1L << FRACTIONAL_PLACES;
23  const long TEN = 10L << FRACTIONAL_PLACES;
24  const long HALF = 1L << (FRACTIONAL_PLACES - 1);
25  const long PI_TIMES_2 = 0x6487ED511;
26  const long PI = 0x3243F6A88;
27  const long PI_OVER_2 = 0x1921FB544;
28  const int LUT_SIZE = (int)(PI_OVER_2 >> 15);
29 
30  // Precision of this type is 2^-32, that is 2,3283064365386962890625E-10
31  public static readonly decimal Precision = (decimal)(new FP(1L));//0.00000000023283064365386962890625m;
32  public static readonly FP MaxValue = new FP(MAX_VALUE-1);
33  public static readonly FP MinValue = new FP(MIN_VALUE+2);
34  public static readonly FP One = new FP(ONE);
35  public static readonly FP Ten = new FP(TEN);
36  public static readonly FP Half = new FP(HALF);
37 
38  public static readonly FP Zero = new FP();
39  public static readonly FP PositiveInfinity = new FP(MAX_VALUE);
40  public static readonly FP NegativeInfinity = new FP(MIN_VALUE+1);
41  public static readonly FP NaN = new FP(MIN_VALUE);
42 
43  public static readonly FP EN1 = FP.One / 10;
44  public static readonly FP EN2 = FP.One / 100;
45  public static readonly FP EN3 = FP.One / 1000;
46  public static readonly FP EN4 = FP.One / 10000;
47  public static readonly FP EN5 = FP.One / 100000;
48  public static readonly FP EN6 = FP.One / 1000000;
49  public static readonly FP EN7 = FP.One / 10000000;
50  public static readonly FP EN8 = FP.One / 100000000;
51  public static readonly FP Epsilon = FP.EN3;
52 
56  public static readonly FP Pi = new FP(PI);
57  public static readonly FP PiOver2 = new FP(PI_OVER_2);
58  public static readonly FP PiTimes2 = new FP(PI_TIMES_2);
59  public static readonly FP PiInv = (FP)0.3183098861837906715377675267M;
60  public static readonly FP PiOver2Inv = (FP)0.6366197723675813430755350535M;
61 
62  public static readonly FP Deg2Rad = Pi / new FP(180);
63 
64  public static readonly FP Rad2Deg = new FP(180) / Pi;
65 
66  static readonly FP LutInterval = (FP)(LUT_SIZE - 1) / PiOver2;
67 
68  public void OnBeforeSerialize() {
69  _serializedValue = m_rawValue.ToString();
70  }
71 
72  public void OnAfterDeserialize() {
73  if (!string.IsNullOrEmpty(_serializedValue)) {
74  m_rawValue = long.Parse(_serializedValue);
75  }
76  }
77 
82  public static int Sign(FP value) {
83  return
84  value.m_rawValue < 0 ? -1 :
85  value.m_rawValue > 0 ? 1 :
86  0;
87  }
88 
89 
94  public static FP Abs(FP value) {
95  if (value.m_rawValue == MIN_VALUE) {
96  return MaxValue;
97  }
98 
99  // branchless implementation, see http://www.strchr.com/optimized_abs_function
100  var mask = value.m_rawValue >> 63;
101  return new FP((value.m_rawValue + mask) ^ mask);
102  }
103 
108  public static FP FastAbs(FP value) {
109  // branchless implementation, see http://www.strchr.com/optimized_abs_function
110  var mask = value.m_rawValue >> 63;
111  return new FP((value.m_rawValue + mask) ^ mask);
112  }
113 
114 
118  public static FP Floor(FP value) {
119  // Just zero out the fractional part
120  return new FP((long)((ulong)value.m_rawValue & 0xFFFFFFFF00000000));
121  }
122 
126  public static FP Ceiling(FP value) {
127  var hasFractionalPart = (value.m_rawValue & 0x00000000FFFFFFFF) != 0;
128  return hasFractionalPart ? Floor(value) + One : value;
129  }
130 
135  public static FP Round(FP value) {
136  var fractionalPart = value.m_rawValue & 0x00000000FFFFFFFF;
137  var integralPart = Floor(value);
138  if (fractionalPart < 0x80000000) {
139  return integralPart;
140  }
141  if (fractionalPart > 0x80000000) {
142  return integralPart + One;
143  }
144  // if number is halfway between two values, round to the nearest even number
145  // this is the method used by System.Math.Round().
146  return (integralPart.m_rawValue & ONE) == 0
147  ? integralPart
148  : integralPart + One;
149  }
150 
155  public static FP operator +(FP x, FP y) {
156  // if(x == PositiveInfinity || y == PositiveInfinity || x == NegativeInfinity || y == NegativeInfinity ){
157  // UnityEngine.Debug.Log("infnity +");
158  // }
159  var xl = x.m_rawValue;
160  var yl = y.m_rawValue;
161  var sum = xl + yl;
162  // if signs of operands are equal and signs of sum and x are different
163  if (((~(xl ^ yl) & (xl ^ sum)) & MIN_VALUE) != 0) {
164  sum = xl > 0 ? MAX_VALUE : MIN_VALUE;
165  }
166  return new FP(sum);
167  }
168 
172  public static FP FastAdd(FP x, FP y) {
173  return new FP(x.m_rawValue + y.m_rawValue);
174  }
175 
180  public static FP operator -(FP x, FP y) {
181  //if(x == PositiveInfinity || y == PositiveInfinity || x == NegativeInfinity || y == NegativeInfinity ){
182  // UnityEngine.Debug.Log("infnity -");
183  //}
184  var xl = x.m_rawValue;
185  var yl = y.m_rawValue;
186  var diff = xl - yl;
187  // if signs of operands are different and signs of sum and x are different
188  if ((((xl ^ yl) & (xl ^ diff)) & MIN_VALUE) != 0) {
189  diff = xl < 0 ? MIN_VALUE : MAX_VALUE;
190  }
191  return new FP(diff);
192  }
193 
197  public static FP FastSub(FP x, FP y) {
198  return new FP(x.m_rawValue - y.m_rawValue);
199  }
200 
201  static long AddOverflowHelper(long x, long y, ref bool overflow) {
202  var sum = x + y;
203  // x + y overflows if sign(x) ^ sign(y) != sign(sum)
204  overflow |= ((x ^ y ^ sum) & MIN_VALUE) != 0;
205  return sum;
206  }
207 
208  public static FP operator *(FP x, FP y) {
209  //if(x == PositiveInfinity || y == PositiveInfinity || x == NegativeInfinity || y == NegativeInfinity ){
210  // UnityEngine.Debug.Log("infnity *");
211  // }
212  var xl = x.m_rawValue;
213  var yl = y.m_rawValue;
214 
215  var xlo = (ulong)(xl & 0x00000000FFFFFFFF);
216  var xhi = xl >> FRACTIONAL_PLACES;
217  var ylo = (ulong)(yl & 0x00000000FFFFFFFF);
218  var yhi = yl >> FRACTIONAL_PLACES;
219 
220  var lolo = xlo * ylo;
221  var lohi = (long)xlo * yhi;
222  var hilo = xhi * (long)ylo;
223  var hihi = xhi * yhi;
224 
225  var loResult = lolo >> FRACTIONAL_PLACES;
226  var midResult1 = lohi;
227  var midResult2 = hilo;
228  var hiResult = hihi << FRACTIONAL_PLACES;
229 
230  bool overflow = false;
231  var sum = AddOverflowHelper((long)loResult, midResult1, ref overflow);
232  sum = AddOverflowHelper(sum, midResult2, ref overflow);
233  sum = AddOverflowHelper(sum, hiResult, ref overflow);
234 
235  bool opSignsEqual = ((xl ^ yl) & MIN_VALUE) == 0;
236 
237  // if signs of operands are equal and sign of result is negative,
238  // then multiplication overflowed positively
239  // the reverse is also true
240  if (opSignsEqual) {
241  if (sum < 0 || (overflow && xl > 0)) {
242  return MaxValue;
243  }
244  } else {
245  if (sum > 0) {
246  return MinValue;
247  }
248  }
249 
250  // if the top 32 bits of hihi (unused in the result) are neither all 0s or 1s,
251  // then this means the result overflowed.
252  var topCarry = hihi >> FRACTIONAL_PLACES;
253  if (topCarry != 0 && topCarry != -1 /*&& xl != -17 && yl != -17*/) {
254  return opSignsEqual ? MaxValue : MinValue;
255  }
256 
257  // If signs differ, both operands' magnitudes are greater than 1,
258  // and the result is greater than the negative operand, then there was negative overflow.
259  if (!opSignsEqual) {
260  long posOp, negOp;
261  if (xl > yl) {
262  posOp = xl;
263  negOp = yl;
264  } else {
265  posOp = yl;
266  negOp = xl;
267  }
268  if (sum > negOp && negOp < -ONE && posOp > ONE) {
269  return MinValue;
270  }
271  }
272 
273  return new FP(sum);
274  }
275 
280  public static FP FastMul(FP x, FP y) {
281 
282  var xl = x.m_rawValue;
283  var yl = y.m_rawValue;
284 
285  var xlo = (ulong)(xl & 0x00000000FFFFFFFF);
286  var xhi = xl >> FRACTIONAL_PLACES;
287  var ylo = (ulong)(yl & 0x00000000FFFFFFFF);
288  var yhi = yl >> FRACTIONAL_PLACES;
289 
290  var lolo = xlo * ylo;
291  var lohi = (long)xlo * yhi;
292  var hilo = xhi * (long)ylo;
293  var hihi = xhi * yhi;
294 
295  var loResult = lolo >> FRACTIONAL_PLACES;
296  var midResult1 = lohi;
297  var midResult2 = hilo;
298  var hiResult = hihi << FRACTIONAL_PLACES;
299 
300  var sum = (long)loResult + midResult1 + midResult2 + hiResult;
301  return new FP(sum);
302  }
303 
304  //[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
305  static int CountLeadingZeroes(ulong x) {
306  int result = 0;
307  while ((x & 0xF000000000000000) == 0) { result += 4; x <<= 4; }
308  while ((x & 0x8000000000000000) == 0) { result += 1; x <<= 1; }
309  return result;
310  }
311 
312  public static FP operator /(FP x, FP y) {
313  // if(x == PositiveInfinity || y == PositiveInfinity || x == NegativeInfinity || y == NegativeInfinity || x == 0 || y == 0){
314  // UnityEngine.Debug.Log("infnity /");
315  // }
316  var xl = x.m_rawValue;
317  var yl = y.m_rawValue;
318 
319  if (yl == 0) {
320  return MAX_VALUE;
321  //throw new DivideByZeroException();
322  }
323 
324  var remainder = (ulong)(xl >= 0 ? xl : -xl);
325  var divider = (ulong)(yl >= 0 ? yl : -yl);
326  var quotient = 0UL;
327  var bitPos = NUM_BITS / 2 + 1;
328 
329 
330  // If the divider is divisible by 2^n, take advantage of it.
331  while ((divider & 0xF) == 0 && bitPos >= 4) {
332  divider >>= 4;
333  bitPos -= 4;
334  }
335 
336  while (remainder != 0 && bitPos >= 0) {
337  int shift = CountLeadingZeroes(remainder);
338  if (shift > bitPos) {
339  shift = bitPos;
340  }
341  remainder <<= shift;
342  bitPos -= shift;
343 
344  var div = remainder / divider;
345  remainder = remainder % divider;
346  quotient += div << bitPos;
347 
348  // Detect overflow
349  if ((div & ~(0xFFFFFFFFFFFFFFFF >> bitPos)) != 0) {
350  return ((xl ^ yl) & MIN_VALUE) == 0 ? MaxValue : MinValue;
351  }
352 
353  remainder <<= 1;
354  --bitPos;
355  }
356 
357  // rounding
358  ++quotient;
359  var result = (long)(quotient >> 1);
360  if (((xl ^ yl) & MIN_VALUE) != 0) {
361  result = -result;
362  }
363 
364  return new FP(result);
365  }
366 
367  public static FP operator %(FP x, FP y) {
368  return new FP(
369  x.m_rawValue == MIN_VALUE & y.m_rawValue == -1 ?
370  0 :
371  x.m_rawValue % y.m_rawValue);
372  }
373 
378  public static FP FastMod(FP x, FP y) {
379  return new FP(x.m_rawValue % y.m_rawValue);
380  }
381 
382  public static FP operator -(FP x) {
383  return x.m_rawValue == MIN_VALUE ? MaxValue : new FP(-x.m_rawValue);
384  }
385 
386  public static bool operator ==(FP x, FP y) {
387  return x.m_rawValue == y.m_rawValue;
388  }
389 
390  public static bool operator !=(FP x, FP y) {
391  return x.m_rawValue != y.m_rawValue;
392  }
393 
394  public static bool operator >(FP x, FP y) {
395  return x.m_rawValue > y.m_rawValue;
396  }
397 
398  public static bool operator <(FP x, FP y) {
399  return x.m_rawValue < y.m_rawValue;
400  }
401 
402  public static bool operator >=(FP x, FP y) {
403  return x.m_rawValue >= y.m_rawValue;
404  }
405 
406  public static bool operator <=(FP x, FP y) {
407  return x.m_rawValue <= y.m_rawValue;
408  }
409 
410 
417  public static FP Sqrt(FP x) {
418  var xl = x.m_rawValue;
419  if (xl < 0) {
420  // We cannot represent infinities like Single and Double, and Sqrt is
421  // mathematically undefined for x < 0. So we just throw an exception.
422  throw new ArgumentOutOfRangeException("Negative value passed to Sqrt", "x");
423  }
424 
425  var num = (ulong)xl;
426  var result = 0UL;
427 
428  // second-to-top bit
429  var bit = 1UL << (NUM_BITS - 2);
430 
431  while (bit > num) {
432  bit >>= 2;
433  }
434 
435  // The main part is executed twice, in order to avoid
436  // using 128 bit values in computations.
437  for (var i = 0; i < 2; ++i) {
438  // First we get the top 48 bits of the answer.
439  while (bit != 0) {
440  if (num >= result + bit) {
441  num -= result + bit;
442  result = (result >> 1) + bit;
443  } else {
444  result = result >> 1;
445  }
446  bit >>= 2;
447  }
448 
449  if (i == 0) {
450  // Then process it again to get the lowest 16 bits.
451  if (num > (1UL << (NUM_BITS / 2)) - 1) {
452  // The remainder 'num' is too large to be shifted left
453  // by 32, so we have to add 1 to result manually and
454  // adjust 'num' accordingly.
455  // num = a - (result + 0.5)^2
456  // = num + result^2 - (result + 0.5)^2
457  // = num - result - 0.5
458  num -= result;
459  num = (num << (NUM_BITS / 2)) - 0x80000000UL;
460  result = (result << (NUM_BITS / 2)) + 0x80000000UL;
461  } else {
462  num <<= (NUM_BITS / 2);
463  result <<= (NUM_BITS / 2);
464  }
465 
466  bit = 1UL << (NUM_BITS / 2 - 2);
467  }
468  }
469  // Finally, if next bit would have been 1, round the result upwards.
470  if (num > result) {
471  ++result;
472  }
473  return new FP((long)result);
474  }
475 
482  public static FP Sin(FP x) {
483  bool flipHorizontal, flipVertical;
484  var clampedL = ClampSinValue(x.m_rawValue, out flipHorizontal, out flipVertical);
485  var clamped = new FP(clampedL);
486 
487  // Find the two closest values in the LUT and perform linear interpolation
488  // This is what kills the performance of this function on x86 - x64 is fine though
489  var rawIndex = FastMul(clamped, LutInterval);
490  var roundedIndex = Round(rawIndex);
491  var indexError = 0;//FastSub(rawIndex, roundedIndex);
492 
493  var nearestValue = new FP(SinLut[flipHorizontal ?
494  SinLut.Length - 1 - (int)roundedIndex :
495  (int)roundedIndex]);
496  var secondNearestValue = new FP(SinLut[flipHorizontal ?
497  SinLut.Length - 1 - (int)roundedIndex - Sign(indexError) :
498  (int)roundedIndex + Sign(indexError)]);
499 
500  var delta = FastMul(indexError, FastAbs(FastSub(nearestValue, secondNearestValue))).m_rawValue;
501  var interpolatedValue = nearestValue.m_rawValue + (flipHorizontal ? -delta : delta);
502  var finalValue = flipVertical ? -interpolatedValue : interpolatedValue;
503  FP a2 = new FP(finalValue);
504  return a2;
505  }
506 
512  public static FP FastSin(FP x) {
513  bool flipHorizontal, flipVertical;
514  var clampedL = ClampSinValue(x.m_rawValue, out flipHorizontal, out flipVertical);
515 
516  // Here we use the fact that the SinLut table has a number of entries
517  // equal to (PI_OVER_2 >> 15) to use the angle to index directly into it
518  var rawIndex = (uint)(clampedL >> 15);
519  if (rawIndex >= LUT_SIZE) {
520  rawIndex = LUT_SIZE - 1;
521  }
522  var nearestValue = SinLut[flipHorizontal ?
523  SinLut.Length - 1 - (int)rawIndex :
524  (int)rawIndex];
525  return new FP(flipVertical ? -nearestValue : nearestValue);
526  }
527 
528 
529 
530  //[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
531  static long ClampSinValue(long angle, out bool flipHorizontal, out bool flipVertical) {
532  // Clamp value to 0 - 2*PI using modulo; this is very slow but there's no better way AFAIK
533  var clamped2Pi = angle % PI_TIMES_2;
534  if (angle < 0) {
535  clamped2Pi += PI_TIMES_2;
536  }
537 
538  // The LUT contains values for 0 - PiOver2; every other value must be obtained by
539  // vertical or horizontal mirroring
540  flipVertical = clamped2Pi >= PI;
541  // obtain (angle % PI) from (angle % 2PI) - much faster than doing another modulo
542  var clampedPi = clamped2Pi;
543  while (clampedPi >= PI) {
544  clampedPi -= PI;
545  }
546  flipHorizontal = clampedPi >= PI_OVER_2;
547  // obtain (angle % PI_OVER_2) from (angle % PI) - much faster than doing another modulo
548  var clampedPiOver2 = clampedPi;
549  if (clampedPiOver2 >= PI_OVER_2) {
550  clampedPiOver2 -= PI_OVER_2;
551  }
552  return clampedPiOver2;
553  }
554 
559  public static FP Cos(FP x) {
560  var xl = x.m_rawValue;
561  var rawAngle = xl + (xl > 0 ? -PI - PI_OVER_2 : PI_OVER_2);
562  FP a2 = Sin(new FP(rawAngle));
563  return a2;
564  }
565 
570  public static FP FastCos(FP x) {
571  var xl = x.m_rawValue;
572  var rawAngle = xl + (xl > 0 ? -PI - PI_OVER_2 : PI_OVER_2);
573  return FastSin(new FP(rawAngle));
574  }
575 
582  public static FP Tan(FP x) {
583  var clampedPi = x.m_rawValue % PI;
584  var flip = false;
585  if (clampedPi < 0) {
586  clampedPi = -clampedPi;
587  flip = true;
588  }
589  if (clampedPi > PI_OVER_2) {
590  flip = !flip;
591  clampedPi = PI_OVER_2 - (clampedPi - PI_OVER_2);
592  }
593 
594  var clamped = new FP(clampedPi);
595 
596  // Find the two closest values in the LUT and perform linear interpolation
597  var rawIndex = FastMul(clamped, LutInterval);
598  var roundedIndex = Round(rawIndex);
599  var indexError = FastSub(rawIndex, roundedIndex);
600 
601  var nearestValue = new FP(TanLut[(int)roundedIndex]);
602  var secondNearestValue = new FP(TanLut[(int)roundedIndex + Sign(indexError)]);
603 
604  var delta = FastMul(indexError, FastAbs(FastSub(nearestValue, secondNearestValue))).m_rawValue;
605  var interpolatedValue = nearestValue.m_rawValue + delta;
606  var finalValue = flip ? -interpolatedValue : interpolatedValue;
607  FP a2 = new FP(finalValue);
608  return a2;
609  }
610 
611  public static FP Atan(FP y) {
612  return Atan2(y, 1);
613  }
614 
615  public static FP Atan2(FP y, FP x) {
616  var yl = y.m_rawValue;
617  var xl = x.m_rawValue;
618  if (xl == 0) {
619  if (yl > 0) {
620  return PiOver2;
621  }
622  if (yl == 0) {
623  return Zero;
624  }
625  return -PiOver2;
626  }
627  FP atan;
628  var z = y / x;
629 
630  FP sm = FP.EN2 * 28;
631  // Deal with overflow
632  if (One + sm * z * z == MaxValue) {
633  return y < Zero ? -PiOver2 : PiOver2;
634  }
635 
636  if (Abs(z) < One) {
637  atan = z / (One + sm * z * z);
638  if (xl < 0) {
639  if (yl < 0) {
640  return atan - Pi;
641  }
642  return atan + Pi;
643  }
644  } else {
645  atan = PiOver2 - z / (z * z + sm);
646  if (yl < 0) {
647  return atan - Pi;
648  }
649  }
650  return atan;
651  }
652 
653  public static FP Asin(FP value) {
654  return 2 * Atan(value / (1 + FP.Sqrt(FP.One - value * value)));
655  }
656 
657  public static FP Acos(FP value) {
658  return 2 * Atan(FP.Sqrt(FP.One - value * value) / (FP.One + value));
659  }
660 
661  public static implicit operator FP(long value) {
662  return new FP(value * ONE);
663  }
664 
665  public static explicit operator long(FP value) {
666  return value.m_rawValue >> FRACTIONAL_PLACES;
667  }
668 
669  public static implicit operator FP(float value) {
670  return new FP((long)(value * ONE));
671  }
672 
673  public static explicit operator float(FP value) {
674  return (float)value.m_rawValue / ONE;
675  }
676 
677  public static implicit operator FP(double value) {
678  return new FP((long)(value * ONE));
679  }
680 
681  public static explicit operator double(FP value) {
682  return (double)value.m_rawValue / ONE;
683  }
684 
685  public static explicit operator FP(decimal value) {
686  return new FP((long)(value * ONE));
687  }
688 
689  public static implicit operator FP(int value) {
690  return new FP(value * ONE);
691  }
692 
693  public static explicit operator decimal(FP value) {
694  return (decimal)value.m_rawValue / ONE;
695  }
696 
697  public float AsFloat() {
698  return (float) this;
699  }
700 
701  public int AsInt() {
702  return (int) this;
703  }
704 
705  public long AsLong() {
706  return (long)this;
707  }
708 
709  public double AsDouble() {
710  return (double)this;
711  }
712 
713  public decimal AsDecimal() {
714  return (decimal)this;
715  }
716 
717  public static float ToFloat(FP value) {
718  return (float)value;
719  }
720 
721  public static int ToInt(FP value) {
722  return (int)value;
723  }
724 
725  public static FP FromFloat(float value) {
726  return (FP)value;
727  }
728 
729  public static bool IsInfinity(FP value) {
730  return value == NegativeInfinity || value == PositiveInfinity;
731  }
732 
733  public static bool IsNaN(FP value) {
734  return value == NaN;
735  }
736 
737  public override bool Equals(object obj) {
738  return obj is FP && ((FP)obj).m_rawValue == m_rawValue;
739  }
740 
741  public override int GetHashCode() {
742  return m_rawValue.GetHashCode();
743  }
744 
745  public bool Equals(FP other) {
746  return m_rawValue == other.m_rawValue;
747  }
748 
749  public int CompareTo(FP other) {
750  return m_rawValue.CompareTo(other.m_rawValue);
751  }
752 
753  public override string ToString() {
754  return ((float)this).ToString();
755  }
756 
757  public static FP FromRaw(long rawValue) {
758  return new FP(rawValue);
759  }
760 
761  internal static void GenerateSinLut() {
762  using (var writer = new StreamWriter("Fix64SinLut.cs")) {
763  writer.Write(
764 @"namespace FixMath.NET {
765  partial struct Fix64 {
766  public static readonly long[] SinLut = new[] {");
767  int lineCounter = 0;
768  for (int i = 0; i < LUT_SIZE; ++i) {
769  var angle = i * Math.PI * 0.5 / (LUT_SIZE - 1);
770  if (lineCounter++ % 8 == 0) {
771  writer.WriteLine();
772  writer.Write(" ");
773  }
774  var sin = Math.Sin(angle);
775  var rawValue = ((FP)sin).m_rawValue;
776  writer.Write(string.Format("0x{0:X}L, ", rawValue));
777  }
778  writer.Write(
779 @"
780  };
781  }
782 }");
783  }
784  }
785 
786  internal static void GenerateTanLut() {
787  using (var writer = new StreamWriter("Fix64TanLut.cs")) {
788  writer.Write(
789 @"namespace FixMath.NET {
790  partial struct Fix64 {
791  public static readonly long[] TanLut = new[] {");
792  int lineCounter = 0;
793  for (int i = 0; i < LUT_SIZE; ++i) {
794  var angle = i * Math.PI * 0.5 / (LUT_SIZE - 1);
795  if (lineCounter++ % 8 == 0) {
796  writer.WriteLine();
797  writer.Write(" ");
798  }
799  var tan = Math.Tan(angle);
800  if (tan > (double)MaxValue || tan < 0.0) {
801  tan = (double)MaxValue;
802  }
803  var rawValue = (((decimal)tan > (decimal)MaxValue || tan < 0.0) ? MaxValue : (FP)tan).m_rawValue;
804  writer.Write(string.Format("0x{0:X}L, ", rawValue));
805  }
806  writer.Write(
807 @"
808  };
809  }
810 }");
811  }
812  }
813 
817  public long RawValue { get { return m_rawValue; } }
818 
823  FP(long rawValue) {
824  m_rawValue = rawValue;
825  _serializedValue = "";
826  }
827 
828  public FP(int value) {
829  m_rawValue = value * ONE;
830  _serializedValue = "";
831  }
832  }
833 }
static readonly FP Pi
The value of Pi
Definition: Fix64.cs:56
static FP Cos(FP x)
Returns the cosine of x. See Sin() for more details.
Definition: Fix64.cs:559
static FP FastCos(FP x)
Returns a rough approximation of the cosine of x. See FastSin for more details.
Definition: Fix64.cs:570
static FP FastAdd(FP x, FP y)
Adds x and y witout performing overflow checking. Should be inlined by the CLR.
Definition: Fix64.cs:172
static FP FastSin(FP x)
Returns a rough approximation of the Sine of x. This is at least 3 times faster than Sin() on x86 and...
Definition: Fix64.cs:512
static FP Tan(FP x)
Returns the tangent of x.
Definition: Fix64.cs:582
static int Sign(FP value)
Returns a number indicating the sign of a Fix64 number. Returns 1 if the value is positive...
Definition: Fix64.cs:82
static FP Sqrt(FP x)
Returns the square root of a specified number.
Definition: Fix64.cs:417
Represents a Q31.32 fixed-point number.
Definition: Fix64.cs:11
long RawValue
The underlying integer representation
Definition: Fix64.cs:817
static FP Ceiling(FP value)
Returns the smallest integral value that is greater than or equal to the specified number...
Definition: Fix64.cs:126
static FP FastAbs(FP value)
Returns the absolute value of a Fix64 number. FastAbs(Fix64.MinValue) is undefined.
Definition: Fix64.cs:108
static FP Round(FP value)
Rounds a value to the nearest integral value. If the value is halfway between an even and an uneven v...
Definition: Fix64.cs:135
static FP Sin(FP x)
Returns the Sine of x. This function has about 9 decimals of accuracy for small values of x...
Definition: Fix64.cs:482
static FP Abs(FP value)
Returns the absolute value of a Fix64 number. Note: Abs(Fix64.MinValue) == Fix64.MaxValue.
Definition: Fix64.cs:94
static FP operator+(FP x, FP y)
Adds x and y. Performs saturating addition, i.e. in case of overflow, rounds to MinValue or MaxValue ...
Definition: Fix64.cs:155
static FP FastMod(FP x, FP y)
Performs modulo as fast as possible; throws if x == MinValue and y == -1. Use the operator (%) for a ...
Definition: Fix64.cs:378
static FP operator-(FP x, FP y)
Subtracts y from x. Performs saturating substraction, i.e. in case of overflow, rounds to MinValue or...
Definition: Fix64.cs:180
static FP FastMul(FP x, FP y)
Performs multiplication without checking for overflow. Useful for performance-critical code where the...
Definition: Fix64.cs:280
FP(long rawValue)
This is the constructor from raw value; it can only be used interally.
Definition: Fix64.cs:823
static FP FastSub(FP x, FP y)
Subtracts y from x witout performing overflow checking. Should be inlined by the CLR.
Definition: Fix64.cs:197
static FP Floor(FP value)
Returns the largest integer less than or equal to the specified number.
Definition: Fix64.cs:118