Skip to content

Commit 046d292

Browse files
authored
u256: log, log2 and sqrt impl (#5329) (#5565)
## Description simple changes that uses newton's method for sqrt and decomposition to `u64` for `log2` - `log` builds up on `log2` for `u256` This should fix #5329 Ping @SwayStar123 ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers.
1 parent 3406358 commit 046d292

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

sway-lib-std/src/math.sw

+76
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,24 @@ pub trait Root {
66
fn sqrt(self) -> Self;
77
}
88

9+
impl Root for u256 {
10+
// Integer square root using [Newton's Method](https://en.wikipedia.org/wiki/Integer_square_root#Algorithm_using_Newton's_method).
11+
fn sqrt(self) -> Self {
12+
let mut x0 = self >> 1;
13+
if x0 == 0 {
14+
return self;
15+
}
16+
let mut x1 = (x0 + self / x0) >> 1;
17+
18+
while x1 < x0 {
19+
x0 = x1;
20+
x1 = (x0 + self / x0) >> 1;
21+
}
22+
23+
x0
24+
}
25+
}
26+
927
impl Root for u64 {
1028
fn sqrt(self) -> Self {
1129
let index: u64 = 2;
@@ -193,15 +211,57 @@ impl BinaryLogarithm for u8 {
193211
}
194212
}
195213

214+
impl BinaryLogarithm for u256 {
215+
fn log2(self) -> Self {
216+
use ::assert::*;
217+
assert(self != 0);
218+
let (a, b, c, d) = asm(r1: self) {
219+
r1: (u64, u64, u64, u64)
220+
};
221+
if a != 0 {
222+
return a.log2().as_u256() + 0xc0u256;
223+
} else if b != 0 {
224+
return b.log2().as_u256() + 0x80u256;
225+
} else if c != 0 {
226+
return c.log2().as_u256() + 0x40u256;
227+
} else if d != 0 {
228+
return d.log2().as_u256();
229+
}
230+
self
231+
}
232+
}
233+
234+
impl Logarithm for u256 {
235+
fn log(self, base: Self) -> Self {
236+
let self_log2 = self.log2();
237+
let base_log2 = base.log2();
238+
self_log2 / base_log2
239+
}
240+
}
241+
196242
#[test]
197243
fn square_root_test_math_sw() {
198244
use ::assert::*;
199245

246+
let max_u256 = u256::max();
200247
let max_u64 = u64::max();
201248
let max_u32 = u32::max();
202249
let max_u16 = u16::max();
203250
let max_u8 = u8::max();
204251

252+
// u256
253+
assert(0x1u256.sqrt() == 1);
254+
assert(0x4u256.sqrt() == 2);
255+
assert(0x9u256.sqrt() == 3);
256+
assert(0x90u256.sqrt() == 12);
257+
assert(0x400u256.sqrt() == 32);
258+
assert(0x2386f26fc10000u256.sqrt() == 100000000);
259+
assert(0x0u256.sqrt() == 0);
260+
assert(0x2u256.sqrt() == 1);
261+
assert(0x5u256.sqrt() == 2);
262+
assert(0x3e8u256.sqrt() == 31);
263+
assert(max_u256.sqrt() == 0xffffffffffffffffffffffffffffffffu256);
264+
205265
// u64
206266
assert(1.sqrt() == 1);
207267
assert(4.sqrt() == 2);
@@ -383,11 +443,27 @@ fn exponentiation_test_math_sw() {
383443
fn logarithmic_test_math_sw() {
384444
use ::assert::*;
385445

446+
let max_u256 = u256::max();
386447
let max_u64 = u64::max();
387448
let max_u32 = u32::max();
388449
let max_u16 = u16::max();
389450
let max_u8 = u8::max();
390451

452+
// u256
453+
assert(0x2u256.log2() == 0x1u256);
454+
assert(0x401u256.log2() == 0xau256);
455+
assert(max_u256.log2() == 0xffu256);
456+
assert(0x2u256.log(0x2u256) == 0x1u256);
457+
assert(0x2u256.log2() == 0x1u256);
458+
assert(0x1u256.log(0x3u256) == 0);
459+
assert(0x8u256.log(0x2u256) == 0x3u256);
460+
assert(0x8u256.log2() == 0x3u256);
461+
assert(0x64u256.log(0xau256) == 0x2u256);
462+
assert(0x64u256.log(0x2u256) == 0x6u256);
463+
assert(0x64u256.log2() == 0x6u256);
464+
assert(0x64u256.log(0x9u256) == 0x2u256);
465+
assert(max_u256.log(0x2u256) == 0xffu256);
466+
391467
// u64
392468
assert(2.log(2) == 1);
393469
assert(2.log2() == 1);

0 commit comments

Comments
 (0)