fixed

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

commit a454aa8ee282ac37b8f206e61b6de7557fbd1278
parent af7d747625e2200ca1a9b2661dbb95e32bcf448f
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat, 25 Jan 2025 13:15:42 +0400

lib: basic documentation

Diffstat:
Mlib/Data/Word/Extended.hs | 67++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mppad-fixed.cabal | 4++--
2 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/lib/Data/Word/Extended.hs b/lib/Data/Word/Extended.hs @@ -4,6 +4,15 @@ {-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE ViewPatterns #-} +-- | +-- Module: Data.Word.Extended +-- Copyright: (c) 2025 Jared Tobin +-- License: MIT +-- Maintainer: Jared Tobin <jared@ppad.tech> +-- +-- Large fixed-width words, complete with support for conversion, +-- comparison, bitwise operations, arithmetic, and modular arithmetic. + module Data.Word.Extended ( Word256(..) , zero @@ -71,15 +80,20 @@ data Word256 = Word256 {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64 - deriving (Eq, Show, Generic) + deriving (Eq, Generic) instance NFData Word256 +instance Show Word256 where + show = show . to_integer + +-- XX avoid sel256 :: Word256 -> Int -> Word64 sel256 (Word256 a0 a1 a2 a3) = \case 0 -> a0; 1 -> a1; 2 -> a2; 3 -> a3 _ -> error "ppad-fixed (sel256): bad index" +-- XX avoid set256 :: Word256 -> Int -> Word64 -> Word256 set256 (Word256 a0 a1 a2 a3) j wo = case j of 0 -> Word256 wo a1 a2 a3 @@ -135,12 +149,14 @@ instance NFData Word576 zero576 :: Word576 zero576 = Word576 0 0 0 0 0 0 0 0 0 +-- XX avoid sel576 :: Word576 -> Int -> Word64 sel576 (Word576 a0 a1 a2 a3 a4 a5 a6 a7 a8) = \case 0 -> a0; 1 -> a1; 2 -> a2; 3 -> a3; 4 -> a4 5 -> a5; 6 -> a6; 7 -> a7; 8 -> a8 _ -> error "ppad-fixed (sel576): bad index" +-- XX avoid set576 :: Word576 -> Int -> Word64 -> Word576 set576 (Word576 a0 a1 a2 a3 a4 a5 a6 a7 a8) j wo = case j of 0 -> Word576 wo a1 a2 a3 a4 a5 a6 a7 a8 @@ -168,7 +184,7 @@ data Word832 = Word832 instance NFData Word832 -data Word1152 = Word1152 -- yikes +data Word1152 = Word1152 {-# UNPACK #-} !Word576 {-# UNPACK #-} !Word576 deriving (Eq, Show, Generic) @@ -177,6 +193,11 @@ instance NFData Word1152 -- conversion ----------------------------------------------------------------- +-- | Convert a fixed-width 'Word256' into a variable-length 'Integer'. +-- +-- >>> let foo = to_integer (Word256 0x1 0x10 0x100 0x1000) +-- >>> foo +-- 25711008708143844408758505763390361887002166947932397379780609 to_integer :: Word256 -> Integer to_integer (Word256 w0 w1 w2 w3) = fi w3 .<<. 192 @@ -184,6 +205,10 @@ to_integer (Word256 w0 w1 w2 w3) = .|. fi w1 .<<. 64 .|. fi w0 +-- | Convert a fixed-width 'Word256' into a variable-length 'Integer'. +-- +-- >>> (\(Word256 l _ _ _) -> l) (to_word256 foo) +-- 1 to_word256 :: Integer -> Word256 to_word256 n = let !mask64 = 2 ^ (64 :: Int) - 1 @@ -219,6 +244,12 @@ to_word512 n = -- comparison ----------------------------------------------------------------- +-- | Strict less-than comparison on 'Word256' values. +-- +-- >>> to_word256 0 `lt` to_word256 1 +-- True +-- >>> to_word256 0 `lt` to_word256 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +-- True lt :: Word256 -> Word256 -> Bool lt (Word256 a0 a1 a2 a3) (Word256 b0 b1 b2 b3) = let !(P _ c0) = sub_b a0 b0 0 @@ -227,15 +258,24 @@ lt (Word256 a0 a1 a2 a3) (Word256 b0 b1 b2 b3) = !(P _ c3) = sub_b a3 b3 c2 in c3 /= 0 +-- | Strict greater-than comparison on 'Word256' values. +-- +-- >>> to_word256 0 `gt` to_word256 1 +-- False +-- >>> to_word256 0 `gt` to_word256 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +-- False gt :: Word256 -> Word256 -> Bool gt a b = lt b a +-- | Zero, as a 'Word256'. zero :: Word256 zero = Word256 0 0 0 0 +-- | One, as a 'Word256'. one :: Word256 one = Word256 1 0 0 0 +-- | Test if a 'Word256' value is zero. is_zero :: Word256 -> Bool is_zero w = w == zero @@ -244,14 +284,17 @@ is_word64 (Word256 _ a b c) = a == 0 && b == 0 && c == 0 -- bits ----------------------------------------------------------------------- +-- | Bitwise-or on 'Word256' values. or :: Word256 -> Word256 -> Word256 or (Word256 a0 a1 a2 a3) (Word256 b0 b1 b2 b3) = Word256 (a0 .|. b0) (a1 .|. b1) (a2 .|. b2) (a3 .|. b3) +-- | Bitwise-and on 'Word256' values. and :: Word256 -> Word256 -> Word256 and (Word256 a0 a1 a2 a3) (Word256 b0 b1 b2 b3) = Word256 (a0 .&. b0) (a1 .&. b1) (a2 .&. b2) (a3 .&. b3) +-- | Bitwise-xor on 'Word256' values. xor :: Word256 -> Word256 -> Word256 xor (Word256 a0 a1 a2 a3) (Word256 b0 b1 b2 b3) = Word256 (a0 .^. b0) (a1 .^. b1) (a2 .^. b2) (a3 .^. b3) @@ -281,7 +324,10 @@ add_of (Word256 a0 a1 a2 a3) (Word256 b0 b1 b2 b3) = !(P s3 c3) = add_c a3 b3 c2 in Word320 (Word256 s0 s1 s2 s3) c3 --- | Addition on 'Word256' values. +-- | Addition on 'Word256' values, with overflow. +-- +-- >>> to_word256 0xFFFFFFFFFF `add` to_word256 0xFFFFFF +-- 18446742974181146625 add :: Word256 -> Word256 -> Word256 add w0 w1 = s where !(Word320 s _) = add_of w0 w1 @@ -309,6 +355,9 @@ sub_of (Word256 a0 a1 a2 a3) (Word256 b0 b1 b2 b3) = in Word320 (Word256 s0 s1 s2 s3) c3 -- | Subtraction on 'Word256' values. +-- +-- >>> to_word256 0xFFFFFFFFFF `sub` to_word256 0xFFFFFF +-- 1099494850560 sub :: Word256 -> Word256 -> Word256 sub w0 w1 = d where !(Word320 d _) = sub_of w0 w1 @@ -358,6 +407,9 @@ umul_step z x y c = in P hi lo -- | Multiplication on 'Word256' values, with overflow. +-- +-- >>> to_word256 0xFFFFFFFFFF `mul` to_word256 0xFFFFFF +-- 18446742974181146625 mul :: Word256 -> Word256 -> Word256 mul (Word256 a0 a1 a2 a3) (Word256 b0 b1 b2 b3) = let !(P c0_0 s0) = mul_c a0 b0 @@ -973,6 +1025,10 @@ quotrem u@(Word576 u0 u1 u2 u3 u4 u5 u6 u7 u8) d@(Word256 d0 d1 d2 d3) = | z0 /= 0 = 1 | otherwise = error "ppad-fixed (quotrem_256): division by zero" +-- | Division on 'Word256' values. +-- +-- >>> to_word256 0xFFFFFFFFFF `div` to_word256 0xFFFFFF +-- 65536 div :: Word256 -> Word256 -> Word256 div a@(Word256 a0 a1 a2 a3) b@(Word256 b0 _ _ _) | is_zero b || b `gt` a = zero -- ? @@ -983,6 +1039,10 @@ div a@(Word256 a0 a1 a2 a3) b@(Word256 b0 _ _ _) !(Word832 (Word576 q0 q1 q2 q3 _ _ _ _ _) _) = quotrem u b in Word256 q0 q1 q2 q3 +-- | Modulo operation on 'Word256' values. +-- +-- >>> to_word256 0xFFFFFFFFFF `mod` to_word256 0xFFFFFF +-- 65535 mod :: Word256 -> Word256 -> Word256 mod a@(Word256 a0 a1 a2 a3) b@(Word256 b0 _ _ _) | is_zero b || a == b = zero -- ? @@ -992,3 +1052,4 @@ mod a@(Word256 a0 a1 a2 a3) b@(Word256 b0 _ _ _) let !u = Word576 a0 a1 a2 a3 0 0 0 0 0 !(Word832 _ r) = quotrem u b in r + diff --git a/ppad-fixed.cabal b/ppad-fixed.cabal @@ -1,7 +1,7 @@ cabal-version: 3.0 name: ppad-fixed version: 0.0.1 -synopsis: Fixed-width integers. +synopsis: A large fixed-width integer library. license: MIT license-file: LICENSE author: Jared Tobin @@ -11,7 +11,7 @@ build-type: Simple tested-with: GHC == { 9.8.1 } extra-doc-files: CHANGELOG description: - Fixed-width integer types and operations. + Representations for, and operations on, large fixed-width integers. source-repository head type: git