mirror of
https://github.com/urbit/shrub.git
synced 2024-12-24 20:47:27 +03:00
urbit-atom: Vendor integer-simple
.
This commit is contained in:
parent
0abf80cc8e
commit
cd656b389f
@ -7,6 +7,7 @@ packages:
|
||||
- urbit-atom
|
||||
- urbit-azimuth
|
||||
- urbit-king
|
||||
- urbit-integer-simple
|
||||
|
||||
extra-deps:
|
||||
- flat-0.3.4@sha256:002a0e0ae656ea8cc02a772d0bcb6ea7dbd7f2e79070959cc748ad1e7138eb38
|
||||
|
26
pkg/hs/urbit-integer-simple/LICENSE
Normal file
26
pkg/hs/urbit-integer-simple/LICENSE
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) Ian Lynagh, 2007-2008.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the author nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
6
pkg/hs/urbit-integer-simple/Setup.hs
Normal file
6
pkg/hs/urbit-integer-simple/Setup.hs
Normal file
@ -0,0 +1,6 @@
|
||||
module Main (main) where
|
||||
|
||||
import Distribution.Simple
|
||||
|
||||
main :: IO ()
|
||||
main = defaultMain
|
42
pkg/hs/urbit-integer-simple/Urbit/Integer.hs
Normal file
42
pkg/hs/urbit-integer-simple/Urbit/Integer.hs
Normal file
@ -0,0 +1,42 @@
|
||||
{-# LANGUAGE CPP, MagicHash, NoImplicitPrelude #-}
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : Urbit.Integer
|
||||
-- Copyright : (c) Ian Lynagh 2007-2012
|
||||
-- License : BSD3
|
||||
--
|
||||
-- Maintainer : igloo@earth.li
|
||||
-- Stability : internal
|
||||
-- Portability : non-portable (GHC Extensions)
|
||||
--
|
||||
-- An simple definition of the 'Integer' type.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
#include "MachDeps.h"
|
||||
|
||||
module Urbit.Integer (
|
||||
Integer, mkInteger,
|
||||
smallInteger, wordToInteger, integerToWord, integerToInt,
|
||||
#if WORD_SIZE_IN_BITS < 64
|
||||
integerToWord64, word64ToInteger,
|
||||
integerToInt64, int64ToInteger,
|
||||
#endif
|
||||
plusInteger, minusInteger, timesInteger, negateInteger,
|
||||
eqInteger, neqInteger, absInteger, signumInteger,
|
||||
leInteger, gtInteger, ltInteger, geInteger, compareInteger,
|
||||
eqInteger#, neqInteger#,
|
||||
leInteger#, gtInteger#, ltInteger#, geInteger#,
|
||||
divInteger, modInteger,
|
||||
divModInteger, quotRemInteger, quotInteger, remInteger,
|
||||
encodeFloatInteger, decodeFloatInteger, floatFromInteger,
|
||||
encodeDoubleInteger, decodeDoubleInteger, doubleFromInteger,
|
||||
-- gcdInteger, lcmInteger, -- XXX
|
||||
andInteger, orInteger, xorInteger, complementInteger,
|
||||
shiftLInteger, shiftRInteger, testBitInteger,
|
||||
hashInteger,
|
||||
) where
|
||||
|
||||
import Urbit.Integer.Type
|
||||
|
43
pkg/hs/urbit-integer-simple/Urbit/Integer/Logarithms.hs
Normal file
43
pkg/hs/urbit-integer-simple/Urbit/Integer/Logarithms.hs
Normal file
@ -0,0 +1,43 @@
|
||||
{-# LANGUAGE MagicHash, UnboxedTuples, NoImplicitPrelude #-}
|
||||
module Urbit.Integer.Logarithms
|
||||
( integerLogBase#
|
||||
, integerLog2#
|
||||
, wordLog2#
|
||||
) where
|
||||
|
||||
import GHC.Prim
|
||||
import Urbit.Integer
|
||||
import qualified Urbit.Integer.Logarithms.Internals as I
|
||||
|
||||
-- | Calculate the integer logarithm for an arbitrary base.
|
||||
-- The base must be greater than 1, the second argument, the number
|
||||
-- whose logarithm is sought, should be positive, otherwise the
|
||||
-- result is meaningless.
|
||||
--
|
||||
-- > base ^ integerLogBase# base m <= m < base ^ (integerLogBase# base m + 1)
|
||||
--
|
||||
-- for @base > 1@ and @m > 0@.
|
||||
integerLogBase# :: Integer -> Integer -> Int#
|
||||
integerLogBase# b m = case step b of
|
||||
(# _, e #) -> e
|
||||
where
|
||||
step pw =
|
||||
if m `ltInteger` pw
|
||||
then (# m, 0# #)
|
||||
else case step (pw `timesInteger` pw) of
|
||||
(# q, e #) ->
|
||||
if q `ltInteger` pw
|
||||
then (# q, 2# *# e #)
|
||||
else (# q `quotInteger` pw, 2# *# e +# 1# #)
|
||||
|
||||
-- | Calculate the integer base 2 logarithm of an 'Integer'.
|
||||
-- The calculation is more efficient than for the general case,
|
||||
-- on platforms with 32- or 64-bit words much more efficient.
|
||||
--
|
||||
-- The argument must be strictly positive, that condition is /not/ checked.
|
||||
integerLog2# :: Integer -> Int#
|
||||
integerLog2# = I.integerLog2#
|
||||
|
||||
-- | This function calculates the integer base 2 logarithm of a 'Word#'.
|
||||
wordLog2# :: Word# -> Int#
|
||||
wordLog2# = I.wordLog2#
|
@ -0,0 +1,166 @@
|
||||
{-# LANGUAGE CPP, MagicHash, UnboxedTuples, NoImplicitPrelude #-}
|
||||
{-# OPTIONS_HADDOCK hide #-}
|
||||
|
||||
#include "MachDeps.h"
|
||||
|
||||
-- (Hopefully) Fast integer logarithms to base 2.
|
||||
-- integerLog2# and wordLog2# are of general usefulness,
|
||||
-- the others are only needed for a fast implementation of
|
||||
-- fromRational.
|
||||
-- Since they are needed in Urbit.Float, we must expose this
|
||||
-- module, but it should not show up in the docs.
|
||||
|
||||
module Urbit.Integer.Logarithms.Internals
|
||||
( integerLog2#
|
||||
, integerLog2IsPowerOf2#
|
||||
, wordLog2#
|
||||
, roundingMode#
|
||||
) where
|
||||
|
||||
import GHC.Prim
|
||||
import Urbit.Integer.Type
|
||||
import GHC.Types
|
||||
|
||||
default ()
|
||||
|
||||
-- When larger word sizes become common, add support for those,
|
||||
-- it's not hard, just tedious.
|
||||
#if (WORD_SIZE_IN_BITS != 32) && (WORD_SIZE_IN_BITS != 64)
|
||||
|
||||
-- We don't know whether the word has 30 bits or 128 or even more,
|
||||
-- so we can't start from the top, although that would be much more
|
||||
-- efficient.
|
||||
wordLog2# :: Word# -> Int#
|
||||
wordLog2# w = go 8# w
|
||||
where
|
||||
go acc u = case u `uncheckedShiftRL#` 8# of
|
||||
0## -> case leadingZeros of
|
||||
BA ba -> acc -# indexInt8Array# ba (word2Int# u)
|
||||
v -> go (acc +# 8#) v
|
||||
|
||||
#else
|
||||
|
||||
-- This one at least can also be done efficiently.
|
||||
-- wordLog2# 0## = -1#
|
||||
{-# INLINE wordLog2# #-}
|
||||
wordLog2# :: Word# -> Int#
|
||||
wordLog2# w =
|
||||
case leadingZeros of
|
||||
BA lz ->
|
||||
let zeros u = indexInt8Array# lz (word2Int# u) in
|
||||
#if WORD_SIZE_IN_BITS == 64
|
||||
case uncheckedShiftRL# w 56# of
|
||||
a ->
|
||||
if isTrue# (a `neWord#` 0##)
|
||||
then 64# -# zeros a
|
||||
else
|
||||
case uncheckedShiftRL# w 48# of
|
||||
b ->
|
||||
if isTrue# (b `neWord#` 0##)
|
||||
then 56# -# zeros b
|
||||
else
|
||||
case uncheckedShiftRL# w 40# of
|
||||
c ->
|
||||
if isTrue# (c `neWord#` 0##)
|
||||
then 48# -# zeros c
|
||||
else
|
||||
case uncheckedShiftRL# w 32# of
|
||||
d ->
|
||||
if isTrue# (d `neWord#` 0##)
|
||||
then 40# -# zeros d
|
||||
else
|
||||
#endif
|
||||
case uncheckedShiftRL# w 24# of
|
||||
e ->
|
||||
if isTrue# (e `neWord#` 0##)
|
||||
then 32# -# zeros e
|
||||
else
|
||||
case uncheckedShiftRL# w 16# of
|
||||
f ->
|
||||
if isTrue# (f `neWord#` 0##)
|
||||
then 24# -# zeros f
|
||||
else
|
||||
case uncheckedShiftRL# w 8# of
|
||||
g ->
|
||||
if isTrue# (g `neWord#` 0##)
|
||||
then 16# -# zeros g
|
||||
else 8# -# zeros w
|
||||
|
||||
#endif
|
||||
|
||||
-- Assumption: Integer is strictly positive,
|
||||
-- otherwise return -1# arbitrarily
|
||||
-- Going up in word-sized steps should not be too bad.
|
||||
integerLog2# :: Integer -> Int#
|
||||
integerLog2# (Positive digits) = step 0# digits
|
||||
where
|
||||
step acc (Some dig None) = acc +# wordLog2# dig
|
||||
step acc (Some _ digs) =
|
||||
step (acc +# WORD_SIZE_IN_BITS#) digs
|
||||
step acc None = acc -- should be impossible, throw error?
|
||||
integerLog2# _ = negateInt# 1#
|
||||
|
||||
-- Again, integer should be strictly positive
|
||||
integerLog2IsPowerOf2# :: Integer -> (# Int#, Int# #)
|
||||
integerLog2IsPowerOf2# (Positive digits) = couldBe 0# digits
|
||||
where
|
||||
couldBe acc (Some dig None) =
|
||||
(# acc +# wordLog2# dig, word2Int# (and# dig (minusWord# dig 1##)) #)
|
||||
couldBe acc (Some dig digs) =
|
||||
if isTrue# (eqWord# dig 0##)
|
||||
then couldBe (acc +# WORD_SIZE_IN_BITS#) digs
|
||||
else noPower (acc +# WORD_SIZE_IN_BITS#) digs
|
||||
couldBe acc None = (# acc, 1# #) -- should be impossible, error?
|
||||
noPower acc (Some dig None) =
|
||||
(# acc +# wordLog2# dig, 1# #)
|
||||
noPower acc (Some _ digs) =
|
||||
noPower (acc +# WORD_SIZE_IN_BITS#) digs
|
||||
noPower acc None = (# acc, 1# #) -- should be impossible, error?
|
||||
integerLog2IsPowerOf2# _ = (# negateInt# 1#, 1# #)
|
||||
|
||||
-- Assumption: Integer and Int# are strictly positive, Int# is less
|
||||
-- than logBase 2 of Integer, otherwise havoc ensues.
|
||||
-- Used only for the numerator in fromRational when the denominator
|
||||
-- is a power of 2.
|
||||
-- The Int# argument is log2 n minus the number of bits in the mantissa
|
||||
-- of the target type, i.e. the index of the first non-integral bit in
|
||||
-- the quotient.
|
||||
--
|
||||
-- 0# means round down (towards zero)
|
||||
-- 1# means we have a half-integer, round to even
|
||||
-- 2# means round up (away from zero)
|
||||
-- This function should probably be improved.
|
||||
roundingMode# :: Integer -> Int# -> Int#
|
||||
roundingMode# m h =
|
||||
case oneInteger `shiftLInteger` h of
|
||||
c -> case m `andInteger`
|
||||
((c `plusInteger` c) `minusInteger` oneInteger) of
|
||||
r ->
|
||||
if c `ltInteger` r
|
||||
then 2#
|
||||
else if c `gtInteger` r
|
||||
then 0#
|
||||
else 1#
|
||||
|
||||
-- Lookup table
|
||||
data BA = BA ByteArray#
|
||||
|
||||
leadingZeros :: BA
|
||||
leadingZeros =
|
||||
let mkArr s =
|
||||
case newByteArray# 256# s of
|
||||
(# s1, mba #) ->
|
||||
case writeInt8Array# mba 0# 9# s1 of
|
||||
s2 ->
|
||||
let fillA lim val idx st =
|
||||
if isTrue# (idx ==# 256#)
|
||||
then st
|
||||
else if isTrue# (idx <# lim)
|
||||
then case writeInt8Array# mba idx val st of
|
||||
nx -> fillA lim val (idx +# 1#) nx
|
||||
else fillA (2# *# lim) (val -# 1#) idx st
|
||||
in case fillA 2# 8# 1# s2 of
|
||||
s3 -> case unsafeFreezeByteArray# mba s3 of
|
||||
(# _, ba #) -> ba
|
||||
in case mkArr realWorld# of
|
||||
b -> BA b
|
@ -0,0 +1,23 @@
|
||||
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : Urbit.Integer.Simple.Internals
|
||||
-- Copyright : (c) Ian Lynagh 2007-2008
|
||||
-- License : BSD3
|
||||
--
|
||||
-- Maintainer : igloo@earth.li
|
||||
-- Stability : internal
|
||||
-- Portability : non-portable (GHC Extensions)
|
||||
--
|
||||
-- An simple definition of the 'Integer' type.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module Urbit.Integer.Simple.Internals (
|
||||
module Urbit.Integer.Type
|
||||
) where
|
||||
|
||||
import Urbit.Integer.Type
|
||||
|
891
pkg/hs/urbit-integer-simple/Urbit/Integer/Type.hs
Normal file
891
pkg/hs/urbit-integer-simple/Urbit/Integer/Type.hs
Normal file
@ -0,0 +1,891 @@
|
||||
|
||||
{-# LANGUAGE CPP, MagicHash, NoImplicitPrelude, BangPatterns, UnboxedTuples,
|
||||
UnliftedFFITypes #-}
|
||||
|
||||
-- Commentary of Integer library is located on the wiki:
|
||||
-- http://ghc.haskell.org/trac/ghc/wiki/Commentary/Libraries/Integer
|
||||
--
|
||||
-- It gives an in-depth description of implementation details and
|
||||
-- decisions.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : Urbit.Integer.Type
|
||||
-- Copyright : (c) Ian Lynagh 2007-2012
|
||||
-- License : BSD3
|
||||
--
|
||||
-- Maintainer : igloo@earth.li
|
||||
-- Stability : internal
|
||||
-- Portability : non-portable (GHC Extensions)
|
||||
--
|
||||
-- An simple definition of the 'Integer' type.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
#include "MachDeps.h"
|
||||
|
||||
module Urbit.Integer.Type where
|
||||
|
||||
import GHC.Prim
|
||||
import GHC.Classes
|
||||
import GHC.Types
|
||||
import GHC.Tuple ()
|
||||
#if WORD_SIZE_IN_BITS < 64
|
||||
import GHC.IntWord64
|
||||
#endif
|
||||
|
||||
data Integer = Positive !Positive | Negative !Positive | Naught
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- The hard work is done on positive numbers
|
||||
|
||||
-- Least significant bit is first
|
||||
|
||||
-- Positive's have the property that they contain at least one Bit,
|
||||
-- and their last Bit is One.
|
||||
type Positive = Digits
|
||||
type Positives = List Positive
|
||||
|
||||
data Digits = Some !Digit !Digits
|
||||
| None
|
||||
type Digit = Word#
|
||||
|
||||
-- XXX Could move [] above us
|
||||
data List a = Nil | Cons a (List a)
|
||||
|
||||
mkInteger :: Bool -- non-negative?
|
||||
-> [Int] -- absolute value in 31 bit chunks, least significant first
|
||||
-- ideally these would be Words rather than Ints, but
|
||||
-- we don't have Word available at the moment.
|
||||
-> Integer
|
||||
mkInteger nonNegative is = let abs = f is
|
||||
in if nonNegative then abs else negateInteger abs
|
||||
where f [] = Naught
|
||||
f (I# i : is') = smallInteger i `orInteger` shiftLInteger (f is') 31#
|
||||
|
||||
errorInteger :: Integer
|
||||
errorInteger = Positive errorPositive
|
||||
|
||||
errorPositive :: Positive
|
||||
errorPositive = Some 47## None -- Random number
|
||||
|
||||
{-# NOINLINE smallInteger #-}
|
||||
smallInteger :: Int# -> Integer
|
||||
smallInteger i = if isTrue# (i >=# 0#) then wordToInteger (int2Word# i)
|
||||
else -- XXX is this right for -minBound?
|
||||
negateInteger (wordToInteger (int2Word# (negateInt# i)))
|
||||
|
||||
{-# NOINLINE wordToInteger #-}
|
||||
wordToInteger :: Word# -> Integer
|
||||
wordToInteger w = if isTrue# (w `eqWord#` 0##)
|
||||
then Naught
|
||||
else Positive (Some w None)
|
||||
|
||||
{-# NOINLINE integerToWord #-}
|
||||
integerToWord :: Integer -> Word#
|
||||
integerToWord (Positive (Some w _)) = w
|
||||
integerToWord (Negative (Some w _)) = 0## `minusWord#` w
|
||||
-- Must be Naught by the invariant:
|
||||
integerToWord _ = 0##
|
||||
|
||||
{-# NOINLINE integerToInt #-}
|
||||
integerToInt :: Integer -> Int#
|
||||
integerToInt i = word2Int# (integerToWord i)
|
||||
|
||||
#if WORD_SIZE_IN_BITS == 64
|
||||
-- Nothing
|
||||
#elif WORD_SIZE_IN_BITS == 32
|
||||
{-# NOINLINE integerToWord64 #-}
|
||||
integerToWord64 :: Integer -> Word64#
|
||||
integerToWord64 i = int64ToWord64# (integerToInt64 i)
|
||||
|
||||
{-# NOINLINE word64ToInteger #-}
|
||||
word64ToInteger:: Word64# -> Integer
|
||||
word64ToInteger w = if isTrue# (w `eqWord64#` wordToWord64# 0##)
|
||||
then Naught
|
||||
else Positive (word64ToPositive w)
|
||||
|
||||
{-# NOINLINE integerToInt64 #-}
|
||||
integerToInt64 :: Integer -> Int64#
|
||||
integerToInt64 Naught = intToInt64# 0#
|
||||
integerToInt64 (Positive p) = word64ToInt64# (positiveToWord64 p)
|
||||
integerToInt64 (Negative p)
|
||||
= negateInt64# (word64ToInt64# (positiveToWord64 p))
|
||||
|
||||
{-# NOINLINE int64ToInteger #-}
|
||||
int64ToInteger :: Int64# -> Integer
|
||||
int64ToInteger i
|
||||
= if isTrue# (i `eqInt64#` intToInt64# 0#)
|
||||
then Naught
|
||||
else if isTrue# (i `gtInt64#` intToInt64# 0#)
|
||||
then Positive (word64ToPositive (int64ToWord64# i))
|
||||
else Negative (word64ToPositive (int64ToWord64# (negateInt64# i)))
|
||||
#else
|
||||
#error WORD_SIZE_IN_BITS not supported
|
||||
#endif
|
||||
|
||||
oneInteger :: Integer
|
||||
oneInteger = Positive onePositive
|
||||
|
||||
negativeOneInteger :: Integer
|
||||
negativeOneInteger = Negative onePositive
|
||||
|
||||
twoToTheThirtytwoInteger :: Integer
|
||||
twoToTheThirtytwoInteger = Positive twoToTheThirtytwoPositive
|
||||
|
||||
{-# NOINLINE encodeDoubleInteger #-}
|
||||
encodeDoubleInteger :: Integer -> Int# -> Double#
|
||||
encodeDoubleInteger (Positive ds0) e0 = f 0.0## ds0 e0
|
||||
where f !acc None (!_) = acc
|
||||
f !acc (Some d ds) !e = f (acc +## encodeDouble# d e)
|
||||
ds
|
||||
-- XXX We assume that this adding to e
|
||||
-- isn't going to overflow
|
||||
(e +# WORD_SIZE_IN_BITS#)
|
||||
encodeDoubleInteger (Negative ds) e
|
||||
= negateDouble# (encodeDoubleInteger (Positive ds) e)
|
||||
encodeDoubleInteger Naught _ = 0.0##
|
||||
|
||||
foreign import ccall unsafe "__word_encodeDouble"
|
||||
encodeDouble# :: Word# -> Int# -> Double#
|
||||
|
||||
{-# NOINLINE encodeFloatInteger #-}
|
||||
encodeFloatInteger :: Integer -> Int# -> Float#
|
||||
encodeFloatInteger (Positive ds0) e0 = f 0.0# ds0 e0
|
||||
where f !acc None (!_) = acc
|
||||
f !acc (Some d ds) !e = f (acc `plusFloat#` encodeFloat# d e)
|
||||
ds
|
||||
-- XXX We assume that this adding to e
|
||||
-- isn't going to overflow
|
||||
(e +# WORD_SIZE_IN_BITS#)
|
||||
encodeFloatInteger (Negative ds) e
|
||||
= negateFloat# (encodeFloatInteger (Positive ds) e)
|
||||
encodeFloatInteger Naught _ = 0.0#
|
||||
|
||||
foreign import ccall unsafe "__word_encodeFloat"
|
||||
encodeFloat# :: Word# -> Int# -> Float#
|
||||
|
||||
{-# NOINLINE decodeFloatInteger #-}
|
||||
decodeFloatInteger :: Float# -> (# Integer, Int# #)
|
||||
decodeFloatInteger f = case decodeFloat_Int# f of
|
||||
(# mant, exp #) -> (# smallInteger mant, exp #)
|
||||
|
||||
-- XXX This could be optimised better, by either (word-size dependent)
|
||||
-- using single 64bit value for the mantissa, or doing the multiplication
|
||||
-- by just building the Digits directly
|
||||
{-# NOINLINE decodeDoubleInteger #-}
|
||||
decodeDoubleInteger :: Double# -> (# Integer, Int# #)
|
||||
decodeDoubleInteger d
|
||||
= case decodeDouble_2Int# d of
|
||||
(# mantSign, mantHigh, mantLow, exp #) ->
|
||||
(# (smallInteger mantSign) `timesInteger`
|
||||
( (wordToInteger mantHigh `timesInteger` twoToTheThirtytwoInteger)
|
||||
`plusInteger` wordToInteger mantLow),
|
||||
exp #)
|
||||
|
||||
{-# NOINLINE doubleFromInteger #-}
|
||||
doubleFromInteger :: Integer -> Double#
|
||||
doubleFromInteger Naught = 0.0##
|
||||
doubleFromInteger (Positive p) = doubleFromPositive p
|
||||
doubleFromInteger (Negative p) = negateDouble# (doubleFromPositive p)
|
||||
|
||||
{-# NOINLINE floatFromInteger #-}
|
||||
floatFromInteger :: Integer -> Float#
|
||||
floatFromInteger Naught = 0.0#
|
||||
floatFromInteger (Positive p) = floatFromPositive p
|
||||
floatFromInteger (Negative p) = negateFloat# (floatFromPositive p)
|
||||
|
||||
{-# NOINLINE andInteger #-}
|
||||
andInteger :: Integer -> Integer -> Integer
|
||||
Naught `andInteger` (!_) = Naught
|
||||
(!_) `andInteger` Naught = Naught
|
||||
Positive x `andInteger` Positive y = digitsToInteger (x `andDigits` y)
|
||||
{-
|
||||
To calculate x & -y we need to calculate
|
||||
x & twosComplement y
|
||||
The (imaginary) sign bits are 0 and 1, so &ing them give 0, i.e. positive.
|
||||
Note that
|
||||
twosComplement y
|
||||
has infinitely many 1s, but x has a finite number of digits, so andDigits
|
||||
will return a finite result.
|
||||
-}
|
||||
Positive x `andInteger` Negative y = let y' = twosComplementPositive y
|
||||
z = y' `andDigitsOnes` x
|
||||
in digitsToInteger z
|
||||
Negative x `andInteger` Positive y = Positive y `andInteger` Negative x
|
||||
{-
|
||||
To calculate -x & -y, naively we need to calculate
|
||||
twosComplement (twosComplement x & twosComplement y)
|
||||
but
|
||||
twosComplement x & twosComplement y
|
||||
has infinitely many 1s, so this won't work. Thus we use de Morgan's law
|
||||
to get
|
||||
-x & -y = !(!(-x) | !(-y))
|
||||
= !(!(twosComplement x) | !(twosComplement y))
|
||||
= !(!(!x + 1) | (!y + 1))
|
||||
= !((x - 1) | (y - 1))
|
||||
but the result is negative, so we need to take the two's complement of
|
||||
this in order to get the magnitude of the result.
|
||||
twosComplement !((x - 1) | (y - 1))
|
||||
= !(!((x - 1) | (y - 1))) + 1
|
||||
= ((x - 1) | (y - 1)) + 1
|
||||
-}
|
||||
-- We don't know that x and y are /strictly/ greater than 1, but
|
||||
-- minusPositive gives us the required answer anyway.
|
||||
Negative x `andInteger` Negative y = let x' = x `minusPositive` onePositive
|
||||
y' = y `minusPositive` onePositive
|
||||
z = x' `orDigits` y'
|
||||
-- XXX Cheating the precondition:
|
||||
z' = succPositive z
|
||||
in digitsToNegativeInteger z'
|
||||
|
||||
{-# NOINLINE orInteger #-}
|
||||
orInteger :: Integer -> Integer -> Integer
|
||||
Naught `orInteger` (!i) = i
|
||||
(!i) `orInteger` Naught = i
|
||||
Positive x `orInteger` Positive y = Positive (x `orDigits` y)
|
||||
{-
|
||||
x | -y = - (twosComplement (x | twosComplement y))
|
||||
= - (twosComplement !(!x & !(twosComplement y)))
|
||||
= - (twosComplement !(!x & !(!y + 1)))
|
||||
= - (twosComplement !(!x & (y - 1)))
|
||||
= - ((!x & (y - 1)) + 1)
|
||||
-}
|
||||
Positive x `orInteger` Negative y = let x' = flipBits x
|
||||
y' = y `minusPositive` onePositive
|
||||
z = x' `andDigitsOnes` y'
|
||||
z' = succPositive z
|
||||
in digitsToNegativeInteger z'
|
||||
Negative x `orInteger` Positive y = Positive y `orInteger` Negative x
|
||||
{-
|
||||
-x | -y = - (twosComplement (twosComplement x | twosComplement y))
|
||||
= - (twosComplement !(!(twosComplement x) & !(twosComplement y)))
|
||||
= - (twosComplement !(!(!x + 1) & !(!y + 1)))
|
||||
= - (twosComplement !((x - 1) & (y - 1)))
|
||||
= - (((x - 1) & (y - 1)) + 1)
|
||||
-}
|
||||
Negative x `orInteger` Negative y = let x' = x `minusPositive` onePositive
|
||||
y' = y `minusPositive` onePositive
|
||||
z = x' `andDigits` y'
|
||||
z' = succPositive z
|
||||
in digitsToNegativeInteger z'
|
||||
|
||||
{-# NOINLINE xorInteger #-}
|
||||
xorInteger :: Integer -> Integer -> Integer
|
||||
Naught `xorInteger` (!i) = i
|
||||
(!i) `xorInteger` Naught = i
|
||||
Positive x `xorInteger` Positive y = digitsToInteger (x `xorDigits` y)
|
||||
{-
|
||||
x ^ -y = - (twosComplement (x ^ twosComplement y))
|
||||
= - (twosComplement !(x ^ !(twosComplement y)))
|
||||
= - (twosComplement !(x ^ !(!y + 1)))
|
||||
= - (twosComplement !(x ^ (y - 1)))
|
||||
= - ((x ^ (y - 1)) + 1)
|
||||
-}
|
||||
Positive x `xorInteger` Negative y = let y' = y `minusPositive` onePositive
|
||||
z = x `xorDigits` y'
|
||||
z' = succPositive z
|
||||
in digitsToNegativeInteger z'
|
||||
Negative x `xorInteger` Positive y = Positive y `xorInteger` Negative x
|
||||
{-
|
||||
-x ^ -y = twosComplement x ^ twosComplement y
|
||||
= (!x + 1) ^ (!y + 1)
|
||||
= (!x + 1) ^ (!y + 1)
|
||||
= !(!x + 1) ^ !(!y + 1)
|
||||
= (x - 1) ^ (y - 1)
|
||||
-}
|
||||
Negative x `xorInteger` Negative y = let x' = x `minusPositive` onePositive
|
||||
y' = y `minusPositive` onePositive
|
||||
z = x' `xorDigits` y'
|
||||
in digitsToInteger z
|
||||
|
||||
{-# NOINLINE complementInteger #-}
|
||||
complementInteger :: Integer -> Integer
|
||||
complementInteger x = negativeOneInteger `minusInteger` x
|
||||
|
||||
{-# NOINLINE shiftLInteger #-}
|
||||
shiftLInteger :: Integer -> Int# -> Integer
|
||||
shiftLInteger (Positive p) i = Positive (shiftLPositive p i)
|
||||
shiftLInteger (Negative n) i = Negative (shiftLPositive n i)
|
||||
shiftLInteger Naught _ = Naught
|
||||
|
||||
{-# NOINLINE shiftRInteger #-}
|
||||
shiftRInteger :: Integer -> Int# -> Integer
|
||||
shiftRInteger (Positive p) i = shiftRPositive p i
|
||||
shiftRInteger j@(Negative _) i
|
||||
= complementInteger (shiftRInteger (complementInteger j) i)
|
||||
shiftRInteger Naught _ = Naught
|
||||
|
||||
-- XXX this could be a lot more efficient, but this is a quick
|
||||
-- reimplementation of the default Data.Bits instance, so that we can
|
||||
-- implement the Integer interface
|
||||
testBitInteger :: Integer -> Int# -> Bool
|
||||
testBitInteger x i = (x `andInteger` (oneInteger `shiftLInteger` i))
|
||||
`neqInteger` Naught
|
||||
|
||||
twosComplementPositive :: Positive -> DigitsOnes
|
||||
twosComplementPositive p = flipBits (p `minusPositive` onePositive)
|
||||
|
||||
flipBits :: Digits -> DigitsOnes
|
||||
flipBits ds = DigitsOnes (flipBitsDigits ds)
|
||||
|
||||
flipBitsDigits :: Digits -> Digits
|
||||
flipBitsDigits None = None
|
||||
flipBitsDigits (Some w ws) = Some (not# w) (flipBitsDigits ws)
|
||||
|
||||
{-# NOINLINE negateInteger #-}
|
||||
negateInteger :: Integer -> Integer
|
||||
negateInteger (Positive p) = Negative p
|
||||
negateInteger (Negative p) = Positive p
|
||||
negateInteger Naught = Naught
|
||||
|
||||
-- Note [Avoid patError]
|
||||
{-# NOINLINE plusInteger #-}
|
||||
plusInteger :: Integer -> Integer -> Integer
|
||||
Positive p1 `plusInteger` Positive p2 = Positive (p1 `plusPositive` p2)
|
||||
Negative p1 `plusInteger` Negative p2 = Negative (p1 `plusPositive` p2)
|
||||
Positive p1 `plusInteger` Negative p2
|
||||
= case p1 `comparePositive` p2 of
|
||||
GT -> Positive (p1 `minusPositive` p2)
|
||||
EQ -> Naught
|
||||
LT -> Negative (p2 `minusPositive` p1)
|
||||
Negative p1 `plusInteger` Positive p2
|
||||
= Positive p2 `plusInteger` Negative p1
|
||||
Naught `plusInteger` Naught = Naught
|
||||
Naught `plusInteger` i@(Positive _) = i
|
||||
Naught `plusInteger` i@(Negative _) = i
|
||||
i@(Positive _) `plusInteger` Naught = i
|
||||
i@(Negative _) `plusInteger` Naught = i
|
||||
|
||||
{-# NOINLINE minusInteger #-}
|
||||
minusInteger :: Integer -> Integer -> Integer
|
||||
i1 `minusInteger` i2 = i1 `plusInteger` negateInteger i2
|
||||
|
||||
{-# NOINLINE timesInteger #-}
|
||||
timesInteger :: Integer -> Integer -> Integer
|
||||
Positive p1 `timesInteger` Positive p2 = Positive (p1 `timesPositive` p2)
|
||||
Negative p1 `timesInteger` Negative p2 = Positive (p1 `timesPositive` p2)
|
||||
Positive p1 `timesInteger` Negative p2 = Negative (p1 `timesPositive` p2)
|
||||
Negative p1 `timesInteger` Positive p2 = Negative (p1 `timesPositive` p2)
|
||||
(!_) `timesInteger` (!_) = Naught
|
||||
|
||||
{-# NOINLINE divModInteger #-}
|
||||
divModInteger :: Integer -> Integer -> (# Integer, Integer #)
|
||||
n `divModInteger` d =
|
||||
case n `quotRemInteger` d of
|
||||
(# q, r #) ->
|
||||
if signumInteger r `eqInteger`
|
||||
negateInteger (signumInteger d)
|
||||
then (# q `minusInteger` oneInteger, r `plusInteger` d #)
|
||||
else (# q, r #)
|
||||
|
||||
{-# NOINLINE divInteger #-}
|
||||
divInteger :: Integer -> Integer -> Integer
|
||||
n `divInteger` d = quotient
|
||||
where (# quotient, _ #) = n `divModInteger` d
|
||||
|
||||
{-# NOINLINE modInteger #-}
|
||||
modInteger :: Integer -> Integer -> Integer
|
||||
n `modInteger` d = modulus
|
||||
where (# _, modulus #) = n `divModInteger` d
|
||||
|
||||
{-# NOINLINE quotRemInteger #-}
|
||||
quotRemInteger :: Integer -> Integer -> (# Integer, Integer #)
|
||||
Naught `quotRemInteger` (!_) = (# Naught, Naught #)
|
||||
(!_) `quotRemInteger` Naught
|
||||
= (# errorInteger, errorInteger #) -- XXX Can't happen
|
||||
-- XXX _ `quotRemInteger` Naught = error "Division by zero"
|
||||
Positive p1 `quotRemInteger` Positive p2 = p1 `quotRemPositive` p2
|
||||
Negative p1 `quotRemInteger` Positive p2 = case p1 `quotRemPositive` p2 of
|
||||
(# q, r #) ->
|
||||
(# negateInteger q,
|
||||
negateInteger r #)
|
||||
Positive p1 `quotRemInteger` Negative p2 = case p1 `quotRemPositive` p2 of
|
||||
(# q, r #) ->
|
||||
(# negateInteger q, r #)
|
||||
Negative p1 `quotRemInteger` Negative p2 = case p1 `quotRemPositive` p2 of
|
||||
(# q, r #) ->
|
||||
(# q, negateInteger r #)
|
||||
|
||||
{-# NOINLINE quotInteger #-}
|
||||
quotInteger :: Integer -> Integer -> Integer
|
||||
x `quotInteger` y = case x `quotRemInteger` y of
|
||||
(# q, _ #) -> q
|
||||
|
||||
{-# NOINLINE remInteger #-}
|
||||
remInteger :: Integer -> Integer -> Integer
|
||||
x `remInteger` y = case x `quotRemInteger` y of
|
||||
(# _, r #) -> r
|
||||
|
||||
{-# NOINLINE compareInteger #-}
|
||||
compareInteger :: Integer -> Integer -> Ordering
|
||||
Positive x `compareInteger` Positive y = x `comparePositive` y
|
||||
Positive _ `compareInteger` (!_) = GT
|
||||
Naught `compareInteger` Naught = EQ
|
||||
Naught `compareInteger` Negative _ = GT
|
||||
Negative x `compareInteger` Negative y = y `comparePositive` x
|
||||
(!_) `compareInteger` (!_) = LT
|
||||
|
||||
{-# NOINLINE eqInteger# #-}
|
||||
eqInteger# :: Integer -> Integer -> Int#
|
||||
x `eqInteger#` y = case x `compareInteger` y of
|
||||
EQ -> 1#
|
||||
_ -> 0#
|
||||
|
||||
{-# NOINLINE neqInteger# #-}
|
||||
neqInteger# :: Integer -> Integer -> Int#
|
||||
x `neqInteger#` y = case x `compareInteger` y of
|
||||
EQ -> 0#
|
||||
_ -> 1#
|
||||
|
||||
{-# INLINE eqInteger #-}
|
||||
{-# INLINE neqInteger #-}
|
||||
eqInteger, neqInteger :: Integer -> Integer -> Bool
|
||||
eqInteger a b = isTrue# (a `eqInteger#` b)
|
||||
neqInteger a b = isTrue# (a `neqInteger#` b)
|
||||
|
||||
instance Eq Integer where
|
||||
(==) = eqInteger
|
||||
(/=) = neqInteger
|
||||
|
||||
{-# NOINLINE ltInteger# #-}
|
||||
ltInteger# :: Integer -> Integer -> Int#
|
||||
x `ltInteger#` y = case x `compareInteger` y of
|
||||
LT -> 1#
|
||||
_ -> 0#
|
||||
|
||||
{-# NOINLINE gtInteger# #-}
|
||||
gtInteger# :: Integer -> Integer -> Int#
|
||||
x `gtInteger#` y = case x `compareInteger` y of
|
||||
GT -> 1#
|
||||
_ -> 0#
|
||||
|
||||
{-# NOINLINE leInteger# #-}
|
||||
leInteger# :: Integer -> Integer -> Int#
|
||||
x `leInteger#` y = case x `compareInteger` y of
|
||||
GT -> 0#
|
||||
_ -> 1#
|
||||
|
||||
{-# NOINLINE geInteger# #-}
|
||||
geInteger# :: Integer -> Integer -> Int#
|
||||
x `geInteger#` y = case x `compareInteger` y of
|
||||
LT -> 0#
|
||||
_ -> 1#
|
||||
|
||||
{-# INLINE leInteger #-}
|
||||
{-# INLINE ltInteger #-}
|
||||
{-# INLINE geInteger #-}
|
||||
{-# INLINE gtInteger #-}
|
||||
leInteger, gtInteger, ltInteger, geInteger :: Integer -> Integer -> Bool
|
||||
leInteger a b = isTrue# (a `leInteger#` b)
|
||||
gtInteger a b = isTrue# (a `gtInteger#` b)
|
||||
ltInteger a b = isTrue# (a `ltInteger#` b)
|
||||
geInteger a b = isTrue# (a `geInteger#` b)
|
||||
|
||||
instance Ord Integer where
|
||||
(<=) = leInteger
|
||||
(>) = gtInteger
|
||||
(<) = ltInteger
|
||||
(>=) = geInteger
|
||||
compare = compareInteger
|
||||
|
||||
{-# NOINLINE absInteger #-}
|
||||
absInteger :: Integer -> Integer
|
||||
absInteger (Negative x) = Positive x
|
||||
absInteger x = x
|
||||
|
||||
{-# NOINLINE signumInteger #-}
|
||||
signumInteger :: Integer -> Integer
|
||||
signumInteger (Negative _) = negativeOneInteger
|
||||
signumInteger Naught = Naught
|
||||
signumInteger (Positive _) = oneInteger
|
||||
|
||||
{-# NOINLINE hashInteger #-}
|
||||
hashInteger :: Integer -> Int#
|
||||
hashInteger = integerToInt
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- The hard work is done on positive numbers
|
||||
|
||||
onePositive :: Positive
|
||||
onePositive = Some 1## None
|
||||
|
||||
halfBoundUp, fullBound :: () -> Digit
|
||||
lowHalfMask :: () -> Digit
|
||||
highHalfShift :: () -> Int#
|
||||
twoToTheThirtytwoPositive :: Positive
|
||||
#if WORD_SIZE_IN_BITS == 64
|
||||
halfBoundUp () = 0x8000000000000000##
|
||||
fullBound () = 0xFFFFFFFFFFFFFFFF##
|
||||
lowHalfMask () = 0xFFFFFFFF##
|
||||
highHalfShift () = 32#
|
||||
twoToTheThirtytwoPositive = Some 0x100000000## None
|
||||
#elif WORD_SIZE_IN_BITS == 32
|
||||
halfBoundUp () = 0x80000000##
|
||||
fullBound () = 0xFFFFFFFF##
|
||||
lowHalfMask () = 0xFFFF##
|
||||
highHalfShift () = 16#
|
||||
twoToTheThirtytwoPositive = Some 0## (Some 1## None)
|
||||
#else
|
||||
#error Unhandled WORD_SIZE_IN_BITS
|
||||
#endif
|
||||
|
||||
digitsMaybeZeroToInteger :: Digits -> Integer
|
||||
digitsMaybeZeroToInteger None = Naught
|
||||
digitsMaybeZeroToInteger ds = Positive ds
|
||||
|
||||
digitsToInteger :: Digits -> Integer
|
||||
digitsToInteger ds = case removeZeroTails ds of
|
||||
None -> Naught
|
||||
ds' -> Positive ds'
|
||||
|
||||
digitsToNegativeInteger :: Digits -> Integer
|
||||
digitsToNegativeInteger ds = case removeZeroTails ds of
|
||||
None -> Naught
|
||||
ds' -> Negative ds'
|
||||
|
||||
removeZeroTails :: Digits -> Digits
|
||||
removeZeroTails (Some w ds) = if isTrue# (w `eqWord#` 0##)
|
||||
then case removeZeroTails ds of
|
||||
None -> None
|
||||
ds' -> Some w ds'
|
||||
else Some w (removeZeroTails ds)
|
||||
removeZeroTails None = None
|
||||
|
||||
#if WORD_SIZE_IN_BITS < 64
|
||||
word64ToPositive :: Word64# -> Positive
|
||||
word64ToPositive w
|
||||
= if isTrue# (w `eqWord64#` wordToWord64# 0##)
|
||||
then None
|
||||
else Some (word64ToWord# w) (word64ToPositive (w `uncheckedShiftRL64#` 32#))
|
||||
|
||||
positiveToWord64 :: Positive -> Word64#
|
||||
positiveToWord64 None = wordToWord64# 0## -- XXX Can't happen
|
||||
positiveToWord64 (Some w None) = wordToWord64# w
|
||||
positiveToWord64 (Some low (Some high _))
|
||||
= wordToWord64# low `or64#` (wordToWord64# high `uncheckedShiftL64#` 32#)
|
||||
#endif
|
||||
|
||||
-- Note [Avoid patError]
|
||||
comparePositive :: Positive -> Positive -> Ordering
|
||||
Some x xs `comparePositive` Some y ys = case xs `comparePositive` ys of
|
||||
EQ -> if isTrue# (x `ltWord#` y) then LT
|
||||
else if isTrue# (x `gtWord#` y) then GT
|
||||
else EQ
|
||||
res -> res
|
||||
None `comparePositive` None = EQ
|
||||
(Some {}) `comparePositive` None = GT
|
||||
None `comparePositive` (Some {}) = LT
|
||||
|
||||
plusPositive :: Positive -> Positive -> Positive
|
||||
plusPositive x0 y0 = addWithCarry 0## x0 y0
|
||||
where -- digit `elem` [0, 1]
|
||||
-- Note [Avoid patError]
|
||||
addWithCarry :: Digit -> Positive -> Positive -> Positive
|
||||
addWithCarry c None None = addOnCarry c None
|
||||
addWithCarry c xs@(Some {}) None = addOnCarry c xs
|
||||
addWithCarry c None ys@(Some {}) = addOnCarry c ys
|
||||
addWithCarry c xs@(Some x xs') ys@(Some y ys')
|
||||
= if isTrue# (x `ltWord#` y) then addWithCarry c ys xs
|
||||
-- Now x >= y
|
||||
else if isTrue# (y `geWord#` halfBoundUp ())
|
||||
-- So they are both at least halfBoundUp, so we subtract
|
||||
-- halfBoundUp from each and thus carry 1
|
||||
then case x `minusWord#` halfBoundUp () of
|
||||
x' ->
|
||||
case y `minusWord#` halfBoundUp () of
|
||||
y' ->
|
||||
case x' `plusWord#` y' `plusWord#` c of
|
||||
this ->
|
||||
Some this withCarry
|
||||
else if isTrue# (x `geWord#` halfBoundUp ())
|
||||
then case x `minusWord#` halfBoundUp () of
|
||||
x' ->
|
||||
case x' `plusWord#` y `plusWord#` c of
|
||||
z ->
|
||||
-- We've taken off halfBoundUp, so now we need to
|
||||
-- add it back on
|
||||
if isTrue# (z `ltWord#` halfBoundUp ())
|
||||
then Some (z `plusWord#` halfBoundUp ()) withoutCarry
|
||||
else Some (z `minusWord#` halfBoundUp ()) withCarry
|
||||
else Some (x `plusWord#` y `plusWord#` c) withoutCarry
|
||||
where withCarry = addWithCarry 1## xs' ys'
|
||||
withoutCarry = addWithCarry 0## xs' ys'
|
||||
|
||||
-- digit `elem` [0, 1]
|
||||
addOnCarry :: Digit -> Positive -> Positive
|
||||
addOnCarry (!c) (!ws) = if isTrue# (c `eqWord#` 0##)
|
||||
then ws
|
||||
else succPositive ws
|
||||
|
||||
-- digit `elem` [0, 1]
|
||||
succPositive :: Positive -> Positive
|
||||
succPositive None = Some 1## None
|
||||
succPositive (Some w ws) = if isTrue# (w `eqWord#` fullBound ())
|
||||
then Some 0## (succPositive ws)
|
||||
else Some (w `plusWord#` 1##) ws
|
||||
|
||||
-- Requires x > y
|
||||
-- In recursive calls, x >= y and x == y => result is None
|
||||
-- Note [Avoid patError]
|
||||
minusPositive :: Positive -> Positive -> Positive
|
||||
Some x xs `minusPositive` Some y ys
|
||||
= if isTrue# (x `eqWord#` y)
|
||||
then case xs `minusPositive` ys of
|
||||
None -> None
|
||||
s -> Some 0## s
|
||||
else if isTrue# (x `gtWord#` y) then
|
||||
Some (x `minusWord#` y) (xs `minusPositive` ys)
|
||||
else case (fullBound () `minusWord#` y) `plusWord#` 1## of
|
||||
z -> -- z = 2^n - y, calculated without overflow
|
||||
case z `plusWord#` x of
|
||||
z' -> -- z = 2^n + (x - y), calculated without overflow
|
||||
Some z' ((xs `minusPositive` ys) `minusPositive` onePositive)
|
||||
xs@(Some {}) `minusPositive` None = xs
|
||||
None `minusPositive` None = None
|
||||
None `minusPositive` (Some {}) = errorPositive -- XXX Can't happen
|
||||
-- XXX None `minusPositive` _ = error "minusPositive: Requirement x > y not met"
|
||||
|
||||
-- Note [Avoid patError]
|
||||
timesPositive :: Positive -> Positive -> Positive
|
||||
-- XXX None's can't happen here:
|
||||
None `timesPositive` None = errorPositive
|
||||
None `timesPositive` (Some {}) = errorPositive
|
||||
(Some {}) `timesPositive` None = errorPositive
|
||||
-- x and y are the last digits in Positive numbers, so are not 0:
|
||||
xs@(Some x xs') `timesPositive` ys@(Some y ys')
|
||||
= case xs' of
|
||||
None ->
|
||||
case ys' of
|
||||
None ->
|
||||
x `timesDigit` y
|
||||
Some {} ->
|
||||
ys `timesPositive` xs
|
||||
Some {} ->
|
||||
case ys' of
|
||||
None ->
|
||||
-- y is the last digit in a Positive number, so is not 0.
|
||||
let zs = Some 0## (xs' `timesPositive` ys)
|
||||
in -- We could actually skip this test, and everything would
|
||||
-- turn out OK. We already play tricks like that in timesPositive.
|
||||
if isTrue# (x `eqWord#` 0##)
|
||||
then zs
|
||||
else (x `timesDigit` y) `plusPositive` zs
|
||||
Some {} ->
|
||||
(Some x None `timesPositive` ys) `plusPositive`
|
||||
Some 0## (xs' `timesPositive` ys)
|
||||
|
||||
{-
|
||||
-- Requires arguments /= 0
|
||||
Suppose we have 2n bits in a Word. Then
|
||||
x = 2^n xh + xl
|
||||
y = 2^n yh + yl
|
||||
x * y = (2^n xh + xl) * (2^n yh + yl)
|
||||
= 2^(2n) (xh yh)
|
||||
+ 2^n (xh yl)
|
||||
+ 2^n (xl yh)
|
||||
+ (xl yl)
|
||||
~~~~~~~ - all fit in 2n bits
|
||||
-}
|
||||
timesDigit :: Digit -> Digit -> Positive
|
||||
timesDigit (!x) (!y)
|
||||
= case splitHalves x of
|
||||
(# xh, xl #) ->
|
||||
case splitHalves y of
|
||||
(# yh, yl #) ->
|
||||
case xh `timesWord#` yh of
|
||||
xhyh ->
|
||||
case splitHalves (xh `timesWord#` yl) of
|
||||
(# xhylh, xhyll #) ->
|
||||
case xhyll `uncheckedShiftL#` highHalfShift () of
|
||||
xhyll' ->
|
||||
case splitHalves (xl `timesWord#` yh) of
|
||||
(# xlyhh, xlyhl #) ->
|
||||
case xlyhl `uncheckedShiftL#` highHalfShift () of
|
||||
xlyhl' ->
|
||||
case xl `timesWord#` yl of
|
||||
xlyl ->
|
||||
-- Add up all the high word results. As the result fits in
|
||||
-- 4n bits this can't overflow.
|
||||
case xhyh `plusWord#` xhylh `plusWord#` xlyhh of
|
||||
high ->
|
||||
-- low: xhyll<<n + xlyhl<<n + xlyl
|
||||
-- From this point we might make (Some 0 None), but we know
|
||||
-- that the final result will be positive and the addition
|
||||
-- will work out OK, so everything will work out in the end.
|
||||
-- One thing we do need to be careful of is avoiding returning
|
||||
-- Some 0 (Some 0 None) + Some n None, as this will result in
|
||||
-- Some n (Some 0 None) instead of Some n None.
|
||||
let low = Some xhyll' None `plusPositive`
|
||||
Some xlyhl' None `plusPositive`
|
||||
Some xlyl None
|
||||
in if isTrue# (high `eqWord#` 0##)
|
||||
then low
|
||||
else Some 0## (Some high None) `plusPositive` low
|
||||
|
||||
splitHalves :: Digit -> (# {- High -} Digit, {- Low -} Digit #)
|
||||
splitHalves (!x) = (# x `uncheckedShiftRL#` highHalfShift (),
|
||||
x `and#` lowHalfMask () #)
|
||||
|
||||
-- Assumes 0 <= i
|
||||
shiftLPositive :: Positive -> Int# -> Positive
|
||||
shiftLPositive p i
|
||||
= if isTrue# (i >=# WORD_SIZE_IN_BITS#)
|
||||
then shiftLPositive (Some 0## p) (i -# WORD_SIZE_IN_BITS#)
|
||||
else smallShiftLPositive p i
|
||||
|
||||
-- Assumes 0 <= i < WORD_SIZE_IN_BITS#
|
||||
smallShiftLPositive :: Positive -> Int# -> Positive
|
||||
smallShiftLPositive (!p) 0# = p
|
||||
smallShiftLPositive (!p) (!i) =
|
||||
case WORD_SIZE_IN_BITS# -# i of
|
||||
j -> let f carry None = if isTrue# (carry `eqWord#` 0##)
|
||||
then None
|
||||
else Some carry None
|
||||
f carry (Some w ws) = case w `uncheckedShiftRL#` j of
|
||||
carry' ->
|
||||
case w `uncheckedShiftL#` i of
|
||||
me ->
|
||||
Some (me `or#` carry) (f carry' ws)
|
||||
in f 0## p
|
||||
|
||||
-- Assumes 0 <= i
|
||||
shiftRPositive :: Positive -> Int# -> Integer
|
||||
shiftRPositive None _ = Naught
|
||||
shiftRPositive p@(Some _ q) i
|
||||
= if isTrue# (i >=# WORD_SIZE_IN_BITS#)
|
||||
then shiftRPositive q (i -# WORD_SIZE_IN_BITS#)
|
||||
else smallShiftRPositive p i
|
||||
|
||||
-- Assumes 0 <= i < WORD_SIZE_IN_BITS#
|
||||
smallShiftRPositive :: Positive -> Int# -> Integer
|
||||
smallShiftRPositive (!p) (!i) =
|
||||
if isTrue# (i ==# 0#)
|
||||
then Positive p
|
||||
else case smallShiftLPositive p (WORD_SIZE_IN_BITS# -# i) of
|
||||
Some _ p'@(Some _ _) -> Positive p'
|
||||
_ -> Naught
|
||||
|
||||
-- Long division
|
||||
quotRemPositive :: Positive -> Positive -> (# Integer, Integer #)
|
||||
(!xs) `quotRemPositive` (!ys)
|
||||
= case f xs of
|
||||
(# d, m #) -> (# digitsMaybeZeroToInteger d,
|
||||
digitsMaybeZeroToInteger m #)
|
||||
where
|
||||
subtractors :: Positives
|
||||
subtractors = mkSubtractors (WORD_SIZE_IN_BITS# -# 1#)
|
||||
|
||||
mkSubtractors (!n) = if isTrue# (n ==# 0#)
|
||||
then Cons ys Nil
|
||||
else Cons (ys `smallShiftLPositive` n)
|
||||
(mkSubtractors (n -# 1#))
|
||||
|
||||
-- The main function. Go the the end of xs, then walk
|
||||
-- back trying to divide the number we accumulate by ys.
|
||||
f :: Positive -> (# Digits, Digits #)
|
||||
f None = (# None, None #)
|
||||
f (Some z zs)
|
||||
= case f zs of
|
||||
(# ds, m #) ->
|
||||
let -- We need to avoid making (Some Zero None) here
|
||||
m' = some z m
|
||||
in case g 0## subtractors m' of
|
||||
(# d, m'' #) ->
|
||||
(# some d ds, m'' #)
|
||||
|
||||
g :: Digit -> Positives -> Digits -> (# Digit, Digits #)
|
||||
g (!d) Nil (!m) = (# d, m #)
|
||||
g (!d) (Cons sub subs) (!m)
|
||||
= case d `uncheckedShiftL#` 1# of
|
||||
d' ->
|
||||
case m `comparePositive` sub of
|
||||
LT -> g d' subs m
|
||||
_ -> g (d' `plusWord#` 1##)
|
||||
subs
|
||||
(m `minusPositive` sub)
|
||||
|
||||
some :: Digit -> Digits -> Digits
|
||||
some (!w) None = if isTrue# (w `eqWord#` 0##) then None else Some w None
|
||||
some (!w) (!ws) = Some w ws
|
||||
|
||||
-- Note [Avoid patError]
|
||||
andDigits :: Digits -> Digits -> Digits
|
||||
andDigits None None = None
|
||||
andDigits (Some {}) None = None
|
||||
andDigits None (Some {}) = None
|
||||
andDigits (Some w1 ws1) (Some w2 ws2) = Some (w1 `and#` w2) (andDigits ws1 ws2)
|
||||
|
||||
-- DigitsOnes is just like Digits, only None is really 0xFFFFFFF...,
|
||||
-- i.e. ones off to infinity. This makes sense when we want to "and"
|
||||
-- a DigitOnes with a Digits, as the latter will bound the size of the
|
||||
-- result.
|
||||
newtype DigitsOnes = DigitsOnes Digits
|
||||
|
||||
-- Note [Avoid patError]
|
||||
andDigitsOnes :: DigitsOnes -> Digits -> Digits
|
||||
andDigitsOnes (DigitsOnes None) None = None
|
||||
andDigitsOnes (DigitsOnes None) ws2@(Some {}) = ws2
|
||||
andDigitsOnes (DigitsOnes (Some {})) None = None
|
||||
andDigitsOnes (DigitsOnes (Some w1 ws1)) (Some w2 ws2)
|
||||
= Some (w1 `and#` w2) (andDigitsOnes (DigitsOnes ws1) ws2)
|
||||
|
||||
-- Note [Avoid patError]
|
||||
orDigits :: Digits -> Digits -> Digits
|
||||
orDigits None None = None
|
||||
orDigits None ds@(Some {}) = ds
|
||||
orDigits ds@(Some {}) None = ds
|
||||
orDigits (Some w1 ds1) (Some w2 ds2) = Some (w1 `or#` w2) (orDigits ds1 ds2)
|
||||
|
||||
-- Note [Avoid patError]
|
||||
xorDigits :: Digits -> Digits -> Digits
|
||||
xorDigits None None = None
|
||||
xorDigits None ds@(Some {}) = ds
|
||||
xorDigits ds@(Some {}) None = ds
|
||||
xorDigits (Some w1 ds1) (Some w2 ds2) = Some (w1 `xor#` w2) (xorDigits ds1 ds2)
|
||||
|
||||
-- XXX We'd really like word2Double# for this
|
||||
doubleFromPositive :: Positive -> Double#
|
||||
doubleFromPositive None = 0.0##
|
||||
doubleFromPositive (Some w ds)
|
||||
= case splitHalves w of
|
||||
(# h, l #) ->
|
||||
(doubleFromPositive ds *## (2.0## **## WORD_SIZE_IN_BITS_FLOAT##))
|
||||
+## (int2Double# (word2Int# h) *##
|
||||
(2.0## **## int2Double# (highHalfShift ())))
|
||||
+## int2Double# (word2Int# l)
|
||||
|
||||
-- XXX We'd really like word2Float# for this
|
||||
floatFromPositive :: Positive -> Float#
|
||||
floatFromPositive None = 0.0#
|
||||
floatFromPositive (Some w ds)
|
||||
= case splitHalves w of
|
||||
(# h, l #) ->
|
||||
(floatFromPositive ds `timesFloat#` (2.0# `powerFloat#` WORD_SIZE_IN_BITS_FLOAT#))
|
||||
`plusFloat#` (int2Float# (word2Int# h) `timesFloat#`
|
||||
(2.0# `powerFloat#` int2Float# (highHalfShift ())))
|
||||
`plusFloat#` int2Float# (word2Int# l)
|
||||
|
||||
{-
|
||||
Note [Avoid patError]
|
||||
|
||||
If we use the natural set of definitions for functions, e.g.:
|
||||
|
||||
orDigits None ds = ds
|
||||
orDigits ds None = ds
|
||||
orDigits (Some w1 ds1) (Some w2 ds2) = Some ... ...
|
||||
|
||||
then GHC may not be smart enough (especially when compiling with -O0)
|
||||
to see that all the cases are handled, and will thus insert calls to
|
||||
base:Control.Exception.Base.patError. But we are below base in the
|
||||
package hierarchy, so this causes build failure!
|
||||
|
||||
We therefore help GHC out, by being more explicit about what all the
|
||||
cases are:
|
||||
|
||||
orDigits None None = None
|
||||
orDigits None ds@(Some {}) = ds
|
||||
orDigits ds@(Some {}) None = ds
|
||||
orDigits (Some w1 ds1) (Some w2 ds2) = Some ... ...
|
||||
-}
|
||||
|
23
pkg/hs/urbit-integer-simple/urbit-integer-simple.cabal
Normal file
23
pkg/hs/urbit-integer-simple/urbit-integer-simple.cabal
Normal file
@ -0,0 +1,23 @@
|
||||
name: urbit-integer-simple
|
||||
version: 0.1.1.1
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
maintainer: igloo@earth.li
|
||||
synopsis: Simple Integer library
|
||||
description:
|
||||
This package contains an simple Integer library.
|
||||
cabal-version: >=1.10
|
||||
build-type: Simple
|
||||
|
||||
Library
|
||||
default-language: Haskell2010
|
||||
|
||||
build-depends: ghc-prim
|
||||
exposed-modules: Urbit.Integer
|
||||
Urbit.Integer.Simple.Internals
|
||||
Urbit.Integer.Logarithms
|
||||
Urbit.Integer.Logarithms.Internals
|
||||
other-modules: Urbit.Integer.Type
|
||||
default-extensions: CPP, MagicHash, BangPatterns, UnboxedTuples,
|
||||
UnliftedFFITypes, NoImplicitPrelude
|
||||
ghc-options: -Wall
|
Loading…
Reference in New Issue
Block a user