@@ -67,6 +67,78 @@ public static partial class FixedMath
6767 internal const double SIN_COEFF_7_DOUBLE = 0.00019588856957852840423583984375d ; // 1/7!
6868 internal static readonly long SIN_COEFF_7_LONG = ( long ) ( SIN_COEFF_7_DOUBLE * ONE_L ) ;
6969
70+ private static readonly long [ ] s_pow2PositiveFractionLookup =
71+ {
72+ 6074001000L ,
73+ 5107605667L ,
74+ 4683695048L ,
75+ 4485121744L ,
76+ 4389014833L ,
77+ 4341736423L ,
78+ 4318288544L ,
79+ 4306612134L ,
80+ 4300785774L ,
81+ 4297875550L ,
82+ 4296421177L ,
83+ 4295694175L ,
84+ 4295330720L ,
85+ 4295149004L ,
86+ 4295058149L ,
87+ 4295012722L ,
88+ 4294990009L ,
89+ 4294978653L ,
90+ 4294972974L ,
91+ 4294970135L ,
92+ 4294968716L ,
93+ 4294968006L ,
94+ 4294967651L ,
95+ 4294967473L ,
96+ 4294967385L ,
97+ 4294967340L ,
98+ 4294967318L ,
99+ 4294967307L ,
100+ 4294967302L ,
101+ 4294967299L ,
102+ 4294967297L ,
103+ 4294967297L
104+ } ;
105+
106+ private static readonly long [ ] s_pow2NegativeFractionLookup =
107+ {
108+ 3037000500L ,
109+ 3611622603L ,
110+ 3938502376L ,
111+ 4112874773L ,
112+ 4202935003L ,
113+ 4248701965L ,
114+ 4271771996L ,
115+ 4283353945L ,
116+ 4289156690L ,
117+ 4292061010L ,
118+ 4293513907L ,
119+ 4294240540L ,
120+ 4294603903L ,
121+ 4294785595L ,
122+ 4294876445L ,
123+ 4294921870L ,
124+ 4294944583L ,
125+ 4294955939L ,
126+ 4294961618L ,
127+ 4294964457L ,
128+ 4294965876L ,
129+ 4294966586L ,
130+ 4294966941L ,
131+ 4294967119L ,
132+ 4294967207L ,
133+ 4294967252L ,
134+ 4294967274L ,
135+ 4294967285L ,
136+ 4294967290L ,
137+ 4294967293L ,
138+ 4294967295L ,
139+ 4294967295L
140+ } ;
141+
70142 #endregion
71143
72144 #region FixedTrigonometry Operations
@@ -110,40 +182,34 @@ public static Fixed64 Pow2(Fixed64 x)
110182 if ( x . m_rawValue == 0 )
111183 return Fixed64 . One ;
112184
113- // Handle negative expFixed64.Onents by using the reciprocal
114185 bool neg = x . m_rawValue < 0 ;
115186 if ( neg )
116187 x = - x ;
117188
118189 if ( x == Fixed64 . One )
119190 return neg ? Fixed64 . One / Fixed64 . Two : Fixed64 . Two ;
120191
121- if ( x >= Fixed64 . Log2Max )
122- return neg ? Fixed64 . One / new Fixed64 ( MAX_VALUE_L ) : new Fixed64 ( MAX_VALUE_L ) ;
123-
124- /*
125- * Taylor series expansion for exp(x)
126- * From term n, we get term n+1 by multiplying with x/n.
127- * When the sum term drops to Fixed64.Zero, we can stop summing.
128- */
129- int integerPart = Fixed64 . RawToInt ( Floor ( x ) ) ;
130- x = Fixed64 . FromRaw ( x . m_rawValue & MAX_SHIFTED_AMOUNT_UI ) ; // Fractional part
131-
132- var result = Fixed64 . One ;
133- var term = Fixed64 . One ;
134- int i = 1 ;
135- while ( term . m_rawValue != 0 )
192+ int integerPart = ( int ) ( x . m_rawValue >> SHIFT_AMOUNT_I ) ;
193+ long fractionalRaw = x . m_rawValue & MAX_SHIFTED_AMOUNT_UI ;
194+
195+ if ( neg )
136196 {
137- term = FastMul ( FastMul ( x , term ) , Fixed64 . Ln2 ) / ( Fixed64 ) i ;
138- result += term ;
139- i ++ ;
197+ if ( integerPart >= SHIFT_AMOUNT_I )
198+ return Fixed64 . MinIncrement ;
199+
200+ Fixed64 result = Pow2Fractional ( fractionalRaw , s_pow2NegativeFractionLookup ) ;
201+ return Fixed64 . FromRaw ( ShiftRightRounded ( result . m_rawValue , integerPart ) ) ;
140202 }
141203
142- result = Fixed64 . FromRaw ( result . m_rawValue << integerPart ) ;
143- if ( neg )
144- result = Fixed64 . One / result ;
204+ if ( integerPart >= 31 )
205+ return Fixed64 . MaxValue ;
145206
146- return result ;
207+ Fixed64 positiveResult = Pow2Fractional ( fractionalRaw , s_pow2PositiveFractionLookup ) ;
208+ long shifted = positiveResult . m_rawValue << integerPart ;
209+
210+ return shifted < 0
211+ ? Fixed64 . MaxValue
212+ : Fixed64 . FromRaw ( shifted ) ;
147213 }
148214
149215 /// <summary>
@@ -160,21 +226,14 @@ public static Fixed64 Log2(Fixed64 x)
160226 throw new ArgumentOutOfRangeException ( nameof ( x ) , "Cannot compute logarithm of non-positive number." ) ;
161227
162228 long b = 1U << ( SHIFT_AMOUNT_I - 1 ) ; // Initial value for binary logarithm
163- long y = 0 ; // Result accumulator
164229 long rawX = x . m_rawValue ;
230+ int shift = FloorLog2 ( ( ulong ) rawX ) - SHIFT_AMOUNT_I ;
231+ long y = ( long ) shift << SHIFT_AMOUNT_I ;
165232
166- // Adjust rawX to the correct range [1, 2)
167- while ( rawX < ONE_L )
168- {
169- rawX <<= 1 ;
170- y -= ONE_L ;
171- }
172-
173- while ( rawX >= ( ONE_L << 1 ) )
174- {
175- rawX >>= 1 ;
176- y += ONE_L ;
177- }
233+ if ( shift > 0 )
234+ rawX >>= shift ;
235+ else if ( shift < 0 )
236+ rawX <<= - shift ;
178237
179238 Fixed64 z = Fixed64 . FromRaw ( rawX ) ; // Remaining fraction
180239
@@ -201,7 +260,75 @@ public static Fixed64 Ln(Fixed64 x)
201260 if ( x . m_rawValue <= 0 )
202261 throw new ArgumentOutOfRangeException ( nameof ( x ) , "Cannot compute logarithm of non-positive number." ) ;
203262
204- return FastMul ( Log2 ( x ) , Fixed64 . Ln2 ) . Round ( ) ;
263+ return FastMul ( Log2 ( x ) , Fixed64 . Ln2 ) ;
264+ }
265+
266+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
267+ private static Fixed64 Pow2Fractional ( long fractionalRaw , long [ ] lookup )
268+ {
269+ Fixed64 result = Fixed64 . One ;
270+ long mask = 1L << ( SHIFT_AMOUNT_I - 1 ) ;
271+
272+ for ( int i = 0 ; i < SHIFT_AMOUNT_I ; i ++ )
273+ {
274+ if ( ( fractionalRaw & mask ) != 0 )
275+ result = FastMul ( result , Fixed64 . FromRaw ( lookup [ i ] ) ) ;
276+
277+ mask >>= 1 ;
278+ }
279+
280+ return result ;
281+ }
282+
283+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
284+ private static long ShiftRightRounded ( long value , int shift )
285+ {
286+ if ( shift == 0 )
287+ return value ;
288+
289+ long half = 1L << ( shift - 1 ) ;
290+ return ( value + half ) >> shift ;
291+ }
292+
293+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
294+ private static int FloorLog2 ( ulong value )
295+ {
296+ int result = 0 ;
297+
298+ if ( value >= 1UL << 32 )
299+ {
300+ value >>= 32 ;
301+ result = 32 ;
302+ }
303+
304+ if ( value >= 1UL << 16 )
305+ {
306+ value >>= 16 ;
307+ result += 16 ;
308+ }
309+
310+ if ( value >= 1UL << 8 )
311+ {
312+ value >>= 8 ;
313+ result += 8 ;
314+ }
315+
316+ if ( value >= 1UL << 4 )
317+ {
318+ value >>= 4 ;
319+ result += 4 ;
320+ }
321+
322+ if ( value >= 1UL << 2 )
323+ {
324+ value >>= 2 ;
325+ result += 2 ;
326+ }
327+
328+ if ( value >= 1UL << 1 )
329+ result ++ ;
330+
331+ return result ;
205332 }
206333
207334 /// <summary>
0 commit comments