Ticket #4344: logarithms-integer-simple.dpatch

File logarithms-integer-simple.dpatch, 8.2 KB (added by daniel.is.fischer, 3 years ago)
Line 
11 patch for repository /home/dafis/Haskell/Hacking/ghc/libraries/integer-simple:
2
3Mon Oct 25 21:56:27 CEST 2010  Daniel Fischer <daniel.is.fischer@web.de>
4  * Logarithms for integer-simple
5  Integer logarithms as needed for fromRational.
6  So far, they have not been optimised at all.
7
8New patches:
9
10[Logarithms for integer-simple
11Daniel Fischer <daniel.is.fischer@web.de>**20101025195627
12 Ignore-this: f720182ed430fcc6788e3296ea250e3c
13 Integer logarithms as needed for fromRational.
14 So far, they have not been optimised at all.
15] {
16adddir ./GHC/Integer/Logarithms
17addfile ./GHC/Integer/Logarithms.hs
18hunk ./GHC/Integer/Logarithms.hs 1
19+{-# LANGUAGE MagicHash, UnboxedTuples, NoImplicitPrelude #-}
20+module GHC.Integer.Logarithms
21+    ( integerLogBase#
22+    , integerLog2#
23+    , wordLog2#
24+    ) where
25+
26+import GHC.Prim
27+import GHC.Integer
28+import qualified GHC.Integer.Logarithms.Internals as I
29+
30+-- | Calculate the integer logarithm for an arbitrary base.
31+--   The base must be greater than 1, the second argument, the number
32+--   whose logarithm is sought, should be positive, otherwise the
33+--   result is meaningless.
34+--
35+-- >
36+--   base ^ integerLogBase# base m <= m < base ^ (integerLogBase# base m + 1)
37+-- >
38+--
39+-- for @base > 1@ and @m > 0@.
40+integerLogBase# :: Integer -> Integer -> Int#
41+integerLogBase# b m = case step b of
42+                        (# _, e #) -> e
43+  where
44+    step pw =
45+      if m `ltInteger` pw
46+        then (# m, 0# #)
47+        else case step (pw `timesInteger` pw) of
48+               (# q, e #) ->
49+                 if q `ltInteger` pw
50+                   then (# q, 2# *# e #)
51+                   else (# q `quotInteger` pw, 2# *# e +# 1# #)
52+
53+-- | Calculate the integer base 2 logarithm of an 'Integer'.
54+--   The calculation should be more efficient than for the general case.
55+--
56+--  The argument must be strictly positive, that condition is /not/ checked.
57+integerLog2# :: Integer -> Int#
58+integerLog2# = I.integerLog2#
59+
60+-- | This function calculates the integer base 2 logarithm of a 'Word#'.
61+wordLog2# :: Word# -> Int#
62+wordLog2# = I.wordLog2#
63addfile ./GHC/Integer/Logarithms/Internals.hs
64hunk ./GHC/Integer/Logarithms/Internals.hs 1
65+{-# LANGUAGE CPP, MagicHash, UnboxedTuples, NoImplicitPrelude #-}
66+{-# OPTIONS_HADDOCK hide #-}
67+
68+#include "MachDeps.h"
69+
70+module GHC.Integer.Logarithms.Internals
71+    ( integerLog2#
72+    , integerLog2IsPowerOf2#
73+    , wordLog2#
74+    , roundingMode#
75+    ) where
76+
77+import GHC.Prim
78+import GHC.Integer.Type
79+import GHC.Integer
80+
81+default ()
82+
83+-- When larger word sizes become common, add support for those,
84+-- it is not hard, just tedious.
85+#if (WORD_SIZE_IN_BITS != 32) && (WORD_SIZE_IN_BITS != 64)
86+
87+-- We do not know whether the word has 30 bits or 128 or even more,
88+-- so we cannot start from the top, although that would be much more
89+-- efficient.
90+wordLog2# :: Word# -> Int#
91+wordLog2# w = go 8# w
92+  where
93+    go acc u = case u `uncheckedShiftRL#` 8# of
94+                0## -> case leadingZeros of
95+                        BA ba -> acc -# indexInt8Array# ba (word2Int# u)
96+                v   -> go (acc +# 8#) v
97+
98+#else
99+
100+-- This one at least can also be done efficiently.
101+-- wordLog2# 0## = -1#
102+{-# INLINE wordLog2# #-}
103+wordLog2# :: Word# -> Int#
104+wordLog2# w =
105+  case leadingZeros of
106+   BA lz ->
107+    let zeros u = indexInt8Array# lz (word2Int# u) in
108+#if WORD_SIZE_IN_BITS == 64
109+    case uncheckedShiftRL# w 56# of
110+     a ->
111+      if a `neWord#` 0##
112+       then 64# -# zeros a
113+       else
114+        case uncheckedShiftRL# w 48# of
115+         b ->
116+          if b `neWord#` 0##
117+           then 56# -# zeros b
118+           else
119+            case uncheckedShiftRL# w 40# of
120+             c ->
121+              if c `neWord#` 0##
122+               then 48# -# zeros c
123+               else
124+                case uncheckedShiftRL# w 32# of
125+                 d ->
126+                  if d `neWord#` 0##
127+                   then 40# -# zeros d
128+                   else
129+#endif
130+                    case uncheckedShiftRL# w 24# of
131+                     e ->
132+                      if e `neWord#` 0##
133+                       then 32# -# zeros e
134+                       else
135+                        case uncheckedShiftRL# w 16# of
136+                         f ->
137+                          if f `neWord#` 0##
138+                           then 24# -# zeros f
139+                           else
140+                            case uncheckedShiftRL# w 8# of
141+                             g ->
142+                              if g `neWord#` 0##
143+                               then 16# -# zeros g
144+                               else  8# -# zeros w
145+
146+#endif
147+
148+-- As for the rest, I will see later what efficiency we can gain.
149+
150+-- Assumption: Integer is strictly positive
151+integerLog2# :: Integer -> Int#
152+integerLog2# m = case step m (smallInteger 2#) 1# of
153+                    (# _, l #) -> l
154+  where
155+    -- Invariants:
156+    -- pw = 2 ^ lg
157+    -- case step n pw lg of
158+    --   (q, e) -> pw^(2*e) <= n < pw^(2*e+2)
159+    --              && q <= n/pw^(2*e) < (q+1)
160+    --              && q < pw^2
161+    step n pw lg =
162+      if n `ltInteger` pw
163+        then (# n, 0# #)
164+        else case step n (shiftLInteger pw lg) (2# *# lg) of
165+              (# q, e #) ->
166+                if q `ltInteger` pw
167+                  then (# q, 2# *# e #)
168+                  else (# q `shiftRInteger` lg, 2# *# e +# 1# #)
169+
170+integerLog2IsPowerOf2# :: Integer -> (# Int#, Int# #)
171+integerLog2IsPowerOf2# m =
172+    case integerLog2# m of
173+      lg -> if m `eqInteger` (smallInteger 1# `shiftLInteger` lg)
174+              then (# lg, 0# #)
175+              else (# lg, 1# #)
176+
177+roundingMode# :: Integer -> Int# -> Int#
178+roundingMode# m h =
179+    case smallInteger 1# `shiftLInteger` h of
180+      c -> case m `andInteger`
181+                ((c `plusInteger` c) `minusInteger` smallInteger 1#) of
182+             r ->
183+               if c `ltInteger` r
184+                 then 2#
185+                 else if c `gtInteger` r
186+                        then 0#
187+                        else 1#
188+
189+-- Lookup table
190+data BA = BA ByteArray#
191+
192+leadingZeros :: BA
193+leadingZeros =
194+    let mkArr s =
195+          case newByteArray# 256# s of
196+            (# s1, mba #) ->
197+              case writeInt8Array# mba 0# 9# s1 of
198+                s2 ->
199+                  let fillA lim val idx st =
200+                        if idx ==# 256#
201+                          then st
202+                          else if idx <# lim
203+                                then case writeInt8Array# mba idx val st of
204+                                        nx -> fillA lim val (idx +# 1#) nx
205+                                else fillA (2# *# lim) (val -# 1#) idx st
206+                  in case fillA 2# 8# 1# s2 of
207+                      s3 -> case unsafeFreezeByteArray# mba s3 of
208+                              (# _, ba #) -> ba
209+    in case mkArr realWorld# of
210+        b -> BA b
211hunk ./integer-simple.cabal 16
212     build-depends: ghc-prim
213     exposed-modules: GHC.Integer
214                      GHC.Integer.Simple.Internals
215+                     GHC.Integer.Logarithms
216+                     GHC.Integer.Logarithms.Internals
217     other-modules: GHC.Integer.Type
218     extensions: CPP, MagicHash, BangPatterns, UnboxedTuples,
219                 ForeignFunctionInterface, UnliftedFFITypes,
220}
221
222Context:
223
224[Follow GHC.Bool/GHC.Types merge
225Ian Lynagh <igloo@earth.li>**20101023153842
226 Ignore-this: eb0bf266cd02a9a11edd84bb0db02b92
227]
228[Pad version to 0.1.0.0
229Ian Lynagh <igloo@earth.li>**20090920141930]
230[Add NoImplicitPrelude to the extensions used
231Ian Lynagh <igloo@earth.li>**20090722174729]
232[Add an import so the deps get sorted out correctly
233Ian Lynagh <igloo@earth.li>**20090722162843]
234[() is now available, so use that instead of our own
235Ian Lynagh <igloo@earth.li>**20090722161829]
236[Follow changes in GHC and the other libraries
237Ian Lynagh <igloo@earth.li>**20090722131507]
238[Fix conversions between Float/Double and simple-integer
239Ian Lynagh <igloo@earth.li>**20080614152452]
240[Sprinkle on some strictness annotations
241Ian Lynagh <igloo@earth.li>**20080602193146]
242[Make the Integer type components strict
243Ian Lynagh <igloo@earth.li>**20080602185149]
244[Avoid the need for infinite Integers when doing bitwise operations
245Ian Lynagh <igloo@earth.li>**20080602184237]
246[Initial commit
247Ian Lynagh <igloo@earth.li>**20080425024824]
248Patch bundle hash:
249b0abc0640f6fa306df1d127dbed7917198b4eab7