This is Unofficial EPICS BASE Doxygen Site
cvtFast.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 /* Fast numeric to string conversions
10  *
11  * Original Authors:
12  * Bob Dalesio, Mark Anderson and Marty Kraimer
13  * Date: 12 January 1993
14  */
15 
16 #include <string.h>
17 #include <limits.h>
18 
19 #include "cvtFast.h"
20 #include "epicsMath.h"
21 #include "epicsStdio.h"
22 
23 /*
24  * These routines convert numbers up to +/- 10,000,000.
25  * They defer to sprintf() for numbers requiring more than
26  * 8 places of precision.
27  */
28 static epicsInt32 frac_multiplier[] =
29  {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
30 
31 int cvtFloatToString(float flt_value, char *pdest,
32  epicsUInt16 precision)
33 {
34  int got_one, i;
35  epicsInt32 whole, iplace, number, fraction, fplace;
36  float ftemp;
37  char *startAddr;
38 
39  /* can this routine handle this conversion */
40  if (isnan(flt_value) || precision > 8 ||
41  flt_value > 10000000.0 || flt_value < -10000000.0) {
42  if (precision > 8 || flt_value >= 1e8 || flt_value <= -1e8) {
43  if (precision > 12) precision = 12; /* FIXME */
44  sprintf(pdest, "%*.*e", precision+6, precision, (double) flt_value);
45  } else {
46  if (precision > 3) precision = 3; /* FIXME */
47  sprintf(pdest, "%.*f", precision, (double) flt_value);
48  }
49  return((int)strlen(pdest));
50  }
51  startAddr = pdest;
52 
53  /* determine the sign */
54  if (flt_value < 0){
55  *pdest++ = '-';
56  flt_value = -flt_value;
57  };
58 
59  /* remove the whole number portion */
60  whole = (epicsInt32)flt_value;
61  ftemp = flt_value - whole;
62 
63  /* multiplier to convert fractional portion to integer */
64  fplace = frac_multiplier[precision];
65  fraction = (epicsInt32)(ftemp * fplace * 10);
66  fraction = (fraction + 5) / 10; /* round up */
67 
68  /* determine rounding into the whole number portion */
69  if ((fraction / fplace) >= 1){
70  whole++;
71  fraction -= fplace;
72  }
73 
74  /* whole numbers */
75  got_one = 0;
76  for (iplace = 10000000; iplace >= 1; iplace /= 10){
77  if (whole >= iplace){
78  got_one = 1;
79  number = whole / iplace;
80  whole = whole - (number * iplace);
81  *pdest = number + '0';
82  pdest++;
83  }else if (got_one){
84  *pdest = '0';
85  pdest++;
86  }
87  }
88  if (!got_one){
89  *pdest = '0';
90  pdest++;
91  }
92 
93  /* fraction */
94  if (precision > 0){
95  /* convert fractional portional to ASCII */
96  *pdest = '.';
97  pdest++;
98  for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){
99  number = fraction / fplace;
100  fraction -= number * fplace;
101  *pdest = number + '0';
102  pdest++;
103  }
104  }
105  *pdest = 0;
106 
107  return((int)(pdest - startAddr));
108 }
109 
111  double flt_value,
112  char *pdest,
113  epicsUInt16 precision)
114 {
115  epicsUInt16 got_one,i;
116  epicsInt32 whole,iplace,number,fraction,fplace;
117  double ftemp;
118  char *startAddr;
119 
120  /* can this routine handle this conversion */
121  if (isnan(flt_value) || precision > 8 || flt_value > 10000000.0 || flt_value < -10000000.0) {
122  if (precision > 8 || flt_value > 1e16 || flt_value < -1e16) {
123  if(precision>17) precision=17;
124  sprintf(pdest,"%*.*e",precision+7,precision,
125  flt_value);
126  } else {
127  if(precision>3) precision=3;
128  sprintf(pdest,"%.*f",precision,flt_value);
129  }
130  return((int)strlen(pdest));
131  }
132  startAddr = pdest;
133 
134  /* determine the sign */
135  if (flt_value < 0){
136  *pdest++ = '-';
137  flt_value = -flt_value;
138  };
139 
140  /* remove the whole number portion */
141  whole = (epicsInt32)flt_value;
142  ftemp = flt_value - whole;
143 
144  /* multiplier to convert fractional portion to integer */
145  fplace = frac_multiplier[precision];
146  fraction = (epicsInt32)(ftemp * fplace * 10);
147  fraction = (fraction + 5) / 10; /* round up */
148 
149  /* determine rounding into the whole number portion */
150  if ((fraction / fplace) >= 1){
151  whole++;
152  fraction -= fplace;
153  }
154 
155  /* whole numbers */
156  got_one = 0;
157  for (iplace = 10000000; iplace >= 1; iplace /= 10){
158  if (whole >= iplace){
159  got_one = 1;
160  number = whole / iplace;
161  whole = whole - (number * iplace);
162  *pdest = number + '0';
163  pdest++;
164  }else if (got_one){
165  *pdest = '0';
166  pdest++;
167  }
168  }
169  if (!got_one){
170  *pdest = '0';
171  pdest++;
172  }
173 
174  /* fraction */
175  if (precision > 0){
176  /* convert fractional portional to ASCII */
177  *pdest = '.';
178  pdest++;
179  for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){
180  number = fraction / fplace;
181  fraction -= number * fplace;
182  *pdest = number + '0';
183  pdest++;
184  }
185  }
186  *pdest = 0;
187 
188  return((int)(pdest - startAddr));
189 }
190 
191 /*
192  * These routines are provided for backwards compatibility,
193  * extensions such as MEDM, edm and histtool use them.
194  */
195 
196 /*
197  * cvtFloatToExpString
198  *
199  * Converts a float to a %e formatted string
200  */
201 int cvtFloatToExpString(float val, char *pdest, epicsUInt16 precision)
202 {
203  return epicsSnprintf(pdest, MAX_STRING_SIZE, "%.*e", precision, val);
204 }
205 
206 /*
207  * cvtFloatToCompactString
208  *
209  * Converts a float to a %g formatted string.
210  * The result uses %f notation for 10e-4 < |value| < 10e+4,
211  * otherwise %e notation.
212  */
213 int cvtFloatToCompactString(float val, char *pdest, epicsUInt16 precision)
214 {
215  if ((val < 1.e4 && val > 1.e-4) ||
216  (val > -1.e4 && val < -1.e-4) ||
217  val == 0.0)
218  return cvtFloatToString(val, pdest, precision);
219 
220  return cvtFloatToExpString(val, pdest, precision);
221 }
222 
223 
224 /*
225  * cvtDoubleToExpString
226  *
227  * Converts a double to a %e formatted string
228  */
229 
230 int cvtDoubleToExpString(double val, char *pdest, epicsUInt16 precision)
231 {
232  return epicsSnprintf(pdest, MAX_STRING_SIZE, "%.*e", precision, val);
233 }
234 
235 
236 /*
237  * cvtDoubleToCompactString
238  *
239  * Converts a double to %g formatted string.
240  * The result uses %f notation for 10e-4 < |value| < 10e+4,
241  * otherwise %e notation.
242  */
243 int cvtDoubleToCompactString(double val, char *pdest, epicsUInt16 precision)
244 {
245  if ((val < 1.e4 && val > 1.e-4) ||
246  (val > -1.e4 && val < -1.e-4) ||
247  val == 0.0)
248  return cvtDoubleToString(val, pdest, precision);
249 
250  return cvtDoubleToExpString(val, pdest, precision);
251 }
252 
253 
254 /* Integer conversion primitives */
255 
256 static size_t
257  UInt32ToDec(epicsUInt32 val, char *pdest)
258 {
259  int i;
260  char digit[10];
261  size_t len;
262 
263  for (i = 0; val; i++) {
264  epicsUInt32 tenth = val / 10;
265 
266  digit[i] = val - tenth * 10 + '0';
267  val = tenth;
268  }
269  len = i;
270 
271  while (i > 0)
272  *pdest++ = digit[--i];
273 
274  *pdest = 0;
275  return len;
276 }
277 
278 static size_t
279  UInt32ToBase(epicsUInt32 val, char *pdest, int base)
280 {
281  int i;
282  char digit, digits[32];
283  size_t len;
284 
285  for (i = 0; val; i++) {
286  epicsUInt32 tenth = val / base;
287 
288  digit = val - tenth * base;
289  digits[i] = digit < 10 ? digit + '0' : digit - 10 + 'a';
290  val = tenth;
291  }
292  len = i;
293 
294  while (i > 0)
295  *pdest++ = digits[--i];
296 
297  *pdest = 0;
298  return len;
299 }
300 
301 static size_t
302  UInt64ToDec(epicsUInt64 val, char *pdest)
303 {
304  int i;
305  char digit[20];
306  size_t len;
307 
308  for (i = 0; val; i++) {
309  epicsUInt64 tenth = val / 10;
310 
311  digit[i] = val - tenth * 10 + '0';
312  val = tenth;
313  }
314 
315  len = i;
316  while (i > 0)
317  *pdest++ = digit[--i];
318 
319  *pdest = 0;
320  return len;
321 }
322 
323 static size_t
324  UInt64ToBase(epicsUInt64 val, char *pdest, int base)
325 {
326  int i;
327  char digit, digits[64];
328  size_t len;
329 
330  for (i = 0; val; i++) {
331  epicsUInt64 tenth = val / base;
332 
333  digit = val - tenth * base;
334  digits[i] = digit < 10 ? digit + '0' : digit - 10 + 'a';
335  val = tenth;
336  }
337  len = i;
338 
339  while (i > 0)
340  *pdest++ = digits[--i];
341 
342  *pdest = 0;
343  return len;
344 }
345 
346 
347 /* Integer conversion routines */
348 
349 size_t
350  cvtUInt32ToString(epicsUInt32 val, char *pdest)
351 {
352  if (val == 0) {
353  *pdest++ = '0';
354  *pdest = 0;
355  return 1;
356  }
357 
358  return UInt32ToDec(val, pdest);
359 }
360 
361 size_t
362  cvtInt32ToString(epicsInt32 val, char *pdest)
363 {
364  if (val == 0) {
365  *pdest++ = '0';
366  *pdest = 0;
367  return 1;
368  }
369 
370  if (val > 0)
371  return UInt32ToDec(val, pdest);
372 
373  if (val == -0x80000000) {
374  strcpy(pdest, "-2147483648");
375  return strlen(pdest);
376  }
377 
378  *pdest++ = '-';
379  return 1 + UInt32ToDec(-val, pdest);
380 }
381 
382 
383 size_t
384  cvtUInt64ToString(epicsUInt64 val, char *pdest)
385 {
386  if (val == 0) {
387  *pdest++ = '0';
388  *pdest = 0;
389  return 1;
390  }
391 
392  return UInt64ToDec(val, pdest);
393 }
394 
395 size_t
396  cvtInt64ToString(epicsInt64 val, char *pdest)
397 {
398  if (val == 0) {
399  *pdest++ = '0';
400  *pdest = 0;
401  return 1;
402  }
403 
404  if (val > 0)
405  return UInt64ToDec(val, pdest);
406 
407  if (val == -0x8000000000000000LL) {
408  strcpy(pdest, "-9223372036854775808");
409  return strlen(pdest);
410  }
411 
412  *pdest++ = '-';
413  return 1 + UInt64ToDec(-val, pdest);
414 }
415 
416 
417 size_t
418  cvtInt32ToHexString(epicsInt32 val, char *pdest)
419 {
420  if (val < 0)
421  *pdest++ = '-';
422 
423  *pdest++ = '0';
424  *pdest++ = 'x';
425 
426  if (val == 0) {
427  *pdest++ = '0';
428  *pdest = 0;
429  return 3;
430  }
431 
432  if (val > 0)
433  return 2 + UInt32ToBase(val, pdest, 16);
434 
435  if (val == -0x80000000) {
436  strcpy(pdest, "80000000");
437  return 11;
438  }
439 
440  return 3 + UInt32ToBase(-val, pdest, 16);
441 }
442 
443 size_t
445 {
446  *pdest++ = '0';
447  *pdest++ = 'x';
448 
449  if (val == 0) {
450  *pdest++ = '0';
451  *pdest = 0;
452  return 3;
453  }
454 
455  return 2 + UInt32ToBase(val, pdest, 16);
456 }
457 
458 size_t
460 {
461  if (val == 0) {
462  *pdest++ = '0';
463  *pdest = 0;
464  return 1;
465  }
466 
467  if (val > 0) {
468  *pdest++ = '0';
469  return 1 + UInt32ToBase(val, pdest, 8);
470  }
471 
472  if (val == -0x80000000) {
473  strcpy(pdest, "-020000000000");
474  return strlen(pdest);
475  }
476 
477  *pdest++ = '-';
478  *pdest++ = '0';
479  return 2 + UInt32ToBase(-val, pdest, 8);
480 }
481 
482 size_t
483  cvtInt64ToHexString(epicsInt64 val, char *pdest)
484 {
485  if (val < 0)
486  *pdest++ = '-';
487 
488  *pdest++ = '0';
489  *pdest++ = 'x';
490 
491  if (val == 0) {
492  *pdest++ = '0';
493  *pdest = 0;
494  return 3;
495  }
496 
497  if (val > 0)
498  return 2 + UInt64ToBase(val, pdest, 16);
499 
500  if (val == -0x8000000000000000LL) {
501  strcpy(pdest, "8000000000000000");
502  return 19;
503  }
504 
505  return 3 + UInt64ToBase(-val, pdest, 16);
506 }
507 
508 size_t
510 {
511  *pdest++ = '0';
512  *pdest++ = 'x';
513 
514  if (val == 0) {
515  *pdest++ = '0';
516  *pdest = 0;
517  return 3;
518  }
519 
520  return 2 + UInt64ToBase(val, pdest, 16);
521 }
522 
size_t cvtInt32ToString(epicsInt32 val, char *pdest)
Definition: cvtFast.c:362
size_t cvtInt32ToHexString(epicsInt32 val, char *pdest)
Definition: cvtFast.c:418
int cvtFloatToExpString(float val, char *pdest, epicsUInt16 precision)
Definition: cvtFast.c:201
int cvtDoubleToString(double flt_value, char *pdest, epicsUInt16 precision)
Definition: cvtFast.c:110
int i
Definition: scan.c:967
size_t cvtUInt32ToString(epicsUInt32 val, char *pdest)
Definition: cvtFast.c:350
unsigned short epicsUInt16
Definition: epicsTypes.h:41
int cvtDoubleToExpString(double val, char *pdest, epicsUInt16 precision)
Definition: cvtFast.c:230
unsigned int epicsUInt32
Definition: epicsTypes.h:43
size_t cvtUInt64ToHexString(epicsUInt64 val, char *pdest)
Definition: cvtFast.c:509
unsigned long long epicsUInt64
Definition: epicsTypes.h:45
size_t cvtInt64ToHexString(epicsInt64 val, char *pdest)
Definition: cvtFast.c:483
int cvtFloatToCompactString(float val, char *pdest, epicsUInt16 precision)
Definition: cvtFast.c:213
#define isnan(x)
Definition: epicsMath.h:21
size_t cvtInt64ToString(epicsInt64 val, char *pdest)
Definition: cvtFast.c:396
int cvtDoubleToCompactString(double val, char *pdest, epicsUInt16 precision)
Definition: cvtFast.c:243
size_t cvtUInt64ToString(epicsUInt64 val, char *pdest)
Definition: cvtFast.c:384
size_t cvtUInt32ToHexString(epicsUInt32 val, char *pdest)
Definition: cvtFast.c:444
#define MAX_STRING_SIZE
Definition: epicsTypes.h:65
int * base
Definition: flex.c:92
int cvtFloatToString(float flt_value, char *pdest, epicsUInt16 precision)
Definition: cvtFast.c:31
int epicsInt32
Definition: epicsTypes.h:42
size_t cvtInt32ToOctalString(epicsInt32 val, char *pdest)
Definition: cvtFast.c:459
LIBCOM_API int epicsStdCall epicsSnprintf(char *str, size_t size, const char *format,...) EPICS_PRINTF_STYLE(3
long long epicsInt64
Definition: epicsTypes.h:44