1 (* ConvStringReal.mod translate floating point numbers to Strings.
3 Copyright (C) 2009-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. *)
27 IMPLEMENTATION MODULE ConvStringReal ;
29 FROM DynamicStrings IMPORT InitString, KillString, ConCat, ConCatChar,
30 Slice, Length, Mult, Mark, InitStringCharStar,
31 InitStringChar, Index, char ;
32 FROM StringConvert IMPORT IntegerToString, ToSigFig ;
33 FROM dtoa IMPORT dtoa, Mode ;
34 FROM libc IMPORT free, printf ;
35 FROM SYSTEM IMPORT ADDRESS ;
42 IsDigit - returns TRUE if, ch, lies between '0'..'9'.
45 PROCEDURE IsDigit (ch: CHAR) : BOOLEAN ;
47 RETURN (ch>='0') AND (ch<='9')
52 RealToFloatString - converts a real with, sigFigs, into a string
53 and returns the result as a string.
56 PROCEDURE RealToFloatString (real: REAL; sigFigs: CARDINAL) : String ;
64 r := dtoa(real, maxsignificant, 100, point, sign) ;
65 s := InitStringCharStar(r) ;
70 IF (l>0) AND IsDigit(char(s, 0))
72 IF VAL(INTEGER, sigFigs)<l
74 s := Slice(ToSigFig(s, sigFigs), 0, sigFigs)
76 (* add '0's to make up significant figures *)
77 s := ConCat(s, Mark(Mult(InitStringChar('0'), l-VAL(INTEGER, sigFigs))))
81 * we reassign point to 1 and adjust the exponent
82 * accordingly, so we can achieve the format X.XXXE+X
84 powerOfTen := point-1 ;
87 IF (point<l) AND (point<VAL(INTEGER, sigFigs))
89 s := ConCat(ConCatChar(Slice(s, 0, point), '.'),
95 s := ConCat(ConCatChar(s, 'E'),
96 IntegerToString(powerOfTen, 0, ' ', TRUE, 10, FALSE))
101 s := ConCat(InitStringChar('-'), Mark(s))
105 END RealToFloatString ;
109 RealToEngString - converts the value of real to floating-point
110 string form, with sigFigs significant figures.
111 The number is scaled with one to three digits
112 in the whole number part and with an exponent
113 that is a multiple of three.
116 PROCEDURE RealToEngString (real: REAL; sigFigs: CARDINAL) : String ;
120 powerOfTen: INTEGER ;
126 r := dtoa(real, maxsignificant, 100, point, sign) ;
127 s := InitStringCharStar(r) ;
132 IF (l>0) AND IsDigit(char(s, 0))
136 s := Slice(ToSigFig(s, sigFigs), 0, sigFigs)
138 (* add '0's to make up significant figures *)
139 s := ConCat(s, Mark(Mult(InitStringChar('0'), l-sigFigs)))
142 IF (point>0) AND (point<=2)
144 (* current range is fine, no need for a exponent *)
146 IF point>VAL(INTEGER, sigFigs)
148 (* add '0's to make up required mantissa length *)
149 s := ConCat(s, Mark(Mult(InitStringChar('0'), point-VAL(INTEGER, sigFigs)))) ;
154 * desire a value of point which lies between 1..3
155 * this allows the mantissa to have the format
156 * X.XXX or XX.XX or XXX.X
158 powerOfTen := point-VAL(INTEGER, l) ;
159 point := point-powerOfTen ;
163 offset := (point DIV 3) * 3 ;
164 point := point-offset ;
165 powerOfTen := powerOfTen+offset
168 offset := (ABS(point) DIV 3) * 3 ;
169 point := point+offset ;
170 powerOfTen := powerOfTen-offset
174 IF ABS(powerOfTen) MOD 3#0
176 offset := 3-(ABS(powerOfTen) MOD 3)
179 (* at this stage, point >= sigFigs *)
180 IF powerOfTen MOD 3#0
182 offset := -(3-(powerOfTen MOD 3))
185 IF offset+point>VAL(INTEGER, sigFigs)
187 (* add '0's to make up required mantissa length *)
188 s := ConCat(s, Mark(Mult(InitStringChar('0'), offset+point-VAL(INTEGER, sigFigs)))) ;
191 (* now adjust point and powerOfTen by offset *)
192 point := point + offset ;
193 powerOfTen := powerOfTen - offset
198 s := ConCat(ConCat(InitString('0.'), Mult(InitStringChar('0'), -point)), s)
199 ELSIF (point>0) AND (point<VAL(INTEGER, l)) AND (point<VAL(INTEGER, sigFigs))
201 s := ConCat(ConCatChar(Slice(s, 0, point), '.'),
207 s := ConCat(ConCatChar(s, 'E'),
208 IntegerToString(powerOfTen, 0, ' ', TRUE, 10, FALSE))
213 s := ConCat(InitStringChar('-'), Mark(s))
217 END RealToEngString ;
221 RealToFixedString - returns the number of characters in the fixed-point
222 string representation of real rounded to the given
223 place relative to the decimal point.
226 PROCEDURE RealToFixedString (real: REAL; place: INTEGER) : String ;
234 r := dtoa(real, maxsignificant, 100, point, sign) ;
235 s := InitStringCharStar(r) ;
240 printf("length of string returned is %d decimal point at position %d\n", l, point)
242 IF (l>0) AND IsDigit(char(s, 0))
246 (* add decimal point at correct position *)
249 s := ConCat(ConCat(InitString('0.'), Mult(InitStringChar('0'), -point)), s)
252 s := ConCat(InitString('0.'), Mark(s))
255 s := ConCat(ConCatChar(Slice(s, 0, point), '.'),
260 s := ToSigFig(s, point+place+1)
262 s := ToSigFig(s, point+place)
267 IF Index(s, '.', 0)<0
269 s := ConCatChar(s, '.') ;
270 s := ConCat(s, Mark(Mult(InitStringChar('0'), place)))
272 point := Index(s, '.', 0) ;
275 s := ConCat(s, Mark(Mult(InitStringChar('0'), l-point-place)))
285 s := InitString('0.')
287 s := InitString('0.0')
293 s := ConCat(InitStringChar('-'), Mark(s))
296 END RealToFixedString ;