{linesize 256}
{library}
{list off}
{Last modification <840120.1607>}
{COPYRIGHT (c) 1984 WEITEK INC}
{range off{}
{
  Known Bugs:
    If the remainder is zero, its sign should be that of the dividend
    Extended has two flavors of the smallest exponent
    Unnormal zero's don't add properly
    Extended not well tested


    This program contains IEEE-compatable arithmetic
    routines.  They are externally callable, using
    single, double, or extended precision.


    Entry point     Operation
    -----------     ---------
      ADDS          Add, single precision
      ADDD          Add, double precision
      ADDE          Add, extended precision
      SUBS          Subtract, single precision
      SUBD          Subtract, double precision
      SUBE          Subtract, extended precision
      MULS          MULTIPLY, single precision
      MULD          MULTIPLY, double precision
      MULE          MULTIPLY, extended precision
      DIVS          Divide, single precision
      DIVD          Divide, double precision
      DIVE          Divide, extended precision
    * REMS          Remainder, single precision
    * REMD          Remainder, double precision
    * REME          Remainder, extended precision
    * SQRTS         Square root, single precision
    * SQRTD         Square root, double precision
    * SQRTE         Square root, extended precision
    * CONSD         Convert single to double precision
    * CONSE         Convert single to extended precision
    * CONSH         Convert single to 16 bit integer
    * CONSI         Convert single to 32 bit integer
    * CONDS         Convert double to single precision
    * CONDE         Convert double to extended precision
    * CONDH         Convert double to 16 bit integer
    * CONDI         Convert double to 32 bit integer
    * CONES         Convert extended to single precision
    * CONED         Convert extended to double precision
    * CONEH         Convert extended to 16 bit integer
    * CONEI         Convert extended to 32 bit integer
    * CONIS         Convert 32 bit integer to single
    * CONID         Convert 32 bit integer to double
    * CONIE         Convert 32 bit integer to extended
    * CONIH         Convert 32 bit integer to 16 bit integer
    * CONHS         Convert 16 bit integer to single
    * CONHD         Convert 16 bit integer to double
    * CONHE         Convert 16 bit integer to extended
    * CONHI         Convert 16 bit integer to 32 bit integer
      INTS          Integerize, single precision
      INTD          Integerize, double precision
      INTE          Integerize, extended precision
    * SDECBIN       Convert decimal string to single precision binary
    * DDECBIN       Convert decimal string to double precision binary
    * EDECBIN       Convert decimal string to extended precision binary
      SCOMPARE      Compare, single precision
      DCOMPARE      Compare, double precision
      ECOMPARE      Compare, extended precision
    * SBINDEC       Convert single precision binary to decimal string
    * DBINDEC       Convert double precision binary to decimal string
    * EBINDEC       Convert extended precision binary to decimal string

    * COPYSIGN      Op1 gets op2's sign
    * SCALB         Adds N to X's exponent
    * LOGB          Returns unbiased exponent of X
    * NEXTAFTER     Next representable X in direction of Y
    * FINITE        True if finite
    * ISNAN         True if NaN
    * UNORDERED     True if unordered
    * CLASS         1=tNaN, 2=ntNaN, 3=-inf, 4=-norm, 5=-unnorm
                    6=-denorm, 7=-0, 8=+0, 9=+denorm, 10=+unnorm,
                    11=+norm, 12=+inf

 * Not finished yet
}
{page}
{heap 0}
{recursive off}
{title 'ARITH'}
{SUBPROGRAM}

Program ARITH(input,output){};
{visible off}     {fix!}

label 99;



{Last mod <820402.1224>}
const   mant←bits         =    112; {Max # of mantissa bits, any form}
        exp←bits          =     15; {Max # of exponent bits, any form}
        max←num←bits      =    128; {1+exp←bits+mant←bits}
        mant←bits←m1      =    111; {mant←bits-1}
        mant←bits←p1      =    113; {mant←bits+1}
        mant←bits←p2      =    114; {mant←bits+2}

{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
        single←exp←bits   ={3 { 4}   8 {Number of exponent bits, single} ;
        single←mant←bits  ={3 { 5}  24 {Number of mantissa bits, single} ;
        single←min←exp    ={-2{-6}-126 {Minimum exponent, single}        ;
        single←max←exp    ={3 { 7} 127 {Maximum exponent, single}        ;
        single←bias       ={3 { 7} 127 {Bias, single}                    ;

        double←exp←bits   =     11; {Number of exponent bits, double}
        double←mant←bits  =     53; {Number of mantissa bits, double}
        double←min←exp    =  -1022; {Minimum exponent, double}
        double←max←exp    =   1023; {Maximum exponent, double}
        double←bias       =   1023; {Bias, double}

        extended←exp←bits =     15; {Number of exponent bits, extended}
        extended←mant←bits=    112; {Number of mantissa bits, extended}
        extended←min←exp  = -16383; {Minimum exponent, extended}
        extended←max←exp  =  16383; {Maximum exponent, extended}
        extended←bias     =  16383; {Maximum exponent, extended}

        nstringchars      =     30; {Max number of chars in a string}
        debug             =  false;

type    bit             = 0..1;
        halfint         = -32768..32767;
        SHORTREAL	= packed array[1..32] of bit;
        LONGREAL        = packed array[1..64] of bit;
        veryLONGREAL    = packed array[1..128] of bit; {extended prec, extern}
        mant←array      = packed array[1..mant←bits] of bit; {mantissa}

        number          = record       {Internal form used for all numbers}
                            sign:  bit;
                            expon: integer;      {unbiased}
                            mant:  mant←array;   {with explicit leading bit}
                          end;

        formattype      = (single, double, extended);
        trap←setting    = (disabled, enabled);
        undermodetype   = (warning, normalizing);
        infinitytype    = (projective, affine);
        roundtype       = (rn, rp, rz, rm);
        expbitstype     = single←exp←bits..extended←exp←bits;
        error←indicator = (off,on);
        error←flag      = error←indicator;
        string          = packed array[1..nstringchars] of char;
        string5         = packed array[1..5] of char;   {for segment loader}
        cc              = (lt,eq,gt,un);  {Condition Codes}
        twooperandtype  = (a,b,c,d,e,f,g,h,i,X,Y,M);
        oneoperandtype  = (pmzero,W,pminf,NaN);

        modestype       = packed record
                            invalid←trap:   trap←setting;
                            divbyzero←trap: trap←setting;
                            overflow←trap:  trap←setting;
                            underflow←trap: trap←setting;
                            inexact←trap:   trap←setting;
                            check←underflow←before←rounding:  boolean;
                            under←mode:     undermodetype;
                            infinity←mode:  infinitytype;
                            round←mode:     roundtype
                          end;

        indicstype      = packed record
                            divbyzero←indic: error←indicator; {indics cleared}
                            invalid←indic:   error←indicator; {before each   }
                            overflow←indic:  error←indicator; {operation     }
                            underflow←indic: error←indicator;
                            inexact←indic:   error←indicator;
                            divbyzero←flag:  error←flag;      {flags are}
                            invalid←flag:    error←flag;      {sticky   }
                            overflow←flag:   error←flag;
                            underflow←flag:  error←flag;
                            inexact←flag:    error←flag
                          end;

        gvarstype       = record
                            format:    formattype;
                            mant←prec: 2..mant←bits;  {# of mantissa bits}
                            min←exp:   integer; {minimum exponent, unbiased}
                            max←exp:   integer; {maximum exponent, unbiased}
                            bias:      integer;
                            expbits:   expbitstype;   {# of exponent bits}
                            guard,round,sticky,carry: bit
                          end;

        access          = (a1,a2,a3,a4,a5,a6);

        pervert         = record
                            case access of
                              a1:  (I:integer);
                              a2:  (H1,H2,H3,H4:integer);
                              a3:  (R:SHORTREAL);
                              a4:  (L:LONGREAL);
                              a5:  (VL:veryLONGREAL);
                              a6:  (B:packed array [1..max←num←bits] of bit)
                          end;

VAR FUBAR:TEXT;

procedure halt(halt←code: integer);
begin
  writeln ('fatal error: code=',halt←code);
  goto 99;
end;

function XOR(a,b:bit):bit;      {Exclusive OR}
begin
  if a=b then xor:=0 else xor:=1;
end;


{subtitle 'ZERO functions',page}
procedure ZERO(var result: number; var{} gvars:gvarstype);
{Returns Normal Zero, undefined sign}

var  I:  1..mant←bits;

begin
  with gvars do begin
    result.expon:=min←exp; {exponent is format's minimum}
    for i:=1 to mant←prec do result.mant[i]:=0
  end
end;


procedure PLUSZERO(var result: number; var{} gvars:gvarstype);
{Returns Positive Normal Zero}

var  I:  1..mant←bits;

begin
  zero (result, gvars);
  result.sign:=0  {0=positive}
end;


procedure MINUSZERO(var result: number; var{} gvars:gvarstype);
{Returns Negative Normal Zero}

var  I:  1..mant←bits;

begin
  zero (result, gvars);
  result.sign := 1  {1=negative}
end;


{subtitle 'ISSIGNIFICANDZERO',page}
function ISSIGNIFICANDZERO(var{} N:number; var{} gvars:gvarstype):boolean;
{Returns True if all significand bits are zero.}
{Number of significand bits checked is the current format's precision}

var I:  1..mant←bits←p1;
    OK←SO←FAR: boolean;

begin
  ok←so←far:=true; i:=1;
  with n,gvars do begin
    while (i<=mant←prec) and ok←so←far do begin
      ok←so←far:= ok←so←far and (mant[i]=0);   i:=i+1   end;
    issignificandzero:=ok←so←far and (guard=0) and (round=0) and (sticky=0)
  end
end;


{subtitle 'IS ZEROS,INFINITY',page}
function ISZERO(var{} N:number; var{} gvars:gvarstype):boolean;
{See if N zero; may be + or - or unnormal}
begin
  iszero := issignificandzero(n,gvars) and (n.expon <> gvars.max←exp+1)
                                           {not a NaN or infinity     }
end;


function ISNORMALZERO(var{} N:number; var{} gvars:gvarstype):boolean;
{See if N is normal zero; may be positive or negative}
begin
  isnormalzero := issignificandzero(n,gvars) and (n.expon=gvars.min←exp)
end;


function ISINFINITY(var{} N:number; var{} gvars:gvarstype):boolean;
{See if op is infinity, ignore sign}
begin
  isinfinity := (n.expon=gvars.max←exp+1) and issignificandzero(n,gvars)
end;


{subtitle 'IS NAN,FINITE',page}
function ISNAN(var{} N:number; var{} gvars:gvarstype):boolean;
{See if op is a NaN}
begin
  isnan := (n.expon=gvars.max←exp+1) and (not issignificandzero(n,gvars))
end;


function ISTRAPPINGNAN(var{} N:number; var{} gvars:gvarstype):boolean;
{Return True if op is a trapping NaN}
{This routine is implementation dependent!}
{Criteria used here is that most significant explicit mantissa bit}
{is 1 if trapping}

begin
  if (gvars.format=single) or (gvars.format=double)
  then istrappingnan := isnan(n,gvars) and (n.mant[2]=1)  {hidden leading}
  else istrappingnan := isnan(n,gvars) and (n.mant[1]=1)  {explicit leading}
end;


function ISFINITE(var{} N:number; var{} gvars:gvarstype):boolean;
begin
  isfinite := not (isinfinity(n,gvars) or isnan(n,gvars))
end;


{subtitle 'issame',page}
function issame(var{} N1,N2:number; var{} gvars:gvarstype):boolean;

var I:integer;

begin               {slow}
  issame:=true;
  if (n1.sign<>n2.sign) or (n1.expon<>n2.expon) then issame:=false
    else for i:=1 to gvars.mant←prec do
           if n1.mant[i]<>n2.mant[i] then issame:=false
end;


{subtitle 'NORMALIZED QUERYS',page}
function ISUNNORMALIZED(var{} N:number;var{} gvars:gvarstype):boolean;
{Return true if N is unnormalized, includes denormalized}
{Returns false for normal zero, true for unnormal zero}
begin
  isunnormalized := (n.mant[1]=0) and not isnormalzero(n,gvars)
end;


function ISDENORMALIZED(var{} N:number; var{} gvars:gvarstype):boolean;
{Return True if N is denormalized}
{Zero is not denormalized.}
begin
  isdenormalized := isunnormalized(n,gvars) and (n.expon=gvars.min←exp)
end;


function ISNORMALIZED(var{} N:number; var{} gvars:gvarstype):boolean;
{Return True if N is normalized.}
{Returns false for zero.}
begin
  isnormalized := (N.mant[1]=1)
end;


{subtitle 'FLAG SETTING',page}
procedure SET←DIVBYZERO(var INDICS:indicstype);
begin
  indics.divbyzero←indic := on
end;


procedure SET←INVALID(var INDICS:indicstype);
begin
  indics.invalid←indic := on
end;


procedure SET←OVERFLOW(var INDICS:indicstype);
begin
  indics.overflow←indic := on
end;


procedure SET←UNDERFLOW(var INDICS:indicstype);
begin
  indics.underflow←indic := on
end;


procedure SET←INEXACT(var INDICS:indicstype);
begin
  indics.inexact←indic := on
end;


procedure UPDATE←FLAGS(var INDICS:indicstype);
begin
  with indics do begin
    if invalid←indic  =on  then begin
                             invalid←flag  :=on;
                             inexact←indic :=off {invalid masks inexact}
                           end;
    if divbyzero←indic=on  then divbyzero←flag:=on;
    if overflow←indic =on  then overflow←flag :=on;
    if underflow←indic=on  then underflow←flag:=on;
    if inexact←indic  =on  then inexact←flag  :=on
  end
end;


{subtitle 'NaN SELECTION',page}
procedure GETTRAPPINGNAN(var result: number; var{} gvars:gvarstype);
{Implementation Dependent!}
{Returns a trapping NaN.  Definition of trapping used here is that      }
{Most significant explicit mantissa bit is 1, all other mant bits set to zero}

var  I:  1..mant←bits;

begin
  result.sign    := 0;
  result.expon   := gvars.max←exp+1;
  for i:=1 to gvars.mant←prec do result.mant[i] := 0;
  if (gvars.format=single) or (gvars.format=double)
    then result.mant[2] := 1  {most sig explicit mant bit}
    else result.mant[1] := 1  {most sig explicit mant bit}
end;


procedure GETNONTRAPPINGNAN(var result: number; var{} gvars:gvarstype);
{Implementation Dependent!}
{Criteria used here is that most significant explicit mantissa bit is   }
{zero; here the following bit is set to one to distinguish from infinity}
var  I:  1..mant←bits;

begin
  result.sign    := 0;
  result.expon   := gvars.max←exp+1;
  for i:=1 to gvars.mant←prec do result.mant[i] := 0;
  if (gvars.format=single) or (gvars.format=double)
    then result.mant[3] := 1 {hidden msb}
    else result.mant[2] := 1 {explicit msb}
end;


procedure GETNAN(var result: number; var{} MODES:MODEStype; var{} gvars:gvarstype);
{Return Trapping NaN if invalid trap enabled, else Nontrapping}
begin
  if MODES.invalid←trap=enabled then gettrappingnan (result, gvars)
                                else getnontrappingnan (result, gvars)
end;


procedure SELECTNAN(var result: number; var{} op1,op2:number);
{Both op's are NaN's, pick one}
{This routine is implementation dependent!}
begin
  result := op1
end;


{subtitle 'PLUSINF',page}
procedure PLUSINF(var result: number; var{} gvars:gvarstype);
{Return positive infinity}

var  I:  1..mant←bits;

begin
  result.sign:=0;
  result.expon:=gvars.max←exp+1;
  for i:=1 to gvars.mant←prec do result.mant[i]:=0
end;


{subtitle 'FLMO',page}
function FLMO(var{} OP:mant←array; var{} GVARS:gvarstype):integer;
{Find left-most one,  far left is 0, far right is mant←prec-1, none is -1}
{ guard is mant←prec,  round is mant←prec+1,  sticky is mant←prec+2}

var i: 1..mant←bits;

begin
  flmo:=-1;
  with gvars do begin
    if sticky=1 then flmo:=mant←prec+2;
    if round =1 then flmo:=mant←prec+1;
    if guard =1 then flmo:=mant←prec;
    for i:=mant←prec downto 1 do  if op[i]=1 then flmo:=i-1
  end
end;


{subtitle 'OPERAND CASES',page}
function ONEOPERANDCASE(var{} OP:   number;
                        var{} gvars:gvarstype):oneoperandtype;
{Unreadable without Coonan's Implementation Guide}
begin
  if isnormalzero(op,gvars) then oneoperandcase:=pmzero else
  if isinfinity(op,gvars)   then oneoperandcase:=pminf  else
  if isnan(op,gvars)        then oneoperandcase:=nan    else
                                 oneoperandcase:=W
end;


function TWOOPERANDCASE(var{} OP1,OP2: number;
                        var{} gvars:   gvarstype):twooperandtype;
{Unreadable without Coonan's Implementation Guide}

{type   row       = array[oneoperandtype] of twooperandtype;
       tabletype = array[oneoperandtype] of row;

const  TABLE = tabletype[row[a, b, c, Y],
                         row[d, e, f, Y],
                         row[g, h, i, Y],
                         row[X, X, X, M]]; }

begin
{ twooperandcase:=table[oneoperandcase(op1,gvars)][oneoperandcase(op2,gvars)] }
  case oneoperandcase (op1,gvars) of
      pmzero: case oneoperandcase (op2, gvars) of
                  pmzero: twooperandcase := a;
                  W:      twooperandcase := b;
                  pminf:  twooperandcase := c;
                  NaN:    twooperandcase := Y;
              end;
      W:      case oneoperandcase (op2, gvars) of
                  pmzero: twooperandcase := d;
                  W:      twooperandcase := e;
                  pminf:  twooperandcase := f;
                  NaN:    twooperandcase := Y;
              end;
      pminf:  case oneoperandcase (op2, gvars) of
                  pmzero: twooperandcase := g;
                  W:      twooperandcase := h;
                  pminf:  twooperandcase := i;
                  NaN:    twooperandcase := Y;
              end;
      NaN:    case oneoperandcase (op2, gvars) of
                  pmzero: twooperandcase := X;
                  W:      twooperandcase := X;
                  pminf:  twooperandcase := X;
                  NaN:    twooperandcase := M;
              end;
  end;
end;


{subtitle 'SHFTL',page}
procedure SHFTL(var N:number; D:integer; var gvars:gvarstype);
{shift significand left, no exponent change, use G,R,S,carry}

var  I:    1..mant←bits←m1;
     CNTR: integer;

begin
  with N,gvars do begin
    if d>mant←prec+3 then d:=mant←prec+3; {allows shift sticky to carry}
    for cntr:=1 to d do begin
      if carry=1 then halt(1); {Shouldn't happen.}
      carry := mant[1];

      for i:=1 to mant←prec-1 do
        mant[i] := mant[i+1];

      mant[mant←prec] := guard;
      guard := round;
      round := sticky
      {sticky := sticky}
    end
  end
end;


{subtitle 'SHFTR',page}
procedure SHFTR(var N:number; D:integer; var gvars:gvarstype);
{shift significand right, D places, no exp change, use G,R,S,carry}

var  I:    2..mant←bits;
     CNTR: integer;

begin
  with N,gvars do begin
    if d>mant←prec+3 then d:=mant←prec+3; {allows shift carry to sticky}
    for cntr:=1 to d do begin
      if sticky=0 then sticky:=round;
      round  := guard;
      guard  := mant[mant←prec];

      for i:=mant←prec downto 2 do
        mant[i] := mant[i-1];

      mant[1] := carry;
      carry   := 0
    end
  end
end;


{subtitle 'EXAMINE', page}
function EXAMINE(var N:number;            var{} MODES:MODEStype;
                 var indics:indicstype;   var gvars:gvarstype):boolean;

{If N is trapping NaN, set Invalid
 If normalizing mode, normalize denormalized operand.}

var SHIFTDIST:  integer;

begin
  with MODES, indics, gvars do
    if istrappingnan(n,gvars)
      then begin set←invalid(indics); examine:=false end
      else begin
        examine:=true;
        if (under←mode=normalizing) and isdenormalized(n,gvars)
          then with n do begin
            shiftdist := flmo(mant,gvars);
            shftl(n, shiftdist, gvars);
            expon := expon-shiftdist
          end
      end
end;


{subtitle 'ROUNDNUM',page}
procedure ROUNDNUM(var N:number;           var{} MODES:MODEStype;
                   var indics:indicstype;  var gvars:gvarstype); {uses G,R,S}

procedure increment(var m:mant←array);
var  i:1..mant←bits;  sum:0..2;  c:bit;
begin
  sum:=0; c:=1;
  for i:=gvars.mant←prec downto 1 do
    begin
      sum:=m[i]+c;
      m[i]:=sum mod 2;
      c:=sum div 2
    end;
  if gvars.carry=1 then halt(2);
  gvars.carry:=c  {what if this carry's out???}
end;


begin
  with N,MODES,indics,gvars do
    if (guard=1) or (round=1) or (sticky=1)
      then begin
        set←inexact(indics);
        case round←mode of
          rp: if (sign=0)
                then begin
                  increment(mant);
                  if carry=1
                    then begin shftr(n,1,gvars); expon:=expon+1 end
                end;
          rm: if (sign=1)
                then begin
                  increment(mant);
                  if carry=1
                    then begin shftr(n,1,gvars); expon:=expon+1 end
                end;
          rz: {nada};
          rn: if (guard=1)
                 and (   ((round=1) or (sticky=1))
                      or ((round=0) and (sticky=0) and (mant[mant←prec]=1)) )
                then begin
                  increment(mant);
                  if carry=1
                    then begin shftr(n,1,gvars); expon:=expon+1 end
                end;
        end
      end
end;


{subtitle 'CHECK←UNDER←AND←ROUND',page}
procedure CHECK←UNDER←AND←ROUND(var N:number;           var{} MODES:MODEStype;
                                var indics:indicstype;  var gvars:gvarstype);
{check underflow and round}

var  I,K:        integer;
     UNROUNDEDN: number;
     OLDGVARS:   gvarstype;

begin
  with n,MODES,indics,gvars do begin
    oldgvars:=gvars;
    unroundedn:=n;
    if not check←underflow←before←rounding
      then roundnum(n,MODES,indics,gvars);
    if expon<min←exp         {BUG: what if unnormalized prod indisting from}
      then if underflow←trap=enabled                          {normal zero?}
             then begin
               set←underflow(indics);
               case format of
                 single:   expon:=expon+192-bias;   {Kludge, pack will add}
                 double:   expon:=expon+1536-bias;  {in the bias}
                 extended: begin
                             k:=1;
                             for i:=1 to mant←prec-2 do k:=k*2;
                             expon:=expon+k-bias
                           end
               end
             end
             else begin
               set←underflow(indics);
               if not check←underflow←before←rounding
                 then begin
                   n:=unroundedn; {avoid double rounding}
                   gvars:=oldgvars {restore possible flags gend by rounding}
                 end;
               shftr(n,min←exp-expon,gvars); expon:=min←exp;
               if not check←underflow←before←rounding
                 then roundnum(n,MODES,indics,gvars) {must re-round}
             end;
    if check←underflow←before←rounding then roundnum(n,MODES,indics,gvars)
  end
end;


{subtitle 'CHECK INVALID AND OVERFLOW',page}
procedure CHECK←INV←AND←OV(var N:number;           var{} MODES:MODEStype;
                           var indics:indicstype;  var gvars:gvarstype);
var  S:    bit;
     I:    1..mant←bits;
     K,J:  integer;

begin with n,MODES,indics,gvars do
  if isunnormalized(N,gvars) and (not isdenormalized(n,gvars))
     and ((format=single) or (format=double))
    then begin set←invalid(indics); getnan(n, MODES,gvars) end
    else with n do begin
      if expon>max←exp
        then case overflow←trap of
               enabled: begin
                 set←overflow(indics);
                 case format of
                   single:   expon:=expon-192-bias;  {Kludge, }
                   double:   expon:=expon-1536-bias; {pack wil}
                   extended: begin                   {add in  }
                               k:=1;                 {the bias}
                               for j:=1 to mant←prec-2 do
                                  k:=k*2;
                               expon:=expon-3*k-bias
                             end
                 end
               end;
               disabled:begin
                 set←overflow(indics);
                 set←inexact(indics);
                 if    ((round←mode=rm) and (sign=0))
                    or ((round←mode=rz) and (sign=0))
                    or ((round←mode=rp) and (sign=1))
                    or ((round←mode=rz) and (sign=1))
                   then begin
                     if isnormalized(n,gvars)
                       then for i:=1 to mant←prec do mant[i]:=1;
                     expon:=max←exp
                   end
                   else begin
                      s:=sign; plusinf(n, gvars); sign:=s
                   end
               end
             end
    end
end;


{subtitle 'ADD UTILITIES',page}
procedure addsignificands(var result:mant←array; var{} op1,op2:mant←array;
                          var gvars:gvarstype);
var i,sum:integer;
begin
  with gvars do
    for i:=mant←prec downto 1 do begin
      sum:=op1[i]+op2[i]+carry;
      result[i]:= sum mod 2;
      carry:=sum div 2
    end
end;


procedure ADDOPERANDS(var RESULT:number;   var{} OP1,OP2:number;
                      var gvars:gvarstype);

{Used by ADD, assumes that operands are aligned, GRS set by alignment}

var  C:  bit;

procedure compl(var n:mant←array);
var i:integer;
begin
  with gvars do begin
    for i:=mant←prec downto 1 do n[i]:=1-n[i];
    guard:=1-guard;  round:=1-round;  sticky:=1-sticky
  end
end;

procedure addtogrs;  {add carry to g,r,s}
var sum:0..2;
begin
  with gvars do begin
    sum:=carry+sticky;    sticky:=sum mod 2;    carry:=sum div 2;
    sum:=carry+round;     round :=sum mod 2;    carry:=sum div 2;
    sum:=carry+guard;     guard :=sum mod 2;    carry:=sum div 2
  end
end;


begin
  with gvars do begin
    if isnormalzero(op1,gvars) then op1.expon:=op2.expon;
    if isnormalzero(op2,gvars) then op2.expon:=op1.expon;
    if op1.expon<>op2.expon then halt(3);   {Ref: Hwang, COMPUTER ARITHMETIC}
    result.expon:=op1.expon;                {     Wiley&Sons, 1979,  p. 73  }
                                            { Extended by adding extra msb  }
    carry:=0;
    if op1.sign <> op2.sign then compl(op2.mant);
    addtogrs; addsignificands(result.mant, op1.mant, op2.mant, gvars);
    c    :=(carry+xor(op1.sign,op2.sign)) div 2;
    carry:=(carry+xor(op1.sign,op2.sign)) mod 2;
    if c=1
      then begin
        carry:=1;
        addtogrs; addsignificands(result.mant, op1.mant, op2.mant, gvars);
        c    :=(carry+xor(op1.sign,op2.sign)) div 2;
        carry:=(carry+xor(op1.sign,op2.sign)) mod 2
      end;
    if (c=0) and (op1.sign<>op2.sign)
      then begin compl(result.mant); carry:=1-carry end;
    if c=1 then result.sign:=op1.sign else result.sign:=op2.sign
  end
end;


{subtitle 'MULTSIGNIFICANDS',page}
procedure MULTSIGNIFICANDS(var RESULT:number; var{} OP1,OP2:number;
                           var gvars:gvarstype);

var  I:  1..mant←bits;

begin
  with result,gvars do begin
    for i:=1 to mant←prec do mant[i]:=0;  {clean it up}
    for i:=mant←prec downto 1 do begin
      shftr(result,1,gvars);
      if op2.mant[i]=1 then addsignificands(mant, mant, op1.mant, gvars)
    end
  end
end;


{subtitle 'DIVIDESIGNIFICANDS',page}
procedure DIVIDESIGNIFICANDS(var RESULT:number;  var{} OP1,OP2:number;
                             var gvars:gvarstype);

var  I:     1..mant←bits←p1;
     J:     1..mant←bits←p2;
     DONE:  boolean;
     DIF:   0..3;
     BORROW:bit;
     G,R:   bit;
     DOIT:  boolean;

begin
  with gvars do begin
    for i:=1 to mant←prec do result.mant[i]:=0;  {clean up}

    for j:=1 to mant←prec+2 do begin {compute result[j]gr and update dividend}
      done:=false; i:=1; doit:=true;
      if j=(mant←prec+2) then r:=1 else
      if j=(mant←prec+1) then g:=1 else
      result.mant[j]:=1;
      while (i<=mant←prec) and not done do begin {see which is bigger}
        if (carry=1) or (op1.mant[i]<>op2.mant[i])
          then begin
            done:=true;
            if (carry=0) and (op1.mant[i]<op2.mant[i])
              then begin
                if j=(mant←prec+2) then r:=0 else
                if j=(mant←prec+1) then g:=0 else
                result.mant[j]:=0;
                doit:=false
              end
          end;
        i:=i+1
      end;

      if doit then begin  {subtract}
        borrow:=1;
        for i:=mant←prec downto 1 do begin
          dif:=op1.mant[i]+(1-op2.mant[i])+borrow;
          op1.mant[i]:=dif mod 2;
          borrow:=dif div 2
        end;
        carry:=(carry+1+borrow) mod 2
      end;
      shftl(op1,1,gvars)
    end;

    {guard:=op1.mant[1]; round:=op1.mant[2]; sticky:=op1.mant[3];}
    guard:=g; round:=r; sticky:=carry; carry:=0;
    for i:=1 to mant←prec do if sticky=0 then sticky:=op1.mant[i]
  end
end;


{subtitle 'PACK',page}
procedure PACK(var result: pervert; var{} N:number; var gvars:gvarstype);

var  temp1: pervert;
     tempE: pervert;
     J:     1..mant←bits;
     start: 1..2;

begin
  with gvars do begin
    if (((format=single) or (format=double)) and (isdenormalized(n,gvars)))
       or isnormalzero(n,gvars)
      then tempE.i := 0
      else tempE.i := n.expon+bias;
    with temp1 do for j:=1 to expbits do
            b[expbits+mant←prec-j]:=tempE.b[expbits-j+1];
    temp1.b[mant←prec+expbits] := n.sign;
    if format=extended then start:=1 else start:=2;
    with temp1 do
      for j:=start to mant←prec do 
            b[1+mant←prec-j]:=n.mant[j];
    result:=temp1
  end
end;


procedure PACKS(var result: SHORTREAL; var{} N:number; var gvars:gvarstype);
var pack←result: pervert;
begin
  pack (pack←result, n, gvars);
  result := pack←result.r;
end;


procedure PACKD(var result: LONGREAL; var{} N:number; var gvars:gvarstype);
var pack←result: pervert;
begin
  pack (pack←result, n, gvars);
  result := pack←result.l
end;

procedure PACKE(var result: veryLONGREAL; var{} N:number; var gvars:gvarstype);
var pack←result: pervert;
begin
  pack (pack←result, n, gvars);
  result := pack←result.vl
end;

{subtitle 'UNPACK',page}
procedure UNPACK(var result: number; var{} T1:pervert; var gvars:gvarstype);

var  TE:     pervert;
     J:      1..mant←bits;
     RES:    number;
     START:  integer;

begin
  with gvars,res do begin
    te.i := 0;
    with te do for j:=1 to expbits do 
            b[expbits-j+1]:=t1.b[expbits+mant←prec-j];
    expon := te.i - bias;
    if format=extended then start:=1 else start:=2;
    for j:=start to mant←prec do 
            mant[j] := t1.b[1+mant←prec-j];
    if format<>extended then
      if expon >= min←exp   {not denorm}
        then mant[1]:=1
        else begin mant[1]:=0; expon:=min←exp end;
    if format<>extended then
      if expon =  max←exp+1  {infinity}
        then mant[1]:=0;
    sign := t1.b[expbits+mant←prec];
    result:=res
  end
end;


procedure UNPACKS(var result: number; var{} N:SHORTREAL; var gvars:gvarstype);
var t:pervert;
begin
  t.r     := n;
  unpack(result, t,gvars)
end;


procedure UNPACKD(var result: number; var{} N:LONGREAL; var gvars:gvarstype);
var  T: pervert;
begin
  t.l     := n;
  unpack(result, t,gvars)
end;


procedure UNPACKE(var result: number; var{} N:veryLONGREAL; var gvars:gvarstype);
var T: pervert;
begin
  t.vl  := n;
  unpack(result, t,gvars)
end;


{subtitle 'ADD',page}
procedure ADD(var RESULT:number;      OP1,OP2:number;
              var{} MODES:MODEStype;  var indics:indicstype;
              var gvars:gvarstype);

var  OP1OK,OP2OK,ONENORMALIZED:  boolean;
     SHIFTDIST:  integer;
     TEMP:       number;

begin
  op1ok:=examine(op1,MODES,indics,gvars);
  op2ok:=examine(op2,MODES,indics,gvars);
  if op1ok and op2ok then with MODES,indics,gvars do
    case twooperandcase(op1,op2,gvars) of
      a:     if ((round←mode<>rm) and not ((op1.sign=1) and (op2.sign=1)))
                or ((op1.sign=0) and (op2.sign=0))
             then pluszero(result, gvars)
             else minuszero(result, gvars);
      c,f:   result := op2; {op2 is inf & op1 is not inf or nan}
      g,h:   result := op1; {op1 is inf & op2 is not inf or nan}
      b,d,e: begin
           {1} if (not isnormalzero(op1,gvars)) and
                  (not isnormalzero(op2,gvars)) and
                  (op1.expon<>op2.expon)
                 then begin
                   if op1.expon<op2.expon
                     then begin
                       temp:=op1; op1:=op2; op2:=temp
                     end;
                   shftr(op2,op1.expon-op2.expon,gvars);
                   op2.expon:=op1.expon
                 end;
               onenormalized := isnormalized(op1,gvars) or
                                isnormalized(op2,gvars);
               addoperands(result, op1, op2, gvars);
           {2} if carry=1 then
                 begin
                   shftr(result,1,gvars);
                   result.expon:=result.expon+1
                 end;
           {3} if issignificandzero(result,gvars)
            {a}  then begin
                        if round←mode=rm
                          then result.sign:=1 else result.sign:=0;
                        if onenormalized then result.expon:=gvars.min←exp
                      end
            {b}  else if onenormalized then begin
                        shiftdist:=flmo(result.mant,gvars);
                        shftl(result, shiftdist, gvars);
                        result.expon:=result.expon-shiftdist
                      end;
           {4} CHECK←UNDER←AND←ROUND(result,MODES,indics,gvars);
               check←inv←and←ov(result, MODES,indics,gvars)
             end;
      i:     begin {both infinity}
               if (infinity←mode=affine) and (op1.sign=op2.sign)
               then result := op1
               else begin
                      set←invalid(indics);
                      getnan(result, MODES,gvars)
                    end
             end;
      X:     result := op1;  {op1 is NaN, op2 is non-NaN}
      Y:     result := op2;  {op2 is NaN, op1 is non-NaN}
      M:     selectnan (result, op1,op2)  {Both op's are NaN}
    end
  else getnan(result, MODES,gvars)
end;


{subtitle 'SUBTRACT',page}
procedure SUBTRACT(var RESULT:number;     OP1,OP2:number;
                   var{} MODES:MODEStype; var indics:indicstype;
                   var gvars:gvarstype);

begin
  if not isnan(op2,gvars) then op2.sign := 1-op2.sign;
  ADD(result, op1,op2, MODES,indics,gvars)
end;


{subtitle 'MULTIPLY',page}
procedure MULTIPLY(var RESULT:number;     OP1,OP2:number;
                   var{} MODES:MODEStype; var indics:indicstype;
                   var gvars:gvarstype);

var  OP1OK,OP2OK:  boolean;

begin
  op1ok:=examine(op1, MODES,indics,gvars);
  op2ok:=examine(op2, MODES,indics,gvars);
  if op1ok and op2ok then with MODES,indics,gvars do
    case twooperandcase(op1,op2,gvars) of
      a,b,d: begin
               zero(result, gvars); result.sign:=xor(op1.sign,op2.sign)
             end;
      c,g:   begin set←invalid(indics); getnan(result, MODES,gvars) end;
      e:     begin
           {1} result.sign:=xor(op1.sign,op2.sign);
               result.expon:=op1.expon+op2.expon;
               multsignificands(result,op1,op2, gvars);
           {2} if carry=1
                 then begin
                   shftr(result,1,gvars);
                   result.expon:=result.expon+1
                 end;
           {3} CHECK←UNDER←AND←ROUND(result,MODES,indics,gvars);
               check←inv←and←ov(result, MODES,indics,gvars)
             end;
      f,h,i: if (iszero(op1,gvars) and not isnormalzero(op1,gvars)) or
                (iszero(op2,gvars) and not isnormalzero(op2,gvars))
             then begin set←invalid(indics); getnan(result, MODES,gvars) end
             else begin
                    plusinf(result, gvars);
                    result.sign:=xor(op1.sign,op2.sign)
                  end;
      X:     result:=op1;
      Y:     result:=op2;
      M:     selectnan (result, op1,op2)
    end
  else getnan (result, MODES,gvars)
end;


{subtitle 'DIVIDE',page}
procedure DIVIDE(var RESULT:number;     OP1,OP2:number;
                 var{} MODES:MODEStype; var indics:indicstype;
                 var gvars:gvarstype);

var  OP1OK,OP2OK:  boolean;

begin
  op1ok:=examine(op1, MODES,indics,gvars);
  op2ok:=examine(op2, MODES,indics,gvars);
  if op1ok and op2ok then with MODES,indics,gvars do
    case twooperandcase(op1,op2,gvars) of
      a,i:   begin set←invalid(indics); getnan (result, MODES,gvars) end;
      b:     begin
               if iszero(op2,gvars) and not isnormalzero(op2,gvars)
                 then begin
                        set←invalid(indics);
                        getnan(result, MODES,gvars)
                      end
                 else begin
                        zero(result, gvars);
                        result.sign := xor(op1.sign, op2.sign)
                      end
             end;
      c,f:   begin
               zero(result, gvars);
               result.sign := xor(op1.sign, op2.sign)
             end;
      d:     if iszero(op1,gvars) and not isnormalzero(op1,gvars)
             then begin set←invalid(indics); getnan(result, MODES,gvars) end
             else begin
                    set←divbyzero(indics);
                    plusinf (result, gvars);
                    result.sign:=xor(op1.sign, op2.sign)
                  end;
      e:     if isunnormalized(op2,gvars)
             then begin set←invalid(indics); getnan (result, MODES,gvars) end
             else begin
                {1} result.sign:=xor(op1.sign, op2.sign);
                    result.expon:=op1.expon-op2.expon;
                    dividesignificands(result,op1,op2,gvars);
                {2} if result.mant[1]=0
                      then begin
                        shftl(result,1,gvars);
                        result.expon:=result.expon-1
                      end;
                {3} CHECK←UNDER←AND←ROUND(result,MODES,indics,gvars);
                    check←inv←and←ov(result, MODES,indics,gvars)
                  end;
      g,h:   begin
               plusinf (result, gvars); result.sign:=xor(op1.sign,op2.sign)
             end;
      X:     result:=op1;
      Y:     result:=op2;
      M:     selectnan (result, op1,op2)
    end
  else getnan(result, MODES,gvars)
end;


{subtitle 'REMAINDER',page}
procedure REMAINDER(var RESULT:number;     OP1,OP2:number;
                    var{} MODES:MODEStype; var indics:indicstype;
                    var gvars:gvarstype);

var  OP1OK,OP2OK:  boolean;
                                           {bugs - incomplete}
{If remainder is zero, its sigh is that of the dividend}
begin
  op1ok:=examine(op1,MODES,indics,gvars);
  op2ok:=examine(op2,MODES,indics,gvars);
  if op1ok and op2ok then with MODES,indics,gvars do
    case twooperandcase(op1,op2,gvars) of
      a,d,g,h,i: begin set←invalid(indics); getnan (result, MODES,gvars) end;
      b,c:       if isunnormalized(op2,gvars)
                   then begin
                          set←invalid(indics);
                          getnan (result, MODES,gvars)
                        end
                   else result:=op1;
      e:     {writeln('Part e not yet implemented')} halt(4) ;
      f:     result:=op2;
      X:     result:=op1;
      Y:     result:=op2;
      M:     selectnan(result, op1,op2)
    end
  else getnan (result, MODES,gvars)
end;


{subtitle 'SQRTT',page}
procedure SQRTT(var RESULT:number;     OP:number;
                var{} MODES:MODEStype; var indics:indicstype;
                var gvars:gvarstype);
{Note: can't call it SQRT in a segment, conflicts with pascal intrinsic}
begin
  if examine(op, MODES,indics,gvars) then with MODES,indics,gvars do
    case oneoperandcase(op, gvars) of
      pmzero:  result:=op;                {bugs - incomplete}
      pminf:   if (op.sign=1) or (infinity←mode=projective)
                 then begin
                   set←invalid(indics);
                   getnan (result, MODES,gvars)
                 end
                 else result:=op;
      W:       {writeln('Not yet')}  halt(5);
      NaN:     result:=op
    end
  else getnan (result, MODES,gvars)
end;


{subtitle 'CONVERT',page}
procedure CONVERT(var   RESULT:number;   RESTYPE:formattype;
                        OP:    number;   OPTYPE: formattype;
    var{} MODES:MODEStype; var indics:indicstype; var gvars:gvarstype);

begin
  {writeln('CONVERT not yet implemented')}  halt(6)    {bugs - incomplete}
end;


{subtitle 'INTEGERIZE',page}
procedure INTEGERIZE(var RESULT:number;     OP:number;
                     var{} MODES:MODEStype; var indics:indicstype;
                     var gvars:gvarstype);
var SHIFTDIST: integer;

begin
  if examine(op, MODES,indics,gvars) then with MODES,indics,gvars do
    case oneoperandcase(op, gvars) of
      pmzero:  result:=op;
      pminf:   result:=op;
      W:       with op do
                 if expon>=mant←prec-1 then result:=op
                 else begin
               {1} shftr(op,mant←prec-1-expon,gvars);
                   expon:=mant←prec-1;
               {2} result:=op; roundnum(result,MODES,indics,gvars);
                   guard:=0; round:=0; sticky:=0;
               {3} if issignificandzero(result,gvars)
                     then result.expon:=min←exp
                     else begin
                       shiftdist:=flmo(result.mant,gvars);
                       shftl(result, shiftdist, gvars);
                       result.expon:=result.expon-shiftdist
                     end
                 end;
      NaN:     result:=op
    end
  else getnan(result, MODES,gvars)
end;


{subtitle 'BINDEC',page}
procedure BINDEC(var RESULT:string;     OP:number;
                 var{} MODES:MODEStype; var indics:indicstype;
                 var gvars:gvarstype);
begin
  {writeln('BINDEC not yet implemented')} halt(7)   {bugs - incomplete}
end;


{subtitle 'DECBIN',page}
procedure DECBIN(var RESULT:number;     var{} OP:string;
                 var{} MODES:MODEStype; var indics:indicstype;
                 var gvars:gvarstype);
begin
  {writeln('DECBIN not yet implemented')} halt(8)   {bugs - incomplete}
end;


{subtitle 'COMPARE',page}
procedure COMPARE(var RESULT:cc;         OP1,OP2:number;
                  var{} MODES:MODEStype; var indics:indicstype;
                  var gvars:gvarstype);

var  i:integer;

begin
  with MODES do begin
    {Unordered cases}
    if   (isnan(op1,gvars) or isnan(op2,gvars))
      or ( (infinity←mode=projective)
                and (   (isinfinity(op2,gvars) and isfinite(op1,gvars))
                     or (isinfinity(op1,gvars) and isfinite(op2,gvars)) ) )
      then RESULT:=UN else

    {Special (sign independent) Equal cases}
    if (infinity←mode=projective) and (isinfinity(op1,gvars)) and
       (isinfinity(op2,gvars))     then RESULT:=EQ else
    if iszero(op1,gvars) and iszero(op2,gvars) then RESULT:=EQ else

    {Equal case}
    if   (issame(op1,op2,gvars))   then RESULT:=EQ else

    {Bit compare necessary}
    if op1.sign<>op2.sign
      then if op1.sign=0           then RESULT:=GT else RESULT:=LT else
    if op1.expon<>op2.expon
      then begin
        if   ((op1.expon>op2.expon) and (op1.sign=0))
          or ((op1.expon<op2.expon) and (op1.sign=1))
          then RESULT:=GT else RESULT:=LT
      end  else
    begin {mantissa check necessary}
      i:=1;
      while (i<=gvars.mant←prec) and (op1.mant[i]=op2.mant[i]) do i:=i+1;
      if i>gvars.mant←prec then halt(9) {were equal, tested above}
        else if    ((op1.mant[i]=1) and (op1.sign=0))
                or ((op1.mant[i]=0) and (op1.sign=1))
               then RESULT:=GT else RESULT:=LT
    end
  end
end;


{subtitle 'RESETIG',page}
procedure RESETIG(var GVARS:gvarstype; var INDICS:indicstype);
begin
  with gvars do begin
    guard:=0;  round:=0;  sticky:=0;  carry:=0
  end;
  with indics do begin
    invalid←indic:=off;   divbyzero←indic:=off;   overflow←indic:=off;
    underflow←indic:=off; inexact←indic:=off
  end
end;


{subtitle 'SET PRECISION UTILITIES',page}
procedure SETSINGLE(var GVARS:gvarstype; var indics:indicstype);
begin
  with gvars do begin
    format    := single;
    expbits   := single←exp←bits;
    mant←prec := single←mant←bits;
    min←exp   := single←min←exp;
    max←exp   := single←max←exp;
    bias      := single←bias
  end
end;


procedure SETDOUBLE(var GVARS:gvarstype; var indics:indicstype);
begin
  with gvars do begin
    format    := double;
    expbits   := double←exp←bits;
    mant←prec := double←mant←bits;
    min←exp   := double←min←exp;
    max←exp   := double←max←exp;
    bias      := double←bias
  end
end;


procedure SETEXTENDED(var GVARS:gvarstype; var indics:indicstype);
begin
  with gvars do begin
    format    := extended;
    expbits   := extended←exp←bits;
    mant←prec := extended←mant←bits;
    min←exp   := extended←min←exp;
    max←exp   := extended←max←exp;
    bias      := extended←bias
  end
end;


{subtitle 'ADDS',page}
{visible on}
procedure ADDS(var result: SHORTREAL; var{} N1,N2:SHORTREAL; var{} MODES:MODEStype;
              var indics:indicstype       );

var  RES:   number;
     GVARS: gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n1←unpacked, n1, gvars);
  unpacks (n2←unpacked, n2, gvars);
  add(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packs(result, res,gvars); update←flags(indics)
end;


procedure ADDD(var result: LONGREAL; var{} N1,N2:LONGREAL; var{} MODES:MODEStype;
              var indics:indicstype           );

var  RES:   number;
     GVARS: gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n1←unpacked, n1, gvars);
  unpackd (n2←unpacked, n2, gvars);
  add(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packd(result, res,gvars); update←flags(indics)
end;


procedure ADDE(var result: veryLONGREAL; var{} N1,N2:veryLONGREAL; var{} MODES:MODEStype;
              var indics:indicstype               );

var  RES:   number;
     GVARS: gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n1←unpacked, n1, gvars);
  unpacke (n2←unpacked, n2, gvars);
  add(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packe(result, res,gvars); update←flags(indics)
end;


{subtitle 'SUBS',page}
procedure SUBS(var result: SHORTREAL; var{} N1,N2:SHORTREAL; var{} MODES:MODEStype;
              var indics:indicstype       );

var  RES:   number;
     GVARS: gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n1←unpacked, n1, gvars);
  unpacks (n2←unpacked, n2, gvars);
  subtract(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packs (result, res,gvars); update←flags(indics)
end;


procedure SUBD(var result: LONGREAL; var{} N1,N2:LONGREAL; var{} MODES:MODEStype;
              var indics:indicstype           );

var  RES:   number;
     GVARS: gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n1←unpacked, n1, gvars);
  unpackd (n2←unpacked, n2, gvars);
  subtract(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packd(result, res,gvars); update←flags(indics)
end;


procedure SUBE(var result: veryLONGREAL; var{} N1,N2:veryLONGREAL; var{} MODES:MODEStype;
              var indics:indicstype               );

var  RES:   number;
     GVARS: gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n1←unpacked, n1, gvars);
  unpacke (n2←unpacked, n2, gvars);
  subtract(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packe (result, res,gvars); update←flags(indics)
end;


{subtitle 'MULS',page}
procedure MULS(var result: SHORTREAL; var{} N1,N2:SHORTREAL; var{} MODES:MODEStype;
              var indics:indicstype       );

var  RES:     number;
     GVARS:   gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n1←unpacked, n1, gvars);
  unpacks (n2←unpacked, n2, gvars);
  MULTIPLY(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packs(result, res, gvars); update←flags(indics)
end;


procedure MULD(var result: LONGREAL; var{} N1,N2:LONGREAL; var{} MODES:MODEStype;
              var indics:indicstype           );

var  RES:     number;
     GVARS:   gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n1←unpacked, n1, gvars);
  unpackd (n2←unpacked, n2, gvars);
  MULTIPLY(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packd(result, res, gvars); update←flags(indics)
end;


procedure MULE(var result: veryLONGREAL; var{} N1,N2:veryLONGREAL; var{} MODES:MODEStype;
              var indics:indicstype               );

var  RES:     number;
     GVARS:   gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n1←unpacked, n1, gvars);
  unpacke (n2←unpacked, n2, gvars);
  MULTIPLY(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packe(result, res, gvars); update←flags(indics)
end;


{subtitle 'DIVS',page}
procedure DIVS(var result: SHORTREAL; var{} N1,N2:SHORTREAL; var{} MODES:MODEStype;
              var indics:indicstype       );

var  RES:     number;
     GVARS:   gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n1←unpacked, n1, gvars);
  unpacks (n2←unpacked, n2, gvars);
  divide(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packs(result, res, gvars); update←flags(indics)
end;


procedure DIVD(var result: LONGREAL; var{} N1,N2:LONGREAL; var{} MODES:MODEStype;
              var indics:indicstype           );

var  RES:     number;
     GVARS:   gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n1←unpacked, n1, gvars);
  unpackd (n2←unpacked, n2, gvars);
  divide(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packd(result, res, gvars); update←flags(indics)
end;


procedure DIVE(var result: veryLONGREAL; var{} N1,N2:veryLONGREAL; var{} MODES:MODEStype;
              var indics:indicstype               );

var  RES:     number;
     GVARS:   gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n1←unpacked, n1, gvars);
  unpacke (n2←unpacked, n2, gvars);
  divide(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packe(result, res, gvars); update←flags(indics)
end;


{subtitle 'REMS',page}
procedure REMS(var result: SHORTREAL; var{} N1,N2:SHORTREAL; var{} MODES:MODEStype;
              var indics:indicstype       );

var  RES:     number;
     GVARS:   gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n1←unpacked, n1, gvars);
  unpacks (n2←unpacked, n2, gvars);
  remainder(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packs(result, res, gvars); update←flags(indics)
end;


procedure REMD(var result: LONGREAL; var{} N1,N2:LONGREAL; var{} MODES:MODEStype;
              var indics:indicstype           );

var  RES:     number;
     GVARS:   gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n1←unpacked, n1, gvars);
  unpackd (n2←unpacked, n2, gvars);
  remainder(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packd(result, res, gvars); update←flags(indics)
end;


procedure REME(var result: veryLONGREAL; var{} N1,N2:veryLONGREAL; var{} MODES:MODEStype;
              var indics:indicstype               );

var  RES:     number;
     GVARS:   gvarstype;
     n1←unpacked, n2←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n1←unpacked, n1, gvars);
  unpacke (n2←unpacked, n2, gvars);
  remainder(RES, n1←unpacked, n2←unpacked, MODES, indics, gvars);
  packe(result, res, gvars); update←flags(indics)
end;


{subtitle 'SQRTS',page}
procedure SQRTS(var result: SHORTREAL; var{} N:SHORTREAL; var{} MODES:MODEStype;
              var indics:indicstype    );

var  RES:     number;
     GVARS:   gvarstype;
     n←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n←unpacked, n, gvars);
  sqrtt(RES, n←unpacked, MODES, indics, gvars);
  packs(result, res, gvars); update←flags(indics)
end;


procedure SQRTD(var result: LONGREAL; var{} N:LONGREAL; var{} MODES:MODEStype;
              var indics:indicstype        );

var  RES:     number;
     GVARS:   gvarstype;
     n←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n←unpacked, n, gvars);
  sqrtt(RES, n←unpacked, MODES, indics, gvars);
  packd(result, res, gvars); update←flags(indics)
end;


procedure SQRTE(var result: veryLONGREAL; var{} N:veryLONGREAL; var{} MODES:MODEStype;
              var indics:indicstype            );

var  RES:     number;
     GVARS:   gvarstype;
     n←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n←unpacked, n, gvars);
  sqrtt(RES, n←unpacked, MODES, indics, gvars);
  packe(result, res, gvars); update←flags(indics)
end;


{subtitle 'CONSde',page}
procedure CONSD(var result: LONGREAL; var{} N:SHORTREAL; var{} MODES:MODEStype;
               var indics:indicstype);

var  RES:   number;
     GVARS: gvarstype;
     n←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n←unpacked, n, gvars);
  convert(res, double, n←unpacked, single,  MODES,indics,gvars);
  packd(result, res, gvars); update←flags(indics)
end;


procedure CONSE(var result: veryLONGREAL; var{} N:SHORTREAL; var{} MODES:MODEStype;
               var indics:indicstype);

var  RES:   number;
     GVARS: gvarstype;
     n←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n←unpacked, n, gvars);
  convert(res, extended, n←unpacked, single,  MODES,indics,gvars);
  packe(result, res, gvars); update←flags(indics)
end;


{subtitle 'CONDse',page}
procedure CONDS(var result: SHORTREAL; var{} N:LONGREAL; var{} MODES:MODEStype;
               var indics:indicstype);

var  RES:   number;
     GVARS: gvarstype;
     n←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n←unpacked, n, gvars);
  convert(res, single, n←unpacked, double,  MODES,indics,gvars);
  packs(result, res, gvars); update←flags(indics)
end;


procedure CONDE(var result: veryLONGREAL; var{} N:LONGREAL; var{} MODES:MODEStype;
               var indics:indicstype);

var  RES:   number;
     GVARS: gvarstype;
     n←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n←unpacked, n, gvars);
  convert(res, extended, n←unpacked, double,  MODES,indics,gvars);
  packe(result, res, gvars); update←flags(indics)
end;


{subtitle 'CONEsd',page}
procedure CONES(var result: SHORTREAL; var{} N:veryLONGREAL; var{} MODES:MODEStype;
               var indics:indicstype);

var  RES:   number;
     GVARS: gvarstype;
     n←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n←unpacked, n, gvars);
  convert(res, single, n←unpacked, extended,  MODES,indics,gvars);
  packs(result, res, gvars); update←flags(indics)
end;


procedure CONED(var result: LONGREAL; var{} N:veryLONGREAL; var{} MODES:MODEStype;
               var indics:indicstype);

var  RES:   number;
     GVARS: gvarstype;
     n←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n←unpacked, n, gvars);
  convert(res, double, n←unpacked, extended,  MODES,indics,gvars);
  packd(result, res, gvars); update←flags(indics)
end;


{subtitle 'INTS',page}
procedure INTS(var result: SHORTREAL; var{} N:SHORTREAL; var{} MODES:MODEStype;
              var indics:indicstype   );

var  RES:     number;
     GVARS:   gvarstype;
     n←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n←unpacked, n, gvars);
  integerize(RES, n←unpacked, MODES, indics, gvars);
  packs(result, res, gvars); update←flags(indics)
end;


procedure INTD(var result: LONGREAL; var{} N:LONGREAL; var{} MODES:MODEStype;
              var indics:indicstype       );

var  RES:     number;
     GVARS:   gvarstype;
     n←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n←unpacked, n, gvars);
  integerize(RES, n←unpacked, MODES, indics, gvars);
  packd(result, res, gvars); update←flags(indics)
end;


procedure INTE(var result: veryLONGREAL; var{} N:veryLONGREAL; var{} MODES:MODEStype;
              var indics:indicstype           );

var  RES:     number;
     GVARS:   gvarstype;
     n←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n←unpacked, n, gvars);
  integerize(RES, n←unpacked, MODES, indics, gvars);
  packe(result, res, gvars); update←flags(indics)
end;


{subtitle 'BINDEC',page}
procedure SBINDEC(var RES:string;  var{} N:SHORTREAL; var{} MODES:MODEStype;
                  var indics:indicstype                    );

var  GVARS:  gvarstype;
     n←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (n←unpacked, n, gvars);
  bindec(res, n←unpacked, MODES, indics, gvars); update←flags(indics)
end;


procedure DBINDEC(var RES:string;  var{} N:LONGREAL; var{} MODES:MODEStype;
                  var indics:indicstype                        );

var  GVARS:  gvarstype;
     n←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (n←unpacked, n, gvars);
  bindec(res, n←unpacked, MODES,indics,gvars); update←flags(indics)
end;


procedure EBINDEC(var RES:string; var{} N:veryLONGREAL; var{} MODES:MODEStype;
                  var indics:indicstype                            );

var  GVARS:  gvarstype;
     n←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (n←unpacked, n, gvars);
  bindec(res, n←unpacked, MODES,indics,gvars); update←flags(indics)
end;


{subtitle 'DECBIN',page}
procedure SDECBIN(var result: SHORTREAL; var OP:string; var{} MODES:MODEStype;
                 var indics:indicstype);

var  GVARS:  gvarstype;
     RES:    number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  decbin(res, op, MODES,indics,gvars);
  packs(result, res, gvars); update←flags(indics)
end;


procedure DDECBIN(var result: LONGREAL; var OP:string; var{} MODES:MODEStype;
                 var indics:indicstype);

var  GVARS:  gvarstype;
     RES:    number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  decbin(res, op, MODES,indics,gvars);
  packd(result, res, gvars); update←flags(indics)
end;


procedure EDECBIN(var result: veryLONGREAL; var OP:string; var{} MODES:MODEStype; var indics:indicstype);

var  GVARS:  gvarstype;
     RES:    number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  decbin(res, op, MODES,indics,gvars);
  packe(result, res, gvars); update←flags(indics)
end;


{subtitle 'COMPARE',page}
function SCOMPARE(var OP1,OP2:SHORTREAL; var{} MODES:MODEStype;
                  var indics:indicstype             ): CC;

var RES:   cc;
    GVARS: gvarstype;
    op1←unpacked, op2←unpacked: number;

begin
  setsingle(gvars, indics); resetig(gvars,indics);
  unpacks (op1←unpacked, op1, gvars);
  unpacks (op2←unpacked, op1, gvars);
  compare(res, op1←unpacked, op2←unpacked, MODES,indics,gvars);
  scompare:=res; update←flags(indics)
end;


function DCOMPARE(var OP1,OP2:LONGREAL; var{} MODES:MODEStype;
                  var indics:indicstype                 ): CC;

var RES:   cc;
    GVARS: gvarstype;
    op1←unpacked, op2←unpacked: number;

begin
  setdouble(gvars, indics); resetig(gvars,indics);
  unpackd (op1←unpacked, op1, gvars);
  unpackd (op2←unpacked, op1, gvars);
  compare(res, op1←unpacked, op2←unpacked, MODES,indics,gvars);
  dcompare:=res; update←flags(indics)
end;


function ECOMPARE(var OP1,OP2:veryLONGREAL; var{} MODES:MODEStype;
                  var indics:indicstype                     ): CC;

var RES:   cc;
    GVARS: gvarstype;
    op1←unpacked, op2←unpacked: number;

begin
  setextended(gvars, indics); resetig(gvars,indics);
  unpacke (op1←unpacked, op1, gvars);
  unpacke (op2←unpacked, op1, gvars);
  compare(res, op1←unpacked, op2←unpacked, MODES,indics,gvars);
  ecompare:=res; update←flags(indics)
end;

{main procedure}
begin
99: ;
end.