    /**************************************************************************\

    MODULE: tools

    SUMMARY:

    Some useful tools that are used throughout NTL.

    \**************************************************************************/

    #include <cstdlib>
    #include <cmath>
    #include <iostream>

    #include <NTL/config.h>
    #include <NTL/mach_desc.h>

    double GetTime();
    // returns number of seconds of CPU time used by this process;

    void PrintTime(ostream& s, double t);
    // prints the time t (in seconds) to s in the format
    //     ss  or  mm:ss  or  hh:mm:ss,
    // where the value t is first rounded to the nearest integer.

    long IsWhiteSpace(long c);
    // returns 1 if c is "white space" (as defined by isspace is the
    // standard library...usually blanks, tabs, newlines), and 0 otherwise.

    long SkipWhiteSpace(istream& s);
    // skips white space (as defined by IsWhiteSpace).
    // Return value is 0 if end-of-file is reached; otherwise,
    // return value is 1.

    long IsEOFChar(long c);
    // test if c == EOF

    long CharToIntVal(long c);
    // returns the hexidecimal value of c if c is '0'..'9', 'A'..'F', or 'a'..'f';
    // otherwise, the return value is -1.

    char IntValToChar(long x);
    // returns the hexadecimal digit '0'..'9', 'a'..'f' representing x;
    // an error is raised if x < 0 or x > 15.

    long IsFinite(double *p);
    // Returns 1 if *p is a "finite" floating point number.
    // A pointer is used to ensure that the number is in memory,
    // which on some architectures (notably x86/Pentium) can make a difference.

    // some min/max and swap routines:

    int min(int a, int b);
    int max(int a, int b);

    long min(long a, long b);
    long max(long a, long b);

    long min(int a, long b);
    long max(int a, long b);

    long min(long a, int b);
    long max(long a, int b);

    unsigned int min(unsigned int a, unsigned int b);
    unsigned int max(unsigned int a, unsigned int b);

    unsigned long min(unsigned long a, unsigned long b);
    unsigned long max(unsigned long a, unsigned long b);

    unsigned long min(unsigned int a, unsigned long b);
    unsigned long max(unsigned int a, unsigned long b);

    unsigned long min(unsigned long a, unsigned int b);
    unsigned long max(unsigned long a, unsigned int b);

    void swap(long& a, long& b);
    void swap(int& a, int& b);

    // defined here are all the conversion routines among the types
    // int, long, float, double.  See conversions.txt for complete details.

    // The following platform-dependent macros are defined:

    #define NTL_BITS_PER_LONG      (...)  /* bits in a long */
    #define NTL_MAX_LONG           (...)  /* max value of a long */
    #define NTL_MIN_LONG           (...)  /* min value of a long */

    #define NTL_BITS_PER_INT       (...)  /* bits in a int */
    #define NTL_MAX_INT            (...)  /* max value of a int */
    #define NTL_MIN_INT            (...)  /* min value of a int */

    #define NTL_DOUBLE_PRECISION   (...)  /* # of bits of precision in a double */
    #define NTL_FDOUBLE_PRECISION  (...)  /* the double value
                                            2^{NTL_DOUBLE_PRECISION-1} */

    #define NTL_ARITH_RIGHT_SHIFT  (...)  /* 1 if signed right-shift is
                                            arithmetic; 0 otherwise */

    #define NTL_EXT_DOUBLE         (...)  /* 1 if platform has "extended" doubles;
                                            0 otherwise */

    // ERROR HANDLING

    void TerminalError(const char *s);
    // print an error message and call abort

    extern void (*ErrorMsgCallback)(const char *);
    extern void (*ErrorCallback)();
    // Pointers (initially NULL) to callback functions.
    // Upon encountering an unrecoverable error with an error
    // message s, the following happens:
    //
    //    if (ErrorMsgCallback)
    //       (*ErrorMsgCallback)(s);
    //    else
    //       cerr << s << "\n";
    //
    //    if (ErrorCallback) (*ErrorCallback)();
    //    abort();
    //
    // NOTE: if threads are enabled, these are actually thread_local variables.

    // The following classes are defined even if exceptions are not
    // enabled with NTL_EXCEPTIONS

    class ErrorObject : public runtime_error {
    public:
       ErrorObject(const char *msg);
    };

    class LogicErrorObject : public ErrorObject {
    public:
       LogicErrorObject(const char *msg);
    };

    class ArithmeticErrorObject : public ErrorObject {
    public:
       ArithmeticErrorObject(const char *msg);
    };

    class ResourceErrorObject : public ErrorObject {
    public:
       ResourceErrorObject(const char *msg);
    };

    class FileErrorObject : public ErrorObject {
    public:
       FileErrorObject(const char *msg);
    };

    class InputErrorObject : public ErrorObject {
    public:
       InputErrorObject(const char *msg);
    };

    // The following functions throw the indicated exception if
    // exceptions are enabled with NTL_EXCEPTIONS; otherwise,
    // they simply invoke TerminalError.

    void MemoryError();
    // throws bad_alloc

    void Error(const char *msg);
    // throws ErrorObject

    void LogicError(const char *msg);
    // throws LogicErrorObject

    void ArithmeticError(const char *msg);
    // throws ArithmeticErrorObject

    void ResourceError(const char *msg);
    // throws ResourceErrorObject

    void FileError(const char *msg);
    // throws FileErrorObject

    void InputError(const char *msg);
    // throws InputErrorObject