fixed

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

commit d84841ead2fb03a91d5f1a6bf0ecaf97e28f9820
parent fcc9667765eb2ed7ddbf9f8e71623ea1cf9c9815
Author: Jared Tobin <jared@jtobin.io>
Date:   Sun, 30 Nov 2025 11:59:28 +0400

test: limb tests

Diffstat:
Mtest/Limb.hs | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mtest/Main.hs | 32+++-----------------------------
2 files changed, 147 insertions(+), 32 deletions(-)

diff --git a/test/Limb.hs b/test/Limb.hs @@ -2,10 +2,151 @@ {-# LANGUAGE MagicHash #-} {-# LANGUAGE UnboxedTuples #-} -module Limb where +module Limb ( + tests + ) where +import qualified Data.Choice as C +import qualified Data.Word.Limb as L +import GHC.Exts import Test.Tasty import qualified Test.Tasty.HUnit as H -import qualified Test.Tasty.QuickCheck as Q -import qualified Data.Word.Limb as L + +overflowing_add_no_carry :: H.Assertion +overflowing_add_no_carry = do + let !(# r, c #) = L.add_o# (L.Limb 0##) (L.Limb 1##) + H.assertBool mempty (L.eq_vartime# r (L.Limb 1##)) + H.assertBool mempty (L.eq_vartime# c (L.Limb 0##)) + +overflowing_add_with_carry :: H.Assertion +overflowing_add_with_carry = do + let !(# r, c #) = L.add_o# (L.Limb (not# 0##)) (L.Limb 1##) + H.assertBool mempty (L.eq_vartime# r (L.Limb 0##)) + H.assertBool mempty (L.eq_vartime# c (L.Limb 1##)) + +wrapping_add_no_carry :: H.Assertion +wrapping_add_no_carry = do + let !r = L.add_w# (L.Limb 0##) (L.Limb 1##) + H.assertBool mempty (L.eq_vartime# r (L.Limb 1##)) + +wrapping_add_with_carry :: H.Assertion +wrapping_add_with_carry = do + let !r = L.add_w# (L.Limb (not# 0##)) (L.Limb 1##) + H.assertBool mempty (L.eq_vartime# r (L.Limb 0##)) + +borrowing_sub_no_borrow :: H.Assertion +borrowing_sub_no_borrow = do + let !(# r, c #) = L.sub_b# (L.Limb 1##) (L.Limb 1##) (L.Limb 0##) + H.assertBool mempty (L.eq_vartime# r (L.Limb 0##)) + H.assertBool mempty (L.eq_vartime# c (L.Limb 0##)) + +borrowing_sub_with_borrow :: H.Assertion +borrowing_sub_with_borrow = do + let !(# r, c #) = L.sub_b# (L.Limb 0##) (L.Limb 1##) (L.Limb 0##) + H.assertBool mempty (L.eq_vartime# r (L.Limb (not# 0##))) + H.assertBool mempty (L.eq_vartime# c (L.Limb (not# 0##))) + +wrapping_sub_no_borrow :: H.Assertion +wrapping_sub_no_borrow = do + let !r = L.sub_w# (L.Limb 1##) (L.Limb 1##) + H.assertBool mempty (L.eq_vartime# r (L.Limb 0##)) + +wrapping_sub_with_borrow :: H.Assertion +wrapping_sub_with_borrow = do + let !r = L.sub_w# (L.Limb 0##) (L.Limb 1##) + H.assertBool mempty (L.eq_vartime# r (L.Limb (not# 0##))) + +shl1 :: H.Assertion +shl1 = do + let !r = L.shl# (L.Limb 1##) 1# + H.assertBool mempty (L.eq_vartime# r (L.Limb 2##)) + +shl2 :: H.Assertion +shl2 = do + let !r = L.shl# (L.Limb 1##) 2# + H.assertBool mempty (L.eq_vartime# r (L.Limb 4##)) + +shr1 :: H.Assertion +shr1 = do + let !r = L.shr# (L.Limb 2##) 1# + H.assertBool mempty (L.eq_vartime# r (L.Limb 1##)) + +shr2 :: H.Assertion +shr2 = do + let !r = L.shr# (L.Limb 16##) 2# + H.assertBool mempty (L.eq_vartime# r (L.Limb 4##)) + +eq :: H.Assertion +eq = do + let !a = L.Limb 0## + !b = L.Limb (not# 0##) + H.assertBool mempty (C.decide (L.eq# a a)) + H.assertBool mempty (not (C.decide (L.eq# a b))) + H.assertBool mempty (not (C.decide (L.eq# b a))) + H.assertBool mempty (C.decide (L.eq# b b)) + +gt :: H.Assertion +gt = do + let !a = L.Limb 0## + !b = L.Limb 1## + !c = L.Limb (not# 0##) + H.assertBool mempty (C.decide (L.gt# b a)) + H.assertBool mempty (C.decide (L.gt# c a)) + H.assertBool mempty (C.decide (L.gt# c b)) + + H.assertBool mempty (not (C.decide (L.gt# a a))) + H.assertBool mempty (not (C.decide (L.gt# b b))) + H.assertBool mempty (not (C.decide (L.gt# c c))) + + H.assertBool mempty (not (C.decide (L.gt# a b))) + H.assertBool mempty (not (C.decide (L.gt# a c))) + H.assertBool mempty (not (C.decide (L.gt# b c))) + +lt :: H.Assertion +lt = do + let !a = L.Limb 0## + !b = L.Limb 1## + !c = L.Limb (not# 0##) + H.assertBool mempty (C.decide (L.lt# a b)) + H.assertBool mempty (C.decide (L.lt# a c)) + H.assertBool mempty (C.decide (L.lt# b c)) + + H.assertBool mempty (not (C.decide (L.lt# a a))) + H.assertBool mempty (not (C.decide (L.lt# b b))) + H.assertBool mempty (not (C.decide (L.lt# c c))) + + H.assertBool mempty (not (C.decide (L.lt# b a))) + H.assertBool mempty (not (C.decide (L.lt# c a))) + H.assertBool mempty (not (C.decide (L.lt# c b))) + +cswap :: H.Assertion +cswap = do + let !a = L.Limb (not# 0##) + !b = L.Limb 0## + !(# a0, b0 #) = L.cswap# a b (C.false# ()) + H.assertBool mempty (L.eq_vartime# a0 (L.Limb (not# 0##))) + H.assertBool mempty (L.eq_vartime# b0 (L.Limb 0##)) + let !(# a1, b1 #) = L.cswap# a0 b0 (C.true# ()) + H.assertBool mempty (L.eq_vartime# a1 (L.Limb 0##)) + H.assertBool mempty (L.eq_vartime# b1 (L.Limb (not# 0##))) + +tests :: TestTree +tests = testGroup "limb tests" [ + H.testCase "overflowing add, no carry" overflowing_add_no_carry + , H.testCase "overflowing add, carry" overflowing_add_with_carry + , H.testCase "wrapping add, no carry" wrapping_add_no_carry + , H.testCase "wrapping add, carry" wrapping_add_with_carry + , H.testCase "borrowing sub, no borrow" borrowing_sub_no_borrow + , H.testCase "borrowing sub, borrow" borrowing_sub_with_borrow + , H.testCase "wrapping sub, no borrow" wrapping_sub_no_borrow + , H.testCase "wrapping sub, borrow" wrapping_sub_with_borrow + , H.testCase "left shift (1)" shl1 + , H.testCase "left shift (2)" shl2 + , H.testCase "right shift (1)" shr1 + , H.testCase "right shift (2)" shr2 + , H.testCase "eq" eq + , H.testCase "gt" gt + , H.testCase "lt" lt + , H.testCase "cswap" cswap + ] diff --git a/test/Main.hs b/test/Main.hs @@ -4,35 +4,9 @@ module Main where +import Limb as L import Test.Tasty -import qualified Test.Tasty.HUnit as H -import qualified Test.Tasty.QuickCheck as Q +main :: IO () +main = defaultMain $ L.tests ---division :: TestTree ---division = testGroup "division" [ --- Q.testProperty "division matches" $ --- Q.withMaxSuccess 1000 div_matches --- , Q.testProperty "mod matches" $ --- Q.withMaxSuccess 1000 mod_matches --- ] --- ---main :: IO () ---main = defaultMain $ testGroup "ppad-fixed" [ --- testGroup "property tests" [ --- add_sub --- , multiplication --- , division --- ] --- , testGroup "unit tests" [ --- H.testCase "quotrem_r matches case0" quotrem_r_case0 --- , H.testCase "quotrem_r matches case1" quotrem_r_case1 --- , H.testCase "quotrem_r matches case2" quotrem_r_case2 --- , H.testCase "recip_2by1 matches case0" recip_2by1_case0 --- , H.testCase "recip_2by1 matches case1" recip_2by1_case1 --- , H.testCase "quotrem_2by1 matches case0" quotrem_2by1_case0 --- , H.testCase "quotrem_by1 matches case0" quotrem_by1_case0 --- ] --- , W.tests --- ] ---