Skip to content

Commit

Permalink
refactor uints
Browse files Browse the repository at this point in the history
  • Loading branch information
zielvna committed Apr 2, 2024
1 parent 0c1cdd3 commit 35dfe49
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 98 deletions.
106 changes: 45 additions & 61 deletions contracts/math/uints.ral
Original file line number Diff line number Diff line change
Expand Up @@ -37,67 +37,55 @@ Contract Uints () {
}
}

pub fn bigDiv(a: U512, divisor: U256, denominator: U256) -> U512 {
assert!(divisor > 0, ArithmeticErrors.NotPositiveDivisor)
pub fn div(a: U512, b: U256, bDenominator: U256, up: Bool) -> U512 {
assert!(b > 0, ArithmeticErrors.NotPositiveDivisor)

if (divisor == 1) {
if (b == 1) {
return a
}

// Calculate new higher
let newh = a.higher * denominator
let h = newh / divisor
let hr = newh % divisor
let newHigher = a.higher * bDenominator
let higher = newHigher / b
let higherRemainder = newHigher % b
// calculate higher remainder
let maxdiv = MaxU256 / divisor
let deltahr = hr * maxdiv
let maxDiv = MaxU256 / b
let deltaHigherRemainder = higherRemainder * maxDiv
// Calculate lower
let l = a.lower * denominator / divisor
let deltal = deltahr + l
let newLower = a.lower * bDenominator
let lower = newLower / b
let mut deltaLower = deltaHigherRemainder + lower

return U512 {
higher: h,
lower: deltal
if (up) {
let lowerRemainder = newLower % b

let higherDecimal = deltaHigherRemainder % b
if (higherDecimal + lowerRemainder != 0) {
deltaLower = deltaLower + 1
}
}
}

pub fn bigDivUp(a: U512, divisor: U256, denominator: U256) -> U512 {
assert!(divisor > 0, 0x02)
if (divisor == 1) {
return a
return U512 {
higher: higher,
lower: deltaLower
}
}

// Calculate new higher
let newh = a.higher * denominator
let h = newh / divisor
let hr = newh % divisor
// calculate higher remainder
let maxdiv = MaxU256 / divisor
let deltahr = hr * maxdiv
let hdecimal = deltahr % divisor
// Calculate lower
let newl = a.lower * denominator
let l = newl / divisor
let lr = newl % divisor
let mut deltaL = deltahr + l

if (hdecimal + lr != 0) {
deltaL = deltaL + 1
}
pub fn bigDiv(a: U512, b: U256, bDenominator: U256) -> U512 {
return div(a, b, bDenominator, false)
}

return U512 {
higher: h,
lower: deltaL
}
pub fn bigDivUp(a: U512, b: U256, bDenominator: U256) -> U512 {
return div(a, b, bDenominator, true)
}

pub fn bigAdd512(a: U512, b: U512) -> U512 {
let (r0, overflow) = overflowingAdd(a.lower, b.lower)
let r1 = wrappingAdd(wrappingAdd(a.higher, b.higher), overflow)
return U512 { higher: r1, lower: r0 }
let (aLowerBLower, overflow) = overflowingAdd(a.lower, b.lower)
let aHigherBHigherOverflow = wrappingAdd(wrappingAdd(a.higher, b.higher), overflow)
return U512 { lower: aLowerBLower, higher: aHigherBHigherOverflow }
}

pub fn bigMul(a: U256, b: U256, denominator: U256) -> U512 {
pub fn mul(a: U256, b: U256) -> U512 {
let aLower = low128(a)
let aHigher = high128(a)
let bLower = low128(b)
Expand All @@ -108,30 +96,26 @@ Contract Uints () {
let aHigherBLower = aHigher * bLower
let aLowerBHigher = aLower * bHigher

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)
let mut result = U512 { lower: aLowerBLower, higher: aHigherBHigher }
result = bigAdd512(result, U512 { lower: low128(aHigherBLower) << 128, higher: high128(aHigherBLower) })
result = bigAdd512(result, U512 { lower: low128(aLowerBHigher) << 128, higher: high128(aLowerBHigher) })

return result
}

pub fn bigMulUp(a: U256, b: U256, denominator: U256) -> U512 {
let aLower = low128(a)
let aHigher = high128(a)
let bLower = low128(b)
let bHigher = high128(b)
pub fn bigMul(a: U256, b: U256, bDenominator: U256) -> U512 {
let mut result = mul(a, b)

let aLowerBLower = aLower * bLower
let aHigherBHigher = aHigher * bHigher
let aHigherBLower = aHigher * bLower
let aLowerBHigher = aLower * bHigher
result = bigDiv(result, bDenominator, 1)

return result
}

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 })
pub fn bigMulUp(a: U256, b: U256, bDenominator: U256) -> U512 {
let mut result = mul(a, b)

result = bigAdd512(result, U512 { higher: 0, lower: denominator - 1 })
result = bigDiv(result, denominator, 1)
result = bigAdd512(result, U512 { higher: 0, lower: bDenominator - 1 })
result = bigDiv(result, bDenominator, 1)

return result
}
Expand All @@ -153,7 +137,7 @@ Contract Uints () {
}

pub fn low128(a: U256) -> U256 {
return a << 128 >> 128
return a & ((1 << 128) - 1)
}

pub fn high128(a: U256) -> U256 {
Expand Down
74 changes: 37 additions & 37 deletions test/uints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ describe('uints tests', () => {
higher: 21n,
lower: 37n
}
const divisor = 50n
const denominator = 10n
const b = 50n
const bDenominator = 10n
{
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, b, bDenominator } })).returns
// expected: 486326774796728020778998137036489212983733935595690368965721000000000000000000
// received: 486326774796728020778998137036489212983733935595690368965721852833235144487731
expect(result).toStrictEqual({
Expand All @@ -62,7 +62,7 @@ describe('uints tests', () => {
})
}
{
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, b, bDenominator } })).returns
expect(result).toStrictEqual({
higher: 4n,
lower: 23158417847463239084714197001737581570653996933128112807891516801582625927988n
Expand All @@ -74,10 +74,10 @@ describe('uints tests', () => {
higher: 50216813883093446110686315385661331328818843555712276103168n,
lower: 0n
}
const divisor = 2n
const denominator = 1n
const b = 2n
const bDenominator = 1n
{
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, b, bDenominator } })).returns
// expected: 2907354897182427562197295231552018137414565442749272241125960796722557152453591693304764202855054262243050086425064711734138406514458624n
// received: 2907354897182427562197295231552018137414565442749272241125960796722557152453591693304764202855054262243050086425064711734138406514458624n
expect(result).toStrictEqual({
Expand All @@ -86,7 +86,7 @@ describe('uints tests', () => {
})
}
{
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, b, bDenominator } })).returns
expect(result).toStrictEqual({
higher: 25108406941546723055343157692830665664409421777856138051584n,
lower: 0n
Expand All @@ -98,17 +98,17 @@ describe('uints tests', () => {
higher: 0n,
lower: 1n
}
const divisor = 2n
const denominator = 1n
const b = 2n
const bDenominator = 1n
{
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, b, bDenominator } })).returns
expect(result).toStrictEqual({
higher: 0n,
lower: 0n
})
}
{
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, b, bDenominator } })).returns
expect(result).toStrictEqual({
higher: 0n,
lower: 1n
Expand All @@ -120,17 +120,17 @@ describe('uints tests', () => {
higher: 0n,
lower: 10n
}
const divisor = 1n
const denominator = 1000n
const b = 1n
const bDenominator = 1000n
{
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, b, bDenominator } })).returns
expect(result).toStrictEqual({
higher: 0n,
lower: 10n
})
}
{
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, b, bDenominator } })).returns
expect(result).toStrictEqual({
higher: 0n,
lower: 10n
Expand All @@ -143,17 +143,17 @@ describe('uints tests', () => {
lower: 6n * 10n ** 1n
}

const divisor = 3n * 10n ** 3n
const denominator = 1000n
const b = 3n * 10n ** 3n
const bDenominator = 1000n
{
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDiv({ args: { a, b, bDenominator } })).returns
expect(result).toStrictEqual({
higher: 0n,
lower: 20n
})
}
{
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, divisor, denominator } })).returns
const result = (await uints.contractInstance.methods.bigDivUp({ args: { a, b, bDenominator } })).returns
expect(result).toStrictEqual({
higher: 0n,
lower: 20n
Expand Down Expand Up @@ -183,58 +183,58 @@ describe('uints tests', () => {
{
const a = 123n
const b = 2n
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, denominator: 1n } })).returns
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, bDenominator: 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.bigMul({ args: { a, b, denominator: 1n } })).returns
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, bDenominator: 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.bigMul({ args: { a, b, denominator: 1n } })).returns
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, bDenominator: 1n } })).returns
expect(result).toStrictEqual({
higher: 115792089237316195423570985008687907853269984665640564039457584007913129639934n,
lower: 680564733841876926926749214863536422909n
})
// expected: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370779510884422601683867654778417822746804225
// real: 13407807929942597099574024998205846127479365820592393377723561443721764030073315392623399665776056285720014482370780191449156443560794581527632686283227133
// real: 13407807929942597099574024998205846127400561808199604419303275337593318622627830165405570560473941536971227656459826923739673630877010000243176725695954945
}
{
const a = 500n
const b = 0n
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, denominator: 1n } })).returns
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, bDenominator: 1n } })).returns
expect(result).toStrictEqual({ higher: 0n, lower: 0n })
}
{
const a = 100n
const b = 100n
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, denominator: 100n } })).returns
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, bDenominator: 100n } })).returns
expect(result).toStrictEqual({ higher: 0n, lower: 100n })
}
{
const a = 30n
const b = 1n
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, denominator: 10n } })).returns
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, bDenominator: 10n } })).returns
expect(result).toStrictEqual({ higher: 0n, lower: 3n })
}
{
const a = 500n
const b = 4000n
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, denominator: 1000n } })).returns
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, bDenominator: 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
const result = (await uints.contractInstance.methods.bigMul({ args: { a, b, bDenominator: 100n } })).returns
expect(result).toStrictEqual({ higher: 0n, lower: 3n })
}
})
Expand All @@ -244,23 +244,23 @@ describe('uints tests', () => {
{
const a = 123n
const b = 2n
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 1n } })).returns
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, bDenominator: 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
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, bDenominator: 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
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, bDenominator: 1n } })).returns
expect(result).toStrictEqual({
higher: 115792089237316195423570985008687907853269984665640564039457584007913129639934n,
lower: 680564733841876926926749214863536422909n
Expand All @@ -271,31 +271,31 @@ describe('uints tests', () => {
{
const a = 500n
const b = 0n
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, denominator: 1n } })).returns
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, bDenominator: 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
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, bDenominator: 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
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, bDenominator: 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
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, bDenominator: 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
const result = (await uints.contractInstance.methods.bigMulUp({ args: { a, b, bDenominator: 100n } })).returns
expect(result).toStrictEqual({ higher: 0n, lower: 4n })
}
})
Expand Down

0 comments on commit 35dfe49

Please sign in to comment.