{$P-} {$M+} {$E+} PROGRAM Mock; {$I i:\opus.i} {$I i:\GCTV.inc} FUNCTION Do_Alert( alert : Str255 ; def_btn : integer ) : integer ; EXTERNAL ; PROCEDURE Hide_Mouse ; EXTERNAL ; PROCEDURE Show_Mouse ; EXTERNAL ; PROCEDURE REAL_TO_STRING ( real_num : REAL; VAR string_real : STRING; digits : INTEGER; sci_not : BOOLEAN ); (* real_num : real number to be converted into a string string_real : working variable that also passes string result to caller digits : specifies # of digits to be displayed right of decimal, valid values are 0-11 sci_not : flag which determines whether to express in sci. not. or not *) (* FORMAT of string returned is: sci. not.: sign ( - or SPACE ), #.#####... , E, sign ( - or nothing ), ##. non-sci. not. : sign ( - or SPACE ), ####.####. *) (* Round-off errors of the nature x.xxxx9999 are corrected; consequently, any number with a sequence of 1 or more terminal 9's is affected, even if this is NOT an artifact. This should rarely be a problem. Also, if a number is to be expressed in expanded form, the magnitude of the exponent plus the # of digits to be displayed can not exceed 8, since LONG_ROUND generates long_ints- size < 2e9. This is not too severe a problem since only 11 digits of precision are supported anyway. That is, specifying 4 digits for the # 100,000,000.9012 is meaningless since the number is rounded to 100,000,000.9 as it becomes a REAL. The last digits are unavailable to real_to_string. In such cases, no action is performed on the number- it emerges untouched by the rounding function. Also, note that the detection of 999 occurs after conversion to 1 <= mag_num < 10. Thus, 99,999,999,999 becomes 9.9999999999 which indicates a rounding error. *) LABEL 1; VAR c,i,j : INTEGER; sign_exp : STRING[1]; loc_char : CHAR; PROCEDURE INSERT_COMMAS; BEGIN dec_pos := POS('.',string_real); IF (dec_pos > 5) OR (dec_pos = 0) THEN BEGIN IF dec_pos = 0 THEN comma_pos := LENGTH(string_real) -2 ELSE comma_pos := dec_pos-3; WHILE comma_pos > 2 DO BEGIN INSERT(',',string_real,comma_pos); comma_pos := comma_pos-3 END END END; { INSERT_COMMAS } PROCEDURE ADJUST_TO_SPECIFIED_LENGTH; (* adjusts appearance following rounding *) BEGIN dec_pos := POS ( '.',string_real ); n_digits := dec_pos+digits; WHILE LENGTH(string_real) < n_digits DO string_real := CONCAT(string_real,'0'); WHILE LENGTH(string_real) > n_digits DO DELETE(string_real,LENGTH(string_real),1); IF POS('.' , string_real ) = LENGTH(string_real) THEN DELETE(string_real,LENGTH(string_real),1) END; (* adjust_to_specified_length *) PROCEDURE DO_EXPONENT; BEGIN temp_1 := ''; IF c >= 30 THEN BEGIN temp_1 := '3'; c := c-30 END; IF c >= 20 THEN BEGIN temp_1 := '2'; c := c-20 END; IF c >= 10 THEN BEGIN temp_1 := '1'; c := c-10 END; temp_1 := CONCAT(temp_1,CHR(c+48)); adjust_to_specified_length; string_real := CONCAT(string_real,'E',sign_exp,temp_1) END; PROCEDURE REMOVE_9s; VAR i , j : INTEGER; BEGIN (* Get rid of artifactual "999999" generated, if any *) temp_1 := COPY(string_real,4,10); i := 10; found := FALSE; WHILE (NOT found) AND (i >= 1) DO IF temp_1[i] <> '9' THEN found := TRUE ELSE i := i-1; i := i+1; IF i <= 10 THEN BEGIN FOR j := 1 TO 15 DO last[j] := 'f'; str_len := i+2; FOR i := 1 TO str_len DO last[i] := string_real[i]; IF str_len = 3 THEN BEGIN (* x.9999999999 *) IF last[2] = '9' THEN BEGIN last[2] := '1'; last[4] := '0'; IF sign_exp = '' THEN c := c+1 ELSE c := c-1 END ELSE BEGIN last[2] := CHR(ORD(last[2])+1); last[4] := '0' END END ELSE (* x.xxxx999999 *) (* needn't check here if last[str_len]=9; it CAN'T be, as it would have been a part of the string of 9's *) last[str_len] := CHR(ORD(last[str_len])+1); string_real := ''; i := 1; WHILE last[i] <> 'f' DO BEGIN (* recreate string_real *) string_real := CONCAT(string_real,last[i]); i := i+1 END END END; (* REMOVE_9s *) BEGIN (* REAL_TO_STRING *) IF real_num <> 0.0 THEN BEGIN (* sign of number *) IF real_num < 0.0 THEN string_real := '-' ELSE string_real := ' '; IF ((real_num < 1.0) AND (real_num > 0.0)) OR ((real_num < 0.0) AND (real_num > -1.0)) THEN sign_exp := '-' ELSE sign_exp := ''; (* got sign, so work with number magnitude *) mag_num := ABS (real_num); (* c counts the number of times the number can be multiplied or div- ided by 10 so that finally 1 <= number < 10 *) c := 0; (* make 1 <= number < 10 *) IF mag_num >= 10.0 THEN REPEAT mag_num := mag_num/10.0; c := c+1 UNTIL mag_num < 10.0 ELSE IF mag_num < 1.0 THEN REPEAT mag_num := mag_num*10.0; c := c+1 UNTIL mag_num >= 1.0; (* Round mag_num to specified # of digits *) IF (sci_not) AND (digits <= 8) THEN mag_num := LONG_ROUND(mag_num*PwrOfTen(digits))/PwrOfTen(digits); IF NOT sci_not THEN BEGIN (* Round to spec # digit if possible *) IF (c+digits <= 8) AND ((real_num > 1) OR (real_num < -1)) THEN mag_num := LONG_ROUND(mag_num*PwrOfTen(c+digits)) / PwrOfTen(c+digits); (* bug fix- account for numbers between -1.0 and 1.0 *) i := digits-c; IF (real_num < 1) AND (real_num > -1) THEN BEGIN IF ABS(i) <= 8 THEN BEGIN IF i >= 0 THEN mag_num := LONG_ROUND(mag_num*PwrOfTen(i))/PwrOfTen(i) ELSE mag_num := LONG_ROUND(mag_num/PwrOfTen(ABS(i)))* PwrOfTen(ABS(i)) END END END; IF mag_num = 0 THEN BEGIN string_real := ' 0'; GOTO 1 END; IF mag_num >= 10 THEN BEGIN (* rounded up to 10 *) IF sign_exp = '-' THEN BEGIN c := c-1; IF c = 0 THEN sign_exp := ''; END ELSE c := c+1; mag_num := 1 END; (* reals have 11 digits of precision *) (* convert REAL to a string equivalent *) FOR i := 1 TO 11 DO BEGIN j := TRUNC (mag_num); string_real := CONCAT(string_real,CHR (j+48)); mag_num := (mag_num-j)*10 END; (* FOR i *) INSERT('.',string_real,3); remove_9s; { now have the mantissa converted in string_real, so... } IF NOT sci_not THEN BEGIN (* express in expanded form *) IF sign_exp = '-' THEN BEGIN (* mag_num < 1, mag_num <> 0 *) loc_char := string_real[2]; DELETE(string_real,2,1); INSERT('0',string_real,2); INSERT(loc_char,string_real,4); FOR i := 1 TO c-1 DO INSERT('0',string_real,4); adjust_to_specified_length END ELSE BEGIN DELETE(string_real,3,1); IF 3+c > LENGTH(string_real) THEN FOR i := LENGTH(string_real) TO 2+c DO string_real := CONCAT(string_real,'0'); INSERT('.',string_real,3+c); adjust_to_specified_length; insert_commas END END ELSE do_exponent; END (* begin of first then clause *) ELSE (* real_num = 0 *) string_real := ' 0'; 1: END; (* REAL_TO_STRING *) FUNCTION STRING_TO_REAL ( VAR str : STR30 ) : REAL; (* Strings passed must follow the following rules: 1. may have been created by REAL_TO_STRING, 2. may have been entered via READ or WINDOW_INPUT a. Strings entered via WINDOW_INPUT may contain NO imbedded spaces, and if given in sci. not. must use either 'e' or 'E' . 3. overflows are trapped, STRING_TO_REAL returns 0 and string_real returns 'OVERFLOW'; otherwise string_real is preserved intact 4. must be an exact image of a valid real! VALID_NUMBER screens out all miswritten numbers, i.e 1.22.4-e0-4 5. must have at least one digit preceding a decimal 6. doesn't check for spaces because the routines that call it either eat up the spaces or don't allow them 7. doesn't check for a null string since one is never passed *) LABEL 1; BEGIN loverflow := FALSE; sign_num := 1; sign_exp := 1; lpower := 1; real_num := 0; exp_val := 0; lfactor := 0; str_pos := 1; str_len := LENGTH(str); IF (str[1] = '+') OR (str[1] = '-') OR (str[1] = ' ') THEN BEGIN IF str[1] = '-' THEN sign_num := -1; str_pos := 2 END; lquit := FALSE; WHILE (str_pos <= str_len) AND (NOT lquit) DO IF str[str_pos] IN digits THEN BEGIN real_num := real_num*10+ORD(str[str_pos])-ORD('0'); str_pos := str_pos+1 END ELSE lquit := TRUE; IF str_pos <= str_len THEN IF str[str_pos] = '.' THEN BEGIN places := 0; str_pos := str_pos+1; lquit := FALSE; WHILE (str_pos <= str_len) AND (NOT lquit) DO IF str[str_pos] IN digits THEN BEGIN places := places+1; real_num := real_num*10+ORD(str[str_pos])-ORD('0'); str_pos := str_pos+1 END ELSE lquit := TRUE; real_num := real_num/PwrOfTen(places) END; IF str_pos <= str_len THEN IF (str[str_pos] = 'E') OR (str[str_pos] = 'e') THEN BEGIN str_pos := str_pos+1; IF str_pos <= str_len THEN BEGIN IF (str[str_pos] = '+') OR (str[str_pos] = '-') THEN BEGIN IF str[str_pos] = '-' THEN sign_exp := -1; str_pos := str_pos+1 END; lquit := FALSE; WHILE (str_pos <= str_len) AND (NOT lquit) DO IF str[str_pos] IN digits THEN BEGIN exp_val := exp_val*10+ORD(str[str_pos])-ORD('0'); str_pos := str_pos+1 END ELSE lquit := TRUE; IF exp_val > 38 THEN BEGIN loverflow := TRUE; GOTO 1 END; lpower := PwrOfTen(exp_val); IF sign_exp < 0 THEN lpower := 1/lpower END END; (* Check for potential overflow *) mag_num := real_num; IF mag_num <> 0 THEN IF mag_num >= 10 THEN REPEAT mag_num := mag_num/10.0; lfactor := lfactor+1 UNTIL mag_num < 10.0 ELSE IF mag_num < 1.0 THEN REPEAT mag_num := mag_num*10.0; lfactor := lfactor-1 UNTIL mag_num >= 1.0; 1: IF (ABS(exp_val*sign_exp+lfactor) >= 37) OR (loverflow) THEN BEGIN alert := Do_Alert(float_over,1); str := 'OVERFLOW'; string_to_real := 0 END ELSE string_to_real := real_num*sign_num*lpower END; (* STRING_TO_REAL *) PROCEDURE INT_TO_STRING ( n : INTEGER; VAR s : STR10 ); { for non_negative integers } VAR digit,divisor : INTEGER; leading : BOOLEAN; BEGIN { INT_TO_STRING } IF n <= 0 THEN s := '0' ELSE BEGIN s := ''; divisor := 10000; leading := TRUE; WHILE divisor > 0 DO BEGIN digit := n DIV divisor; IF (digit <> 0) OR (NOT leading) THEN BEGIN s := CONCAT(s,CHR(digit+48)); leading := FALSE END; n := n MOD divisor; divisor := divisor DIV 10 END END END; { INT_TO_STRING } BEGIN (* dummy program for modular compilation *) END.