|
Packit |
785658 |
-- |
|
|
Packit |
785658 |
-- Module: GHC.Integer.Logarithms.Compat
|
|
Packit |
785658 |
-- Copyright: (c) 2011 Daniel Fischer
|
|
Packit |
785658 |
-- Licence: MIT
|
|
Packit |
785658 |
-- Maintainer: Daniel Fischer <daniel.is.fischer@googlemail.com>
|
|
Packit |
785658 |
-- Stability: Provisional
|
|
Packit |
785658 |
-- Portability: Non-portable (GHC extensions)
|
|
Packit |
785658 |
--
|
|
Packit |
785658 |
-- Low level stuff for integer logarithms.
|
|
Packit |
785658 |
{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}
|
|
Packit |
785658 |
module GHC.Integer.Logarithms.Compat
|
|
Packit |
785658 |
( -- * Functions
|
|
Packit |
785658 |
integerLogBase#
|
|
Packit |
785658 |
, integerLog2#
|
|
Packit |
785658 |
, wordLog2#
|
|
Packit |
785658 |
) where
|
|
Packit |
785658 |
|
|
Packit |
785658 |
#if __GLASGOW_HASKELL__ >= 702
|
|
Packit |
785658 |
|
|
Packit |
785658 |
-- Stuff is already there
|
|
Packit |
785658 |
import GHC.Integer.Logarithms
|
|
Packit |
785658 |
|
|
Packit |
785658 |
#else
|
|
Packit |
785658 |
|
|
Packit |
785658 |
-- We have to define it here
|
|
Packit |
785658 |
#include "MachDeps.h"
|
|
Packit |
785658 |
|
|
Packit |
785658 |
import GHC.Base
|
|
Packit |
785658 |
import GHC.Integer.GMP.Internals
|
|
Packit |
785658 |
|
|
Packit |
785658 |
#if (WORD_SIZE_IN_BITS != 32) && (WORD_SIZE_IN_BITS != 64)
|
|
Packit |
785658 |
#error Only word sizes 32 and 64 are supported.
|
|
Packit |
785658 |
#endif
|
|
Packit |
785658 |
|
|
Packit |
785658 |
|
|
Packit |
785658 |
#if WORD_SIZE_IN_BITS == 32
|
|
Packit |
785658 |
|
|
Packit |
785658 |
#define WSHIFT 5
|
|
Packit |
785658 |
#define MMASK 31
|
|
Packit |
785658 |
|
|
Packit |
785658 |
#else
|
|
Packit |
785658 |
|
|
Packit |
785658 |
#define WSHIFT 6
|
|
Packit |
785658 |
#define MMASK 63
|
|
Packit |
785658 |
|
|
Packit |
785658 |
#endif
|
|
Packit |
785658 |
|
|
Packit |
785658 |
-- Reference implementation only, the algorithm in M.NT.Logarithms is better.
|
|
Packit |
785658 |
|
|
Packit |
785658 |
-- | Calculate the integer logarithm for an arbitrary base.
|
|
Packit |
785658 |
-- The base must be greater than 1, the second argument, the number
|
|
Packit |
785658 |
-- whose logarithm is sought; should be positive, otherwise the
|
|
Packit |
785658 |
-- result is meaningless.
|
|
Packit |
785658 |
--
|
|
Packit |
785658 |
-- > base ^ integerLogBase# base m <= m < base ^ (integerLogBase# base m + 1)
|
|
Packit |
785658 |
--
|
|
Packit |
785658 |
-- for @base > 1@ and @m > 0@.
|
|
Packit |
785658 |
integerLogBase# :: Integer -> Integer -> Int#
|
|
Packit |
785658 |
integerLogBase# b m = case step b of
|
|
Packit |
785658 |
(# _, e #) -> e
|
|
Packit |
785658 |
where
|
|
Packit |
785658 |
step pw =
|
|
Packit |
785658 |
if m < pw
|
|
Packit |
785658 |
then (# m, 0# #)
|
|
Packit |
785658 |
else case step (pw * pw) of
|
|
Packit |
785658 |
(# q, e #) ->
|
|
Packit |
785658 |
if q < pw
|
|
Packit |
785658 |
then (# q, 2# *# e #)
|
|
Packit |
785658 |
else (# q `quot` pw, 2# *# e +# 1# #)
|
|
Packit |
785658 |
|
|
Packit |
785658 |
-- | Calculate the integer base 2 logarithm of an 'Integer'.
|
|
Packit |
785658 |
-- The calculation is much more efficient than for the general case.
|
|
Packit |
785658 |
--
|
|
Packit |
785658 |
-- The argument must be strictly positive, that condition is /not/ checked.
|
|
Packit |
785658 |
integerLog2# :: Integer -> Int#
|
|
Packit |
785658 |
integerLog2# (S# i) = wordLog2# (int2Word# i)
|
|
Packit |
785658 |
integerLog2# (J# s ba) = check (s -# 1#)
|
|
Packit |
785658 |
where
|
|
Packit |
785658 |
check i = case indexWordArray# ba i of
|
|
Packit |
785658 |
0## -> check (i -# 1#)
|
|
Packit |
785658 |
w -> wordLog2# w +# (uncheckedIShiftL# i WSHIFT#)
|
|
Packit |
785658 |
|
|
Packit |
785658 |
-- | This function calculates the integer base 2 logarithm of a 'Word#'.
|
|
Packit |
785658 |
-- @'wordLog2#' 0## = -1#@.
|
|
Packit |
785658 |
{-# INLINE wordLog2# #-}
|
|
Packit |
785658 |
wordLog2# :: Word# -> Int#
|
|
Packit |
785658 |
wordLog2# w =
|
|
Packit |
785658 |
case leadingZeros of
|
|
Packit |
785658 |
BA lz ->
|
|
Packit |
785658 |
let zeros u = indexInt8Array# lz (word2Int# u) in
|
|
Packit |
785658 |
#if WORD_SIZE_IN_BITS == 64
|
|
Packit |
785658 |
case uncheckedShiftRL# w 56# of
|
|
Packit |
785658 |
a ->
|
|
Packit |
785658 |
if a `neWord#` 0##
|
|
Packit |
785658 |
then 64# -# zeros a
|
|
Packit |
785658 |
else
|
|
Packit |
785658 |
case uncheckedShiftRL# w 48# of
|
|
Packit |
785658 |
b ->
|
|
Packit |
785658 |
if b `neWord#` 0##
|
|
Packit |
785658 |
then 56# -# zeros b
|
|
Packit |
785658 |
else
|
|
Packit |
785658 |
case uncheckedShiftRL# w 40# of
|
|
Packit |
785658 |
c ->
|
|
Packit |
785658 |
if c `neWord#` 0##
|
|
Packit |
785658 |
then 48# -# zeros c
|
|
Packit |
785658 |
else
|
|
Packit |
785658 |
case uncheckedShiftRL# w 32# of
|
|
Packit |
785658 |
d ->
|
|
Packit |
785658 |
if d `neWord#` 0##
|
|
Packit |
785658 |
then 40# -# zeros d
|
|
Packit |
785658 |
else
|
|
Packit |
785658 |
#endif
|
|
Packit |
785658 |
case uncheckedShiftRL# w 24# of
|
|
Packit |
785658 |
e ->
|
|
Packit |
785658 |
if e `neWord#` 0##
|
|
Packit |
785658 |
then 32# -# zeros e
|
|
Packit |
785658 |
else
|
|
Packit |
785658 |
case uncheckedShiftRL# w 16# of
|
|
Packit |
785658 |
f ->
|
|
Packit |
785658 |
if f `neWord#` 0##
|
|
Packit |
785658 |
then 24# -# zeros f
|
|
Packit |
785658 |
else
|
|
Packit |
785658 |
case uncheckedShiftRL# w 8# of
|
|
Packit |
785658 |
g ->
|
|
Packit |
785658 |
if g `neWord#` 0##
|
|
Packit |
785658 |
then 16# -# zeros g
|
|
Packit |
785658 |
else 8# -# zeros w
|
|
Packit |
785658 |
|
|
Packit |
785658 |
-- Lookup table
|
|
Packit |
785658 |
data BA = BA ByteArray#
|
|
Packit |
785658 |
|
|
Packit |
785658 |
leadingZeros :: BA
|
|
Packit |
785658 |
leadingZeros =
|
|
Packit |
785658 |
let mkArr s =
|
|
Packit |
785658 |
case newByteArray# 256# s of
|
|
Packit |
785658 |
(# s1, mba #) ->
|
|
Packit |
785658 |
case writeInt8Array# mba 0# 9# s1 of
|
|
Packit |
785658 |
s2 ->
|
|
Packit |
785658 |
let fillA lim val idx st =
|
|
Packit |
785658 |
if idx ==# 256#
|
|
Packit |
785658 |
then st
|
|
Packit |
785658 |
else if idx <# lim
|
|
Packit |
785658 |
then case writeInt8Array# mba idx val st of
|
|
Packit |
785658 |
nx -> fillA lim val (idx +# 1#) nx
|
|
Packit |
785658 |
else fillA (2# *# lim) (val -# 1#) idx st
|
|
Packit |
785658 |
in case fillA 2# 8# 1# s2 of
|
|
Packit |
785658 |
s3 -> case unsafeFreezeByteArray# mba s3 of
|
|
Packit |
785658 |
(# _, ba #) -> ba
|
|
Packit |
785658 |
in case mkArr realWorld# of
|
|
Packit |
785658 |
b -> BA b
|
|
Packit |
785658 |
|
|
Packit |
785658 |
#endif
|