diff --git a/contracts/math/uints.ral b/contracts/math/uints.ral index c92624a..26cd972 100644 --- a/contracts/math/uints.ral +++ b/contracts/math/uints.ral @@ -103,13 +103,13 @@ Contract Uints () { let bLower = low128(b) let bHigher = high128(b) - let rLowerLower = aLower * bLower - let rHigherHigher = aHigher * bHigher - let rHigherLower = aHigher * bLower - let rLowerHigher = aLower * bHigher + let aLowerBLower = aLower * bLower + let aHigherBHigher = aHigher * bHigher + let aHigherBLower = aHigher * bLower + let aLowerBHigher = aLower * bHigher - let mut result = bigAdd512(U512 { higher: rHigherHigher, lower: rLowerLower }, U512 { higher: high128(rHigherLower), lower: low128(rHigherLower) << 128 }) - result = bigAdd512(result, U512 { higher: high128(rLowerHigher), lower: low128(rLowerHigher) << 128 }) + let mut result = bigAdd512(U512 { higher: aHigherBHigher, lower: aLowerBLower }, U512 { higher: high128(aHigherBLower), lower: low128(aHigherBLower) << 128 }) + result = bigAdd512(result, U512 { higher: high128(aLowerBHigher), lower: low128(aLowerBHigher) << 128 }) result = bigDiv(result, denominator, 1) @@ -117,40 +117,38 @@ Contract Uints () { } pub fn bigMulUp(a: U256, b: U256, denominator: U256) -> U512 { - let a0 = low128(a) - let a1 = high128(a) - let b0 = low128(b) - let b1 = high128(b) + let aLower = low128(a) + let aHigher = high128(a) + let bLower = low128(b) + let bHigher = high128(b) - let r0 = a0 * b0 - let r1 = a1 * b1 - let r2 = a1 * b0 - let r3 = a0 * b1 + let aLowerBLower = aLower * bLower + let aHigherBHigher = aHigher * bHigher + let aHigherBLower = aHigher * bLower + let aLowerBHigher = aLower * bHigher - let mut result = bigAdd512(U512 { higher: r1, lower: r0 }, U512 { higher: high128(r2), lower: low128(r2) << 128 }) - result = bigAdd512(result, U512 { higher: high128(r3), lower: low128(r3) << 128 }) + let mut result = bigAdd512(U512 { higher: aHigherBHigher, lower: aLowerBLower }, U512 { higher: high128(aHigherBLower), lower: low128(aHigherBLower) << 128 }) + result = bigAdd512(result, U512 { higher: high128(aLowerBHigher), lower: low128(aLowerBHigher) << 128 }) - result = bigAdd512(result, U512 { higher: 0, lower: 10 ** denominator - 1 }) + result = bigAdd512(result, U512 { higher: 0, lower: denominator - 1 }) result = bigDiv(result, denominator, 1) return result } pub fn overflowingAdd(a: U256, b: U256) -> (U256, U256) { - if (u256Max!() - a >= b) { + if (MaxU256 - a >= b) { return a + b, 0 } else { - return b + (u256Max!() - a) - 1, 1 + return b + (MaxU256 - a) - 1, 1 } } pub fn wrappingAdd(a: U256, b: U256) -> U256 { - let u256Max = u256Max!() - - if (u256Max - a >= b) { + if (MaxU256 - a >= b) { return a + b } else { - return b + (u256Max - a) - 1 + return b + (MaxU256 - a) - 1 } } diff --git a/test/uints.test.ts b/test/uints.test.ts index 8847aa4..261c96f 100644 --- a/test/uints.test.ts +++ b/test/uints.test.ts @@ -231,6 +231,73 @@ describe('uints tests', () => { const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, denominator: 1000n } })).returns expect(result).toStrictEqual({ higher: 0n, lower: 2000n }) } + { + const a = 10n + const b = 37n + const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, denominator: 100n } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 3n }) + } + }) + + test('big mul up', async () => { + const uints = await deployUints(sender) + { + const a = 123n + const b = 2n + const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 1n } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 246n }) + // expected: 246 + // real: 246 + } + { + const a = 340282366920938463463374607431768211457n + const b = 340282366920938463463374607431768211457n + const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 1n } })).returns + expect(result).toStrictEqual({ higher: 1n, lower: 680564733841876926926749214863536422913n }) + // expected: 115792089237316195423570985008687907853950549399482440966384333222776666062849 + // real: 115792089237316195423570985008687907853950549399482440966384333222776666062849 + } + { + const a = 115792089237316195423570985008687907853269984665640564039457584007913129639935n + const b = 115792089237316195423570985008687907853269984665640564039457584007913129639935n + const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 1n } })).returns + expect(result).toStrictEqual({ + higher: 115792089237316195423570985008687907853269984665640564039457584007913129639934n, + lower: 680564733841876926926749214863536422909n + }) + // expected: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370779510884422601683867654778417822746804225 + // real: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370780191449156443560794581527632686283227133 + } + { + const a = 500n + const b = 0n + const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 1n } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 0n }) + } + { + const a = 100n + const b = 100n + const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 100n } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 100n }) + } + { + const a = 30n + const b = 1n + const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 10n } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 3n }) + } + { + const a = 500n + const b = 4000n + const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 1000n } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 2000n }) + } + { + const a = 10n + const b = 37n + const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 100n } })).returns + expect(result).toStrictEqual({ higher: 0n, lower: 4n }) + } }) test('overflowing add', async () => {