Shift the gold testing infrastructure into its own module, and add the Haskell program I used to generate the tests.
This commit is contained in:
6003
tests/add_tests.txt
6003
tests/add_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
10005
tests/barrett_tests.txt
10005
tests/barrett_tests.txt
File diff suppressed because it is too large
Load Diff
6006
tests/div_tests.txt
6006
tests/div_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
244
tests/math/GenerateMathTests.hs
Normal file
244
tests/math/GenerateMathTests.hs
Normal file
@@ -0,0 +1,244 @@
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
import Control.Monad
|
||||
import Data.Bits
|
||||
import Data.List
|
||||
import qualified Data.Map.Strict as Map
|
||||
import GHC.Integer.GMP.Internals
|
||||
import Numeric
|
||||
import System.IO
|
||||
import System.Random
|
||||
import Debug.Trace
|
||||
|
||||
type Generator a = StdGen -> a -> (Maybe [(String, Integer)], a, StdGen)
|
||||
|
||||
iterations :: Int
|
||||
iterations = 5000
|
||||
|
||||
maxSize :: Int
|
||||
maxSize = 8
|
||||
|
||||
randomVal :: (Integer -> Bool) -> StdGen -> (Integer, StdGen)
|
||||
randomVal filter g =
|
||||
let (mySize, g') = randomR (1, maxSize) g
|
||||
(possible, g'') = go g' mySize
|
||||
in if filter possible
|
||||
then (possible, g'')
|
||||
else randomVal filter g''
|
||||
where
|
||||
go rng 0 = (0, rng)
|
||||
go rng i =
|
||||
let (other, rng') = go rng (i - 1)
|
||||
(self, rng'') = random rng'
|
||||
in ((other `shiftL` 64) + self, rng'')
|
||||
|
||||
buildBasicGenerator :: (Integer -> Bool) ->
|
||||
(Integer -> Integer -> Maybe Integer) ->
|
||||
Generator ()
|
||||
buildBasicGenerator filter f g () =
|
||||
let (x, g') = randomVal filter g
|
||||
(y, g'') = randomVal filter g'
|
||||
in case f x y of
|
||||
Nothing ->
|
||||
(Nothing, (), g'')
|
||||
Just z ->
|
||||
(Just [("x", x), ("y", y), ("z", z)], (), g'')
|
||||
|
||||
buildBasicLimitingGenerator :: (Integer -> Bool) ->
|
||||
(Integer -> Integer -> Maybe Integer) ->
|
||||
Generator (Map.Map Integer Int)
|
||||
buildBasicLimitingGenerator filter f g m =
|
||||
let (x, g') = randomVal filter g
|
||||
(y, g'') = randomVal filter g'
|
||||
in case f x y of
|
||||
Nothing -> (Nothing, m, g'')
|
||||
Just z ->
|
||||
case Map.lookup z m of
|
||||
Nothing ->
|
||||
(Just [("x",x),("y",y),("z",z)], Map.insert z 1 m, g'')
|
||||
Just c | c >= 100 ->
|
||||
(Nothing, m, g'')
|
||||
Just c ->
|
||||
(Just [("x",x),("y",y),("z",z)], Map.insert z (c + 1) m, g'')
|
||||
|
||||
buildBasicAccGenerator :: (Integer -> Bool) ->
|
||||
(Integer -> Integer -> a -> Maybe (Integer, a)) ->
|
||||
Generator a
|
||||
buildBasicAccGenerator filter f g acc =
|
||||
let (x, g') = randomVal filter g
|
||||
(y, g'') = randomVal filter g'
|
||||
in case f x y acc of
|
||||
Nothing ->
|
||||
(Nothing, acc, g'')
|
||||
Just (z, acc') ->
|
||||
(Just [("x", x), ("y", y), ("z", z)], acc', g'')
|
||||
|
||||
runGenerator :: forall a. StdGen -> String -> a -> Generator a -> IO StdGen
|
||||
runGenerator g filename initVal generator =
|
||||
withFile (filename ++ ".tests") WriteMode $ \ hndl ->
|
||||
do putStrLn ("Generating " ++ filename ++ ".tests")
|
||||
go hndl g initVal iterations
|
||||
where
|
||||
go :: Handle -> StdGen -> a -> Int -> IO StdGen
|
||||
go _ g _ 0 = return g
|
||||
go hndl g acc iterations =
|
||||
case generator g acc of
|
||||
(Nothing, acc', g') ->
|
||||
go hndl g' acc' iterations
|
||||
(Just res, acc', g') ->
|
||||
do let sorted = sort res
|
||||
forM_ sorted $ \ (key, val) ->
|
||||
do let neg = if val < 0 then "-" else ""
|
||||
val' = abs val
|
||||
hPutStrLn hndl (key ++ ": " ++ neg ++ showHex val' "")
|
||||
go hndl g' acc' (iterations - 1)
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
do g0 <- newStdGen
|
||||
g1 <- runGenerator g0 "unsigned_add" () $
|
||||
buildBasicGenerator (>= 0) $ \ a b -> Just (a + b)
|
||||
g2 <- runGenerator g1 "signed_add" () $
|
||||
buildBasicGenerator (const True) $ \ a b -> Just (a + b)
|
||||
g3 <- runGenerator g2 "unsigned_sub" () $
|
||||
buildBasicGenerator (>= 0) $ \ a b ->
|
||||
if a >= b then Just (a - b) else Nothing
|
||||
g4 <- runGenerator g3 "signed_sub" () $
|
||||
buildBasicGenerator (const True) $ \ a b -> Just (a - b)
|
||||
g5 <- runGenerator g4 "unsigned_mul" () $
|
||||
buildBasicGenerator (>= 0) $ \ a b -> Just (a * b)
|
||||
g6 <- runGenerator g5 "signed_mul" () $
|
||||
buildBasicGenerator (const True) $ \ a b -> Just (a * b)
|
||||
g7 <- runGenerator g6 "unsigned_div" Map.empty $
|
||||
buildBasicLimitingGenerator (>= 0) $ \ a b ->
|
||||
if b == 0 then Nothing else Just (a `div` b)
|
||||
g8 <- runGenerator g7 "signed_div" Map.empty $
|
||||
buildBasicLimitingGenerator (const True) $ \ a b ->
|
||||
if b == 0 then Nothing else Just (a `div` b)
|
||||
g7 <- runGenerator g6 "unsigned_mod" 0 $
|
||||
buildBasicAccGenerator (>= 0) $ \ a b i ->
|
||||
case a `mod` b of
|
||||
_ | b == 0 -> Nothing
|
||||
x | (a == x) && (i == 100) -> Nothing
|
||||
x | a == x -> Just (x, i + 1)
|
||||
x -> Just (x, i)
|
||||
g8 <- runGenerator g7 "signed_mod" 0 $
|
||||
buildBasicAccGenerator (const True) $ \ a b i ->
|
||||
case a `mod` b of
|
||||
_ | b == 0 -> Nothing
|
||||
x | (a == x) && (i == 100) -> Nothing
|
||||
x | a == x -> Just (x, i + 1)
|
||||
x -> Just (x, i)
|
||||
g9 <- runGenerator g8 "modexp" () $ \ g () ->
|
||||
let (a, g') = randomVal (>= 0) g
|
||||
(b, g'') = randomVal (>= 0) g'
|
||||
(m, g''') = randomVal (>= 0) g''
|
||||
z = powModInteger a b m
|
||||
res = [("a",a),("b",b),("m",m),("z",z)]
|
||||
in if m == 0
|
||||
then (Nothing, (), g''')
|
||||
else (Just res, (), g''')
|
||||
_ <- runGenerator g9 "barrett" () $ \ g () ->
|
||||
let (m, g') = randomVal (>= 0) g
|
||||
(v, g'') = randomVal (>= 0) g'
|
||||
barrett = barrett_u m
|
||||
vk = computeK v
|
||||
in if vk > (2 * (bk barrett))
|
||||
then (Nothing, (), g'')
|
||||
else let me = reduce v barrett
|
||||
standard = v `mod` m
|
||||
res = [("m", m), ("v", v), ("r", me),
|
||||
("u", bu barrett), ("k", fromIntegral (bk barrett))]
|
||||
in if me /= standard
|
||||
then error "Barrett broken"
|
||||
else (Just res, (), g'')
|
||||
|
||||
return ()
|
||||
|
||||
-- Implement Barrett reduction using incredibly simplistic implementations, to
|
||||
-- be sure we got it right.
|
||||
--
|
||||
b :: Integer
|
||||
b = 2 ^ 64
|
||||
|
||||
computeK :: Integer -> Int
|
||||
computeK v = go 0 1
|
||||
where
|
||||
go k acc
|
||||
| v < acc = k
|
||||
| otherwise = go (k + 1) (acc * b)
|
||||
|
||||
data Barrett = Barrett { bm :: Integer, bu :: Integer, bk :: Int }
|
||||
deriving (Show)
|
||||
|
||||
barrett_u :: Integer -> Barrett
|
||||
barrett_u x = Barrett {
|
||||
bm = x,
|
||||
bu = (b ^ (2 * k)) `div` x,
|
||||
bk = k
|
||||
}
|
||||
where k = computeK x
|
||||
|
||||
reduce :: Integer -> Barrett -> Integer
|
||||
reduce x barrett = result
|
||||
where
|
||||
k = bk barrett
|
||||
u = bu barrett
|
||||
m = bm barrett
|
||||
--
|
||||
q1 = x `div` (b ^ (k - 1))
|
||||
q2 = q1 * u
|
||||
q3 = q2 `div` (b ^ (k + 1))
|
||||
r1 = x `mod` (b ^ (k + 1))
|
||||
r2 = (q3 * m) `mod` (b ^ (k + 1))
|
||||
r = r1 - r2
|
||||
r' = if r < 0 then r + (b ^ (k + 1)) else r
|
||||
result = minimize r' m
|
||||
|
||||
minimize :: Integer -> Integer -> Integer
|
||||
minimize r m | r < 0 = error "BLECH"
|
||||
| r >= m = minimize (r - m) m
|
||||
| otherwise = r
|
||||
|
||||
-- runOperation :: Handle -> IO ()
|
||||
-- runOperation hndl =
|
||||
-- do m <- randomVal =<< randomRIO (1,size)
|
||||
-- v <- randomVal =<< randomRIO (1,size)
|
||||
-- let barrett = barrett_u m
|
||||
-- let vk = computeK v
|
||||
-- if vk > (2 * (bk barrett))
|
||||
-- then runOperation hndl
|
||||
-- else do hPutStrLn hndl ("m: " ++ showHex m "")
|
||||
-- hPutStrLn hndl ("k: " ++ show (bk barrett))
|
||||
-- hPutStrLn hndl ("u: " ++ show (bu barrett))
|
||||
-- let me = reduce v barrett
|
||||
-- standard = v `mod` m
|
||||
-- unless (me == standard) $
|
||||
-- fail "Barrett messed up."
|
||||
-- hPutStrLn hndl ("v: " ++ showHex v "")
|
||||
-- hPutStrLn hndl ("r: " ++ showHex me "")
|
||||
-- hFlush hndl
|
||||
--
|
||||
-- generateFile :: String ->
|
||||
-- IO ()
|
||||
-- generateFile file =
|
||||
-- withFile (file ++ "_tests.txt") WriteMode $ \ hndl ->
|
||||
-- forM_ [0..2000] $ \ _ ->
|
||||
-- runOperation hndl
|
||||
--
|
||||
-- main :: IO ()
|
||||
-- main =
|
||||
-- do generateFile "add" $ \ x y ->
|
||||
-- (x, y, x + y)
|
||||
-- generateFile "sub" $ \ x y ->
|
||||
-- let x' = max x y
|
||||
-- y' = min x y
|
||||
-- in (x', y', x' - y')
|
||||
-- generateFile "mul" $ \ x y ->
|
||||
-- (x, y, x * y)
|
||||
-- generateFile "div" $ \ x y ->
|
||||
-- let y' = if y == 0 then 1 else y
|
||||
-- in (x, y', x / y')
|
||||
-- generateFile "mod" $ \ x y ->
|
||||
-- let y' = if y == 0 then 1 else y
|
||||
-- in (x, y', x / y')
|
||||
-- generateFile "barrett"
|
||||
25000
tests/math/barrett.tests
Normal file
25000
tests/math/barrett.tests
Normal file
File diff suppressed because it is too large
Load Diff
20000
tests/math/modexp.tests
Normal file
20000
tests/math/modexp.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_add.tests
Normal file
15000
tests/math/signed_add.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_div.tests
Normal file
15000
tests/math/signed_div.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_mod.tests
Normal file
15000
tests/math/signed_mod.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_mul.tests
Normal file
15000
tests/math/signed_mul.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/signed_sub.tests
Normal file
15000
tests/math/signed_sub.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_add.tests
Normal file
15000
tests/math/unsigned_add.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_div.tests
Normal file
15000
tests/math/unsigned_div.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_mod.tests
Normal file
15000
tests/math/unsigned_mod.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_mul.tests
Normal file
15000
tests/math/unsigned_mul.tests
Normal file
File diff suppressed because it is too large
Load Diff
15000
tests/math/unsigned_sub.tests
Normal file
15000
tests/math/unsigned_sub.tests
Normal file
File diff suppressed because it is too large
Load Diff
6003
tests/mod_tests.txt
6003
tests/mod_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6003
tests/mul_tests.txt
6003
tests/mul_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6003
tests/sub_tests.txt
6003
tests/sub_tests.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user