Much wider support for Catacomb in all its glory.
[catacomb-perl] / t / mp.t
diff --git a/t/mp.t b/t/mp.t
new file mode 100644 (file)
index 0000000..39bbaf2
--- /dev/null
+++ b/t/mp.t
@@ -0,0 +1,208 @@
+# -*-mode: perl; comment-column: 68-*-
+use Test;
+BEGIN { plan tests => 121; }
+use Catacomb qw(:const mp);
+
+# Addition
+ok mp("5") + mp("4") == mp("9");                                   #t    1
+ok mp("5") + mp("-4") == mp("1");                                  #t    2
+ok mp("-5") + mp("4") == mp("-1");                                 #t    3
+ok mp("-5") + mp("-4") == mp("-9");                                #t    4
+ok mp("0xffffffff") + mp("1") == mp("0x100000000");                #t    5
+
+# Subtraction
+ok mp("5") - mp("4") == mp("1");                                   #t    6
+ok mp("5") - mp("-4") == mp("9");                                  #t    7
+ok mp("-5") - mp("4") == mp("-9");                                 #t    8
+ok mp("-5") - mp("-4") == mp("-1");                                #t    9
+ok mp("4") - mp("5") == mp("-1");                                  #t   10
+ok mp("4") - mp("-5") == mp("9");                                  #t   11
+ok mp("-4") - mp("5") == mp("-9");                                 #t   12
+ok mp("-4") - mp("-5") == mp("1");                                 #t   13
+
+# Squaring
+ok mp("5")->sqr() == mp("25");                                     #t   14
+ok mp("-5")->sqr() == mp("25");                                            #t   15
+ok mp("56309812098453")->sqr()==mp("3170794938563083851364993209"); #t   16
+
+# Multiplication
+ok mp("5") * mp("4") == mp("20");                                  #t   17
+ok mp("5") * mp("-4") == mp("-20");                                #t   18
+ok mp("-5") * mp("4") == mp("-20");                                #t   19
+ok mp("-5") * mp("-4") == mp("20");                                #t   20
+ok mp("0x10000") * mp("0x10000") == mp("0x100000000");             #t   21
+
+# Division
+sub divtest {
+  my ($x, $y, $q, $r) = @_;
+  my ($qq, $rr) = Catacomb::MP::div($x, $y);
+  ok $qq == $q && $rr == $r;
+} 
+divtest "9", "4", "2", "1";                                        #t   22
+divtest "-9", "4", "-3", "3";                                      #t   23
+divtest "9", "-4", "-3", "-3";                                     #t   24
+divtest "-9", "-4", "2", "-1";                                     #t   25
+divtest                                                                    #t   26
+  "-3", "6277101735386680763835789423207666416083908700390324961279",
+  "-1", "6277101735386680763835789423207666416083908700390324961276";
+divtest                                                                    #t   27
+  "3131675836296406071791252329528905062261497366991742517193",
+  "1110875761630725856340142297645383444629395595869672555585",
+  "2", "909924313034954359110967734238138173002706175252397406023";
+divtest                                                                    #t   28
+  "3131675836296406071791252329528905062261497366991742517193", "53",
+  "59088223326347284373419855274130284193613157867768726739", "26";
+ok mp("-9") / mp("-4") == mp("2");                                 #t   29
+ok mp("-9") % mp("-4") == mp("-1");                                #t   30
+
+# Exponentiation
+ok mp("4") ** mp("0") == mp("1");                                  #t   31
+ok mp("4") ** mp("1") == mp("4");                                  #t   32
+ok mp("7") ** mp("2") == mp("49");                                 #t   33
+ok mp("3") ** mp("64") == mp("3433683820292512484657849089281");    #t   34
+
+# Bit ops tests
+ok ~mp("6") == mp("-7");                                           #t   35
+ok ~mp("-7") == mp("6");                                           #t   36
+
+ok +(mp("5") & mp("3")) == mp("1");                                #t   37
+ok +(mp("5") | mp("3")) == mp("7");                                #t   38
+ok +(mp("5") ^ mp("3")) == mp("6");                                #t   39
+ok +(mp("45") | mp("-7")) == mp("-3");                             #t   40
+ok +(mp("0x343cd5") ^ mp("-0x6a49c")) == mp("-0x32984f");          #t   41
+
+ok +(mp("-1") >> 5) == mp("-1");                                   #t   42
+ok +(mp("1") >> 5) == mp("0");                                     #t   43
+ok +(mp("-6") >> 2) == mp("-2");                                   #t   44
+ok +(mp("5") >> 0) == mp("5");                                     #t   45
+ok +(mp("-4") >> 0) == mp("-4");                                   #t   46
+ok +(mp("7") >> 2) == mp("1");                                     #t   47
+ok +(mp("-7") >> 2) == mp("-2");                                   #t   48
+ok +(mp("-7") >> 20) == mp("-1");                                  #t   49
+
+ok +(mp("-1") << 5) == mp("-32");                                  #t   50
+ok +(mp("5") << 0) == mp("5");                                     #t   51
+ok +(mp("-4") << 0) == mp("-4");                                   #t   52
+ok +(mp("7") << 2) == mp("28");                                            #t   53
+ok +(mp("-7") << 2) == mp("-28");                                  #t   54
+ok +(mp("0xc0000000") << 1) == mp("0x180000000");                  #t   55
+ok +(mp("-0xc0000000") << 1) == mp("-0x180000000");                #t   56
+ok +(mp("-1") << 32) == mp("-0x100000000");                        #t   57
+
+ok mp("0")->setbit2c(40) == mp("0x10000000000");                   #t   58
+ok mp("0x87348")->setbit2c(40) == mp("0x10000087348");             #t   59
+ok mp("5")->setbit2c(1) == mp("7");                                #t   60
+ok mp("7")->setbit2c(1) == mp("7");                                #t   61
+ok mp("-3")->setbit2c(1) == mp("-1");                              #t   62
+
+ok mp("0x10000000000")->clearbit2c(40) == mp("0");                 #t   63
+ok mp("0x87348")->clearbit2c(40) == mp("0x87348");                 #t   64
+ok mp("5")->clearbit2c(1) == mp("5");                              #t   65
+ok mp("7")->clearbit2c(1) == mp("5");                              #t   66
+ok mp("-1")->clearbit2c(1) == mp("-3");                                    #t   67
+
+# Negation
+ok -mp("0") == mp("0");                                                    #t   68
+ok -mp("15") == mp("-15");                                         #t   69
+ok -mp("-15") == mp("15");                                         #t   70
+
+# Extraction of even powers
+sub oddtest {
+  my ($x, $s, $t) = @_;
+  my ($ss, $tt) = mp($x)->odd();
+  ok $ss == $s && $tt == $t;
+}
+oddtest "1", 0, "1";                                               #t   71
+oddtest "2", 1, "1";                                               #t   72
+oddtest "4", 2, "1";                                               #t   73
+oddtest "12", 2, "3";                                              #t   74
+oddtest "0x10000000000000", 52, "1";                               #t   75
+oddtest "0x10000000400000", 22, "0x40000001";                      #t   76
+
+# Integer square root
+ok mp("0")->sqrt() == mp("0");                                     #t   77
+ok mp("1")->sqrt() == mp("1");                                     #t   78
+ok mp("4")->sqrt() == mp("2");                                     #t   79
+ok mp("9")->sqrt() == mp("3");                                     #t   80
+ok mp("16")->sqrt() == mp("4");                                            #t   81
+ok mp("99")->sqrt() == mp("9");                                            #t   82
+ok mp("100")->sqrt() == mp("10");                                  #t   83
+ok mp("101")->sqrt() == mp("10");                                  #t   84
+ok mp("120")->sqrt() == mp("10");                                  #t   85
+ok mp("121")->sqrt() == mp("11");                                  #t   86
+ok mp("10106623487257186586")->sqrt() == mp("3179091613");         #t   87
+ok mp("14565040310136678240")->sqrt() == mp("3816417208");         #t   88
+
+# Greatest common divisor
+
+ok Catacomb::MP::gcd("16", "12") == mp("4");                       #t   89
+ok mp("90980984098081324")->modinv("4398082908043") ==             #t   90
+  mp("58497120524729235");
+
+sub gcdtest {
+  my ($u, $v, $g, $x, $y) = @_;
+  my ($gg, $xx, $yy) = Catacomb::MP::gcd($u, $v);
+  ok $g == $gg && $x == $xx && $y == $yy;
+}
+gcdtest "16", "12", "4", "-11", "15";                              #t   91
+gcdtest "12", "16", "4", "-1", "1";                                #t   92
+gcdtest "693", "609", "21", "-7", "8";                             #t   93
+gcdtest                                                                    #t   94
+  "4398082908043", "90980984098081324",
+  "1", "-32483863573352089", "1570292150447";
+
+gcdtest "16", "-12", "4", "-11", "-15";                                    #t   95
+gcdtest "-16", "12", "4", "11", "15";                              #t   96
+gcdtest "-12", "-16", "4", "1", "-1";                              #t   97
+gcdtest "-12", "16", "4", "1", "1";                                #t   98
+gcdtest "-693", "609", "21", "7", "8";                             #t   99
+gcdtest "693", "-609", "21", "-7", "-8";                           #t  100
+
+gcdtest "15", "0", "15", "1", "0";                                 #t  101
+gcdtest "0", "15", "15", "0", "1";                                 #t  102
+gcdtest "-5", "0", "5", "-1", "0";                                 #t  103
+gcdtest "0", "-5", "5", "0", "-1";                                 #t  104
+gcdtest "0", "0", "0", "0", "0";                                   #t  105
+
+gcdtest                                                            #t  106
+  "829561629303257626084392170900075",
+  "32498098450983560651904114638965",
+  "5",
+  "-29340810037249902802634060204608",
+  "748967211613630574419802053172497";
+
+# Jacobi symbol
+ok mp("5")->jac("4") == 1;                                         #t  107
+ok mp("7")->jac("6") == -1;                                        #t  108
+ok mp("27")->jac("15") == 0;                                       #t  109
+ok mp("98729378979237498798347932749951")                          #t  110
+  ->jac("2132498039840981") == 1;
+
+# Modular square-root
+sub modsqrttest {
+  my ($p, $x, $r) = @_;
+  my $rr = mp($p)->modsqrt($x);
+  ok $rr == $r || $rr == mp($p) - $r;
+}
+modsqrttest "3", "1", "1";                                         #t  111
+modsqrttest "5", "4", "3";                                         #t  112
+modsqrttest                                                        #t  113
+ "13391974640168007623", "9775592058107450692", "3264570455655810730";
+
+# Factorial
+ok +Catacomb::MP->factorial(0) == mp("1");                         #t  114
+ok +Catacomb::MP->factorial(5) == mp("120");                       #t  115
+ok +Catacomb::MP->factorial(30) ==                                 #t  116
+  mp("265252859812191058636308480000000");
+
+# Parsing
+sub parsetest {
+  my ($str, $rx, $x, $r) = @_;
+  my ($xx, $rr) = Catacomb::MP->fromstring($str, $rx);
+  ok defined($x) ? ($xx == $x && $rr eq $r) : !defined($xx);
+}
+parsetest "0", 10, mp("0"), "";                                            #t  117
+parsetest "0z", 10, mp("0"), "z";                                  #t  118
+parsetest "z", 10, undef, "";                                      #t  119
+parsetest "8_27785", 0, mp("191"), "85";                           #t  120
+parsetest "8_27785", 10, mp("8"), "_27785";                        #t  121