summaryrefslogtreecommitdiff
path: root/testsuite/tests/lib/integer/gcdeInteger.hs
blob: 9fabc2cbce26f03d5a2fa168affea5bfee568840 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

{-# 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)