diff --git a/Core/Simulation/Math/FixedMath.cs b/Core/Simulation/Math/FixedMath.cs
index 34c1b009..388666ae 100755
--- a/Core/Simulation/Math/FixedMath.cs
+++ b/Core/Simulation/Math/FixedMath.cs
@@ -11,10 +11,15 @@
using System.Collections;
using System;
-namespace Lockstep
-{
- public static class FixedMath
- {
+namespace Lockstep {
+ ///
+ /// Utility class for fixed point numbers.
+ /// The lower (right) 16 bits are used as the fraction
+ /// component and the upper (left) 48 bits are used as the decimal
+ /// and sign. The numbers use 2-s compliment so they can
+ /// be added and subtracted like normal long values.
+ ///
+ public static class FixedMath {
#region Meta
@@ -37,13 +42,11 @@ public static class FixedMath
/// Create a fixed point number from an integer.
///
/// Integer.
- public static long Create(long integer)
- {
+ public static long Create(long integer) {
return integer << SHIFT_AMOUNT;
}
- public static long Create(float singleFloat)
- {
+ public static long Create(float singleFloat) {
return (long)((double)singleFloat * One);
}
@@ -51,8 +54,7 @@ public static long Create(float singleFloat)
/// Create a fixed point number from a double.
///
/// Double float.
- public static long Create(double doubleFloat)
- {
+ public static long Create(double doubleFloat) {
return (long)(doubleFloat * One);
}
@@ -61,8 +63,7 @@ public static long Create(double doubleFloat)
///
/// Whole.
/// Fraction.
- public static long Create(long Numerator, long Denominator)
- {
+ public static long Create(long Numerator, long Denominator) {
return (Numerator << SHIFT_AMOUNT) / Denominator;
}
@@ -72,27 +73,20 @@ public static long Create(long Numerator, long Denominator)
/// true, if parse was tried, false otherwise.
/// S.
/// Result.
- public static bool TryParse(string s, out long result)
- {
+ public static bool TryParse(string s, out long result) {
string[] NewValues = s.Split('.');
- if (NewValues.Length <= 2)
- {
+ if (NewValues.Length <= 2) {
long Whole;
- if (long.TryParse(NewValues [0], out Whole))
- {
- if (NewValues.Length == 1)
- {
+ if (long.TryParse(NewValues[0], out Whole)) {
+ if (NewValues.Length == 1) {
result = Whole << SHIFT_AMOUNT;
return true;
- } else
- {
+ } else {
long Numerator;
- if (long.TryParse(NewValues [1], out Numerator))
- {
- int fractionDigits = NewValues [1].Length;
+ if (long.TryParse(NewValues[1], out Numerator)) {
+ int fractionDigits = NewValues[1].Length;
long Denominator = 1;
- for (int i = 0; i < fractionDigits; i++)
- {
+ for (int i = 0; i < fractionDigits; i++) {
Denominator *= 10;
}
result = (Whole << SHIFT_AMOUNT) + FixedMath.Create(Numerator, Denominator);
@@ -114,8 +108,7 @@ public static bool TryParse(string s, out long result)
///
/// f1.
/// f2.
- public static long Add(this long f1, long f2)
- {
+ public static long Add(this long f1, long f2) {
return f1 + f2;
}
@@ -124,8 +117,7 @@ public static long Add(this long f1, long f2)
///
/// f1.
/// f2.
- public static long Sub(this long f1, long f2)
- {
+ public static long Sub(this long f1, long f2) {
return f1 - f2;
}
@@ -134,13 +126,11 @@ public static long Sub(this long f1, long f2)
///
/// f1.
/// f2.
- public static long Mul(this long f1, long f2)
- {
+ public static long Mul(this long f1, long f2) {
return (f1 * f2) >> SHIFT_AMOUNT;
}
- public static long Mul(this long f1, int intr)
- {
+ public static long Mul(this long f1, int intr) {
return (f1 * intr);
}
@@ -149,8 +139,7 @@ public static long Mul(this long f1, int intr)
///
/// f1.
/// f2.
- public static long Div(this long f1, long f2)
- {
+ public static long Div(this long f1, long f2) {
return (f1 << SHIFT_AMOUNT) / f2;
}
@@ -159,13 +148,11 @@ public static long Div(this long f1, long f2)
///
/// f1.
/// f2.
- public static long Remainder(this long f1, long f2)
- {
+ public static long Remainder(this long f1, long f2) {
return f1 % f2;
}
- public static long Mod(this long f1, long f2)
- {
+ public static long Mod(this long f1, long f2) {
long f = f1 % f2;
return f < 0 ? f + f2 : f;
}
@@ -177,47 +164,38 @@ public static long Mod(this long f1, long f2)
static long n, n1;
- public static long Sqrt(long f1)
- {
+ public static long Sqrt(long f1) {
if (f1 == 0)
return 0;
n = (f1 >> 1) + 1;
n1 = (n + (f1 / n)) >> 1;
- while (n1 < n)
- {
+ while (n1 < n) {
n = n1;
n1 = (n + (f1 / n)) >> 1;
}
return n << (SHIFT_AMOUNT / 2);
}
-
-
- public static long Normalized(this long f1)
- {
+ public static long Normalized(this long f1) {
return f1 >> FixedMath.SHIFT_AMOUNT;
}
- public static long Abs(this long f1)
- {
+ public static long Abs(this long f1) {
return f1 < 0 ? -f1 : f1;
}
- public static bool AbsMoreThan(this long f1, long f2)
- {
+ public static bool AbsMoreThan(this long f1, long f2) {
if (f1 < 0) {
return -f1 > f2;
- }
- else {
+ } else {
return f1 > f2;
}
}
- public static bool AbsLessThan (this long f1, long f2) {
+ public static bool AbsLessThan(this long f1, long f2) {
if (f1 < 0) {
return -f1 < f2;
- }
- else {
+ } else {
return f1 < f2;
}
}
@@ -230,8 +208,7 @@ public static bool AbsLessThan (this long f1, long f2) {
/// Truncate the specified fixed-point number.
///
/// F1.
- public static long Truncate(long f1)
- {
+ public static long Truncate(long f1) {
return ((f1) >> SHIFT_AMOUNT) << SHIFT_AMOUNT;
}
@@ -239,28 +216,23 @@ public static long Truncate(long f1)
/// Round the specified fixed point number.
///
/// F1.
- public static long Round(long f1)
- {
+ public static long Round(long f1) {
return ((f1 + FixedMath.Half - 1) >> SHIFT_AMOUNT) << SHIFT_AMOUNT;
}
-
-
///
/// Ceil the specified fixed point number.
///
/// F1.
- public static long Ceil(long f1)
- {
+ public static long Ceil(long f1) {
return ((f1 + One - 1) >> SHIFT_AMOUNT) << SHIFT_AMOUNT;
}
- public static long Floor (long f1) {
+ public static long Floor(long f1) {
return ((f1) >> SHIFT_AMOUNT) << SHIFT_AMOUNT;
}
- public static long Lerp(long from, long to, long t)
- {
+ public static long Lerp(long from, long to, long t) {
if (t >= One)
return to;
else if (t <= 0)
@@ -268,38 +240,36 @@ public static long Lerp(long from, long to, long t)
return (to * t + from * (One - t)) >> SHIFT_AMOUNT;
}
- public static long Min(this long f1, long f2)
- {
+ public static long Min(this long f1, long f2) {
return f1 <= f2 ? f1 : f2;
}
- public static long Max(this long f1, long f2)
- {
+ public static long Max(this long f1, long f2) {
return f1 >= f2 ? f1 : f2;
}
- public static long Clamp (this long f1, long min, long max) {
- if (f1 < min) return min;
- if (f1 > max) return max;
+
+ public static long Clamp(this long f1, long min, long max) {
+ if (f1 < min)
+ return min;
+ if (f1 > max)
+ return max;
return f1;
}
- public static double ToFormattedDouble(this long f1)
- {
+
+ public static double ToFormattedDouble(this long f1) {
return Math.Round(FixedMath.ToDouble(f1), 2, MidpointRounding.AwayFromZero);
}
- public static bool MoreThanEpsilon(this long f1)
- {
+ public static bool MoreThanEpsilon(this long f1) {
return f1 > Epsilon || f1 < Epsilon;
}
- public static long MoveTowards (long from, long to, long maxAmount) {
- if (from < to)
- {
+ public static long MoveTowards(long from, long to, long maxAmount) {
+ if (from < to) {
from += maxAmount;
if (from > to)
from = to;
- }
- else if (from > to) {
+ } else if (from > to) {
from -= maxAmount;
if (from < to)
from = to;
@@ -310,7 +280,8 @@ public static long MoveTowards (long from, long to, long maxAmount) {
#endregion
#region Convert
- public static int Sign (this long f1) {
+
+ public static int Sign(this long f1) {
if (f1 > 0)
return 1;
else if (f1 == 0)
@@ -319,18 +290,15 @@ public static int Sign (this long f1) {
return -1;
}
- public static int ToInt(this long f1)
- {
+ public static int ToInt(this long f1) {
return (int)(f1 >> SHIFT_AMOUNT);
}
- public static int RoundToInt(this long f1)
- {
+ public static int RoundToInt(this long f1) {
return (int)((f1 + Half - 1) >> SHIFT_AMOUNT);
}
- public static int CeilToInt(this long f1)
- {
+ public static int CeilToInt(this long f1) {
return (int)((f1 + One - 1) >> SHIFT_AMOUNT);
}
@@ -339,8 +307,7 @@ public static int CeilToInt(this long f1)
///
/// The double.
/// f1.
- public static double ToDouble(this long f1)
- {
+ public static double ToDouble(this long f1) {
return (f1 / OneD);
}
@@ -349,13 +316,11 @@ public static double ToDouble(this long f1)
///
/// The float.
/// f1.
- public static float ToFloat(this long f1)
- {
+ public static float ToFloat(this long f1) {
return (float)(f1 / OneD);
}
- public static float ToPreciseFloat(this long f1)
- {
+ public static float ToPreciseFloat(this long f1) {
return (float)ToDouble(f1);
}
@@ -365,19 +330,14 @@ public static float ToPreciseFloat(this long f1)
/// The string.
/// f1.
- public static string GetString(this long f1)
- {
+ public static string GetString(this long f1) {
return (System.Math.Round((f1) / OneD, 4, System.MidpointRounding.AwayFromZero)).ToString();
}
-
-
#endregion
- public static class Trig
- {
- public static long Sin(long theta)
- {
+ public static class Trig {
+ public static long Sin(long theta) {
//Taylor series cuz easy
//TODO: Profiling
//Note: Max 4 multiplications before overflow
@@ -400,7 +360,7 @@ public static long Sin(long theta)
n *= thetaSquared;
n >>= shift;
const long Factorial7 = Factorial5 * 6 * 7;
- result -= n / Factorial7;
+ result -= n / Factorial7;
#if true || HIGH_ACCURACY
//Required or there'll be .07 inaccuracy
@@ -411,15 +371,17 @@ public static long Sin(long theta)
#endif
return result;
}
+
public static long Cos(long theta) {
- return Sin (theta - FixedMath.Pi / 2);
+ return Sin(theta - FixedMath.Pi / 2);
}
- public static long SinToCos(long sin)
- {
- return Sqrt(FixedMath.One - (sin.Mul( sin)).Normalized());
+
+ public static long SinToCos(long sin) {
+ return Sqrt(FixedMath.One - (sin.Mul(sin)).Normalized());
}
- public static long Tan (long theta) {
+
+ public static long Tan(long theta) {
return Sin(theta).Div(Cos(theta));
}
}
diff --git a/Core/Simulation/Math/Tests.meta b/Core/Simulation/Math/Tests.meta
new file mode 100644
index 00000000..2024fe7b
--- /dev/null
+++ b/Core/Simulation/Math/Tests.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 395a367a4de0e4d0baf5153e2a59fabb
+folderAsset: yes
+timeCreated: 1468530563
+licenseType: Free
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Core/Simulation/Math/Tests/Editor.meta b/Core/Simulation/Math/Tests/Editor.meta
new file mode 100644
index 00000000..2225e432
--- /dev/null
+++ b/Core/Simulation/Math/Tests/Editor.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: b77cfd3739c7b42c9805fe5a03b98222
+folderAsset: yes
+timeCreated: 1468530563
+licenseType: Free
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Core/Simulation/Math/Tests/Editor/FixedMathTest.cs b/Core/Simulation/Math/Tests/Editor/FixedMathTest.cs
new file mode 100644
index 00000000..098ee305
--- /dev/null
+++ b/Core/Simulation/Math/Tests/Editor/FixedMathTest.cs
@@ -0,0 +1,123 @@
+using System;
+using UnityEngine;
+using UnityEditor;
+using NUnit.Framework;
+using Lockstep;
+
+namespace MonoTests.Lockstep {
+ [TestFixture]
+ public class FixedMathTest {
+
+ [SetUp]
+ public void GetReady() {
+ }
+
+ [TearDown]
+ public void Clean() {
+ }
+
+ [Test]
+ public void CreateLongTest() {
+ Assert.AreEqual(0L, FixedMath.Create(0L));
+ Assert.AreEqual(1L << 16, FixedMath.Create(1L));
+ Assert.AreEqual(-1L << 16, FixedMath.Create(-1L));
+ Assert.AreEqual(132414LL << 16, FixedMath.Create(132414L));
+ }
+
+ [Test]
+ public void AddSubIntTest() {
+ long n1 = FixedMath.Create(-1L);
+ long p1 = FixedMath.Create(1L);
+
+ // Assert 1 + -1 = 0
+ Assert.AreEqual(0, n1.Add(p1));
+
+ // Assert 1 + 1 = 2
+ Assert.AreEqual(2 << 16, p1.Add(p1));
+
+ // Assert -1 + -1 = -2
+ Assert.AreEqual(-2 << 16, n1.Add(n1));
+
+ // Assert 12 - 7 = 5
+ Assert.AreEqual(5 << 16, FixedMath.Create(12L).Sub(FixedMath.Create(7L)));
+
+ // Assert 33 - 66 = -33
+ Assert.AreEqual(-33 << 16, FixedMath.Create(33L).Sub(FixedMath.Create(66L)));
+
+ // Assert -33 - -66 = 33
+ Assert.AreEqual(33 << 16, FixedMath.Create(-33L).Sub(FixedMath.Create(-66L)));
+ }
+
+ [Test]
+ public void CreateFloatTest() {
+ // The left 48 bits in the number are the whole number
+ // and the right 16 are the fraction. This test ensures
+ // the fractional numbers are being assigned correctly.
+ Assert.AreEqual(0, FixedMath.Create(0f));
+ // Assert 1.5 = ..001|100..
+ Assert.AreEqual((1 << 16) + (1 << 15), FixedMath.Create(1.5f));
+ // Assert .75 = ..0000|1100..
+ Assert.AreEqual((1 << 14) + (1 << 15), FixedMath.Create(.75f));
+ Assert.AreEqual((1 << 26) + (1 << 15), FixedMath.Create(1024.5f));
+ Assert.AreEqual(-((1 << 26) + (1 << 15)), FixedMath.Create(-1024.5f));
+ }
+
+ [Test]
+ public void AddSubFloatTest() {
+ long half = FixedMath.Create(0.5f);
+ Assert.AreEqual(1 << 16, half.Add(half));
+
+ long quarter = FixedMath.Create(0.5f);
+ Assert.AreEqual(1 << 16, half.Add(half));
+ }
+
+ [Test]
+ public void RoundTest() {
+ // Keep in mind the current rounding uses 0.5 -> 0
+ Assert.AreEqual(0, FixedMath.Round(FixedMath.Create(0.5f)));
+ Assert.AreEqual(1 << 16, FixedMath.Round(FixedMath.Create(0.6f)));
+ Assert.AreEqual(0, FixedMath.Round(FixedMath.Create(0.4f)));
+ Assert.AreEqual(0, FixedMath.Round(FixedMath.Create(0.1f)));
+
+ // Keep in mind the current rounding uses 0.5 -> -1
+ Assert.AreEqual(-1 << 16, FixedMath.Round(FixedMath.Create(-0.5f)));
+ Assert.AreEqual(-1 << 16, FixedMath.Round(FixedMath.Create(-0.6f)));
+ Assert.AreEqual(0, FixedMath.Round(FixedMath.Create(-0.4f)));
+ Assert.AreEqual(0, FixedMath.Round(FixedMath.Create(-0.1f)));
+ }
+
+ [Test]
+ public void CreateFromFractionTest() {
+ Assert.AreEqual(0, FixedMath.Create(0, 100));
+ Assert.AreEqual(1 << 15, FixedMath.Create(1, 2));
+ Assert.AreEqual(-1 << 15, FixedMath.Create(-1, 2));
+ Assert.AreEqual(-1 << 15, FixedMath.Create(1, -2));
+ Assert.AreEqual(1 << 15, FixedMath.Create(-1, -2));
+ }
+
+ [Test]
+ public void MulDivTest() {
+ long two = FixedMath.Create(2);
+ // Assert 2x2 = 4
+ Assert.AreEqual(1 << 18, two.Mul(two));
+
+ // Assert 2/2 = 1
+ Assert.AreEqual(1 << 16, two.Div(two));
+
+ long max = FixedMath.Create(int.MaxValue);
+ long answer = FixedMath.Create(1073741823.5);
+ Assert.AreEqual(70368744144896L, answer);
+
+ Assert.AreEqual(answer, max.Div(two));
+ Assert.AreEqual(1 << 16, max.Div(max));
+ }
+
+ [Test]
+ public void ToIntTest() {
+ Assert.AreEqual(0, FixedMath.Create(0).ToInt());
+ Assert.AreEqual(1, FixedMath.Create(1).ToInt());
+ Assert.AreEqual(-1, FixedMath.Create(-1).ToInt());
+ }
+ }
+}
+
diff --git a/Core/Simulation/Math/Tests/Editor/FixedMathTest.cs.meta b/Core/Simulation/Math/Tests/Editor/FixedMathTest.cs.meta
new file mode 100644
index 00000000..4f8366bc
--- /dev/null
+++ b/Core/Simulation/Math/Tests/Editor/FixedMathTest.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 8293726fbe2e445eaa66b1e04a99e6dd
+timeCreated: 1468530563
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: