-- IeeeIOA.mesa
-- Last Modified: August 27, 1982 1:02 pm
-- Utilities for IO

DIRECTORY
  Ieee,
  Inline USING [BITOR, LongNumber],
  Real,
  RealOps;

IeeeIOA: CEDAR PROGRAM IMPORTS Ieee, Inline EXPORTS Real =
  BEGIN

  PowTen: TYPE = RECORD [f: LONG CARDINAL, e: INTEGER];

  TenTable: TYPE = RECORD [tens: ARRAY [0..13] OF PowTen, t26, t39: PowTen];

  posTable: TenTable =
    [tens:
     [[20000000000B, 0], [24000000000B, 3], [31000000000B, 6], [37200000000B, 9],
       [23420000000B, 13], [30324000000B, 16], [36411000000B, 19],
       [23045500000B, 23], [27657020000B, 26], [35632624000B, 29],
       [22500574400B, 33], [27220733500B, 36], [35065122420B, 39],
       [22141163452B, 43]], t26: [24533722672B, 86], t39: [27405037645B, 129]];

  negTable: TenTable =
    [tens:
     [[20000000000B, 0], [31463146315B, -4], [24365605075B, -7],
       [20304467230B, -10], [32155613531B, -14], [24761326107B, -17],
       [20615736406B, -20], [32657712326B, -24], [25363073422B, -27],
       [21134057501B, -30], [33371577317B, -34], [25772777414B, -37],
       [21457146011B, -40], [34113411502B, -44]], t26: [30604403045B, -87],
      t39: [25616276613B, -130]];

  iTenTable: ARRAY [0..9] OF LONG INTEGER =
    [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000];

  MulExtended: PROC [x, y: Ieee.Ext] RETURNS [z: Ieee.Ext] = TRUSTED {
    hi, lo: Inline.LongNumber;
    z.exp ← x.exp + y.exp + 1;
    z.det.sign ← x.det.sign # y.det.sign;
    z.det.type ← normal;
    z.det.sticky ← x.det.sticky OR y.det.sticky;
    [hi, lo] ← Ieee.Mul32[x.frac, y.frac]; -- normalize 64
    WHILE NOT Ieee.BitOn[hi.highbits, Ieee.HiBit] DO
      hi.lc ← hi.lc + hi.lc;
      IF Ieee.BitOn[lo.highbits, Ieee.HiBit] THEN
	hi.lowbits ← Inline.BITOR[hi.lowbits, 1];
      lo.lc ← lo.lc + lo.lc;
      z.exp ← z.exp - 1;
      ENDLOOP;
    z.frac ← hi; -- Round to 32 bits.
    IF lo.lc > Ieee.HalfLC OR
      (lo.lc = Ieee.HalfLC AND Ieee.BitOn[z.frac.lowbits, 1]) THEN {
      -- Overflow
      z.frac.lc ← z.frac.lc + 1;
      IF z.frac.lc < hi.lc THEN {
	z.frac.lc ← Ieee.RShift1in1[z.frac.lc]; z.exp ← z.exp + 1; };
      };
    IF lo.lc # 0 THEN z.det.sticky ← TRUE;
    };

  RealToPair: PUBLIC PROC [
    r: REAL, precision: CARDINAL ← Real.DefaultSinglePrecision]
    RETURNS [type: Real.NumberType, fr: LONG INTEGER, exp10: INTEGER] = TRUSTED {
    x, zz: Ieee.Ext;
    t1, t2, sign, normalized: BOOLEAN;
    Ieee.thisTimeExceptions ← Real.NoExceptions;
    precision ← MAX[1, MIN[precision, 9]];
    x ← Ieee.Unpack[r];
    sign ← x.det.sign;
    SELECT x.det.type FROM
      nan => RETURN[nan, 0, 0];
      infinity => {
	fr ← IF sign THEN LAST[LONG INTEGER] ELSE FIRST[LONG INTEGER];
	exp10 ← 99;
	RETURN[infinity, fr, exp10];
	};
      zero => RETURN[zero, 0, 0];
      ENDCASE => NULL;
    x.det.sign ← FALSE;
    normalized ← Ieee.Normalized[x.frac.highbits];
    exp10 ← IF normalized THEN (x.exp*3)/10 ELSE -38;
    exp10 ← exp10 + 1 - precision;
    DO
      zz ← Scale[x, -exp10];
      [v: fr, invalid: t1, overflow: t2] ← Ieee.FixExtended[zz, rn];
      IF t1 OR t2 THEN ERROR;
      SELECT TRUE FROM
	fr > iTenTable[precision] => exp10 ← exp10 + 1;
	fr = iTenTable[precision] => {exp10 ← exp10 + 1; fr ← fr/10; EXIT; };
	fr < iTenTable[precision - 1] =>
	  IF normalized THEN exp10 ← exp10 - 1 ELSE EXIT;
	ENDCASE => EXIT;
      ENDLOOP;
    IF sign THEN fr ← -fr;
    RETURN[normal, fr, exp10];
    };

  Scale: PROC [x: Ieee.Ext, exp10: INTEGER] RETURNS [y: Ieee.Ext] = TRUSTED {
    table: TenTable;
    mul: PowTen;
    big: BOOLEAN;
    IF exp10 = 0 THEN RETURN[x];
    big ← exp10 < 0;
    table ← IF big THEN negTable ELSE posTable;
    exp10 ← ABS[exp10];
    SELECT exp10 FROM
      IN [1..13] => mul ← table.tens[exp10];
      IN (13..26) => {
	x ← MulExtended[x, CVExt[table.tens[13]]];
	mul ← table.tens[exp10 - 13];
	};
      = 26 => mul ← table.t26;
      IN (26..39] => {
	x ← MulExtended[x, CVExt[table.t26]]; mul ← table.tens[exp10 - 26]; };
      = 39 => mul ← table.t39;
      IN (39..52] => {
	x ← MulExtended[x, CVExt[table.t39]]; mul ← table.tens[exp10 - 39]; };
      ENDCASE => {
	WHILE exp10 > 52 DO
	  x ← MulExtended[x, CVExt[table.t39]]; exp10 ← exp10 - 39; ENDLOOP;
	RETURN[Scale[x, IF big THEN -exp10 ELSE exp10]];
	};
    y ← CVExt[mul];
    y ← MulExtended[x, y];
    };

  CVExt: PROC [t: PowTen] RETURNS [y: Ieee.Ext] = {
    y.det.sticky ← y.det.sign ← FALSE;
    y.det.type ← normal;
    y.frac.lc ← t.f;
    y.exp ← t.e;
    };

  PairToReal: PUBLIC PROC [fr: LONG INTEGER, exp10: INTEGER] RETURNS [REAL] = TRUSTED {
    y: Ieee.Ext;
    or: RealOps.RoundingMode ← Ieee.fpmode.round;
    Ieee.fpmode.round ← rn;
    Ieee.thisTimeExceptions ← Real.NoExceptions;
    IF fr = 0 THEN RETURN[Real.PlusZero];
    y.exp ← 31;
    y.det.sign ← fr < 0;
    y.det.sticky ← FALSE;
    y.det.type ← normal;
    y.frac.li ← IF y.det.sign THEN -fr ELSE fr;
    Ieee.PostNormalize[@y];
    y ← Scale[y, exp10];
    Ieee.StepTwo[@y];
    Ieee.fpmode.round ← or;
    RETURN[Ieee.Pack[@y]];
    };

  END.
August25, 1980  4:28 PM, LStewart; formatting and qualification
August 27, 1982 1:04 pm, L. Stewart, CEDAR