Blame src/GHC/Integer/Logarithms/Compat.hs

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