Ported test cases for class Integer
authorArjen Baart <arjen@andromeda.nl>
Sun, 3 Nov 2019 11:16:09 +0000 (12:16 +0100)
committerArjen Baart <arjen@andromeda.nl>
Sun, 3 Nov 2019 11:16:09 +0000 (12:16 +0100)
19 files changed:
.gitignore
ChangeLog
doc/Integer.xml [new file with mode: 0644]
doc/Makefile.am
doc/manual.xml
src/Integer.cpp
src/Integer.h
src/builtin.h
test/Makefile.am
test/integer_assign.cpp [new file with mode: 0644]
test/integer_factorial.cpp [new file with mode: 0644]
test/integer_factorial.exp [new file with mode: 0644]
test/integer_fibonacci.cpp [new file with mode: 0644]
test/integer_fibonacci.exp [new file with mode: 0644]
test/integer_modulo.cpp [new file with mode: 0644]
test/integer_modulo.exp [new file with mode: 0644]
test/integer_pow64.cpp [new file with mode: 0644]
test/integer_pow64.exp [new file with mode: 0644]
test/tInteger.cpp [new file with mode: 0644]

index 70845e0..0bc84cf 100644 (file)
@@ -1 +1,6 @@
 Makefile.in
+aclocal.m4
+configure
+missing
+ylwrap
+
index bdaf9c2..f436736 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,5 @@
+  - Ported class Integer from the Gnu libg++ library.
+
 Oct 31, 2019 - Release 0.2
 ============================
 
diff --git a/doc/Integer.xml b/doc/Integer.xml
new file mode 100644 (file)
index 0000000..7890ac3
--- /dev/null
@@ -0,0 +1,261 @@
+<?xml version="1.0"?>
+<chapter>
+<heading>Integer - Arbitrary length integer numbers</heading>
+<para>
+The <code>Integer</code> class provides multiple precision integer arithmetic
+facilities. Some representation details are discussed in the 
+Representation section.
+</para>
+<para>
+<code>Integers</code> may be up to <code>b * ((1 &lt;&lt; b) - 1)</code> bits long, where
+<code>b</code> is the number of bits per short (typically 1048560 bits when
+<code>b = 16</code>).  The implementation assumes that a <code>long</code> is at least
+twice as long as a <code>short</code>. This assumption hides beneath almost all
+primitive operations, and would be very difficult to change. It also relies
+on correct behavior of <emph>unsigned</emph> arithmetic operations.
+</para>
+<para>
+Some of the arithmetic algorithms are very loosely based on those
+provided in the MIT Scheme <tt>`bignum.c'</tt> release, which is
+Copyright (c) 1987 Massachusetts Institute of Technology. Their use
+here falls within the provisions described in the Scheme release.
+</para>
+
+<section>
+<heading>Construction</heading>
+<para>
+Integers may be constructed in the following ways:
+</para>
+<description>
+<item tag="Integer x;">
+Declares an uninitialized Integer.
+</item>
+<item tag="Integer x = 2; Integer y(2);">
+Set x and y to the Integer value 2;
+</item>
+<item tag="Integer u(x); Integer v = x;">
+Set u and v to the same value as x.
+</item>
+</description>
+
+</section>
+
+<section>
+<heading>Conversion</heading>
+<description>
+<item tag="long as_long()">
+Used to coerce an <code>Integer</code> back into longs via the <code>long</code>
+coercion operator. If the Integer cannot fit into a long, this returns
+MINLONG or MAXLONG (depending on the sign) where MINLONG is the most
+negative, and MAXLONG is the most positive representable long.
+</item>
+<item tag="int fits_in_long()">
+Returns true iff the <code>Integer</code> is <code>&lt; MAXLONG</code> and <code>&gt; MINLONG</code>.
+</item>
+<item tag="double as_double()">
+Coerce the <code>Integer</code> to a <code>double</code>, with potential
+loss of precision.
+<code>+/-HUGE</code> is returned if the Integer cannot fit into a double.
+</item>
+<item tag="int fits_in_double()">
+Returns true iff the <code>Integer</code> can fit into a double.
+</item>
+</description>
+</section>
+
+<section>
+<heading>Operators</heading>
+<para>
+All of the usual arithmetic operators are provided (<code>+, -, *, /,
+%, +=, ++, -=, --, *=, /=, %=, ==, !=, &lt;, &lt;=, &gt;, &gt;=</code>).  All operators
+support special versions for mixed arguments of Integers and regular
+C++ longs in order to avoid useless coercions, as well as to allow
+automatic promotion of shorts and ints to longs, so that they may be
+applied without additional Integer coercion operators.  The only
+operators that behave differently than the corresponding int or long
+operators are <code>++</code> and <code>--</code>.  Because C++ does not
+distinguish prefix from postfix application, these are declared as
+<code>void</code> operators, so that no confusion can result from applying
+them as postfix.  Thus, for Integers x and y, <code> ++x; y = x; </code> is
+correct, but <code> y = ++x; </code> and <code> y = x++; </code> are not.
+</para>
+<para>
+Bitwise operators (<code>~</code>, <code>&amp;</code>, <code>|</code>, <code>^</code>, <code>&lt;&lt;</code>, 
+<code>&gt;&gt;</code>, <code>&amp;=</code>, <code>|=</code>, <code>^=</code>, <code>&lt;&lt;=</code>, <code>&gt;&gt;=</code>) are
+also provided.  However, these operate on sign-magnitude, rather than
+two's complement representations. The sign of the result is arbitrarily
+taken as the sign of the first argument. For example, <code>Integer(-3)
+&amp; Integer(5)</code> returns <code>Integer(-1)</code>, not -3, as it would using
+two's complement. Also, <code>~</code>, the complement operator, complements
+only those bits needed for the representation.  Bit operators are also
+provided in the BitSet and BitString classes. One of these classes
+should be used instead of Integers when the results of bit manipulations
+are not interpreted numerically.
+</para>
+</section>
+
+<section>
+<heading>Functions</heading>
+<para>
+The following utility functions are also provided. (All arguments
+are Integers unless otherwise noted).
+</para>
+<description>
+<item tag="void divide(const Integer&amp; x, const Integer&amp; y, Integer&amp; q, Integer&amp; r)">
+Sets <emph>q</emph> to the quotient and <emph>r</emph> to the remainder of <emph>x</emph> and <emph>y</emph>.
+(<emph>q</emph> and <emph>r</emph> are returned by reference). 
+</item>
+
+<item tag="Integer pow(const Integer&amp; x, const Integer&amp; p)">
+Returns <emph>x</emph> raised to the power <emph>p</emph>.
+</item>
+
+<item tag="Integer Ipow(long x, long p)">
+Returns <emph>x</emph> raised to the power <emph>p</emph>.
+</item>
+
+<item tag="Integer gcd(const Integer&amp; x, const Integer&amp; p)">
+Returns the greatest common divisor of <emph>x</emph> and <emph>y</emph>.
+</item>
+
+<item tag="Integer lcm(const Integer&amp; x, const Integer&amp; p)">
+Returns the least common multiple of <emph>x</emph> and <emph>y</emph>.
+</item>
+
+<item tag="Integer abs(const Integer&amp; x)">
+Returns the absolute value of <emph>x</emph>.
+</item>
+
+<item tag="Method: void Integer::negate()">
+Negates <code>this</code> in place.
+</item>
+
+<item tag="Integer sqr(x)">
+returns x * x;
+</item>
+
+<item tag="Integer sqrt(x)">
+returns the floor of the  square root of x.
+</item>
+
+<item tag="long lg(x)">
+returns the floor of the base 2 logarithm of abs(x)
+</item>
+
+<item tag="int sign(x)">
+returns -1 if x is negative, 0 if zero, else +1.
+Using <code>if (sign(x) == 0)</code> is a generally faster method
+of testing for zero than using relational operators.
+</item>
+
+<item tag="int even(x)">
+returns true if x is an even number
+</item>
+
+<item tag="int odd(x)">
+returns true if x is an odd number.
+</item>
+
+<item tag="void setbit(Integer&amp; x, long b)">
+sets the b'th bit (counting right-to-left from zero) of x to 1.
+</item>
+
+<item tag="void clearbit(Integer&amp; x, long b)">
+sets the b'th bit of x to 0.
+</item>
+
+<item tag="int testbit(Integer x, long b)">
+returns true if the b'th bit of x is 1.
+</item>
+
+<item tag="Integer atoI(char* asciinumber, int base = 10)">
+converts the base base char* string into its Integer form.
+</item>
+
+<item tag="void Integer::printon(ostream&amp; s, int base = 10, int width = 0)">
+prints the ascii string value of <code>(*this)</code> as a base <code>base</code>
+number, in field width at least <code>width</code>.
+</item>
+
+<item tag="ostream &lt;&lt; x">
+prints x in base ten format.
+</item>
+
+<item tag="istream &gt;&gt; x">
+reads x as a base ten number.
+</item>
+
+<item tag="int compare(Integer x, Integer y)">
+returns a negative number if x&lt;y, zero if x==y, or positive if x&gt;y.
+</item>
+
+<item tag="int ucompare(Integer x, Integer y)">
+like compare, but performs unsigned comparison.
+</item>
+
+<item tag="add(x, y, z)">
+A faster way to say z = x + y.
+</item>
+
+<item tag="sub(x, y, z)">
+A faster way to say z = x - y.
+</item>
+
+<item tag="mul(x, y, z)">
+A faster way to say z = x * y.
+</item>
+
+<item tag="div(x, y, z)">
+A faster way to say z = x / y.
+</item>
+
+<item tag="mod(x, y, z)">
+A faster way to say z = x % y.
+</item>
+
+<item tag="I_and(x, y, z)">
+A faster way to say z = x &amp; y.
+</item>
+
+<item tag="I_or(x, y, z)">
+A faster way to say z = x | y.
+</item>
+
+<item tag="I_xor(x, y, z)">
+A faster way to say z = x ^ y.
+</item>
+
+<item tag="lshift(x, y, z)">
+A faster way to say z = x &lt;&lt; y.
+</item>
+
+<item tag="rshift(x, y, z)">
+A faster way to say z = x &gt;&gt; y.
+</item>
+
+<item tag="pow(x, y, z)">
+A faster way to say z = pow(x, y).
+</item>
+
+<item tag="complement(x, z)">
+A faster way to say z = ~x.
+</item>
+
+<item tag="negate(x, z)">
+A faster way to say z = -x.
+</item>
+
+</description>
+
+</section>
+
+<section>
+<heading>SEE ALSO</heading>
+<para>
+<reference xml:link="simple"
+    href="https://www.slac.stanford.edu/comp/unix/gnu-info/libg++_toc.html#SEC31">
+The Integer class in the Gnu libg++ manual.
+</reference>
+</para>
+</section>
+</chapter>
index 94b843e..76537f1 100644 (file)
@@ -7,7 +7,7 @@ SUFFIXES = .obj .eps .png
 .obj.eps:
        tgif -print -eps -color $<
 
-XMLS = manual.xml string.xml date.xml hour.xml utc.xml
+XMLS = manual.xml string.xml date.xml hour.xml utc.xml Integer.xml
 IMAGES=
 
 PICTURES=
index bbb9745..79bb2b9 100644 (file)
@@ -13,5 +13,7 @@
          xmlns:xi="http://www.w3.org/2001/XInclude"/>
     <xi:include href="utc.xml"
          xmlns:xi="http://www.w3.org/2001/XInclude"/>
+    <xi:include href="Integer.xml"
+         xmlns:xi="http://www.w3.org/2001/XInclude"/>
   </book>
 </doc>
index 1e69029..c6a931a 100644 (file)
@@ -80,6 +80,17 @@ IntRep _OneRep = {1, 0, 1, {1}};
 IntRep _MinusOneRep = {1, 0, 0, {1}};
 
 
+void lib_error_handler (const char* kind, const char* msg)
+{
+  fputs(kind, stderr);
+  fputs(" Error: ", stderr);
+  fputs(msg, stderr);
+  fputs("\n", stderr);
+  abort();
+}
+
+
+
 // utilities to extract and transfer bits 
 
 // get low bits
@@ -110,7 +121,10 @@ inline static int docmp(const unsigned short* x, const unsigned short* y, int l)
   int diff = 0;
   const unsigned short* xs = &(x[l]);
   const unsigned short* ys = &(y[l]);
-  while (l-- > 0 && (diff = (*--xs) - (*--ys)) == 0);
+  while (l-- > 0 && diff == 0)
+  {
+    diff = (*--xs) - (*--ys);
+  }
   return diff;
 }
 
@@ -153,7 +167,7 @@ static inline void scpy(const unsigned short* src, unsigned short* dest,int nb)
 static inline void nonnil(const IntRep* rep)
 {
   if (rep == 0) 
-    (*lib_error_handler)("Integer", "operation on uninitialized Integer");
+    lib_error_handler("Integer", "operation on uninitialized Integer");
 }
 
 // allocate a new Irep. Pad to something close to a power of two.
@@ -166,7 +180,7 @@ inline static IntRep* Inew(int newlen)
   while (allocsiz < siz) allocsiz <<= 1;  // find a power of 2
   allocsiz -= MALLOC_MIN_OVERHEAD;
   if (allocsiz >= MAXIntRep_SIZE * sizeof(short))
-    (*lib_error_handler)("Integer", "Requested length out of range");
+    lib_error_handler("Integer", "Requested length out of range");
     
   IntRep* rep = (IntRep *) new char[allocsiz];
   rep->sz = (allocsiz - sizeof(IntRep) + sizeof(short)) / sizeof(short);
@@ -300,11 +314,12 @@ IntRep* Icopy_ulong(IntRep* old, unsigned long x)
   unsigned short src[SHORT_PER_LONG];
   
   unsigned short srclen = 0;
-  while (x != 0)
+  do
   {
     src[srclen++] = extract(x);
     x = down(x);
   }
+  while (x != 0);
 
   IntRep* rep;
   if (old == 0 || srclen > old->sz)
@@ -544,7 +559,7 @@ int compare(const IntRep* x, long  y)
   int xsgn = x->sgn;
   if (y == 0)
   {
-    if (xl == 0)
+    if (xl == 0 || xl == 1 && x->s[0] == 0)
       return 0;
     else if (xsgn == I_NEGATIVE)
       return -1;
@@ -1203,7 +1218,7 @@ IntRep* div(const IntRep* x, const IntRep* y, IntRep* q)
   nonnil(y);
   int xl = x->len;
   int yl = y->len;
-  if (yl == 0) (*lib_error_handler)("Integer", "attempted division by zero");
+  if (yl == 0) lib_error_handler("Integer", "attempted division by zero");
 
   int comp = ucompare(x, y);
   int xsgn = x->sgn;
@@ -1254,7 +1269,7 @@ IntRep* div(const IntRep* x, long y, IntRep* q)
 {
   nonnil(x);
   int xl = x->len;
-  if (y == 0) (*lib_error_handler)("Integer", "attempted division by zero");
+  if (y == 0) lib_error_handler("Integer", "attempted division by zero");
 
   unsigned short ys[SHORT_PER_LONG];
   unsigned long u;
@@ -1324,7 +1339,7 @@ void divide(const Integer& Ix, long y, Integer& Iq, long& rem)
   nonnil(x);
   IntRep* q = Iq.rep;
   int xl = x->len;
-  if (y == 0) (*lib_error_handler)("Integer", "attempted division by zero");
+  if (y == 0) lib_error_handler("Integer", "attempted division by zero");
 
   unsigned short ys[SHORT_PER_LONG];
   unsigned long u;
@@ -1414,7 +1429,7 @@ void divide(const Integer& Ix, const Integer& Iy, Integer& Iq, Integer& Ir)
   int xl = x->len;
   int yl = y->len;
   if (yl == 0)
-    (*lib_error_handler)("Integer", "attempted division by zero");
+    lib_error_handler("Integer", "attempted division by zero");
 
   int comp = ucompare(x, y);
   int xsgn = x->sgn;
@@ -1481,7 +1496,7 @@ IntRep* mod(const IntRep* x, const IntRep* y, IntRep* r)
   nonnil(y);
   int xl = x->len;
   int yl = y->len;
-  if (yl == 0) (*lib_error_handler)("Integer", "attempted division by zero");
+  if (yl == 0) lib_error_handler("Integer", "attempted division by zero");
 
   int comp = ucompare(x, y);
   int xsgn = x->sgn;
@@ -1531,7 +1546,7 @@ IntRep* mod(const IntRep* x, long y, IntRep* r)
 {
   nonnil(x);
   int xl = x->len;
-  if (y == 0) (*lib_error_handler)("Integer", "attempted division by zero");
+  if (y == 0) lib_error_handler("Integer", "attempted division by zero");
 
   unsigned short ys[SHORT_PER_LONG];
   unsigned long u;
@@ -1962,6 +1977,16 @@ IntRep* gcd(const IntRep* x, const IntRep* y)
 }
 
 
+long lg(unsigned long x)
+{
+  long l = 0;
+  while (x > 1)
+  {
+    x = x >> 1;
+    ++l;
+  }
+  return l;
+}
 
 long lg(const IntRep* x)
 {
@@ -2151,6 +2176,7 @@ char*  cvtItoa(const IntRep* x, char* fmt, int& fmtlen, int base, int showbase,
               int width, int align_right, char fillchar, char Xcase, 
               int showpos)
 {
+
   char* e = fmt + fmtlen - 1;
   char* s = e;
   *--s = 0;
@@ -2180,7 +2206,7 @@ char*  cvtItoa(const IntRep* x, char* fmt, int& fmtlen, int base, int showbase,
       Icheck(z);
       if (z->len == 0)
       {
-        while (rem != 0)
+        while (rem != 0 || *s == '\0')
         {
           char ch = rem % base;
           rem /= base;
@@ -2218,6 +2244,7 @@ char*  cvtItoa(const IntRep* x, char* fmt, int& fmtlen, int base, int showbase,
   }
   if (x->sgn == I_NEGATIVE) *--s = '-';
   else if (showpos) *--s = '+';
+
   int w = e - s - 1;
   if (!align_right || w >= width)
   {
@@ -2369,6 +2396,6 @@ int Integer::OK() const
 
 void Integer::error(const char* msg) const
 {
-  (*lib_error_handler)("Integer", msg);
+  lib_error_handler("Integer", msg);
 }
 
index f004732..58da747 100644 (file)
@@ -85,12 +85,18 @@ protected:
 public:
                   Integer();
                   Integer(long);
+                  Integer(int);
                   Integer(unsigned long);
                   Integer(IntRep*);
                   Integer(const Integer&);
 
                   ~Integer();
 
+//   for debugging
+  unsigned short  len() { return rep->len; }
+  unsigned short  *numbers () { return rep->s; }
+
+
   void            operator =  (const Integer&);
   void            operator =  (long);
 
@@ -221,6 +227,7 @@ public:
 
   int      operator == (const Integer&, const Integer&);
   int      operator == (const Integer&, long);
+  int      operator == (const Integer&, int);
   int      operator != (const Integer&, const Integer&);
   int      operator != (const Integer&, long);
   int      operator <  (const Integer&, const Integer&);
@@ -277,12 +284,17 @@ extern Integer  lcm(const Integer& x, const Integer& y); // least common mult
 
 typedef Integer IntTmp; // for backward compatibility
 
-inline Integer::Integer() :rep(&_ZeroRep) {}
+inline Integer::Integer()
+{
+   rep = &_ZeroRep;
+}
 
 inline Integer::Integer(IntRep* r) :rep(r) {}
 
 inline Integer::Integer(long y) :rep(Icopy_long(0, y)) {}
 
+inline Integer::Integer(int y)  :rep(Icopy_long(0, long(y))) {}
+
 inline Integer::Integer(unsigned long y) :rep(Icopy_ulong(0, y)) {}
 
 inline Integer::Integer(const Integer&  y) :rep(Icopy(0, y.rep)) {}
@@ -524,6 +536,11 @@ inline int operator == (const Integer&  x, long y)
   return compare(x, y) == 0; 
 }
 
+inline int operator == (const Integer&  x, int y)
+{
+  return compare(x, long(y)) == 0; 
+}
+
 inline int operator != (const Integer&  x, const Integer&  y)
 {
   return compare(x, y) != 0; 
index d6a41a4..8a00f6e 100644 (file)
@@ -69,8 +69,6 @@ unsigned int foldhash(double);
 extern _VOLATILE_VOID default_one_arg_error_handler(const char*);
 extern _VOLATILE_VOID default_two_arg_error_handler(const char*, const char*);
 
-extern two_arg_error_handler_t lib_error_handler;
-
 extern two_arg_error_handler_t 
        set_lib_error_handler(two_arg_error_handler_t f);
 
index 0d8369c..7a33525 100644 (file)
@@ -5,7 +5,8 @@ LDADD = ../src/.libs/libACL.la
 check_PROGRAMS = string_assign string_basics string_compare string_cat string_substring string_regex \
                  date_assign date_parse date_compare date_arithmetic date_attributes date_check_today \
                  hour_assign hour_parse hour_compare hour_arithmetic hour_check_now \
-                 utc_assign utc_compare utc_arithmetic
+                 utc_assign utc_compare utc_arithmetic \
+                 integer_assign integer_factorial integer_fibonacci integer_pow64 integer_modulo
 
 string_assign_SOURCES      = string_assign.cpp
 string_basics_SOURCES      = string_basics.cpp
@@ -34,3 +35,9 @@ hour_now : hour_check_now
 utc_assign_SOURCES         = utc_assign.cpp
 utc_compare_SOURCES        = utc_compare.cpp
 utc_arithmetic_SOURCES     = utc_arithmetic.cpp
+
+integer_assign_SOURCES     = integer_assign.cpp
+integer_factorial_SOURCES  = integer_factorial.cpp tInteger.cpp
+integer_fibonacci_SOURCES  = integer_fibonacci.cpp tInteger.cpp
+integer_pow64_SOURCES      = integer_pow64.cpp tInteger.cpp
+integer_modulo_SOURCES     = integer_modulo.cpp tInteger.cpp
diff --git a/test/integer_assign.cpp b/test/integer_assign.cpp
new file mode 100644 (file)
index 0000000..6bef070
--- /dev/null
@@ -0,0 +1,60 @@
+/*******************************************************
+ *  Unit test for the Integer class
+ *
+ * test contrustor and assignment of Integer objects
+ ******************************************************
+ *
+ */
+
+#include "Integer.h"
+#include <assert.h>
+
+int main()
+{
+   // Default contructor: all zero
+   Integer i0;
+
+   std::cout << "The default contructor makes a zero number: \"" << i0 << "\"\n";
+   std::cout.flush();
+   assert(i0 == 0);
+
+   // Constructors with a literal value
+   Integer i1(5);
+
+   std::cout << "Contructor with a number = 5: \"" << i1 << "\"\n";
+   std::cout.flush();
+   assert(i1 == 5);
+
+   // Initializer with a literal value
+   Integer i2 = 42;
+
+   std::cout << "Initializer with a number = 42: \"" << i2 << "\"\n";
+   std::cout.flush();
+   assert(i2 == 42);
+
+   // Assignment of a literal value
+   Integer i3;
+   i3 = 123;
+
+   std::cout << "Assignment with a number = 123: \"" << i3 << "\"\n";
+   std::cout.flush();
+   assert(i3 == 123);
+
+   // Contructor with an Integer object
+   Integer i4(i2);
+
+   std::cout << "Contructor with Integer: \"" << i4 << "\"\n";
+   std::cout.flush();
+   assert(i4 == i2);
+
+   // Assignment of a Integer object
+   Integer i5;
+   i5 = i3;
+
+   std::cout << "Assignment with Integer: \"" << i5 << "\"\n";
+   std::cout.flush();
+   assert(i5 == i3);
+
+   return 0;
+}
+
diff --git a/test/integer_factorial.cpp b/test/integer_factorial.cpp
new file mode 100644 (file)
index 0000000..c7f24a1
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************
+ *  Unit test for the Integer class
+ *
+ * test several functions with a factorial calculation
+ ******************************************************
+ *
+ */
+
+#include "Integer.h"
+#include <assert.h>
+
+
+void facttest(Integer& one, Integer& two);
+
+int main()
+{
+  Integer one = 1;
+  std::cout << "one = " << one << "\n";
+  assert(one.OK());
+  assert(one == 1);
+  std::cout << "one + 1 = " << (one + long(1)) << "\n";
+
+  Integer two = 2;
+  std::cout << "two = " << two << "\n";
+  assert(two.OK());
+  assert(two == 2);
+
+  facttest(one, two);
+  //anothertest();
+  //iotest();
+  //modtest();
+
+  std::cout << "\nEnd of test\n";
+}
diff --git a/test/integer_factorial.exp b/test/integer_factorial.exp
new file mode 100644 (file)
index 0000000..fad52da
--- /dev/null
@@ -0,0 +1,24 @@
+one = 1
+one + 1 = 2
+two = 2
+fact30 = factorial(30) = 265252859812191058636308480000000
+fact28 = factorial(28) = 304888344611713860501504000000
+fact30 + fact28 = 265557748156802772496809984000000
+fact30 - fact28 = 264947971467579344775806976000000
+fact30 * fact28 = 80872505331661933764010628483512781121876047953920000000000000
+fact30 / fact28 = 870
+fact30 % fact28 = 0
+-fact30 = -265252859812191058636308480000000
+lg(fact30) = 107
+gcd(fact30, fact28) = 304888344611713860501504000000
+sqrt(fact30) = 16286585271694955
+negfact31 = -8222838654177922817725562880000000
+fact30 + negfact31 = -7957585794365731759089254400000000
+fact30 - negfact31 = 8488091513990113876361871360000000
+fact30 * negfact31 = -2181131468794922353615366650200339706856997013317222400000000000000
+fact30 / negfact31 = 0
+fact30 % negfact31 = 265252859812191058636308480000000
+gcd(fact30, negfact31) = 265252859812191058636308480000000
+
+End of test
+PASS integer_factorial (exit status: 0)
diff --git a/test/integer_fibonacci.cpp b/test/integer_fibonacci.cpp
new file mode 100644 (file)
index 0000000..098da80
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************
+ *  Unit test for the Integer class
+ *
+ * test several functions with a fibonacci calculation
+ ******************************************************
+ *
+ */
+
+#include "Integer.h"
+#include <assert.h>
+
+
+void fibtest();
+
+int main()
+{
+  Integer one = 1;
+  std::cout << "one = " << one << "\n";
+  assert(one.OK());
+  assert(one == 1);
+  std::cout << "one + 1 = " << (one + long(1)) << "\n";
+
+  Integer two = 2;
+  std::cout << "two = " << two << "\n";
+  assert(two.OK());
+  assert(two == 2);
+
+  fibtest();
+  //anothertest();
+  //iotest();
+  //modtest();
+
+  std::cout << "\nEnd of test\n";
+}
diff --git a/test/integer_fibonacci.exp b/test/integer_fibonacci.exp
new file mode 100644 (file)
index 0000000..0d1f2fe
--- /dev/null
@@ -0,0 +1,15 @@
+one = 1
+one + 1 = 2
+two = 2
+fib50 = fibonacci(50) = 12586269025
+fib48 = fibonacci(48) = 4807526976
+fib48 + fib50 = 17393796001
+fib48 - fib50 = -7778742049
+fib48 * fib50 = 60508827864880718400
+fib48 / fib50 = 0
+fib48 % fib50 = 4807526976
+gcd(fib50, fib48) = 1
+sqrt(fib50) = 112188
+
+End of test
+PASS integer_fibonacci (exit status: 0)
diff --git a/test/integer_modulo.cpp b/test/integer_modulo.cpp
new file mode 100644 (file)
index 0000000..b20b812
--- /dev/null
@@ -0,0 +1,20 @@
+/*******************************************************
+ *  Unit test for the Integer class
+ *
+ * test the Integer modulo function
+ ******************************************************
+ *
+ */
+
+#include "Integer.h"
+#include <assert.h>
+
+
+void modtest();
+
+int main()
+{
+  modtest();
+
+  std::cout << "\nEnd of test\n";
+}
diff --git a/test/integer_modulo.exp b/test/integer_modulo.exp
new file mode 100644 (file)
index 0000000..25b6ce1
--- /dev/null
@@ -0,0 +1,6 @@
+2^32 = 4294967296
+2^32 % (2^32-1) = 1
+2^32 % (2^32-1) = 1
+
+End of test
+PASS integer_modulo (exit status: 0)
diff --git a/test/integer_pow64.cpp b/test/integer_pow64.cpp
new file mode 100644 (file)
index 0000000..fc2ea86
--- /dev/null
@@ -0,0 +1,21 @@
+/*******************************************************
+ *  Unit test for the Integer class
+ *
+ * test cases with 2 ^ 64 numbers
+ ******************************************************
+ *
+ */
+
+#include "Integer.h"
+#include <assert.h>
+
+
+void anothertest();
+
+int main()
+{
+  anothertest();
+  //modtest();
+
+  std::cout << "\nEnd of test\n";
+}
diff --git a/test/integer_pow64.exp b/test/integer_pow64.exp
new file mode 100644 (file)
index 0000000..e9c53ba
--- /dev/null
@@ -0,0 +1,11 @@
+pow64 = Ipow(2, 64) = 18446744073709551616
+lg(pow64) = 64
+s64 = 1 << 64 = 18446744073709551616
+s32 = s64 >> 32 = 4294967296
+comps64 = ~s64 = 18446744073709551615
+comps64 & s32 = 4294967296
+comps64 | s32 = 18446744073709551615
+comps64 ^ s32 = 18446744069414584319
+
+End of test
+PASS integer_pow64 (exit status: 0)
diff --git a/test/tInteger.cpp b/test/tInteger.cpp
new file mode 100644 (file)
index 0000000..d0b7c83
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ a test file for Integer class
+ */
+
+#include <Integer.h>
+#include <assert.h>
+
+Integer factorial(Integer n)
+{
+  Integer f;
+  if (n < long(0))
+    f = 0;
+  else
+  {
+    f = 1;
+    while (n > long(0))
+    {
+      f *= n;
+      --n;
+    }
+  }
+  return f;
+}
+
+Integer fibonacci(long n)
+{
+  Integer f;
+  if (n <= 0)
+    f = 0;
+  else
+  {
+    f = 1;
+    Integer prev = 0;
+    Integer tmp;
+    while (n > 1)
+    {
+      tmp = f;
+      f += prev;
+      prev = tmp;
+      --n;
+    }
+  }
+  return f;
+}
+
+
+void identitytest(Integer& a, Integer& b, Integer& c)
+{
+  assert( -(-a) ==  a);
+  assert( (a + b) ==  (b + a));
+  assert( (a + (-b)) ==  (a - b));
+  assert( (a * b) ==  (b * a));
+  assert( (a * (-b)) ==  -(a * b));
+  assert( (a / (-b)) ==  -(a / b));
+  assert( (a - b) ==  -(b - a));
+  assert( (a + (b + c)) ==  ((a + b) + c));
+  assert( (a * (b * c)) ==  ((a * b) * c));
+  assert( (a * (b + c)) ==  ((a * b) + (a * c)));
+  assert( ((a - b) + b) ==  a);
+  assert( ((a + b) - b) ==  a);
+  assert( ((a * b) / b) ==  a);
+  assert( ((a * b) % b) ==  0);
+  assert( (b * (a / b) + (a % b)) ==  a);
+  assert( ((a + b) % c) ==  ((a % c) + (b % c)) % c);
+}
+
+void utiltest(Integer& a)
+{
+  assert(sqrt(sqr(a)) == a);
+  assert(sqr(sqrt(a)) <= a);
+
+  Integer x = 1;
+  for (int i = 0; i < 10; ++i)
+  {
+    assert(pow(a, i) == x);
+    x *= a;
+  }
+  setbit(x, 0);
+  assert(testbit(x, 0));
+  assert(odd(x));
+  assert(!even(x));
+  clearbit(x, 0);
+  clearbit(x, 1);
+  assert(even(x));
+  assert(!odd(x));
+  assert(x % long(4) == 0);
+
+}
+
+void bittest(Integer& a, Integer& b, Integer& c)
+{
+  assert( (a | b) ==  (b | a));
+  assert( (a & b) ==  (b & a));
+  assert( (a ^ b) ==  (b ^ a));
+  assert( (a | (b | c)) ==  ((a | b) | c));
+  assert( (a & (b & c)) ==  ((a & b) & c));
+  assert( (a & (b | c)) ==  ((a & b) | (a & c)));
+  assert( (a | (b & c)) ==  ((a | b) & (a | c)));
+  assert( (a & (a | b)) ==  a);
+  assert( (a | (a & b)) ==  a);
+}
+
+void accumtest(Integer& a, Integer& b, Integer& c)
+{
+  Integer x = a;
+  x *= b;
+  assert(x == (a * b));
+  x += c;
+  assert(x == ((a * b) + c));
+  x -= a;
+  assert(x == (((a * b) + c) - a));
+  x /= b;
+  assert(x == ((((a * b) + c) - a) / b));
+  x %= c;
+  assert(x == (((((a * b) + c) - a) / b) % c));
+  x &= a;
+  assert(x == ((((((a * b) + c) - a) / b) % c) & a));
+  x |= b;
+  assert(x == (((((((a * b) + c) - a) / b) % c) & a) | b));
+  x ^= c;
+  assert(x == ((((((((a * b) + c) - a) / b) % c) & a) | b) ^ c));
+
+  assert(x.OK());
+}
+
+void longidentitytest(Integer& a, long b, long c)
+{
+  assert( (a + b) ==  (b + a));
+  assert( (a + (-b)) ==  (a - b));
+  assert( (a * b) ==  (b * a));
+  assert( (a * (-b)) ==  -(a * b));
+  assert( (a / (-b)) ==  -(a / b));
+  assert( (a - b) ==  -(b - a));
+  assert( (a + (b + c)) ==  ((a + b) + c));
+  assert( (a * (b * c)) ==  ((a * b) * c));
+  assert( (a * (b + c)) ==  ((a * b) + (a * c)));
+  assert( ((a - b) + b) ==  a);
+  assert( ((a + b) - b) ==  a);
+  assert( ((a * b) / b) ==  a);
+  assert( ((a * b) % b) ==  0);
+  assert( (b * (a / b) + (a % b)) ==  a);
+  assert( ((a + b) % c) ==  ((a % c) + (b % c)) % c);
+}
+
+void longbittest(Integer& a, long b, long c)
+{
+  assert( (a | b) ==  (b | a));
+  assert( (a & b) ==  (b & a));
+  assert( (a ^ b) ==  (b ^ a));
+  assert( (a | (b | c)) ==  ((a | b) | c));
+  assert( (a & (b & c)) ==  ((a & b) & c));
+  assert( (a & (b | c)) ==  ((a & b) | (a & c)));
+  assert( (a | (b & c)) ==  ((a | b) & (a | c)));
+  assert( (a & (a | b)) ==  a);
+  assert( (a | (a & b)) ==  a);
+}
+
+void longaccumtest(Integer& a, long b, long c)
+{
+  Integer x = a;
+  x *= b;
+  assert(x == (a * b));
+  x += c;
+  assert(x == ((a * b) + c));
+  x -= a;
+  assert(x == (((a * b) + c) - a));
+  x /= b;
+  assert(x == ((((a * b) + c) - a) / b));
+  x %= c;
+  assert(x == (((((a * b) + c) - a) / b) % c));
+  x &= a;
+  assert(x == ((((((a * b) + c) - a) / b) % c) & a));
+  x |= b;
+  assert(x == (((((((a * b) + c) - a) / b) % c) & a) | b));
+  x ^= c;
+  assert(x == ((((((((a * b) + c) - a) / b) % c) & a) | b) ^ c));
+
+  assert(x.OK());
+}
+
+void anothertest()
+{
+  long k;
+
+  Integer pow64 = Ipow(2, 64);
+  std::cout << "pow64 = Ipow(2, 64) = " << pow64 << "\n";
+  assert(pow64.OK());
+  std::cout << "lg(pow64) = " << lg(pow64) << "\n";
+  assert(lg(pow64) == 64);
+
+  for (k = 0; k < 64; ++k)
+    assert(testbit(pow64, k) == 0);
+
+  assert(testbit(pow64, k) != 0);
+
+  Integer s64 = 1;
+  s64 <<= 64;
+  std::cout << "s64 = 1 << 64 = " << s64 << "\n";
+  assert(s64.OK());
+
+  assert(s64 == pow64);
+  assert(s64 >= pow64);
+  assert(s64 <= pow64);
+  assert(!(s64 != pow64));
+  assert(!(s64 > pow64));
+  assert(!(s64 < pow64));
+
+  Integer s32 = s64 >> long(32);
+  std::cout << "s32 = s64 >> 32 = " << s32 << "\n";
+  assert(s32.OK());
+  assert(lg(s32) == 32);
+  assert(!(pow64 == s32));
+  assert(!(pow64 < s32));
+  assert(!(pow64 <= s32));
+  assert(pow64 != s32);
+  assert(pow64 >= s32);
+  assert(pow64 > s32);
+
+  Integer comps64 = ~s64;
+  std::cout << "comps64 = ~s64 = " << comps64 << "\n";
+  for (k = 0; k < 64; ++k) assert(testbit(comps64, k) == !testbit(s64, k));
+  Integer result = (comps64 & s32);
+  std::cout << "comps64 & s32 = " << result << "\n";
+  assert(result.OK());
+  result = (comps64 | s32);
+  std::cout << "comps64 | s32 = " << result << "\n";
+  assert(result.OK());
+  result = (comps64 ^ s32);
+  std::cout << "comps64 ^ s32 = " << result << "\n";
+  assert(result.OK());
+
+  identitytest(s64, s32, comps64);
+  bittest(s32, s64, comps64);
+  accumtest(comps64, s32, pow64);
+  utiltest(s32);
+  longidentitytest(s64, 1000, 50);
+  longbittest(s64, 12345, 67890);
+  longaccumtest(s32, 100000, 1);
+
+}
+
+void iotest()
+{
+  Integer result;
+  std::cout << "\nenter an Integer: ";
+  std::cin >> result;
+  std::cout << "number = " << result << "\n";
+  assert(result.OK());
+}
+
+void fibtest()
+{
+  Integer fib50 = fibonacci(50);
+  std::cout << "fib50 = fibonacci(50) = " << fib50 << "\n";
+  assert(fib50.OK());
+  Integer fib48 = fibonacci(48);
+  std::cout << "fib48 = fibonacci(48) = " << fib48 << "\n";
+  assert(fib48.OK());
+
+  Integer result = fib48 + fib50;
+  std::cout << "fib48 + fib50 = " << result << "\n";
+  result = fib48 - fib50;
+  std::cout << "fib48 - fib50 = " << result << "\n";
+  result = fib48 * fib50;
+  std::cout << "fib48 * fib50 = " << result << "\n";
+  result = fib48 / fib50;
+  std::cout << "fib48 / fib50 = " << result << "\n";
+  result = fib48 % fib50;
+  std::cout << "fib48 % fib50 = " << result << "\n";
+  result = gcd(fib50, fib48);
+  std::cout << "gcd(fib50, fib48) = " << result << "\n";
+  result = sqrt(fib50);
+  std::cout << "sqrt(fib50) = " << result << "\n";
+
+  identitytest(result, fib50, fib48);
+  bittest(result, fib50, fib48);
+  accumtest(result, fib50, fib48);
+  utiltest(fib48);
+  longidentitytest(fib50, 1000, 50);
+  longaccumtest(fib48, 100000, 1);
+}
+
+
+void facttest(Integer& one, Integer& two)
+{
+  Integer fact30(factorial(30));
+  std::cout << "fact30 = factorial(30) = " << fact30 << "\n";
+  assert(fact30.OK());
+
+  Integer fact28(factorial(28));
+  std::cout << "fact28 = factorial(28) = " << fact28 << "\n";
+  assert(fact28.OK());
+  assert(fact30 == fact28 * long(870));
+
+  Integer result = fact30 + fact28;
+  std::cout << "fact30 + fact28 = " <<  result << "\n";
+  result = fact30 - fact28;
+  std::cout << "fact30 - fact28 = " << result << "\n";
+  result = fact30 * fact28;
+  std::cout << "fact30 * fact28 = " << result << "\n";
+  result = fact30 / fact28;
+  std::cout << "fact30 / fact28 = " << result << "\n";
+  result = fact30 % fact28;
+  std::cout << "fact30 % fact28 = " << result << "\n";
+
+  result = -fact30;
+  std::cout << "-fact30 = " << result << "\n";
+  assert(abs(result) == fact30);
+
+  std::cout << "lg(fact30) = " << lg(fact30) << "\n";
+  assert(lg(fact30) == 107);
+
+  result = gcd(fact30, fact28);
+  std::cout << "gcd(fact30, fact28) = " << result << "\n";
+  assert(result == fact28);
+
+  result = sqrt(fact30);
+  std::cout << "sqrt(fact30) = " << result << "\n";
+
+  Integer negfact31 = fact30 * -31;
+  Integer posfact31 = abs(negfact31);
+  assert(negfact31.OK());
+  assert(posfact31.OK());
+  std::cout << "negfact31 = " << negfact31 << "\n";
+  result = fact30 + negfact31;
+  std::cout << "fact30 + negfact31 = " << result << "\n";
+  result = fact30 - negfact31;
+  std::cout << "fact30 - negfact31 = " << result << "\n";
+  result = fact30 * negfact31;
+  std::cout << "fact30 * negfact31 = " << result << "\n";
+  result = fact30 / negfact31;
+  std::cout << "fact30 / negfact31 = " << result << "\n";
+  result = fact30 % negfact31;
+  std::cout << "fact30 % negfact31 = " << result << "\n";
+  result = gcd(fact30, negfact31);
+  std::cout << "gcd(fact30, negfact31) = " << result << "\n";
+  assert(result == fact30);
+
+  identitytest(one, one, one);
+  identitytest(one, one, one);
+  identitytest(one, two, fact30);
+  identitytest(fact30, posfact31, fact28);
+  identitytest(fact30, negfact31, fact28);
+  identitytest(negfact31, posfact31, fact28);
+
+  bittest(one, one, one);
+  bittest(one, one, one);
+  bittest(one, two, fact30);
+  bittest(fact30, posfact31, fact28);
+
+  accumtest(one, one, one);
+  accumtest(one, one, one);
+  accumtest(one, two, fact30);
+  accumtest(fact30, posfact31, fact28);
+
+  utiltest(one);
+  utiltest(fact30);
+  utiltest(posfact31);
+
+  longidentitytest(one, 1, 1);
+  longidentitytest(one, 2, 3);
+  longidentitytest(fact30, 3, -20);
+  longidentitytest(fact30, 4, 20000);
+  longidentitytest(negfact31, -100, 20000);
+
+  longbittest(one, 1, 1);
+  longbittest(one, 2, 3);
+  longbittest(fact30, 4, 20000);
+  longbittest(fact28, 1000, 50);
+
+  longaccumtest(one, 1, 1);
+  longaccumtest(one, 2, 3);
+  longaccumtest(fact30, 4, 20000);
+  longaccumtest(fact30, 1000, 50);
+  longaccumtest(fact28, 10000000, 100000000);
+}
+
+void modtest()
+{
+  Integer b, e, m;
+
+  m = 1; m <<= 32;
+  b = m + 1;
+
+  e = Ipow( 2, 32 );
+  b = Ipow( 2, 32 );                  // use b as a comparison
+  std::cout << "2^32 = " << e << "\n";
+
+  e %= (e-1);                         // do same op two ways...
+  b = b % (b - 1);
+
+  std::cout << "2^32 % (2^32-1) = " << e << "\n"; // e is incorrect here
+  std::cout << "2^32 % (2^32-1) = " << b << "\n"; // but b is ok
+}