content: module T23907 (loop) where
  
  import Data.Word
  import Data.Bits
  
  {-# NOINLINE loop #-}
  loop :: Int -> Double -> SMGen -> (Double, SMGen)
  loop 0 !a !s = (a, s)
  loop n !a !s = loop (n - 1) (a + b) t where (b, t) = nextDouble s
  
  mix64 :: Word64 -> Word64
  mix64 z0 =
     -- MurmurHash3Mixer
      let z1 = shiftXorMultiply 33 0xff51afd7ed558ccd z0
          z2 = shiftXorMultiply 33 0xc4ceb9fe1a85ec53 z1
          z3 = shiftXor 33 z2
      in z3
  
  shiftXor :: Int -> Word64 -> Word64
  shiftXor n w = w `xor` (w `shiftR` n)
  
  shiftXorMultiply :: Int -> Word64 -> Word64 -> Word64
  shiftXorMultiply n k w = shiftXor n w * k
  
  nextWord64 :: SMGen -> (Word64, SMGen)
  nextWord64 (SMGen seed gamma) = (mix64 seed', SMGen seed' gamma)
    where
      seed' = seed + gamma
  
  nextDouble :: SMGen -> (Double, SMGen)
  nextDouble g = case nextWord64 g of
      (w64, g') -> (fromIntegral (w64 `shiftR` 11) * doubleUlp, g')
  
  data SMGen = SMGen !Word64 !Word64 -- seed and gamma; gamma is odd
  
  mkSMGen :: Word64 -> SMGen
  mkSMGen s = SMGen (mix64 s) (mixGamma (s + goldenGamma))
  
  goldenGamma :: Word64
  goldenGamma = 0x9e3779b97f4a7c15
  
  floatUlp :: Float
  floatUlp =  1.0 / fromIntegral (1 `shiftL` 24 :: Word32)
  
  doubleUlp :: Double
  doubleUlp =  1.0 / fromIntegral (1 `shiftL` 53 :: Word64)
  
  mix64variant13 :: Word64 -> Word64
  mix64variant13 z0 =
     -- Better Bit Mixing - Improving on MurmurHash3's 64-bit Finalizer
     -- http://zimbry.blogspot.fi/2011/09/better-bit-mixing-improving-on.html
     --
     -- Stafford's Mix13
      let z1 = shiftXorMultiply 30 0xbf58476d1ce4e5b9 z0 -- MurmurHash3 mix constants
          z2 = shiftXorMultiply 27 0x94d049bb133111eb z1
          z3 = shiftXor 31 z2
      in z3
  
  mixGamma :: Word64 -> Word64
  mixGamma z0 =
      let z1 = mix64variant13 z0 .|. 1             -- force to be odd
          n  = popCount (z1 `xor` (z1 `shiftR` 1))
      -- see: http://www.pcg-random.org/posts/bugs-in-splitmix.html
      -- let's trust the text of the paper, not the code.
      in if n >= 24
          then z1
          else z1 `xor` 0xaaaaaaaaaaaaaaaa
  