@@ -326,25 +326,76 @@ library ABDKMath64x64 {
326326 * @return signed 64.64-bit fixed point number
327327 */
328328 function pow (int128 x , uint256 y ) internal pure returns (int128 ) {
329- uint256 absoluteResult;
330- bool negativeResult = false ;
331- if (x >= 0 ) {
332- absoluteResult = powu (uint256 (x) << 63 , y);
333- } else {
334- // We rely on overflow behavior here
335- absoluteResult = powu (uint256 (uint128 (- x)) << 63 , y);
336- negativeResult = y & 1 > 0 ;
337- }
329+ bool negative = x < 0 && y & 1 == 1 ;
338330
339- absoluteResult >>= 63 ;
331+ uint256 absX = uint128 (x < 0 ? - x : x);
332+ uint256 absResult;
333+ absResult = 0x100000000000000000000000000000000 ;
340334
341- if (negativeResult) {
342- require (absoluteResult <= 0x80000000000000000000000000000000 );
343- return - int128 (absoluteResult); // We rely on overflow behavior here
335+ if (absX <= 0x10000000000000000 ) {
336+ absX <<= 63 ;
337+ while (y != 0 ) {
338+ if (y & 0x1 != 0 ) {
339+ absResult = absResult * absX >> 127 ;
340+ }
341+ absX = absX * absX >> 127 ;
342+
343+ if (y & 0x2 != 0 ) {
344+ absResult = absResult * absX >> 127 ;
345+ }
346+ absX = absX * absX >> 127 ;
347+
348+ if (y & 0x4 != 0 ) {
349+ absResult = absResult * absX >> 127 ;
350+ }
351+ absX = absX * absX >> 127 ;
352+
353+ if (y & 0x8 != 0 ) {
354+ absResult = absResult * absX >> 127 ;
355+ }
356+ absX = absX * absX >> 127 ;
357+
358+ y >>= 4 ;
359+ }
360+
361+ absResult >>= 64 ;
344362 } else {
345- require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF );
346- return int128 (absoluteResult); // We rely on overflow behavior here
363+ uint256 absXShift = 63 ;
364+ if (absX < 0x1000000000000000000000000 ) { absX <<= 32 ; absXShift -= 32 ; }
365+ if (absX < 0x10000000000000000000000000000 ) { absX <<= 16 ; absXShift -= 16 ; }
366+ if (absX < 0x1000000000000000000000000000000 ) { absX <<= 8 ; absXShift -= 8 ; }
367+ if (absX < 0x10000000000000000000000000000000 ) { absX <<= 4 ; absXShift -= 4 ; }
368+ if (absX < 0x40000000000000000000000000000000 ) { absX <<= 2 ; absXShift -= 2 ; }
369+ if (absX < 0x80000000000000000000000000000000 ) { absX <<= 1 ; absXShift -= 1 ; }
370+
371+ uint256 resultShift = 0 ;
372+ while (y != 0 ) {
373+ require (absXShift < 64 );
374+
375+ if (y & 0x1 != 0 ) {
376+ absResult = absResult * absX >> 127 ;
377+ resultShift += absXShift;
378+ if (absResult > 0x100000000000000000000000000000000 ) {
379+ absResult >>= 1 ;
380+ resultShift += 1 ;
381+ }
382+ }
383+ absX = absX * absX >> 127 ;
384+ absXShift <<= 1 ;
385+ if (absX >= 0x100000000000000000000000000000000 ) {
386+ absX >>= 1 ;
387+ absXShift += 1 ;
388+ }
389+
390+ y >>= 1 ;
391+ }
392+
393+ require (resultShift < 64 );
394+ absResult >>= 64 - resultShift;
347395 }
396+ int256 result = negative ? - int256 (absResult) : int256 (absResult);
397+ require (result >= MIN_64x64 && result <= MAX_64x64);
398+ return int128 (result);
348399 }
349400
350401 /**
@@ -614,69 +665,6 @@ library ABDKMath64x64 {
614665 return uint128 (result);
615666 }
616667
617- /**
618- * Calculate x^y assuming 0^0 is 1, where x is unsigned 129.127 fixed point
619- * number and y is unsigned 256-bit integer number. Revert on overflow.
620- *
621- * @param x unsigned 129.127-bit fixed point number
622- * @param y uint256 value
623- * @return unsigned 129.127-bit fixed point number
624- */
625- function powu (uint256 x , uint256 y ) private pure returns (uint256 ) {
626- if (y == 0 ) return 0x80000000000000000000000000000000 ;
627- else if (x == 0 ) return 0 ;
628- else {
629- int256 msb = 0 ;
630- uint256 xc = x;
631- if (xc >= 0x100000000000000000000000000000000 ) { xc >>= 128 ; msb += 128 ; }
632- if (xc >= 0x10000000000000000 ) { xc >>= 64 ; msb += 64 ; }
633- if (xc >= 0x100000000 ) { xc >>= 32 ; msb += 32 ; }
634- if (xc >= 0x10000 ) { xc >>= 16 ; msb += 16 ; }
635- if (xc >= 0x100 ) { xc >>= 8 ; msb += 8 ; }
636- if (xc >= 0x10 ) { xc >>= 4 ; msb += 4 ; }
637- if (xc >= 0x4 ) { xc >>= 2 ; msb += 2 ; }
638- if (xc >= 0x2 ) msb += 1 ; // No need to shift xc anymore
639-
640- int256 xe = msb - 127 ;
641- if (xe > 0 ) x >>= uint256 (xe);
642- else x <<= uint256 (- xe);
643-
644- uint256 result = 0x80000000000000000000000000000000 ;
645- int256 re = 0 ;
646-
647- while (y > 0 ) {
648- if (y & 1 > 0 ) {
649- result = result * x;
650- y -= 1 ;
651- re += xe;
652- if (result >=
653- 0x8000000000000000000000000000000000000000000000000000000000000000 ) {
654- result >>= 128 ;
655- re += 1 ;
656- } else result >>= 127 ;
657- if (re < - 127 ) return 0 ; // Underflow
658- require (re < 128 ); // Overflow
659- } else {
660- x = x * x;
661- y >>= 1 ;
662- xe <<= 1 ;
663- if (x >=
664- 0x8000000000000000000000000000000000000000000000000000000000000000 ) {
665- x >>= 128 ;
666- xe += 1 ;
667- } else x >>= 127 ;
668- if (xe < - 127 ) return 0 ; // Underflow
669- require (xe < 128 ); // Overflow
670- }
671- }
672-
673- if (re > 0 ) result <<= uint256 (re);
674- else if (re < 0 ) result >>= uint256 (- re);
675-
676- return result;
677- }
678- }
679-
680668 /**
681669 * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
682670 * number.
0 commit comments