Fixed a bug in the nth root that affects speed of computation. Also started playing with retaining decimal places of root computation

This commit is contained in:
Greg Hysen
2019-06-05 23:57:48 -07:00
parent 8dd74bcf82
commit 202dcfb4c5
3 changed files with 50 additions and 14 deletions

View File

@@ -30,26 +30,27 @@ library LibMath {
///// See https://en.wikipedia.org/wiki/Nth_root#nth_root_algorithm
// 1. Find greatest power-of-2 <= `value`
let nearestPowerOf2 := 0x80000000000000000000000000000000
let nearestPowerOf2 := 0x100000000000000000000000000000000
let m := 128
for {let p := 64}
gt(p, 0)
{ p := div(p, 2) }
{
switch gt(nearestPowerOf2, base)
case 1 {
nearestPowerOf2 := shr(p, nearestPowerOf2)
m := sub(m, p)
}
case 0 {
switch lt(nearestPowerOf2, base)
case 0 {
p := 0
}
case 1 {
nearestPowerOf2 := shl(p, nearestPowerOf2)
m := add(m, p)
}
}
case 1 {
nearestPowerOf2 := shr(p, nearestPowerOf2)
m := sub(m, p)
case 0 {
p := 0
}
}
}
if gt(nearestPowerOf2, base) {
@@ -57,21 +58,32 @@ library LibMath {
m := sub(m, 1)
}
// 2. Find greatest power-of-2 that, when raised to the power of `n`,
// is <= `value`
let x := exp(2, div(m, n))
// 3. Find y such that `x` + `y` = `value`
let y := xor(base, exp(2, mul(div(m, n), n)))
// 3. Find y such that `x` + `y` = `base`
let y := sub(base, exp2(x, n))
// 4. Run Newton's Approximation to approximate the root
root := add(x, div(y, mul(n, exp(2, mul(div(m, n), sub(n, 1))))))
let denominator := mul(n, exp2(x, sub(n, 1)))
// -- playing with turning root into fixed point to retain decimals --
//let numerator := y
//let fixedPointScaleFactor := exp2(10, 18)
//let fixedPointNumerator := mul(y, fixedPointScaleFactor)
//let fixedPointX := mul(x, fixedPointScaleFactor)
//let fixedPointRoot := add(fixedPointX, div(fixedPointNumerator, denominator))
root := add(x, div(y, denominator))
// 5. Run Newton's nth Root Algorithm
let delta := 1 // run at least once
for {let i := 0}
and(lt(i, 20), gt(delta, 0))
{i := add(i,1)}
for {}
gt(delta, 0)
{}
{
// compute lhs
let lhsDenominator := exp2(root, sub(n, 1))

View File

@@ -551,6 +551,7 @@ describe('Staking Core', () => {
it('nth root #3 with fixed point (integer nth root would fail here)', async () => {
const decimals = 18;
const base = stakingWrapper.toFixedPoint(5429503678976, decimals);
console.log(base);
const n = new BigNumber(9);
const decimalsAsBn = new BigNumber(decimals);
const root = await stakingWrapper.nthRootFixedPoint(base, n, decimalsAsBn);
@@ -559,6 +560,19 @@ describe('Staking Core', () => {
expect(rootAsFloatingPoint).to.be.bignumber.equal(expectedResult);
});
it.skip('nth root #4 with fixed point (integer nth root would fail here) (max number of decimals - currently does not retain)', async () => {
const decimals = 18;
const base = stakingWrapper.toFixedPoint(new BigNumber('5429503678976.295036789761543678', 10), decimals);
console.log(base);
const n = new BigNumber(9);
const decimalsAsBn = new BigNumber(decimals);
const root = await stakingWrapper.nthRootFixedPoint(base, n, decimalsAsBn);
console.log(`root - ${root}`);
const rootAsFloatingPoint = stakingWrapper.toFloatingPoint(root, decimals);
const expectedResult = new BigNumber(26);
expect(rootAsFloatingPoint).to.be.bignumber.equal(expectedResult);
});
it('cobb douglas - approximate', async() => {
const totalRewards = stakingWrapper.toBaseUnitAmount(57.154398);
const ownerFees = stakingWrapper.toBaseUnitAmount(5.64375);

View File

@@ -330,6 +330,7 @@ export class StakingWrapper {
return balance;
}
public async nthRoot(value: BigNumber, n: BigNumber): Promise<BigNumber> {
//const txReceipt = await this.getLibMathTestContract().nthRoot.await(value, n);
const output = await this.getLibMathTestContract().nthRoot.callAsync(value, n);
return output;
}
@@ -365,6 +366,15 @@ export class StakingWrapper {
totalStake: BigNumber,
alphaDenominator: BigNumber
) {
const txReceipt = await this.getLibMathTestContract().cobbDouglasSimplifiedInverse.awaitTransactionSuccessAsync(
totalRewards,
ownerFees,
totalFees,
ownerStake,
totalStake,
alphaDenominator
);
console.log(`Gas Used: ${txReceipt.gasUsed}`);
const output = await this.getLibMathTestContract().cobbDouglasSimplified.callAsync(
totalRewards,
ownerFees,