m3middle/src/TFloat.m3


 Copyright (C) 1993, Digital Equipment Corporation           
 All rights reserved.                                        
 See the file COPYRIGHT for a full description.              
                                                             
 File: TFloat.m3                                             
 Last Modified On Thu Jul 28 10:18:03 PDT 1994 By kalsow     
      Modified On Thu May 20 08:46:32 PDT 1993 By muller     

UNSAFE MODULE TFloat;

IMPORT Convert, TargetMap;
FROM Target IMPORT Float, Precision;

PROCEDURE New (READONLY chars: ARRAY OF CHAR;  pre: Precision;
               VAR f: Float): BOOLEAN =
  VAR used: INTEGER;
  BEGIN
    f.pre      := pre;
    f.exponent := 0;
    TRY f.fraction := Convert.ToExtended (chars, used);
    EXCEPT Convert.Failed => RETURN FALSE;
    END;
    RETURN (used = NUMBER (chars)) AND Normalize (f);
  END New;

PROCEDURE Prec (READONLY f: Float): Precision =
  BEGIN
    RETURN f.pre;
  END Prec;

PROCEDURE Add (READONLY a, b: Float;  VAR f: Float): BOOLEAN =
  BEGIN
    IF (a.pre # b.pre) THEN RETURN FALSE END;
    f.pre      := a.pre;
    f.exponent := 0;
    f.fraction := a.fraction + b.fraction;
    RETURN Normalize (f);
  END Add;

PROCEDURE Subtract (READONLY a, b: Float;  VAR f: Float): BOOLEAN =
  BEGIN
    IF (a.pre # b.pre) THEN RETURN FALSE END;
    f.pre      := a.pre;
    f.exponent := 0;
    f.fraction := a.fraction - b.fraction;
    RETURN Normalize (f);
  END Subtract;

PROCEDURE Multiply (READONLY a, b: Float;  VAR f: Float): BOOLEAN =
  BEGIN
    IF (a.pre # b.pre) THEN RETURN FALSE END;
    f.pre      := a.pre;
    f.exponent := 0;
    f.fraction := a.fraction * b.fraction;
    RETURN Normalize (f);
  END Multiply;

PROCEDURE Divide (READONLY a, b: Float;  VAR f: Float): BOOLEAN =
  BEGIN
    IF (a.pre # b.pre) THEN RETURN FALSE END;
    IF (b.fraction = 0.0x+0) THEN RETURN FALSE END;
    f.pre      := a.pre;
    f.exponent := 0;
    f.fraction := a.fraction / b.fraction;
    RETURN Normalize (f);
  END Divide;

PROCEDURE Mod (READONLY a, b: Float;  VAR f: Float): BOOLEAN =
  VAR x, y: EXTENDED;
  BEGIN
    IF (a.pre # b.pre) THEN RETURN FALSE END;
    x := a.fraction;
    y := b.fraction;
    IF (y = 0.0x+0) THEN RETURN FALSE END;
    f.pre      := a.pre;
    f.exponent := 0;
    f.fraction := x - y * FLOAT (FLOOR (x / y), EXTENDED);
    RETURN Normalize (f);
  END Mod;

PROCEDURE EQ (READONLY a, b: Float): BOOLEAN =
  BEGIN
    IF (a.pre # b.pre) THEN RETURN FALSE END;
    IF (a.exponent # b.exponent) THEN RETURN FALSE END;
    IF (a.fraction # b.fraction) THEN RETURN FALSE END;
    RETURN TRUE;
  END EQ;

PROCEDURE LT (READONLY a, b: Float): BOOLEAN =
  BEGIN
    IF (a.pre # b.pre) THEN RETURN FALSE END;
    RETURN (a.fraction < b.fraction);
  END LT;

PROCEDURE LE (READONLY a, b: Float): BOOLEAN =
  BEGIN
    IF (a.pre # b.pre) THEN RETURN FALSE END;
    RETURN (a.fraction <= b.fraction);
  END LE;

PROCEDURE FloatF (READONLY a: Float;  p: Precision;  VAR f: Float): BOOLEAN =
  BEGIN
    f.pre      := p;
    f.exponent := a.exponent;
    f.fraction := a.fraction;
    RETURN Normalize (f);
  END FloatF;

PROCEDURE FloatI (READONLY i: INTEGER;  p: Precision;  VAR f: Float): BOOLEAN =
  BEGIN
    f.pre      := p;
    f.exponent := 0;
    f.fraction := FLOAT (i, EXTENDED);
    RETURN Normalize (f);
  END FloatI;

PROCEDURE Trunc (READONLY a: Float): INTEGER =
  BEGIN
    CASE a.pre OF
    | Precision.Short    => RETURN TRUNC (ToReal (a));
    | Precision.Long     => RETURN TRUNC (ToLongreal (a));
    | Precision.Extended => RETURN TRUNC (ToExtended (a));
    END;
  END Trunc;

PROCEDURE Round (READONLY a: Float): INTEGER =
  BEGIN
    CASE a.pre OF
    | Precision.Short    => RETURN ROUND (ToReal (a));
    | Precision.Long     => RETURN ROUND (ToLongreal (a));
    | Precision.Extended => RETURN ROUND (ToExtended (a));
    END;
  END Round;

PROCEDURE Floor (READONLY a: Float): INTEGER =
  BEGIN
    CASE a.pre OF
    | Precision.Short    => RETURN FLOOR (ToReal (a));
    | Precision.Long     => RETURN FLOOR (ToLongreal (a));
    | Precision.Extended => RETURN FLOOR (ToExtended (a));
    END;
  END Floor;

PROCEDURE Ceiling (READONLY a: Float): INTEGER =
  BEGIN
    CASE a.pre OF
    | Precision.Short    => RETURN CEILING (ToReal (a));
    | Precision.Long     => RETURN CEILING (ToLongreal (a));
    | Precision.Extended => RETURN CEILING (ToExtended (a));
    END;
  END Ceiling;

PROCEDURE ToChars (READONLY f: Float;  VAR buf: ARRAY OF CHAR): INTEGER =
  <*FATAL Convert.Failed *>
  VAR zz: ARRAY [0..31] OF CHAR;  len: INTEGER;
  BEGIN
    <*ASSERT f.exponent = 0*>
    len := Convert.FromExtended (zz, f.fraction, 13, Convert.Style.Sci);
    IF (len > NUMBER (buf)) THEN RETURN -1 END;
    SUBARRAY (buf, 0, len) := SUBARRAY (zz, 0, len);
    RETURN len;
  END ToChars;

TYPE
  Ptr = UNTRACED REF ARRAY [0..BITSIZE(EXTENDED) DIV BITSIZE(Byte) - 1] OF Byte;

PROCEDURE ToBytes (READONLY f: Float;  VAR buf: ARRAY OF Byte): INTEGER =
  VAR
    x1  : REAL;
    x2  : LONGREAL;
    x3  : EXTENDED;
    adr : ADDRESS;
    ptr : Ptr;
    len := TargetMap.Float_types[f.pre].size DIV BITSIZE (Byte);
  BEGIN
    IF (NUMBER (buf) < len) THEN RETURN -1 END;
    IF    (f.pre = Precision.Short) THEN x1 := ToReal (f);     adr := ADR (x1);
    ELSIF (f.pre = Precision.Long)  THEN x2 := ToLongreal (f); adr := ADR (x2);
    ELSE                                 x3 := ToExtended (f); adr := ADR (x3);
    END;
    ptr := adr;
    SUBARRAY (buf, 0, len) := SUBARRAY (ptr^, 0, len);
    RETURN len;
  END ToBytes;

PROCEDURE FromBytes (READONLY buf: ARRAY OF Byte;  p: Precision;
                    VAR f: Float) =
  VAR
    len  := NUMBER (buf);
    ptr  : Ptr;
    x1   : REAL;
    x2   : LONGREAL;
    x3   : EXTENDED;
  BEGIN
    len := TargetMap.Float_types[p].size DIV BITSIZE (Byte);
    <*ASSERT len <= NUMBER (buf) *>

    f.pre      := p;
    f.exponent := 0;

    CASE p OF
    | Precision.Short =>
        ptr := LOOPHOLE(ADR (x1), Ptr);
        SUBARRAY (ptr^, 0, len) := SUBARRAY (buf, 0, len);
        f.fraction := FLOAT (x1, EXTENDED);
    | Precision.Long =>
        ptr := LOOPHOLE(ADR (x2), Ptr);
        SUBARRAY (ptr^, 0, len) := SUBARRAY (buf, 0, len);
        f.fraction := FLOAT (x2, EXTENDED);
    | Precision.Extended =>
        ptr := LOOPHOLE(ADR (x3), Ptr);
        SUBARRAY (ptr^, 0, len) := SUBARRAY (buf, 0, len);
        f.fraction := x3;
    END;
  END FromBytes;
-------------------------------------------------------------- internal ---

PROCEDURE Normalize (VAR f: Float): BOOLEAN =
  BEGIN
    RETURN (f.exponent = 0);
  END Normalize;

PROCEDURE ToReal (READONLY f: Float): REAL =
  BEGIN
    RETURN FLOAT (f.fraction, REAL);
  END ToReal;

PROCEDURE ToLongreal (READONLY f: Float): LONGREAL =
  BEGIN
    RETURN FLOAT (f.fraction, LONGREAL);
  END ToLongreal;

PROCEDURE ToExtended (READONLY f: Float): EXTENDED =
  BEGIN
    RETURN f.fraction;
  END ToExtended;

BEGIN
END TFloat.