content: 
  {-# LANGUAGE MagicHash #-}
  {-# LANGUAGE MultiWayIf #-}
  
  module Main (main) where
  
  import GHC.Base
  import GHC.Num.Integer
  import Control.Monad
  import System.Exit
  
  main :: IO ()
  main = do
  
     let test a b = do
           putStrLn $ "GCDE " ++ show a ++ " " ++ show b
           let r@(g,x,y) = integerGcde a b
           putStrLn $ "   -> g = " ++ show g
           putStrLn $ "   -> x = " ++ show x
           putStrLn $ "   -> y = " ++ show y
           let sign a | a >= 0    = 1
                      | otherwise = -1
           let assert text cond term
                 | not cond  = return ()
                 | term      = return ()
                 | otherwise = do
                    putStrLn $ "FAILED: " ++ text
                    putStrLn $ "a*x + b*y = g"
                    putStrLn $ "a = " ++ show a
                    putStrLn $ "b = " ++ show b
                    putStrLn $ "x = " ++ show x
                    putStrLn $ "y = " ++ show y
                    putStrLn $ "g = " ++ show g
                    putStrLn $ "expected g = " ++ show (abs (integerGcd a b))
                    exitFailure
  
           -- check properties
           assert "g >= 0"            True (g >= 0)
           assert "a*x + b*y = g"     True (a*x + b*y == g)
           assert "g = abs (gcd a b)" True (g == abs (integerGcd a b))
  
           if -- special cases
              | a == 0 && b == 0 -> do
                 assert "a == 0 && b ==0 ==> g == 0" (a == 0 && b == 0) (g == 0)
  
              | abs a == abs b -> do
                 assert "abs a == abs b ==> x == 0 && y == sign b && g == abs a"
                    (abs a == abs b) (x == 0 && y == sign b && g == abs a)
  
              -- non special cases
              | otherwise -> do
                 assert "b == 0 ==> x=sign a"
                    (b == 0)
                    (x == sign a)
  
                 assert "abs b == 2g ==> x=sign a"
                    (abs b == 2*g)
                    (x == sign a)
  
                 assert "b /= 0 ==> abs x <= abs b / 2*g"
                    (b /= 0)
                    (abs x <= abs b `div` 2 * g)
  
                 assert "a /= 0 ==> abs y <= abs a / 2*g"
                    (a /= 0)
                    (abs y <= abs a `div` 2 * g)
  
                 assert "a == 0 ==> y=sign b"
                    (a == 0)
                    (y == sign b)
  
                 assert "abs a == 2g ==> y==sign b"
                    (abs a == 2*g)
                    (y == sign b)
  
                 assert "x == 0 ==> g == abs b"
                    (x == 0)
                    (g == abs b)
  
         nums =
              [ 0
              , 1
              , 7
              , 14
              , 123
              , 1230
              , 123456789456789456789456789456789456789465789465456789465454645789
              , 4 * 123456789456789456789456789456789456789465789465456789465454645789
              , -1
              , -123
              , -123456789456789456789456789456789456789465789465456789465454645789
              , 4567897897897897899789897897978978979789
              , 2988348162058574136915891421498819466320163312926952423791023078876139
              , 2351399303373464486466122544523690094744975233415544072992656881240319
              , 5328841272400314897981163497728751426
              , 32052182750761975518649228050096851724
              ]
  
     forM_ nums $ \a ->
        forM_ nums $ \b ->
           test a b
  
     -- see #15350
     do
         let a = 2
             b = 2^65 + 1
         test a b
         test a (-b)
         test (-a) b
         test (-a) (-b)
         test b a
         test b (-a)
         test (-b) a
         test (-b) (-a)
  