Skip to content

Commit 0445edf

Browse files
committed
The pow function optimized
1 parent 16d7e1d commit 0445edf

File tree

1 file changed

+66
-78
lines changed

1 file changed

+66
-78
lines changed

ABDKMath64x64.sol

Lines changed: 66 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)