forked from MoonsideGames/MoonWorks
				
			add exponentiation functions to Fix64
							parent
							
								
									7f6b6a7bae
								
							
						
					
					
						commit
						be77e8bad1
					
				|  | @ -17,6 +17,9 @@ namespace MoonWorks.Math.Fixed | ||||||
| 		const long PI_TIMES_2 = 0x6487ED511; | 		const long PI_TIMES_2 = 0x6487ED511; | ||||||
| 		const long PI = 0x3243F6A88; | 		const long PI = 0x3243F6A88; | ||||||
| 		const long PI_OVER_2 = 0x1921FB544; | 		const long PI_OVER_2 = 0x1921FB544; | ||||||
|  | 		const long LN2 = 0xB17217F7; | ||||||
|  | 		const long LOG2MAX = 0x1F00000000; | ||||||
|  | 		const long LOG2MIN = -0x2000000000; | ||||||
| 
 | 
 | ||||||
| 		public static readonly Fix64 MaxValue = new Fix64(MAX_VALUE); | 		public static readonly Fix64 MaxValue = new Fix64(MAX_VALUE); | ||||||
| 		public static readonly Fix64 MinValue = new Fix64(MIN_VALUE); | 		public static readonly Fix64 MinValue = new Fix64(MIN_VALUE); | ||||||
|  | @ -28,6 +31,10 @@ namespace MoonWorks.Math.Fixed | ||||||
| 		public static readonly Fix64 PiOver4 = PiOver2 / new Fix64(2); | 		public static readonly Fix64 PiOver4 = PiOver2 / new Fix64(2); | ||||||
| 		public static readonly Fix64 PiTimes2 = new Fix64(PI_TIMES_2); | 		public static readonly Fix64 PiTimes2 = new Fix64(PI_TIMES_2); | ||||||
| 
 | 
 | ||||||
|  | 		static readonly Fix64 Ln2 = new Fix64(LN2); | ||||||
|  | 		static readonly Fix64 Log2Max = new Fix64(LOG2MAX); | ||||||
|  | 		static readonly Fix64 Log2Min = new Fix64(LOG2MIN); | ||||||
|  | 
 | ||||||
| 		const int LUT_SIZE = (int)(PI_OVER_2 >> 15); | 		const int LUT_SIZE = (int)(PI_OVER_2 >> 15); | ||||||
| 		static readonly Fix64 LutInterval = (Fix64)(LUT_SIZE - 1) / PiOver2; | 		static readonly Fix64 LutInterval = (Fix64)(LUT_SIZE - 1) / PiOver2; | ||||||
| 
 | 
 | ||||||
|  | @ -122,27 +129,27 @@ namespace MoonWorks.Math.Fixed | ||||||
| 			return new Fix64((value.RawValue + mask) ^ mask); | 			return new Fix64((value.RawValue + mask) ^ mask); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|         /// <summary> | 		/// <summary> | ||||||
|         /// Returns the largest integral value less than or equal to the specified number. | 		/// Returns the largest integral value less than or equal to the specified number. | ||||||
|         /// </summary> | 		/// </summary> | ||||||
| 		public static Fix64 Floor(Fix64 value) | 		public static Fix64 Floor(Fix64 value) | ||||||
| 		{ | 		{ | ||||||
| 			// Zero out the fractional part. | 			// Zero out the fractional part. | ||||||
| 			return new Fix64((long)((ulong)value.RawValue & 0xFFFFFFFF00000000)); | 			return new Fix64((long)((ulong)value.RawValue & 0xFFFFFFFF00000000)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|         /// <summary> | 		/// <summary> | ||||||
|         /// Returns the smallest integral value that is greater than or equal to the specified number. | 		/// Returns the smallest integral value that is greater than or equal to the specified number. | ||||||
|         /// </summary> | 		/// </summary> | ||||||
| 		public static Fix64 Ceiling(Fix64 value) | 		public static Fix64 Ceiling(Fix64 value) | ||||||
| 		{ | 		{ | ||||||
| 			return value.IsFractional ? Floor(value) + One : value; | 			return value.IsFractional ? Floor(value) + One : value; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|         /// <summary> | 		/// <summary> | ||||||
|         /// Rounds to the nearest integral value. | 		/// Rounds to the nearest integral value. | ||||||
|         /// If the value is halfway between an even and an uneven value, returns the even value. | 		/// If the value is halfway between an even and an uneven value, returns the even value. | ||||||
|         /// </summary> | 		/// </summary> | ||||||
| 		public static Fix64 Round(Fix64 value) | 		public static Fix64 Round(Fix64 value) | ||||||
| 		{ | 		{ | ||||||
| 			var fractionalPart = value.RawValue & 0x00000000FFFFFFFF; | 			var fractionalPart = value.RawValue & 0x00000000FFFFFFFF; | ||||||
|  | @ -217,7 +224,145 @@ namespace MoonWorks.Math.Fixed | ||||||
| 			return Fix64.Floor(value / step) * step; | 			return Fix64.Floor(value / step) * step; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Trigonometry functions | 		// Exponentiation functions | ||||||
|  | 
 | ||||||
|  | 		/// <summary> | ||||||
|  | 		/// Returns 2 raised to the specified power. | ||||||
|  | 		/// Provides at least 6 decimals of accuracy. | ||||||
|  | 		/// </summary> | ||||||
|  | 		internal static Fix64 Pow2(Fix64 x) | ||||||
|  | 		{ | ||||||
|  | 			if (x.RawValue == 0) | ||||||
|  | 			{ | ||||||
|  | 				return One; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// Avoid negative arguments by exploiting that exp(-x) = 1/exp(x). | ||||||
|  | 			bool neg = x.RawValue < 0; | ||||||
|  | 			if (neg) | ||||||
|  | 			{ | ||||||
|  | 				x = -x; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (x == One) | ||||||
|  | 			{ | ||||||
|  | 				return neg ? One / (Fix64)2 : (Fix64)2; | ||||||
|  | 			} | ||||||
|  | 			if (x >= Log2Max) | ||||||
|  | 			{ | ||||||
|  | 				return neg ? One / MaxValue : MaxValue; | ||||||
|  | 			} | ||||||
|  | 			if (x <= Log2Min) | ||||||
|  | 			{ | ||||||
|  | 				return neg ? MaxValue : Zero; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			/* The algorithm is based on the power series for exp(x): | ||||||
|  | 			 * http://en.wikipedia.org/wiki/Exponential_function#Formal_definition | ||||||
|  | 			 * | ||||||
|  | 			 * From term n, we get term n+1 by multiplying with x/n. | ||||||
|  | 			 * When the sum term drops to zero, we can stop summing. | ||||||
|  | 			 */ | ||||||
|  | 
 | ||||||
|  | 			int integerPart = (int)Floor(x); | ||||||
|  | 			// Take fractional part of exponent | ||||||
|  | 			x = new Fix64(x.RawValue & 0x00000000FFFFFFFF); | ||||||
|  | 
 | ||||||
|  | 			var result = One; | ||||||
|  | 			var term = One; | ||||||
|  | 			int i = 1; | ||||||
|  | 			while (term.RawValue != 0) | ||||||
|  | 			{ | ||||||
|  | 				term = FastMul(FastMul(x, term), Ln2) / (Fix64)i; | ||||||
|  | 				result += term; | ||||||
|  | 				i++; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			result = new Fix64(result.RawValue << integerPart); | ||||||
|  | 			if (neg) | ||||||
|  | 			{ | ||||||
|  | 				result = One / result; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return result; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/// <summary> | ||||||
|  | 		/// Returns the base-2 logarithm of a specified number. | ||||||
|  | 		/// Provides at least 9 decimals of accuracy. | ||||||
|  | 		/// </summary> | ||||||
|  | 		/// <exception cref="ArgumentOutOfRangeException"> | ||||||
|  | 		/// The argument was non-positive | ||||||
|  | 		/// </exception> | ||||||
|  | 		internal static Fix64 Log2(Fix64 x) | ||||||
|  | 		{ | ||||||
|  | 			if (x.RawValue <= 0) | ||||||
|  | 			{ | ||||||
|  | 				throw new ArgumentOutOfRangeException("Non-positive value passed to Ln", "x"); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// This implementation is based on Clay. S. Turner's fast binary logarithm | ||||||
|  | 			// algorithm (C. S. Turner,  "A Fast Binary Logarithm Algorithm", IEEE Signal | ||||||
|  | 			//     Processing Mag., pp. 124,140, Sep. 2010.) | ||||||
|  | 
 | ||||||
|  | 			long b = 1U << (FRACTIONAL_PLACES - 1); | ||||||
|  | 			long y = 0; | ||||||
|  | 
 | ||||||
|  | 			long rawX = x.RawValue; | ||||||
|  | 			while (rawX < ONE) | ||||||
|  | 			{ | ||||||
|  | 				rawX <<= 1; | ||||||
|  | 				y -= ONE; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			while (rawX >= (ONE << 1)) | ||||||
|  | 			{ | ||||||
|  | 				rawX >>= 1; | ||||||
|  | 				y += ONE; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			var z = new Fix64(rawX); | ||||||
|  | 
 | ||||||
|  | 			for (int i = 0; i < FRACTIONAL_PLACES; i++) | ||||||
|  | 			{ | ||||||
|  | 				z = FastMul(z, z); | ||||||
|  | 				if (z.RawValue >= (ONE << 1)) | ||||||
|  | 				{ | ||||||
|  | 					z = new Fix64(z.RawValue >> 1); | ||||||
|  | 					y += b; | ||||||
|  | 				} | ||||||
|  | 				b >>= 1; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return new Fix64(y); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public static Fix64 Pow(Fix64 b, Fix64 exp) | ||||||
|  | 		{ | ||||||
|  | 			if (b == One) | ||||||
|  | 			{ | ||||||
|  | 				return One; | ||||||
|  | 			} | ||||||
|  | 			if (exp.RawValue == 0) | ||||||
|  | 			{ | ||||||
|  | 				return One; | ||||||
|  | 			} | ||||||
|  | 			if (exp.RawValue == ONE) | ||||||
|  | 			{ | ||||||
|  | 				return b; | ||||||
|  | 			} | ||||||
|  | 			if (b.RawValue == 0) | ||||||
|  | 			{ | ||||||
|  | 				if (exp.RawValue < 0) | ||||||
|  | 				{ | ||||||
|  | 					throw new DivideByZeroException(); | ||||||
|  | 				} | ||||||
|  | 				return Zero; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			Fix64 log2 = Log2(b); | ||||||
|  | 			return Pow2(exp * log2); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		/// <summary> | 		/// <summary> | ||||||
| 		/// Returns the square root of the given Fix64 value. | 		/// Returns the square root of the given Fix64 value. | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue