bump to -rc12
[gnucap-felix.git] / lib / l_ftos.cc
blob00aa76274ebc60ca80c8371cacd2017e89d4b97e
1 /*$Id: l_ftos.cc,v 1.3 2010-08-16 12:23:30 felix Exp $ -*- C++ -*-
2 * vim:ts=8:sw=2:et:
3 * Copyright (C) 2001 Albert Davis
4 * Author: Albert Davis <aldavis@gnu.org>
6 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
8 * This program 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)
11 * any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *------------------------------------------------------------------
23 * float to string
24 * builds string representing floating number
25 * num = number to convert.
26 * str = string to put it in. Must be big enough, or else!!
27 * Must have length at least len+6.
28 * sig digits + dec.pt.(1) + sign(1) + exp(4)
29 * len = max number of displayed digits. (left + right of dp)
30 * (includes d.p. if 'e' notation and 2 digit exp)
31 * fmt = format : 0 = alpha for exp notation
32 * FMTEXP = exponential notation
33 * FMTSIGN = always inlcude sign
34 * FMTFILL = fill in zeros
35 * //BUG//
36 * returns a pointer to static space where the string is.
37 * there is a finite pool, so repeated calls work, to a point.
38 * after that, the space is overwritten, every POOLSIZE calls
40 //testing=script 2005.10.11
41 #include "l_lib.h"
42 #include "constant.h"
43 /*--------------------------------------------------------------------------*/
44 char* ftos(double,int,int,int);
45 /*--------------------------------------------------------------------------*/
46 const int POOLSIZE = 100;
47 const int MAXLENGTH = 40;
48 static double ftos_floor = 1e-99;
49 /*--------------------------------------------------------------------------*/
50 std::string to_string(std::string s)
52 return s;
54 /*--------------------------------------------------------------------------*/
55 std::string to_string(unsigned n)
57 char s[100];
58 sprintf(s, "%u", n);
59 return s;
61 /*--------------------------------------------------------------------------*/
62 string to_string(unsigned long int n)
64 char s[100];
65 sprintf(s, "%d", (int)n);
66 return s;
68 /*--------------------------------------------------------------------------*/
69 string to_string(int n)
71 char s[100];
72 sprintf(s, "%d", n);
73 return s;
75 /*--------------------------------------------------------------------------*/
76 string to_string(long int n)
78 char s[100];
79 sprintf(s, "%li", n);
80 return s;
82 /*--------------------------------------------------------------------------*/
83 string to_string(std::vector<double> n)
85 string buf("");
86 // FIXME: remove one ,
87 if (n.size()==0){return "( )";}
89 std::vector<double>::iterator i=n.begin();
90 buf += string("(") + ftos((double)*i, 0, 7, 0);
91 ++i;
93 while (i!=n.end()){
94 buf += std::string(",") + ftos((double)*i, 0, 7, 0);
95 ++i;
97 return buf + std::string(" )");;
99 /*--------------------------------------------------------------------------*/
100 std::string to_string(std::list<double> n)
102 trace1("to_string(list", n.size());
103 std::string buf("");
104 // FIXME: remove one ,
105 for(std::list<double>::iterator i=n.begin();
106 i!=n.end(); ++i){
107 buf += std::string(", ") + ftos((double)*i, 0, 7, 0);
109 return buf;
111 /*--------------------------------------------------------------------------*/
112 std::string to_string(double n)
114 return ftos((double)n, 0, 7, 0);
116 /*--------------------------------------------------------------------------*/
117 std::string to_string(long double n)
119 return ftos((double)n, 0, 7, 0);
121 /*--------------------------------------------------------------------------*/
122 template <class T>
123 std::string to_string(T n)
125 return ftos((double)n, 0, 7, 0);
127 /*--------------------------------------------------------------------------*/
128 char* ftos(double num, int fieldwidth, int len, int fmt)
129 // num = number to convert
130 // fieldwidth = size for fixed width, 0 for variable width
131 // len = max length of new string
132 // fmt = how to format it
134 if (len < 3) {
135 untested();
136 len = 3;
138 if (len > MAXLENGTH-6) {
139 untested();
140 len = MAXLENGTH-6;
142 if (fieldwidth > MAXLENGTH-1) {
143 untested();
144 fieldwidth = MAXLENGTH-1;
147 char *str;
148 { /* get a buffer from the pool */
149 //BUG// It is possible to have too many buffers active
150 // then the extras are overwritten, giving bad output
151 // There are no known cases, but it is not checked.
152 static char strpool[POOLSIZE][MAXLENGTH];
153 static int poolindex = 0;
154 ++poolindex;
155 if (poolindex >= POOLSIZE) {
156 poolindex = 0;
158 str = strpool[poolindex];
161 { /* build a clean blank string */
162 int string_size = std::max(fieldwidth, len+6);
163 for (int iii=0; iii<string_size; ++iii) {
164 str[iii] = ' ';
166 for (int iii=string_size; iii<MAXLENGTH; ++iii) {
167 str[iii] = '\0';
171 #ifdef HAS_NUMERIC_LIMITS
172 if (num == std::numeric_limits<double>::infinity()) {
173 untested();
174 strncpy(str," Over", 5);
175 }else if (num == -std::numeric_limits<double>::infinity()) {
176 untested();
177 strncpy(str,"-Over", 5);
178 }else if (num == std::numeric_limits<double>::quiet_NaN()) {
179 untested();
180 strncpy(str," nan", 4);
181 }else if (num == std::numeric_limits<double>::signaling_NaN()) {
182 untested();
183 strncpy(str," nan", 4);
184 }else
185 #endif
186 trace1("ftos ", num );
187 if (num == NOT_VALID) {
188 strncpy(str," ??", 3);
189 }else if (num == NOT_INPUT) {
190 strncpy(str," NA", 3);
191 }else if (num >= BIGBIG) {
192 strncpy(str," Inf", 4);
193 }else if (num <= -BIGBIG) {
194 strncpy(str,"-Inf", 4);
195 }else if (num != num) {
196 strncpy(str," NaN", 4);
197 }else{
198 if (std::abs(num) < ftos_floor) { /* hide noise */
199 num = 0.;
202 int expo = 0; /* exponent */
203 int nnn = 0; /* char counter -- pos in string */
204 if (num == 0.) {
205 strcpy(str, " 0.");
206 nnn = static_cast<int>(strlen(str)); /* num==0 .. build string 0.000... */
207 while (--len) {
208 str[nnn++] = '0';
210 assert(expo == 0);
211 }else{ /* num != 0 */
212 { // insert sign
213 if (num < 0.) {
214 str[0] = '-';
215 num = -num;
216 }else if (fmt & ftos_SIGN) {
217 untested();
218 str[0] = '+';
219 }else{
220 assert(str[0] == ' ');
223 { // scale to .001 - 1.0. adjust expo.
224 expo = -3;
225 while (num < .001) {
226 num *= 1000.;
227 expo -= 3;
229 while (num >= 1.) {
230 num *= .001;
231 expo += 3;
234 { // adjust len to compensate for length of printed exponent
235 if ((fmt&ftos_EXP && expo<-9) || expo>10 || expo<-16) {
236 --len; /* one less digit if 'e' notation */
237 } /* and exp is 2 digits */
238 if (len < 3) {
239 ++len;
242 { // round to correct number of digits
243 double rnd = .5 / pow(10., len); /* find amt to add to round */
244 if (num < .01) {
245 rnd /= 100.;
246 }else if (num < .1) {
247 rnd /= 10.;
249 num += rnd; /* add it */
250 if (num >= 1.) {
251 num *= .001; /* created an extra digit: rescale */
252 expo += 3;
255 { // build mantissa
256 nnn = 1;
257 if (expo == -3) { /* .001 is preferable to 1e-3 */
258 int flg = 0; /* print in fixed point, no exponent*/
259 expo = 0;
260 str[nnn++] = '0';
261 str[nnn++] = '.';
262 while (len > 0) {
263 num *= 10.;
264 int digit = static_cast<int>(floor(num));
265 num -= static_cast<double>(digit);
266 str[nnn++] = static_cast<char>(digit + '0');
267 if ((flg += digit)) {
268 --len;
271 }else{
272 int flg = 0;
273 for (int iii=2; len>0; --iii) {/* mantissa */
274 num *= 10.; /* get next digit */
275 int digit = static_cast<int>(floor(num));
276 num -= static_cast<double>(digit);/* subtract off last digit */
277 if ((flg += digit)) { /* if int part !=0 */
278 str[nnn++]=static_cast<char>(digit+'0');/*(not all zeros so far)*/
279 --len; /* stuff the digit into the string */
281 if (iii==0) { /* if we found the dec.pt. and */
282 str[nnn++] = '.'; /* haven't used up all the space */
283 } /* put a dec.pt. in the string */
288 assert(nnn > 0);
289 assert(str[nnn] == ' ' || str[nnn] == '\0');
291 { // suppress trailing zeros
292 if (!(fmt&ftos_FILL)) {
293 while (str[--nnn]=='0') {
294 str[nnn] = static_cast<char>((nnn < fieldwidth) ? ' ' : '\0');
296 ++nnn;
297 }else{
298 untested();
302 { // append exponent
303 if (expo == 0) {
304 // nothing;
305 }else if (fmt&ftos_EXP || expo>10 || expo<-16) {/* exponential format */
306 char c = str[nnn+4];
307 sprintf(&str[nnn], ((expo < 100) ? "E%+-3d" : "E%3u"), expo);
308 nnn+=4;
309 str[nnn++] = c;
310 }else{ /* if letter-scale format */
311 str[nnn++] = "fpnum KMGT"[(expo+15)/3];/* put the appropriate letter*/
312 } /* note that letter-scale is not valid */
313 /* for exp==-3 or exp not in -15..+12 */
314 /* this is trapped but letter-scale is also */
315 /* not valid if exp not divisible by 3. */
316 /* This is not trapped, since it supposedly */
317 /* cant happen. */
318 if (str[nnn-1] == 'M') {
319 str[nnn++] = 'e'; /* Spice kluge "MEG" */
320 str[nnn++] = 'g';
324 { // clean up trailing blanks
325 if (fieldwidth==0) {
326 trim(str);
330 return str;
332 /*--------------------------------------------------------------------------*/
333 /*--------------------------------------------------------------------------*/
334 // vim:ts=8:sw=2:noet: