Math Processor Unit Library

libmpu – library of arithmetic functions for integer, real, and complex numbers of increased digit capacity

16 Commits   0 Branches   2 Tags
.\" Copyright 2024 Andrew V.Kosteltsev (kx@radix-linux.su)
.\"
.\"
.TH LIBMPU 7  "December 27, 2024" "libmpu" "libmpu Programmer's Manual"
.SH NAME
libmpu \- Math Processor Unit Library (libmpu).
.SH DESCRIPTION
The library is designed as a processor emulator with a set of registers and flags that are set according
to the results of the operations performed. The set of integer functions contains arithmetic and logical
operations, as well as all types of shift operations. Basic trigonometric functions are implemented for
real and complex numbers.
.PP
Bit capacity is limited to \fB65536\fP bits for arithmetic operations and \fB16384\fP bits
for trigonometry. The limitations are due to the order of the approximation series.
.SH Data formats
The library supports integer, real and complex types. Variables are stored in byte arrays.
.sp
.SS Integer numbers
The \fBlibmpu.h\fP header file defines constants that represent the number of bytes
to store integer variables:
.nf
.sp
#define NB_I8           1
#define NB_I16          2
#define NB_I32          4
#define NB_I64          8
#define NB_I128        16
#define NB_I256        32
#define NB_I512        64
#define NB_I1024      128
#define NB_I2048      256
#define NB_I4096      512
#define NB_I8192     1024
#define NB_I16384    2048
#define NB_I32768    4096
#define NB_I65536    8192
#define NB_I_MAX     8192
.fi
.PP
These constants can be used as the value of the \fBnb\fP argument for integer operations.
.PP
In systems with \fBbig\-endian\fP byte order, the high byte of a number is stored at the
lowest memory address and the low byte at the highest memory address. In a system with
\fBlittle\-endian\fP byte order, on the contrary, the smallest byte is stored at the
smallest address.
.PP
The following diagram shows the placement of the integer depending on the machine
architecture:
.nf
.sp
if( MPU_BYTE_ORDER_BIG_ENDIAN == 0 )
{
      [NB-1],                      . . . ,                       [0];
      ┌─────────────────────────── . . . ───────────────────────────┐
      │  high                                                  low  │
      └─────────────────────────── . . . ───────────────────────────┘
       ^Sign bit
  size:                                                           NB.
}

if( MPU_BYTE_ORDER_BIG_ENDIAN == 1 )
{
      [0],                         . . . ,                    [NB-1];
      ┌─────────────────────────── . . . ───────────────────────────┐
      │  high                                                  low  │
      └─────────────────────────── . . . ───────────────────────────┘
       ^Sign bit
  size:                                                           NB.
}
.fi
.PP
Here, the symbol \fBNB\fP — denotes the number of bytes of the number.
.PP
To represent integer variables, the user can independently create byte arrays in any
of the following ways:
.nf
.sp
  __mpu_byte_t   a[NB_I65536];
  mpu_int        a[NB_I65536];

  mpu_int       *a = (mpu_int *)malloc( NB_I65536 * sizeof(__mpu_byte_t) );
.fi
.PP
and also use, predefined in \fBlibmpu.h\fP, data types that explicitly talk
about dimensionality:
.nf
.sp
  mpu_int4096_t  a;
.fi
.PP
Integers can be considered both signed and unsigned. Signed variables are represented in two’s
complement form for convenience of operations with them. Below is a table of some values of an
8\-bit variable in two’s complement form.
.nf
.sp
      ┌────────────────┬─────────────────┐
      │     Decimal    │     Binary      │
      │ representation │ representation  │
      ├────────────────┼─────────────────┤
      │       127      │    0111 1111    │
      │         3      │    0000 0011    │
      │         2      │    0000 0010    │
      │         1      │    0000 0001    │
      │         0      │    0000 0000    │
      │        -1      │    1111 1111    │
      │        -2      │    1111 1110    │
      │        -3      │    1111 1101    │
      │      -127      │    1000 0001    │
      │      -128      │    1000 0000    │
      └────────────────┴─────────────────┘
.fi
.sp
.SS Real numbers
Real variables, just like integer variables, are stored as byte arrays. The \fBlibmpu.h\fP
header file defines constants that represent the number of bytes for storing real variables:
.nf
.sp
#define NB_R32          4
#define NB_R64          8
#define NB_R128        16
#define NB_R256        32
#define NB_R512        64
#define NB_R1024      128
#define NB_R2048      256
#define NB_R4096      512
#define NB_R8192     1024
#define NB_R16384    2048
#define NB_R32768    4096
#define NB_R65536    8192
#define NB_R_MAX     8192
.fi
.PP
These constants can be used as the value of the \fBnb\fP argument for operations
with real numbers.
.PP
Real numbers have two fields: the shifted exponent and the mantissa. The integer
unit bit is implicit. The sign is located in the high bit of the number.
.PP
The following diagram shows the placement of a real number depending on the
architecture of the machine:
.nf
.sp
if( MPU_BYTE_ORDER_BIG_ENDIAN == 0 )
{
      [NB-1], . . . , [nS] │ [nS-1],        . . . ,              [0];
      ┌────── . . . ───────┬─────────────── . . . ──────────────────┐
      │ Sign  + Exponent   │              Significand               │
      └────── . . . ───────┴─────────────── . . . ──────────────────┘
       ^Sign bit           ^(1. - implicit)
  size:                  nE                                       nS.
}

if( MPU_BYTE_ORDER_BIG_ENDIAN == 1 )
{
      [0],  . . . , [nE-1] │ [nE],          . . . ,           [NB-1];
      ┌────── . . . ───────┬─────────────── . . . ──────────────────┐
      │ Sign  + Exponent   │              Significand               │
      └────── . . . ───────┴─────────────── . . . ──────────────────┘
       ^Sign bit           ^(1. - implicit)
  size:                  nE                                       nS.
}
.fi
.PP
Here, the symbols \fBnE\fP and \fBnS\fP denote the number of bytes of the exponent and the
number of bytes of the mantissa, respectively.
.PP
The number of bits allocated to represent the sign, exponent and mantissa is distributed
as follows:
.nf
.sp
      ┌───────────────────────┬───────────────────┬─────────────┐
      │  Total number of bits │ (Sign + Exponent) │ Significand │
      ├───────────────────────┼───────────────────┼─────────────┤
      │                32     │  1  +       8   + │       23    │
      │                64     │  1  +      11   + │       52    │
      │               128     │  1  +      31   + │       96    │
      │               256     │  1  +      31   + │      224    │
      │               512     │  1  +      63   + │      448    │
      │              1024     │  1  +      63   + │      960    │
      │              2048     │  1  +     127   + │     1920    │
      │              4096     │  1  +     127   + │     3968    │
      │              8192     │  1  +     255   + │     7936    │
      │             16384     │  1  +     255   + │    16128    │
      │             32768     │  1  +     511   + │    32256    │
      │             65536     │  1  +     511   + │    65024    │
      └───────────────────────┴───────────────────┴─────────────┘
.fi
.PP
The 32\- and 64\-bit number formats are fully consistent with the \fBIEEE\fP (Institute
of Electrical and Electronics Engineers) format.
.PP
For convenience in declaring real\-type variables, the \fBlibmpu.h\fP header file
defines the corresponding data types, the application of which may look, for example,
as follows:
.nf
.sp
  mpu_real16384_t  a, b;
.fi
.sp
.SS Not\-a\-Numbers
To enhance computational capabilities, the floating\-point number format provides
several special values along with the usual real numbers. These have some meaning
and provide important information about the algorithms and operations in which these
values appear. Special values include real numbers with normalization violations,
indeterminacy, zeros, infinities, and non\-numbers, shown in the following table.
.nf
.sp
      ┌──────┬───────────────────┬───────────────────┬──────────────────┐
      │ Sign │      Exponent     │    Significand    │   comments       │
      ├──────┼───────────────────┼───────────────────┼──────────────────┤
      │   S  │  1111 . . . 1111  │  0000 . . . 0000  │   +/- inf        │
      │   S  │  0000 . . . 0000  │  0000 . . . 0000  │   +/- 0          │
      │   1  │  1111 . . . 1111  │  1000 . . . 0000  │     - ind        │
      │   S  │  1111 . . . 1111  │  0000 . . . 0001  │   +/- NaN (min)  │
      │   S  │  1111 . . . 1111  │  1111 . . . 1111  │   +/- NaN (max)  │
      └──────┴───────────────────┴───────────────────┴──────────────────┘

      Здесь:
        +/- inf         -  +/- infinity;
        +/- 0           -  +/- signed zero;
          - ind         -      indeterminacy;
        +/- NaN (min)   -  +/- minimal Not-a-Number;
        +/- NaN (max)   -  +/- maximal Not-a-Number.
.fi
.PP
Denormalized numbers:
.nf
.sp
      ┌──────┬───────────────────┬───────────────────┬──────────────────┐
      │ Sign │      Exponent     │    Significand    │   comments       │
      ├──────┼───────────────────┼───────────────────┼──────────────────┤
      │   S  │  0000 . . . 0000  │  0000 . . . 0001  │   +/- min        │
      │   S  │  0000 . . . 0000  │  1111 . . . 1111  │   +/- max        │
      └──────┴───────────────────┴───────────────────┴──────────────────┘
.fi
.PP
Maximum and minimum real numbers:
.nf
.sp
      ┌──────┬───────────────────┬───────────────────┬──────────────────┐
      │ Sign │      Exponent     │    Significand    │   comments       │
      ├──────┼───────────────────┼───────────────────┼──────────────────┤
      │   S  │  0000 . . . 0001  │  0000 . . . 0000  │   +/- MIN        │
      │   S  │  1111 . . . 1110  │  1111 . . . 1111  │   +/- MAX        │
      └──────┴───────────────────┴───────────────────┴──────────────────┘
.fi
.sp
.SS Complex numbers
Complex numbers are stored in the machine's memory as a structure consisting
of two real numbers.
.PP
The constants that define the size of complex numbers in bytes are set so
that they represent half the size of the complex number:
.nf
.sp
#define NB_C32          4
#define NB_C64          8
#define NB_C128        16
#define NB_C256        32
#define NB_C512        64
#define NB_C1024      128
#define NB_C2048      256
#define NB_C4096      512
#define NB_C8192     1024
#define NB_C16384    2048
#define NB_C32768    4096
#define NB_C65536    8192
#define NB_C_MAX     8192
.fi
.PP
It is important to note here that functions working with complex variables accept these very
values as a parameter determining the operand size. Thus, for example, to work with a variable
of the \fBmpu_complex256_t\fP type, \fBnb\fP = 32 == \fBNB_C256\fP must be supplied to the
function input, while \fBsizeof\fP(\fBmpu_complex256_t\fP) == 64 == \fBNB_C256\fP * 2.
.PP
The representation of complex numbers in memory is shown in the following diagram:
.nf
.sp
if( MPU_BYTE_ORDER_BIG_ENDIAN == 0 )
{
      [NB*2-1],     . . . ,     [NB] │ [NB-1],     . . . ,       [0];
      ┌──────────── . . . ───────────┬──────────── . . . ───────────┐
      │           Real part          │           Imaginary          │
      └──────────── . . . ───────────┴──────────── . . . ───────────┘
  size:            NB_Real == NB_CXXX             NB_Imag == NB_CXXX.
}

if( MPU_BYTE_ORDER_BIG_ENDIAN == 1 )
{
      [0],          . . . ,   [NB-1] │ [NB],       . . . ,  [NB*2-1];
      ┌──────────── . . . ───────────┬──────────── . . . ───────────┐
      │           Real part          │           Imaginary          │
      └──────────── . . . ───────────┴──────────── . . . ───────────┘
  size:            NB_Real == NB_CXXX             NB_Imag == NB_CXXX.
}
.fi
.PP
The Imaginary and Real part formats of complex variables are the same as those of real numbers.
.sp
.SH Flags
Most operations on integers and real numbers expose flags. The flags of operations are
placed in an integer 32\-bit variable. The lower 8 bits [7 ... 0] are given for flags
of integer operations. Bits 8 through 15 are occupied by flags set by operations with
real numbers.
.sp
.SS Flags of integer operations:
.nf
.sp
               7     6     5     4     3     2     1     0
    . . . ─┬────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
           │ V  │  R  │  Z  │  P  │  S  │  O  │  C  │  A  │
    . . . ─┴────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
.sp
        A - Auxiliary Carry Flag (carry from lowest 4-bit word)
        C - Carry Flag
        O - Overflow Flag
        S - Sign Flag
        P - Parity Flag (of lowest significant byte)
        Z - Zero Flag
        R - major || remainder
        V - Invalid operation
.fi
.PP
NOTE: The \fBA\fP and \fBP\fP flags are exposed only by operations on 8\-bit
and 16\-bit variables.
.sp
.SS Flags of operations with real variables:
.nf
.sp
               15    14    13    12    11    10     9     8
    . . . ─┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬ . . .
           │ INX │ IND │ PLS │ TLS │ UDF │ OVF │ SNG │ DOM │
    . . . ─┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴ . . .
.sp
      DOM - Domain Flag
      SNG - Singularity Flag
      OVF - Overflow Flag
      UDF - Underflow Flag
      TLS - TLOSS Flag
      PLS - PLOSS Flag
      IND - ind-produsing operation Flag
      INX - Inexact Flag
.fi
.PP
The \fBlibmpu.h\fP header file defines flag handling functions such as clearing flags,
resetting, setting, and checking operation flags.
.sp
.SH Exceptions and error codes
Besides flagging operations with integers and real numbers, the \fBLibMPU\fP library supports
the standard \fBerrno\fP variable and, in addition, its own variables \fB__mpu_integer_error_no\fP,
\fB__mpu_real_error_no\fP, \fB__mpu_complex_error_no\fP, \fB__mpu_math_error_no\fP.
.PP
Error codes are defined in the \fBlibmpu.h\fP header file.
.PP
The \fBLibMPU\fP library supports error handling through the \fB__mpu_math_error()\fP function,
which can be overridden by the user at the object code linking stage in the same way that it is
possible to override the \fBmatherr()\fP function when linking programs with a standard \fBC\fP
language library (e.g., \fBGNU Libc\fP).
.PP
In addition, the user can override the \fB__mpu_warning()\fP function, which
can output additional error information.
.PP
As in the case of the \fBmatherr()\fP function of the \fBC\fP standard library,
the parameter of the \fB__mpu_math_error()\fP and \fB__mpu_warning()\fP functions
is a pointer to the \fB__exception\fP structure:
.nf
.sp
struct __exception
{
   int             who;      /* _COMPLEX_, _REAL_, _INTEGER_, _MATH_ */

   int             type;
   __mpu_char8_t  *name;
   __mpu_char8_t  *msg;
   int             msg_type; /* >= 1 - error, 0 - warning */

   int             nb_a1;    /* number of bytes in arg_1        */
   int             nb_a2;    /* number of bytes in arg_2        */
   int             nb_rv;    /* number of bytes in return_value */

   unsigned char  *arg_1;
   unsigned char  *arg_2;
   unsigned char  *return_value;
};
.fi
.PP
where the error source, error type, the name of the function whose execution caused
the error, as well as pointers to the function arguments and the received return
value are defined.
.PP
Using \fB__mpu_utf8mpu_error()\fP function you can get a pointer to a string constant
containing a text description of the error corresponding to the error code (see
\fB__mpu_integer_error_no\fP, \fB__mpu_real_error_no\fP, \fB__mpu_complex_error_no\fP,
\fB__mpu_math_error_no\fP variables).
.PP
For simple calculations, we usually do not have to override the functions \fBmatherr()\fP,
\fB__mpu_math_error()\fP and \fB__mpu_warning()\fP, but we have kept this possibility as one
of the standard features provided by the \fBC\fP language library.
.sp
.SH SEE ALSO
.BR iadd(3),
.BR isub(3),
.BR iadc(3),
.BR isbb(3),
.BR ishl(3),
.BR ishr(3),
.BR isal(3),
.BR isar(3),
.BR irol(3),
.BR iror(3),
.BR ircl(3),
.BR ircr(3),
.BR ishln(3),
.BR ishrn(3),
.BR isaln(3),
.BR isarn(3),
.BR iroln(3),
.BR irorn(3),
.BR ircln(3),
.BR ircrn(3),
.BR ineg(3),
.BR inot(3),
.BR iand(3),
.BR itest(3),
.BR icmp(3),
.BR ior(3),
.BR ixor(3),
.BR iinc(3),
.BR idec(3),
.BR ixchg(3),
.BR icpy(3),
.BR icvt(3),
.BR imul(3),
.BR ismul(3),
.BR idiv(3),
.BR isdiv(3),
.BR iatoi(3),
.BR iatoui(3),
.BR iitoa(3),
.BR iuitoa(3).