arithm.ha (2255B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 // The following code was initially ported from BearSSL. 5 // 6 // Copyright (c) 2017 Thomas Pornin <pornin@bolet.org> 7 // 8 // Permission is hereby granted, free of charge, to any person obtaining a copy 9 // of this software and associated documentation files (the "Software"), to deal 10 // in the Software without restriction, including without limitation the rights 11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 // copies of the Software, and to permit persons to whom the Software is 13 // furnished to do so, subject to the following conditions: 14 // 15 // The above copyright notice and this permission notice shall be included in 16 // all copies or substantial portions of the Software. 17 // 18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 // SOFTWARE. 25 26 // Returns the quotient and remainder of (hi, lo) divided by y: 27 // quo = (hi, lo) / y, rem = (hi, lo) % y with the dividend bits' upper 28 // half in parameter hi and the lower half in parameter lo. 29 // Panics for y == 0 (division by zero) or y <= hi (quotient overflow). 30 export fn divu32(hi: u32, lo: u32, y: u32) (u32, u32) = { 31 assert(y != 0); 32 assert(y > hi); 33 34 let q: u32 = 0; 35 const ch: u32 = equ32(hi, y); 36 hi = muxu32(ch, 0, hi); 37 for (let k: u32 = 31; k > 0; k -= 1) { 38 const j = (32 - k); 39 const w = (hi << j) | (lo >> k); 40 const ctl = geu32(w, y) | (hi >> k); 41 const hi2 = (w - y) >> j; 42 const lo2 = lo - (y << k); 43 hi = muxu32(ctl, hi2, hi); 44 lo = muxu32(ctl, lo2, lo); 45 q |= ctl << k; 46 }; 47 let cf = geu32(lo, y) | hi; 48 q |= cf; 49 const r = muxu32(cf, lo - y, lo); 50 return (q, r); 51 }; 52 53 @test fn divu32() void = { 54 const r = divu32(1, 4294967295, 9); 55 assert(r.0 == 954437176); 56 assert(r.1 == 7); 57 58 const r = divu32(0, 485, 13); 59 assert(r.0 == 37); 60 assert(r.1 == 4); 61 };