%externallongrealfn Text to Floating %alias "3L___text_to_float" - (%string(255) S, %integer Exp) {NOTE: it is CRUCIAL for purposes of bootstrapping that this } { routine does NOT need any compile-time floating-point ops } {This function converts a string representation of a floating-point} {number into the host machine's hardward long real format } {the routine should work for IEEE, VAX and IBM-oid representations } {***************** LITTLE CHECKING IS PERFORMED *******************} {this is deliberate as it seems that most callers will have hade } {to build up the digit string anyway and the checks seem to be } {better applied there. Also it results in this function not needing} {to know the exponent delimiter (E or @) } {******************************************************************} {S is a string containing a representation of a floating-point number} {the format of S is informally: } { } { = "_" } { = "." } {Exp is the power of 10 by which the result is to be scaled } {**** the actual event to be signalled needs to be defined ****} {**** 4,1 has been chosen for compatability with StoI ****} {event 1,2,0 is signalled on overflow } {This function will signal event 4,1,N where N is the character } {position of the error if: } { (i) an explicit base is not in the range 2..36 eg 40_33} { (ii) a digit is outwith the range required by the base eg 2_012} %constinteger Max Power = 50, {enough 24 bit chunks for max precision} Min Power = -50, Window = 8 {number of 24 bits in mantissa + a bit} {This value of WINDOW allows perfect input of powers of 2 } {from 2^(-93) upwards. Increasing WINDOW improves the accuracy but} {slows down the input of numbers } %longreal Value %integer Min, Max, Power, Base, Q, Point, Char, Sign, CharN, Len %integer Two = 2, {to prevent compile-time floating} One24 = 1<<24 %integerarray A(Min Power : Max Power) %routine Mul(%integer Carry) {A = A*Base + Carry} {This assumes that BASE is in the range 1..255} %integer J, N %for J = 1, 1, Max %cycle N = A(J)*Base + Carry Carry = N>>24 A(J) = N&16_00FF FFFF %repeat %if Carry # 0 %start %signal 1,2,0 %if Max = Max Power Max = Max+1; A(Max) = Carry %finish %end %longrealfn Evaluate %longreal Answer, Next, Last %integer D, J, M, N, Carry %if Power > 0 %start %cycle Mul(0) Power = Power-1 %repeat %until Power = 0 %else %if Power < 0 Power = -Power %cycle {first, maximise the divisor} M = 0 D = 1 N = 16_00FF %while M < Power %cycle N = N//Base %exit %if N = 0 D = D*Base M = M+1 %repeat {Now, D is the best divisor to use, giving M powers of the base} %while Power >= M %cycle Power = Power-M Carry = 0 %for J = Max, -1, Min %cycle N = A(J)+Carry A(J) = N//D Carry = Rem(N, D)<<24 %repeat %while Carry # 0 %cycle %exit %if Max-Min > Window %or Min = Min Power Min = Min-1 A(Min) = Carry//D Carry = Rem(Carry, D)<<24 %repeat Max = Max-1 %while Max > Min %and A(Max) = 0 %repeat %repeat %until Power = 0 %finish {Use the machine's f-p to accumulate the final answer} {Note that as 24 is a multiple of 4 the scale factor } {1<<24 should be exact on base 2 and base 16 systems } Answer = 0 Last = 0 Next = TWO^(24*(Max-1)) %for J = Max, -1, Min %cycle %if Next = 0 %start {the machine cannot represent the new scale factor as it } {is too small, but the new scale factor * the next chunk } {may well give a value which IS representable although tiny} Last = TWO^(24*Max) %if Last = 0 Answer = Answer + (A(J)*Last)/(ONE24) %exit %finish Answer = Answer + A(J)*Next Last = Next Next = Next/(ONE24) %repeat %result = Answer %end Base = 10 {assume base 10 to start with} Sign = 0 Max = 0; Min = 1; Point = 0; Power = 0 CharN = 0 Len = Length(S) %while CharN # Len %cycle CharN = CharN+1 Char = Charno(S, CharN) %if Char = '.' %start {decimal point} Point = -1 %else %if Char = '_' {radix selector} Base = Int(Evaluate) %signal 4,1,CharN %unless 2 <= Base <= 36 %and Point = 0 Max = 0; Min = 1; Power = 0 %else %if Char # ' ' {digit} Q = Char-'0'; Q = Q+'0'-'A'+10 %if Q > 9 %signal 4,1,CharN %unless 0 <= Q < Base Power = Power+Point Mul(Q) %finish %repeat Power = Power+Exp Value = Evaluate Value = -Value %if Sign < 0 %result = Value %end