Skip to content

Commit

Permalink
feat(math): add exp3 taylor polynomial
Browse files Browse the repository at this point in the history
  • Loading branch information
Rubilmax committed Sep 28, 2023
1 parent 4ebeeaf commit 9226c98
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 15 deletions.
99 changes: 96 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ BigInt.from(WAD * 2n).rayMul(0.5e27); // WAD
- [wadSub](#wadSub)
- [wadAvg](#wadAvg)
- [wadPow](#wadPow)
- [wadPowUp](#wadPowUp)
- [wadPowDown](#wadPowDown)
- [wadExp3](#wadExp3)
- [wadMulUp](#wadMulUp)
- [wadMulDown](#wadMulDown)
- [wadDivUp](#wadDivUp)
Expand All @@ -80,6 +83,9 @@ BigInt.from(WAD * 2n).rayMul(0.5e27); // WAD
- [raySub](#raySub)
- [rayAvg](#rayAvg)
- [rayPow](#rayPow)
- [rayPowUp](#rayPowUp)
- [rayPowDown](#rayPowDown)
- [rayExp3](#rayExp3)
- [rayMulUp](#rayMulUp)
- [rayMulDown](#rayMulDown)
- [rayDivUp](#rayDivUp)
Expand All @@ -96,6 +102,9 @@ BigInt.from(WAD * 2n).rayMul(0.5e27); // WAD
- [percentSub](#percentSub)
- [percentAvg](#percentAvg)
- [percentPow](#percentPow)
- [percentPowUp](#percentPowUp)
- [percentPowDown](#percentPowDown)
- [percentExp3](#percentExp3)
- [percentMulUp](#percentMulUp)
- [percentMulDown](#percentMulDown)
- [percentDivUp](#percentDivUp)
Expand Down Expand Up @@ -392,6 +401,34 @@ BigInt.WAD *
.wadPow(2); // 2.0 ** 2 = 4.0 (in wad)
```

#### `wadPowUp`

Returns the integer power of a BigInt, calculated using wad-based multiplications (4 decimals precision), rounded up

```typescript
BigInt.PERCENT *
2n // 200% in wad
.wadPowUp(2); // 2.0 ** 2 = 4.0 (in wad)
```

#### `wadPowDown`

Returns the integer power of a BigInt, calculated using wad-based multiplications (4 decimals precision), rounded down

```typescript
BigInt.PERCENT *
2n // 200% in wad
.wadPowDown(2); // 2.0 ** 2 = 4.0 (in wad)
```

#### `wadExp3`

Returns the third order Taylor polynomial approximation of the integer exp of a BigInt, calculated using wad-based multiplications (4 decimals precision), rounded down

```typescript
BigInt.PERCENT.wadExp3(1); // ~exp(1.0 * 1) ~= exp (in wad)
```

#### `wadMulUp`

Returns the result of the wad-based multiplication (18 decimals precision), rounded up
Expand Down Expand Up @@ -526,6 +563,34 @@ Returns the integer power of a BigInt, calculated using ray-based multiplication
.rayPow(2); // 2.0 ** 2 = 4.0 (in ray)
```

#### `rayPowUp`

Returns the integer power of a BigInt, calculated using ray-based multiplications (4 decimals precision), rounded up

```typescript
BigInt.PERCENT *
2n // 200% in ray
.rayPowUp(2); // 2.0 ** 2 = 4.0 (in ray)
```

#### `rayPowDown`

Returns the integer power of a BigInt, calculated using ray-based multiplications (4 decimals precision), rounded down

```typescript
BigInt.PERCENT *
2n // 200% in ray
.rayPowDown(2); // 2.0 ** 2 = 4.0 (in ray)
```

#### `rayExp3`

Returns the third order Taylor polynomial approximation of the integer exp of a BigInt, calculated using ray-based multiplications (4 decimals precision), rounded down

```typescript
BigInt.PERCENT.rayExp3(1); // ~exp(1.0 * 1) ~= exp (in ray)
```

#### `rayMulUp`

Returns the result of the ray-based multiplication (27 decimals precision), rounded up
Expand Down Expand Up @@ -646,8 +711,8 @@ Returns the weighted average of 2 BigNumberishs, using a percent-based weight (4

```typescript
BigInt.PERCENT.percentAvg(
BigInt.PERCENT * 2n, // 2 PERCENT
BigInt.HALF_PERCENT, // 50% in PERCENT
BigInt.PERCENT * 2n, // 200% in percent
BigInt.HALF_PERCENT, // 50% in percent
); // 1.0 * (1.0 - 0.5) + 2.0 * 0.5 = 1.5 (in percent)
```

Expand All @@ -657,10 +722,38 @@ Returns the integer power of a BigInt, calculated using percent-based multiplica

```typescript
BigInt.PERCENT *
2n // 2 PERCENT
2n // 200% in percent
.percentPow(2); // 2.0 ** 2 = 4.0 (in percent)
```

#### `percentPowUp`

Returns the integer power of a BigInt, calculated using percent-based multiplications (4 decimals precision), rounded up

```typescript
BigInt.PERCENT *
2n // 200% in percent
.percentPowUp(2); // 2.0 ** 2 = 4.0 (in percent)
```

#### `percentPowDown`

Returns the integer power of a BigInt, calculated using percent-based multiplications (4 decimals precision), rounded down

```typescript
BigInt.PERCENT *
2n // 200% in percent
.percentPowDown(2); // 2.0 ** 2 = 4.0 (in percent)
```

#### `percentExp3`

Returns the third order Taylor polynomial approximation of the integer exp of a BigInt, calculated using percent-based multiplications (4 decimals precision), rounded down

```typescript
BigInt.PERCENT.percentExp3(1); // ~exp(1.0 * 1) ~= exp (in percent)
```

#### `percentMulUp`

Returns the result of the percent-based multiplication (4 decimals precision), rounded up
Expand Down
45 changes: 41 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import {
parsePercent,
parseRay,
parseWad,
powHalfUp,
pow,
mulDivUp,
mulDivDown,
approxEqAbs,
abs,
exp3,
} from "./utils";

declare global {
Expand Down Expand Up @@ -45,6 +46,9 @@ declare global {
percentDivDown: (other: BigNumberish) => bigint;
percentAvg: (other: BigNumberish, pct: BigNumberish) => bigint;
percentPow: (exponent: BigNumberish) => bigint;
percentPowUp: (exponent: BigNumberish) => bigint;
percentPowDown: (exponent: BigNumberish) => bigint;
percentExp3: (exponent: BigNumberish) => bigint;
percentToDecimals: (decimals: number) => bigint;
percentToWad: () => bigint;
percentToRay: () => bigint;
Expand All @@ -61,6 +65,9 @@ declare global {
wadDivDown: (other: BigNumberish) => bigint;
wadAvg: (other: BigNumberish, wad: BigNumberish) => bigint;
wadPow: (exponent: BigNumberish) => bigint;
wadPowUp: (exponent: BigNumberish) => bigint;
wadPowDown: (exponent: BigNumberish) => bigint;
wadExp3: (exponent: BigNumberish) => bigint;
wadToDecimals: (decimals: number) => bigint;
wadToPercent: () => bigint;
wadToRay: () => bigint;
Expand All @@ -77,6 +84,9 @@ declare global {
rayDivDown: (other: BigNumberish) => bigint;
rayAvg: (other: BigNumberish, ray: BigNumberish) => bigint;
rayPow: (exponent: BigNumberish) => bigint;
rayPowUp: (exponent: BigNumberish) => bigint;
rayPowDown: (exponent: BigNumberish) => bigint;
rayExp3: (exponent: BigNumberish) => bigint;
rayToDecimals: (decimals: number) => bigint;
rayToPercent: () => bigint;
rayToWad: () => bigint;
Expand Down Expand Up @@ -180,7 +190,16 @@ BigInt.prototype.percentAvg = function (other: BigNumberish, pct: BigNumberish)
return avgHalfUp(this as bigint, other, pct, PERCENT);
};
BigInt.prototype.percentPow = function (exponent: BigNumberish) {
return powHalfUp(this as bigint, exponent, PERCENT);
return pow(this as bigint, exponent, PERCENT, mulDivHalfUp);
};
BigInt.prototype.percentPowUp = function (exponent: BigNumberish) {
return pow(this as bigint, exponent, PERCENT, mulDivUp);
};
BigInt.prototype.percentPowDown = function (exponent: BigNumberish) {
return pow(this as bigint, exponent, PERCENT, mulDivDown);
};
BigInt.prototype.percentExp3 = function (exponent: BigNumberish) {
return exp3(this as bigint, exponent, PERCENT, mulDivDown);
};
BigInt.prototype.percentToDecimals = function (decimals: number) {
if (decimals <= 4) {
Expand Down Expand Up @@ -232,7 +251,16 @@ BigInt.prototype.wadAvg = function (other: BigNumberish, wad: BigNumberish) {
return avgHalfUp(this as bigint, other, wad, WAD);
};
BigInt.prototype.wadPow = function (exponent: BigNumberish) {
return powHalfUp(this as bigint, exponent, WAD);
return pow(this as bigint, exponent, WAD, mulDivHalfUp);
};
BigInt.prototype.wadPowUp = function (exponent: BigNumberish) {
return pow(this as bigint, exponent, WAD, mulDivUp);
};
BigInt.prototype.wadPowDown = function (exponent: BigNumberish) {
return pow(this as bigint, exponent, WAD, mulDivDown);
};
BigInt.prototype.wadExp3 = function (exponent: BigNumberish) {
return exp3(this as bigint, exponent, WAD, mulDivDown);
};
BigInt.prototype.wadToDecimals = function (decimals: number) {
if (decimals <= 18) {
Expand Down Expand Up @@ -284,7 +312,16 @@ BigInt.prototype.rayAvg = function (other: BigNumberish, ray: BigNumberish) {
return avgHalfUp(this as bigint, other, ray, RAY);
};
BigInt.prototype.rayPow = function (exponent: BigNumberish) {
return powHalfUp(this as bigint, exponent, RAY);
return pow(this as bigint, exponent, RAY, mulDivHalfUp);
};
BigInt.prototype.rayPowUp = function (exponent: BigNumberish) {
return pow(this as bigint, exponent, RAY, mulDivUp);
};
BigInt.prototype.rayPowDown = function (exponent: BigNumberish) {
return pow(this as bigint, exponent, RAY, mulDivDown);
};
BigInt.prototype.rayExp3 = function (exponent: BigNumberish) {
return exp3(this as bigint, exponent, RAY, mulDivDown);
};
BigInt.prototype.rayToDecimals = function (decimals: number) {
if (decimals <= 27) {
Expand Down
40 changes: 32 additions & 8 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { BigNumberish, parseUnits, toBigInt } from "ethers";

export type MulDiv = (x: BigNumberish, y: BigNumberish, scale: BigNumberish) => bigint;

export const pow10 = (power: BigNumberish) => toBigInt(10) ** toBigInt(power);

export const approxEqAbs = (x: BigNumberish, y: BigNumberish, tolerance: BigNumberish = 0) => {
Expand Down Expand Up @@ -40,7 +42,7 @@ export const sum = (initialValue: BigNumberish, others: BigNumberish[]) => {
return others.reduce<bigint>((acc, val) => acc + toBigInt(val), toBigInt(initialValue));
};

export const mulDivHalfUp = (x: BigNumberish, y: BigNumberish, scale: BigNumberish) => {
export const mulDivHalfUp: MulDiv = (x, y, scale) => {
x = toBigInt(x);
y = toBigInt(y);
scale = toBigInt(scale);
Expand All @@ -49,7 +51,7 @@ export const mulDivHalfUp = (x: BigNumberish, y: BigNumberish, scale: BigNumberi
return (x * y + scale / 2n) / scale;
};

export const mulDivDown = (x: BigNumberish, y: BigNumberish, scale: BigNumberish) => {
export const mulDivDown: MulDiv = (x, y, scale) => {
x = toBigInt(x);
y = toBigInt(y);
scale = toBigInt(scale);
Expand All @@ -58,7 +60,7 @@ export const mulDivDown = (x: BigNumberish, y: BigNumberish, scale: BigNumberish
return (x * y) / scale;
};

export const mulDivUp = (x: BigNumberish, y: BigNumberish, scale: BigNumberish) => {
export const mulDivUp: MulDiv = (x, y, scale) => {
x = toBigInt(x);
y = toBigInt(y);
scale = toBigInt(scale);
Expand All @@ -71,7 +73,7 @@ export const avgHalfUp = (
x: BigNumberish,
y: BigNumberish,
pct: BigNumberish,
scale: BigNumberish
scale: BigNumberish,
) => {
x = toBigInt(x);
y = toBigInt(y);
Expand All @@ -85,14 +87,36 @@ export const parsePercent = (value: string) => parseUnits(value, 2);
export const parseWad = (value: string) => parseUnits(value, 18);
export const parseRay = (value: string) => parseUnits(value, 27);

export const powHalfUp = (x: BigNumberish, exponent: BigNumberish, scale: bigint): bigint => {
export const pow = (
x: BigNumberish,
exponent: BigNumberish,
scale: bigint,
mulDiv: MulDiv = mulDivHalfUp,
): bigint => {
exponent = toBigInt(exponent);

if (exponent === 0n) return toBigInt(scale);
if (exponent === 1n) return toBigInt(x);

const xSquared = mulDivHalfUp(x, x, scale);
if (exponent % 2n === 0n) return powHalfUp(xSquared, exponent / 2n, scale);
const xSquared = mulDiv(x, x, scale);
if (exponent % 2n === 0n) return pow(xSquared, exponent / 2n, scale, mulDiv);

return mulDiv(x, pow(xSquared, (exponent - 1n) / 2n, scale, mulDiv), scale);
};

export const exp3 = (
x: BigNumberish,
exponent: BigNumberish,
scale: BigNumberish,
mulDiv: MulDiv = mulDivDown,
) => {
x = toBigInt(x);
exponent = toBigInt(exponent);
scale = toBigInt(scale);

const firstTerm = x * exponent;
const secondTerm = mulDiv(firstTerm, firstTerm, 2n * scale);
const thirdTerm = mulDiv(secondTerm, firstTerm, 3n * scale);

return mulDivHalfUp(x, powHalfUp(xSquared, (exponent - 1n) / 2n, scale), scale);
return scale + firstTerm + secondTerm + thirdTerm;
};

0 comments on commit 9226c98

Please sign in to comment.