1 (* ConvStringLong.mod converts 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 ConvStringLong
;
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 ldtoa
IMPORT ldtoa
, Mode
;
34 FROM libc
IMPORT free
;
35 FROM SYSTEM
IMPORT ADDRESS
;
39 IsDigit - returns TRUE if, ch, lies between '0'..'9'.
42 PROCEDURE IsDigit (ch
: CHAR) : BOOLEAN ;
44 RETURN (ch
>='0') AND (ch
<='9')
49 RealToFloatString - converts a real with, sigFigs, into a string
50 and returns the result as a string.
53 PROCEDURE RealToFloatString (real
: LONGREAL; sigFigs
: CARDINAL) : String
;
61 r
:= ldtoa(real
, maxsignificant
, 100, point
, sign
) ;
62 s
:= InitStringCharStar(r
) ;
67 IF (l
>0) AND IsDigit(char(s
, 0))
69 IF VAL(INTEGER, sigFigs
)<l
71 s
:= Slice(ToSigFig(s
, sigFigs
), 0, sigFigs
)
73 (* add '0's to make up significant figures *)
74 s
:= ConCat(s
, Mark(Mult(InitStringChar('0'), l
-VAL(INTEGER, sigFigs
))))
78 * we reassign point to 1 and adjust the exponent
79 * accordingly, so we can achieve the format X.XXXE+X
81 powerOfTen
:= point
-1 ;
84 IF (point
<l
) AND (point
<VAL(INTEGER, sigFigs
))
86 s
:= ConCat(ConCatChar(Slice(s
, 0, point
), '.'),
92 s
:= ConCat(ConCatChar(s
, 'E'),
93 IntegerToString(powerOfTen
, 0, ' ', TRUE, 10, FALSE))
98 s
:= ConCat(InitStringChar('-'), Mark(s
))
102 END RealToFloatString
;
106 RealToEngString - converts the value of real to floating-point
107 string form, with sigFigs significant figures.
108 The number is scaled with one to three digits
109 in the whole number part and with an exponent
110 that is a multiple of three.
113 PROCEDURE RealToEngString (real
: LONGREAL; sigFigs
: CARDINAL) : String
;
117 powerOfTen
: INTEGER ;
123 r
:= ldtoa(real
, maxsignificant
, 100, point
, sign
) ;
124 s
:= InitStringCharStar(r
) ;
129 IF (l
>0) AND IsDigit(char(s
, 0))
133 s
:= Slice(ToSigFig(s
, sigFigs
), 0, sigFigs
)
135 (* add '0's to make up significant figures *)
136 s
:= ConCat(s
, Mark(Mult(InitStringChar('0'), l
-sigFigs
)))
139 IF (point
>0) AND (point
<=2)
141 (* current range is fine, no need for a exponent *)
143 IF point
>VAL(INTEGER, sigFigs
)
145 (* add '0's to make up required mantissa length *)
146 s
:= ConCat(s
, Mark(Mult(InitStringChar('0'), point
-VAL(INTEGER, sigFigs
)))) ;
151 * desire a value of point which lies between 1..3
152 * this allows the mantissa to have the format
153 * X.XXX or XX.XX or XXX.X
155 powerOfTen
:= point
-VAL(INTEGER, l
) ;
156 point
:= point
-powerOfTen
;
160 offset
:= (point
DIV 3) * 3 ;
161 point
:= point
-offset
;
162 powerOfTen
:= powerOfTen
+offset
165 offset
:= (ABS(point
) DIV 3) * 3 ;
166 point
:= point
+offset
;
167 powerOfTen
:= powerOfTen
-offset
171 IF ABS(powerOfTen
) MOD 3#
0
173 offset
:= 3-(ABS(powerOfTen
) MOD 3)
176 (* at this stage, point >= sigFigs *)
177 IF powerOfTen
MOD 3#
0
179 offset
:= -(3-(powerOfTen
MOD 3))
182 IF offset
+point
>VAL(INTEGER, sigFigs
)
184 (* add '0's to make up required mantissa length *)
185 s
:= ConCat(s
, Mark(Mult(InitStringChar('0'), offset
+point
-VAL(INTEGER, sigFigs
)))) ;
188 (* now adjust point and powerOfTen by offset *)
189 point
:= point
+ offset
;
190 powerOfTen
:= powerOfTen
- offset
195 s
:= ConCat(ConCat(InitString('0.'), Mult(InitStringChar('0'), -point
)), s
)
196 ELSIF (point
>0) AND (point
<VAL(INTEGER, l
)) AND (point
<VAL(INTEGER, sigFigs
))
198 s
:= ConCat(ConCatChar(Slice(s
, 0, point
), '.'),
204 s
:= ConCat(ConCatChar(s
, 'E'),
205 IntegerToString(powerOfTen
, 0, ' ', TRUE, 10, FALSE))
210 s
:= ConCat(InitStringChar('-'), Mark(s
))
214 END RealToEngString
;
218 RealToFixedString - returns the number of characters in the fixed-point
219 string representation of real rounded to the given
220 place relative to the decimal point.
223 PROCEDURE RealToFixedString (real
: LONGREAL; place
: INTEGER) : String
;
231 r
:= ldtoa(real
, maxsignificant
, 100, point
, sign
) ;
232 s
:= InitStringCharStar(r
) ;
235 IF (l
>0) AND IsDigit(char(s
, 0))
239 (* add decimal point at correct position *)
242 s
:= ConCat(ConCat(InitString('0.'), Mult(InitStringChar('0'), -point
)), s
)
245 s
:= ConCat(InitString('0.'), Mark(s
))
248 s
:= ConCat(ConCatChar(Slice(s
, 0, point
), '.'),
253 s
:= ToSigFig(s
, point
+place
+1)
255 s
:= ToSigFig(s
, point
+place
)
260 IF Index(s
, '.', 0)<0
262 s
:= ConCatChar(s
, '.') ;
263 s
:= ConCat(s
, Mark(Mult(InitStringChar('0'), place
)))
265 point
:= Index(s
, '.', 0) ;
268 s
:= ConCat(s
, Mark(Mult(InitStringChar('0'), l
-point
-place
)))
278 s
:= InitString('0.')
280 s
:= InitString('0.0')
286 s
:= ConCat(InitStringChar('-'), Mark(s
))
289 END RealToFixedString
;