fixed

Pure Haskell large fixed-width integers.
git clone git://git.ppad.tech/fixed.git
Log | Files | Refs | README | LICENSE

commit 568440d7d884e1ed680d3a8ebdd4bd18a2f5edcb
parent 5528a92eec3314ed8d287223e137382db9002c61
Author: Jared Tobin <jared@jtobin.io>
Date:   Thu, 23 Jan 2025 23:18:12 +0400

lib: clean up remainder handling

Diffstat:
Mlib/Data/Word/Extended.hs | 71++++++++++++++++++++++++++++++++++-------------------------------------
Mtest/Main.hs | 31++++++++++++++-----------------
2 files changed, 48 insertions(+), 54 deletions(-)

diff --git a/lib/Data/Word/Extended.hs b/lib/Data/Word/Extended.hs @@ -487,9 +487,8 @@ quotrem => PA.MutablePrimArray (PrimState m) Word64 -> PA.PrimArray Word64 -> PA.PrimArray Word64 - -> Maybe (PA.MutablePrimArray (PrimState m) Word64) - -> m () -quotrem quo u d mr = do + -> m Word256 +quotrem quo u d = do let !ld = PA.sizeofPrimArray d !lu = PA.sizeofPrimArray u !dlen = len_loop d (ld - 1) @@ -508,9 +507,16 @@ quotrem quo u d mr = do PA.writePrimArray dn 0 (PA.indexPrimArray d 0 .<<. shift) let !ulen = len_loop u (lu - 1) if ulen < dlen - then case mr of - Nothing -> pure () - Just !r -> PA.copyPrimArray r 0 u 0 lu + then do + let !u0 | lu >= 1 = PA.indexPrimArray u 0 + | otherwise = 0 + !u1 | lu >= 2 = PA.indexPrimArray u 1 + | otherwise = 0 + !u2 | lu >= 3 = PA.indexPrimArray u 2 + | otherwise = 0 + !u3 | lu >= 4 = PA.indexPrimArray u 3 + | otherwise = 0 + pure (Word256 u0 u1 u2 u3) else do un <- PA.newPrimArray (ulen + 1) PA.setPrimArray un 0 (ulen + 1) 0 @@ -532,37 +538,35 @@ quotrem quo u d mr = do dn_0 <- PA.readPrimArray dn 0 un_c <- PA.freezePrimArray un 0 (ulen + 1) r <- quotrem_by1 quo un_c dn_0 - case mr of - Nothing -> pure () - Just !re -> do - PA.writePrimArray re 0 (r .>>. shift) - PA.writePrimArray re 1 0 - PA.writePrimArray re 2 0 - PA.writePrimArray re 3 0 + pure (Word256 (r .>>. shift) 0 0 0) else do dnf <- PA.unsafeFreezePrimArray dn quotrem_knuth quo un dnf - case mr of - Nothing -> pure () - Just !r -> do - let go_r !j - | j == dlen = pure () - | otherwise = do - un_j <- PA.readPrimArray un j - un_j_1 <- PA.readPrimArray un (j + 1) - let !val = (un_j .>>. shift) - .|. (un_j_1 .<<. (64 - shift)) - PA.writePrimArray r j val - go_r (succ j) - go_r 0 - un_dlen_1 <- PA.readPrimArray un (dlen - 1) - PA.writePrimArray r (dlen - 1) (un_dlen_1 .>>. shift) + let go_r !j !acc + | j == dlen = pure acc + | otherwise = do + un_j <- PA.readPrimArray un j + un_j_1 <- PA.readPrimArray un (j + 1) + let !val = (un_j .>>. shift) + .|. (un_j_1 .<<. (64 - shift)) + !nacc = setr acc j val + go_r (succ j) nacc + !r <- go_r 0 zero + un_dlen_1 <- PA.readPrimArray un (dlen - 1) + pure (setr r (dlen - 1) (un_dlen_1 .>>. shift)) where len_loop !arr !j | j < 0 = 0 | PA.indexPrimArray arr j /= 0 = j + 1 | otherwise = len_loop arr (pred j) + setr w@(Word256 z0 z1 z2 z3) j val + | j == 0 = Word256 val z1 z2 z3 + | j == 1 = Word256 z0 val z2 z3 + | j == 2 = Word256 z0 z1 val z3 + | j == 3 = Word256 z0 z1 z2 val + | otherwise = w + -- primarray div :: Word256 -> Word256 -> Word256 div a@(Word256 a0 a1 a2 a3) b@(Word256 b0 b1 b2 b3) @@ -584,7 +588,7 @@ div a@(Word256 a0 a1 a2 a3) b@(Word256 b0 b1 b2 b3) PA.writePrimArray my 3 b3 x <- PA.unsafeFreezePrimArray mx y <- PA.unsafeFreezePrimArray my - quotrem quo x y Nothing + _ <- quotrem quo x y z0 <- PA.readPrimArray quo 0 z1 <- PA.readPrimArray quo 1 z2 <- PA.readPrimArray quo 2 @@ -612,12 +616,5 @@ mod a@(Word256 a0 a1 a2 a3) b@(Word256 b0 b1 b2 b3) PA.writePrimArray my 3 b3 x <- PA.unsafeFreezePrimArray mx y <- PA.unsafeFreezePrimArray my - re <- PA.newPrimArray 4 - PA.setPrimArray re 0 4 0 - quotrem quo x y (Just re) - z0 <- PA.readPrimArray re 0 - z1 <- PA.readPrimArray re 1 - z2 <- PA.readPrimArray re 2 - z3 <- PA.readPrimArray re 3 - pure (Word256 z0 z1 z2 z3) + quotrem quo x y diff --git a/test/Main.hs b/test/Main.hs @@ -248,20 +248,20 @@ quotrem_case0 :: H.Assertion quotrem_case0 = do let (q, r) = runST $ do quo <- PA.newPrimArray 5 - PA.setPrimArray quo 0 5 0 + PA.setPrimArray quo 0 5 (0 :: Word64) let !u = PA.primArrayFromList [0x1234567890ABCDEF, 0xFEDCBA0987654321, 0x123456789ABCDEF0] !d = PA.primArrayFromList [0x0, 0x0, 0x1, 0x100000000] - re <- PA.newPrimArray 4 - PA.setPrimArray re 0 4 0 - quotrem quo u d (Just re) + rf <- quotrem quo u d qf <- PA.unsafeFreezePrimArray quo - rf <- PA.unsafeFreezePrimArray re pure (qf, rf) let pec_q = PA.primArrayFromList [0, 0, 0, 0, 0] - pec_r = PA.primArrayFromList - [1311768467294899695, 18364757930599072545, 1311768467463790320, 0] + pec_r = Word256 + 1311768467294899695 + 18364757930599072545 + 1311768467463790320 + 0 H.assertEqual "remainder matches" pec_r r H.assertEqual "quotient matches" pec_q q @@ -283,19 +283,16 @@ quotrem_case1 = do , 3741537094902495500 ] - re <- PA.newPrimArray 4 - PA.setPrimArray re 0 4 0 - quotrem quo u d (Just re) + rf <- quotrem quo u d qf <- PA.unsafeFreezePrimArray quo - rf <- PA.unsafeFreezePrimArray re pure (qf, rf) let pec_q = PA.primArrayFromList [2, 0, 0, 0, 0] - pec_r = PA.primArrayFromList [ - 5900249524800868845 - , 5517428755773076570 - , 10075736392120451746 - , 1328497989567373942 - ] + pec_r = Word256 + 5900249524800868845 + 5517428755773076570 + 10075736392120451746 + 1328497989567373942 + H.assertEqual "remainder matches" pec_r r H.assertEqual "quotient matches" pec_q q