(* $Id: LRealConv.Mod,v 1.7 1999/10/12 07:17:54 ooc-devel Exp $ *) MODULE oocLRealConv; (* LRealConv - Low-level LONGREAL/string conversions. Copyright (C) 1996 Michael Griebling This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) IMPORT Char := oocCharClass, Low := oocLowLReal, Str := oocStrings, Conv := oocConvTypes, LInt := oocLongInts, SYSTEM; CONST ZERO=0.0D0; SigFigs*=15; (* accuracy of LONGREALs *) DEBUG = FALSE; TYPE ConvResults*= Conv.ConvResults; (* strAllRight, strOutOfRange, strWrongFormat, strEmpty *) LongInt=LInt.LongInt; CONST strAllRight*=Conv.strAllRight; (* the string format is correct for the corresponding conversion *) strOutOfRange*=Conv.strOutOfRange; (* the string is well-formed but the value cannot be represented *) strWrongFormat*=Conv.strWrongFormat; (* the string is in the wrong format for the conversion *) strEmpty*=Conv.strEmpty; (* the given string is empty *) VAR RS, P, F, E, SE, WE, SR: Conv.ScanState; PROCEDURE IsExponent (ch: CHAR) : BOOLEAN; BEGIN RETURN (ch="E") OR (ch="D") END IsExponent; PROCEDURE IsSign (ch: CHAR): BOOLEAN; (* Return TRUE for '+' or '-' *) BEGIN RETURN (ch='+')OR(ch='-') END IsSign; (* internal state machine procedures *) PROCEDURE RSState(inputCh: CHAR; VAR chClass: Conv.ScanClass; VAR nextState: Conv.ScanState); BEGIN IF Char.IsNumeric(inputCh) THEN chClass:=Conv.valid; nextState:=P ELSE chClass:=Conv.invalid; nextState:=RS END END RSState; PROCEDURE PState(inputCh: CHAR; VAR chClass: Conv.ScanClass; VAR nextState: Conv.ScanState); BEGIN IF Char.IsNumeric(inputCh) THEN chClass:=Conv.valid; nextState:=P ELSIF inputCh="." THEN chClass:=Conv.valid; nextState:=F ELSIF IsExponent(inputCh) THEN chClass:=Conv.valid; nextState:=E ELSE chClass:=Conv.terminator; nextState:=NIL END END PState; PROCEDURE FState(inputCh: CHAR; VAR chClass: Conv.ScanClass; VAR nextState: Conv.ScanState); BEGIN IF Char.IsNumeric(inputCh) THEN chClass:=Conv.valid; nextState:=F ELSIF IsExponent(inputCh) THEN chClass:=Conv.valid; nextState:=E ELSE chClass:=Conv.terminator; nextState:=NIL END END FState; PROCEDURE EState(inputCh: CHAR; VAR chClass: Conv.ScanClass; VAR nextState: Conv.ScanState); BEGIN IF IsSign(inputCh) THEN chClass:=Conv.valid; nextState:=SE ELSIF Char.IsNumeric(inputCh) THEN chClass:=Conv.valid; nextState:=WE ELSE chClass:=Conv.invalid; nextState:=E END END EState; PROCEDURE SEState(inputCh: CHAR; VAR chClass: Conv.ScanClass; VAR nextState: Conv.ScanState); BEGIN IF Char.IsNumeric(inputCh) THEN chClass:=Conv.valid; nextState:=WE ELSE chClass:=Conv.invalid; nextState:=SE END END SEState; PROCEDURE WEState(inputCh: CHAR; VAR chClass: Conv.ScanClass; VAR nextState: Conv.ScanState); BEGIN IF Char.IsNumeric(inputCh) THEN chClass:=Conv.valid; nextState:=WE ELSE chClass:=Conv.terminator; nextState:=NIL END END WEState; PROCEDURE Real (VAR x: LongInt; exp, digits: LONGINT; VAR outOfRange: BOOLEAN): LONGREAL; CONST BR=LInt.B+ZERO; InvLOGB=0.221461873; (* real version *) VAR cnt, len, scale, Bscale, start, bexp, max: LONGINT; r: LONGREAL; BEGIN (* scale by the exponent *) scale:=exp+digits; IF scale>=ABS(digits) THEN Bscale:=0; LInt.TenPower(x, SHORT(scale)) ELSE Bscale:=ENTIER(-scale*InvLOGB)+6; LInt.BPower(x, SHORT(Bscale)); (* x*B^Bscale *) LInt.TenPower(x, SHORT(scale)); (* x*B^BScale*10^scale *) END; (* prescale to left-justify the number *) start:=LInt.MinDigit(x); bexp:=0; (* find starting digit *) IF (start=LEN(x)-1)&(x[start]=0) THEN (* exit here for zero *) outOfRange:=FALSE; RETURN ZERO END; WHILE x[start]len THEN max:=len END; FOR cnt:=start TO max DO r:=r*BR+x[cnt] END; (* post scaling *) INC(bexp, (Bscale-len+max)*15); (* quick check for overflow *) max:=Low.exponent(r)-SHORT(bexp); IF (max>Low.expoMax) OR (max1 THEN INC(len) END; (* account for the decimal point *) IF exp>10 THEN INC(len, 4) (* account for the exponent *) ELSIF exp#0 THEN INC(len, 3) END; RETURN len END LengthFloatReal; PROCEDURE LengthEngReal*(real: LONGREAL; sigFigs: INTEGER): INTEGER; (* Returns the number of characters in the floating-point engineering string representation of real with sigFigs significant figures. This value corresponds to the capacity of an array `str' which is of the minimum capacity needed to avoid truncation of the result in the call LongStr.RealToEng(real,sigFigs,str). *) VAR len, exp, off: INTEGER; BEGIN IF Low.IsNaN(real) THEN RETURN 3 ELSIF Low.IsInfinity(real) THEN IF real10 THEN INC(len, 4) ELSIF exp-off#0 THEN INC(len, 3) END; IF sigFigs>off+1 THEN INC(len) END; (* account for the decimal point *) IF off+1-sigFigs>0 THEN INC(len, off+1-sigFigs) END; (* account for extra padding digits *) RETURN len END LengthEngReal; PROCEDURE LengthFixedReal*(real: LONGREAL; place: INTEGER): INTEGER; (* Returns the number of characters in the fixed-point string representation of real rounded to the given place relative to the decimal point. This value corresponds to the capacity of an array `str' which is of the minimum capacity needed to avoid truncation of the result in the call LongStr.RealToFixed(real,sigFigs,str). *) VAR len, exp: INTEGER; addDecPt: BOOLEAN; BEGIN IF Low.IsNaN(real) THEN RETURN 3 ELSIF Low.IsInfinity(real) THEN IF real=0; IF place<0 THEN INC(place, 2) ELSE INC(place) END; IF exp<0 THEN (* account for digits *) IF place<=0 THEN len:=1 ELSE len:=place END ELSE len:=exp+place; IF 1-place>0 THEN INC(len, 1-place) END END; IF real