Re: [Haskell-cafe] Looking for largest power of 2 <= Integer

On Dec 3, 2007 10:05 PM, David Benbennick
Could you please post your code here when you're done? I'd be interested to see the final result.
This is just experimental code I'm playing with in order to implement exact real arithmetic, so there'll never be a "final" result :-) But this is what I'm currently playing with. It's hard-coded for a platform with 64 bit Ints and 64 bit "limbs" of Integers. This is my first ever foray into the binary underbelly of Haskell, using information from http://www.haskell.org/ghc/docs/4.06/users_guide/ghc-libs-ghc.html, and I've probably written this code really stupidly. import GHC.Exts import Data.Bits fastTestBit :: Integer -> Int -> Bool fastTestBit n i = case n of S# m -> testBit (I# m) i J# l d -> let I# w = shiftR i 6 b = i .&. 63 in testBit (I# (indexIntArray# d w)) b -- Assumes n/=0 topBit :: Integer -> Int topBit n = case n of S# m -> topBit' n 63 J# l _ -> topBit' n (64*I# l-1) where topBit' n i = if fastTestBit n i then i else topBit' n (i-1) I don't need something super-fast (ie. clever bit twiddling tricks), just something not stupidly slow. Despite what dons says, testBit is stupidly slow :-) fastTestbit takes microseconds instead of seconds on 2^10000000. Maybe a portable tidied up version of fastTestBit ought to go into Data.Bits. These kinds of operations are ubiquitous in numerical algorithms. And note the fixed title :-) -- Dan

dpiponi:
On Dec 3, 2007 10:05 PM, David Benbennick
wrote: Could you please post your code here when you're done? I'd be interested to see the final result.
This is just experimental code I'm playing with in order to implement exact real arithmetic, so there'll never be a "final" result :-) But this is what I'm currently playing with. It's hard-coded for a platform with 64 bit Ints and 64 bit "limbs" of Integers. This is my first ever foray into the binary underbelly of Haskell, using information from http://www.haskell.org/ghc/docs/4.06/users_guide/ghc-libs-ghc.html, and I've probably written this code really stupidly.
import GHC.Exts import Data.Bits
fastTestBit :: Integer -> Int -> Bool fastTestBit n i = case n of S# m -> testBit (I# m) i J# l d -> let I# w = shiftR i 6 b = i .&. 63 in testBit (I# (indexIntArray# d w)) b
-- Assumes n/=0 topBit :: Integer -> Int topBit n = case n of S# m -> topBit' n 63 J# l _ -> topBit' n (64*I# l-1) where topBit' n i = if fastTestBit n i then i else topBit' n (i-1)
I don't need something super-fast (ie. clever bit twiddling tricks), just something not stupidly slow. Despite what dons says, testBit is stupidly slow :-) fastTestbit takes microseconds instead of seconds on 2^10000000. Maybe a portable tidied up version of fastTestBit ought to go into Data.Bits. These kinds of operations are ubiquitous in numerical algorithms.
Awesome. We can use this in Data.Bits, if you've got some QuickChecks for it. -- Don

On Dec 4, 2007 11:51 AM, Don Stewart
Awesome. We can use this in Data.Bits, if you've got some QuickChecks for it.
Hear hear. But is there any way to just make the compiler use fastTestBit in place of testBit :: (Bits a) => a -> Int -> Bool when a = Integer? (That is, without having to introduce a new function to the public interface of Data.Bits.) Some kind of SPECIALIZE pragma, perhaps? I've attached a program with two QuickCheck properties. Unfortunately they fail on negative Integers. I can't figure out why.

dbenbenn:
On Dec 4, 2007 11:51 AM, Don Stewart
wrote: Awesome. We can use this in Data.Bits, if you've got some QuickChecks for it.
Hear hear. But is there any way to just make the compiler use fastTestBit in place of testBit :: (Bits a) => a -> Int -> Bool when a = Integer? (That is, without having to introduce a new function to the public interface of Data.Bits.) Some kind of SPECIALIZE pragma, perhaps?
{-# RULES "Integer fastTestBit" forall x n. testBit x n = fastTestBit :: Integer -> Int -> Bool #-} I think should work. If testBit is in the Bits class though, we can just add it for instance Bits Integer -- Don

There's a bit of work required to make this code good enough for general consumption, and I don't know much about Haskell internals. (1) What is the "official" way to find the size of a word? A quick look at 6.8.1's base/GHC/Num.lhs reveals that it uses a #defined symbol. (2) Is it safe to assume an underlying implementation based on GMP? (In Num.lhs there is an alternative definition for .NET. Is that ever used?) Is it safe to assume the size of a GMP "limb" is the same as the word size? (I'm assuming it is for now.) David said:
I've attached a program with two QuickCheck properties. Unfortunately they fail on negative Integers. I can't figure out why.
Judging by Num.lhs, the sign of the Integer is stored as the sign of the length of the Integer in "limbs". The code needs to deal with that explicitly, as well as doing some bounds checking on the index. Anyway, if someone can help with those questions I can try to write a bulletproof version of the code. -- Dan

| (2) Is it safe to assume an underlying implementation based on GMP? | (In Num.lhs there is an alternative definition for .NET. Is that ever | used?) Is it safe to assume the size of a GMP "limb" is the same as | the word size? (I'm assuming it is for now.) I think it's safe for now. In principle the impl of Integer could be anything, and various people would like it to be something other than gmp for licensing reasons. But as of today, it's always gmp. Simon

Dan Piponi wrote:
There's a bit of work required to make this code good enough for general consumption, and I don't know much about Haskell internals.
(1) What is the "official" way to find the size of a word? A quick look at 6.8.1's base/GHC/Num.lhs reveals that it uses a #defined symbol.
I'm not 100% sure what you mean by "word" in this context, but assuming you mean the same thing as we do in GHC when we say "word" (a pointer-sized integral type), then one way is Foreign.sizeOf (undefined :: Int) or Foreign.sizeOf (undefined :: Ptr ()) (in GHC these are guaranteed to be the same). There's also Data.Bits.bitSize (undefined :: Int) which might be more appropriate since you're using Data.Bits anyway. Cheers, Simon

On Tuesday 04 December 2007 15:47:19 David Benbennick wrote:
On Dec 4, 2007 11:51 AM, Don Stewart
wrote: Awesome. We can use this in Data.Bits, if you've got some QuickChecks for it.
Hear hear. But is there any way to just make the compiler use fastTestBit in place of testBit :: (Bits a) => a -> Int -> Bool when a = Integer? (That is, without having to introduce a new function to the public interface of Data.Bits.) Some kind of SPECIALIZE pragma, perhaps?
I've attached a program with two QuickCheck properties. Unfortunately they fail on negative Integers. I can't figure out why.
No fancy specialization is needed. Since testBit is part of the Bits class, simply 'testBit = fastTestBit' in the instance for Integer. Cheers, Spencer Janssen
participants (6)
-
Dan Piponi
-
David Benbennick
-
Don Stewart
-
Simon Marlow
-
Simon Peyton-Jones
-
Spencer Janssen