.\" 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).