RealConversions.Mod 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. MODULE RealConversions; (* GF *)
  2. IMPORT SYSTEM;
  3. TYPE
  4. ReadProc* = PROCEDURE {DELEGATE} ( ): CHAR;
  5. VAR
  6. H, L: INTEGER;
  7. (** Scan a floating-point number.
  8. EBNF: Real = Digit {Digit} '.' Digit {Digit} ['e'|'E' ['+'|'-'] Digit {Digit}]. *)
  9. PROCEDURE ScanReal*( next: ReadProc ): LONGREAL;
  10. VAR
  11. e: INTEGER; y, g: LONGREAL; neg, negE: BOOLEAN; ch: CHAR;
  12. BEGIN
  13. ch := next();
  14. WHILE (ch = "0") DO ch := next() END;
  15. IF ch = "-" THEN neg := TRUE; ch := next() ELSE neg := FALSE END;
  16. WHILE (ch = " ") OR (ch = "0") DO ch := next() END;
  17. y := 0;
  18. WHILE ("0" <= ch) & (ch <= "9") DO
  19. y := y * 10 + (ORD(ch) - ORD("0"));
  20. ch := next();
  21. END;
  22. IF ch = "." THEN
  23. ch := next();
  24. g := 1;
  25. WHILE ("0" <= ch) & (ch <= "9") DO
  26. g := g / 10; y := y + g * (ORD(ch) - ORD("0"));
  27. ch := next()
  28. END;
  29. END;
  30. IF (ch = "d") OR (ch = "D") OR (ch = "e") OR (ch = "E") THEN
  31. ch := next(); e := 0;
  32. IF ch = "-" THEN negE := TRUE; ch := next()
  33. ELSIF ch = "+" THEN negE := FALSE; ch := next()
  34. ELSE negE := FALSE
  35. END;
  36. WHILE (ch = "0") DO ch := next() END;
  37. WHILE ("0" <= ch) & (ch <= "9") DO
  38. e := e * 10 + (ORD(ch) - ORD("0"));
  39. ch := next()
  40. END;
  41. IF negE THEN y := y / Ten(e)
  42. ELSE y := y * Ten(e)
  43. END;
  44. END;
  45. IF neg THEN y := -y END;
  46. RETURN y
  47. END ScanReal;
  48. (** Convert LONGREAL x to string using n character positions. *)
  49. PROCEDURE RealToString*( x: LONGREAL; n: WORD; VAR buf: ARRAY OF CHAR );
  50. (* BM 1993.4.22. Do not simplify rounding! *)
  51. VAR
  52. e, h, l, i, pos: LONGINT; z: LONGREAL; d: ARRAY 16 OF CHAR;
  53. PROCEDURE Char( c: CHAR );
  54. BEGIN
  55. buf[pos] := c; INC( pos )
  56. END Char;
  57. PROCEDURE String( CONST s: ARRAY OF CHAR );
  58. VAR i: LONGINT;
  59. BEGIN
  60. i := 0;
  61. WHILE s[i] # 0X DO Char( s[i] ); INC( i ) END
  62. END String;
  63. BEGIN
  64. pos := 0;
  65. e := ExpoL( x );
  66. IF e = 2047 THEN
  67. WHILE n > 5 DO Char( " " ); DEC( n ) END;
  68. NaNCodeL( x, h, l );
  69. IF (h # 0) OR (l # 0) THEN String( " NaN" )
  70. ELSIF x < 0 THEN String(" -INF" )
  71. ELSE String(" INF" )
  72. END
  73. ELSE
  74. IF n <= 9 THEN n := 1 ELSE DEC( n, 8 ) END;
  75. REPEAT Char( " " ); DEC( n ) UNTIL n <= 15; (* 0 <= n <= 15 fraction digits *)
  76. IF (e # 0) & (x < 0) THEN Char( "-" ); x := -x ELSE Char( " " ) END;
  77. IF e = 0 THEN
  78. h := 0; l := 0 (* no denormals *)
  79. ELSE
  80. e := (e - 1023) * 301029 DIV 1000000; (* ln(2)/ln(10) = 0.301029996 *)
  81. z := Ten( e + 1 );
  82. IF x >= z THEN x := x / z; INC( e ) ELSE x := x * Ten( -e ) END;
  83. IF x >= 10 THEN x := x * Ten( -1 ) + 0.5D0 / Ten( n ); INC( e )
  84. ELSE
  85. x := x + 0.5D0 / Ten( n );
  86. IF x >= 10 THEN x := x * Ten( -1 ); INC( e ) END
  87. END;
  88. x := x * Ten( 7 ); h := ENTIER( x ); x := (x - h) * Ten( 8 ); l := ENTIER( x )
  89. END;
  90. i := 15;
  91. WHILE i > 7 DO d[i] := CHR( l MOD 10 + ORD( "0" ) ); l := l DIV 10; DEC( i ) END;
  92. WHILE i >= 0 DO d[i] := CHR( h MOD 10 + ORD( "0" ) ); h := h DIV 10; DEC( i ) END;
  93. Char( d[0] ); Char( "." ); i := 1;
  94. WHILE i <= n DO Char( d[i] ); INC( i ) END;
  95. IF e < 0 THEN String( "E-" ); e := -e ELSE String( "E+" ) END;
  96. Char( CHR( e DIV 100 + ORD( "0" ) ) ); e := e MOD 100;
  97. Char( CHR( e DIV 10 + ORD( "0" ) ) ); Char( CHR( e MOD 10 + ORD( "0" ) ) )
  98. END;
  99. Char( 0X )
  100. END RealToString;
  101. (** Convert LONGREAL x to string in a fixed point notation.
  102. n is the overall minimal length for the output field, f the number of fraction digits following the decimal point,
  103. D the fixed exponent (printed only when D # 0). *)
  104. PROCEDURE RealToStringFix*( x: LONGREAL; n, f, D: WORD; VAR buf: ARRAY OF CHAR );
  105. (* BM 1993.4.22. Do not simplify rounding! / JG formatting adjusted *)
  106. VAR
  107. e, h, l, i, pos: LONGINT; r, z: LONGREAL;
  108. d: ARRAY 16 OF CHAR;
  109. s: CHAR; dot: BOOLEAN;
  110. PROCEDURE Char( c: CHAR );
  111. BEGIN
  112. buf[pos] := c; INC( pos )
  113. END Char;
  114. PROCEDURE String( CONST s: ARRAY OF CHAR );
  115. VAR i: LONGINT; ch: CHAR;
  116. BEGIN
  117. ch := s[0]; i := 1;
  118. WHILE ch # 0X DO Char( ch ); ch := s[i]; INC( i ) END
  119. END String;
  120. BEGIN
  121. pos := 0;
  122. e := ExpoL( x );
  123. IF (e = 2047) OR (ABS( D ) > 308) THEN
  124. WHILE n > 5 DO Char( " " ); DEC( n ) END;
  125. NaNCodeL( x, h, l );
  126. IF (h # 0) OR (l # 0) THEN String( " NaN" )
  127. ELSIF x < 0 THEN String( " -INF" )
  128. ELSE String( " INF" )
  129. END
  130. ELSE
  131. IF D = 0 THEN
  132. IF f = 0 THEN dot := FALSE; DEC( n, 1 ) ELSE dot := TRUE; DEC( n, 2 ) END
  133. ELSE dot := TRUE; DEC( n, 7 )
  134. END;
  135. IF n < 2 THEN n := 2 END;
  136. IF f < 0 THEN f := 0 END;
  137. IF n < f + 2 THEN n := f + 2 END;
  138. DEC( n, f );
  139. IF (e # 0) & (x < 0) THEN s := "-"; x := -x ELSE s := " " END;
  140. IF e = 0 THEN
  141. h := 0; l := 0; DEC( e, D - 1 ) (* no denormals *)
  142. ELSE
  143. e := (e - 1023) * 301029 DIV 1000000; (* ln(2)/ln(10) = 0.301029996 *)
  144. z := Ten( e + 1 );
  145. IF x >= z THEN x := x / z; INC( e ) ELSE x := x * Ten( -e ) END;
  146. DEC( e, D - 1 ); i := -(e + f);
  147. IF i <= 0 THEN r := 5 * Ten( i ) ELSE r := 0 END;
  148. IF x >= 10 THEN x := x * Ten( -1 ) + r; INC( e )
  149. ELSE
  150. x := x + r;
  151. IF x >= 10 THEN x := x * Ten( -1 ); INC( e ) END
  152. END;
  153. x := x * Ten( 7 ); h := ENTIER( x ); x := (x - h) * Ten( 8 ); l := ENTIER( x )
  154. END;
  155. i := 15;
  156. WHILE i > 7 DO d[i] := CHR( l MOD 10 + ORD( "0" ) ); l := l DIV 10; DEC( i ) END;
  157. WHILE i >= 0 DO d[i] := CHR( h MOD 10 + ORD( "0" ) ); h := h DIV 10; DEC( i ) END;
  158. IF n <= e THEN n := e + 1 END;
  159. IF e > 0 THEN
  160. WHILE n > e DO Char( " " ); DEC( n ) END;
  161. Char( s ); e := 0;
  162. WHILE n > 0 DO
  163. DEC( n );
  164. IF e < 16 THEN Char( d[e] ); INC( e ) ELSE Char( "0" ) END
  165. END;
  166. IF dot THEN Char( "." ) END;
  167. ELSE
  168. WHILE n > 1 DO Char( " " ); DEC( n ) END;
  169. Char( s ); Char( "0" ); IF dot THEN Char( "." ) END;
  170. WHILE (0 < f) & (e < 0) DO Char( "0" ); DEC( f ); INC( e ) END
  171. END;
  172. WHILE f > 0 DO
  173. DEC( f );
  174. IF e < 16 THEN Char( d[e] ); INC( e ) ELSE Char( "0" ) END
  175. END;
  176. IF D # 0 THEN
  177. IF D < 0 THEN String( "E-" ); D := -D ELSE String( "E+" ) END;
  178. Char( CHR( D DIV 100 + ORD( "0" ) ) ); D := D MOD 100;
  179. Char( CHR( D DIV 10 + ORD( "0" ) ) ); Char( CHR( D MOD 10 + ORD( "0" ) ) )
  180. END
  181. END;
  182. Char( 0X )
  183. END RealToStringFix;
  184. (*** the following procedures stem from Reals.Mod *)
  185. (** Returns the NaN code (0 <= h < 1048576, MIN(LONGINT) <= l <= MAX(LONGINT)) or (-1,-1) if not NaN/Infinite. *)
  186. PROCEDURE NaNCodeL( x: LONGREAL; VAR h, l: LONGINT );
  187. BEGIN
  188. SYSTEM.GET( ADDRESSOF( x ) + H, h ); SYSTEM.GET( ADDRESSOF( x ) + L, l );
  189. IF ASH( h, -20 ) MOD 2048 = 2047 THEN (* Infinite or NaN *)
  190. h := h MOD 100000H (* lowest 20 bits *)
  191. ELSE h := -1; l := -1
  192. END
  193. END NaNCodeL;
  194. (** Returns the shifted binary exponent (0 <= e < 2048). *)
  195. PROCEDURE ExpoL( x: LONGREAL ): LONGINT;
  196. VAR i: LONGINT;
  197. BEGIN
  198. SYSTEM.GET( ADDRESSOF( x ) + H, i ); RETURN ASH( i, -20 ) MOD 2048
  199. END ExpoL;
  200. (** Convert hexadecimal to LONGREAL. h and l are the high and low parts.*)
  201. PROCEDURE RealL( h, l: LONGINT ): LONGREAL;
  202. VAR x: LONGREAL;
  203. BEGIN
  204. SYSTEM.PUT( ADDRESSOF( x ) + H, h ); SYSTEM.PUT( ADDRESSOF( x ) + L, l ); RETURN x
  205. END RealL;
  206. (** Returns 10^e (e <= 308, 308 < e delivers IEEE-code +INF). *)
  207. PROCEDURE Ten( e: LONGINT ): LONGREAL; (* naiive version *)
  208. VAR r: LONGREAL;
  209. BEGIN
  210. IF e < -307 THEN RETURN 0
  211. ELSIF 308 < e THEN RETURN RealL( 2146435072, 0 )
  212. END;
  213. r := 1;
  214. WHILE (e > 0) DO r := r * 10; DEC( e ); END;
  215. WHILE (e < 0) DO r := r / 10; INC( e ); END;
  216. RETURN r;
  217. END Ten;
  218. PROCEDURE InitHL;
  219. VAR i: ADDRESS; dmy: INTEGER; littleEndian: BOOLEAN;
  220. BEGIN
  221. dmy := 1; i := ADDRESSOF( dmy );
  222. SYSTEM.GET( i, littleEndian ); (* indirection via i avoids warning on SUN cc -O *)
  223. IF littleEndian THEN H := 4; L := 0 ELSE H := 0; L := 4 END
  224. END InitHL;
  225. BEGIN
  226. InitHL
  227. END RealConversions.