diff --git a/src/libCom/cvtNumbers.c b/src/libCom/cvtNumbers.c new file mode 100644 index 000000000..949a60b73 --- /dev/null +++ b/src/libCom/cvtNumbers.c @@ -0,0 +1,388 @@ +/* $Id$ + * Author: Roger A. Cole + * Date: unknown + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1992, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * Modification Log: + * ----------------- + * .01 unknown rac initial version, cloned from WETF code + * .02 02-19-92 rac added proper treatment for fractional values + * and printing for integers + * + * make options + * -DvxWorks makes a version for VxWorks + * -DNDEBUG don't compile assert() checking + * -DDEBUG compile various debug code, including checks on + * malloc'd memory + */ +/*+/mod*********************************************************************** +* TITLE cvtNumbers.c - convert numeric to text +* +* DESCRIPTION +* These routines provide service to convert numeric values to text +* form. +* +* QUICK REFERENCE +* int cvtDblToTxt( text, width, dblVal, decPl ) +* int cvtLngToTxt( text, width, lngVal ) +* +* +*-***************************************************************************/ +#ifdef vxWorks +# include +# include +#else +# include +# include +#endif + +#include + + +#ifdef vxWorks +#define nint(value) (value>=0 ? (int)((value)+.5) : (int)((value)-.5)) +#define exp10(value) (exp(value * log(10.))) +#endif + +#if 0 +main() +{ + float x, y; + char text[100]; + int i, iter; + int xi, yi; + + for (x=.000123; x<1000; x*=10.) { + printf("%10.5f", x); + for (i=1; i<10; i++) { + cvtDblToTxt(text, i, x, 3); + printf(" %s", text); + } + printf("\n"); + y = -1. * x; + printf("%10.5f", y); + for (i=1; i<10; i++) { + cvtDblToTxt(text, i, y, 3); + printf(" %s", text); + } + printf("\n"); + } + for (iter=1,xi=0; iter<=12; iter++,xi+=xi*10+xi+1) { + printf("%12d", xi); + for (i=1; i<=iter; i++) { + cvtLngToTxt(text, i, xi); + printf(" %s", text); + } + printf("\n"); + yi = -1 * xi; + printf("%12d", yi); + for (i=1; i<=iter+1; i++) { + cvtLngToTxt(text, i, yi); + printf(" %s", text); + } + printf("\n"); + } +} +#endif + +/*+/subr********************************************************************** +* NAME cvtDblToTxt - convert double to text, being STINGY with space +* +* DESCRIPTION +* Convert a double value to text. The main usefulness of this routine +* is that it maximizes the amount of information presented in a +* minimum number of characters. For example, if a 1 column width +* is specified, only the sign of the value is presented. +* +* When an exponent is needed to represent the value, for narrow +* column widths only the exponent appears. If there isn't room +* even for the exponent, large positive exponents will appear as E*, +* and large negative exponents will appear as E-. +* +* Negative numbers receive some special treatment. In narrow +* columns, very large negative numbers may be represented as - and +* very small negative numbers may be represented as -. or -.E- . +* +* Some example outputs follow (with 3 decimal places assumed): +* +* value printed values for column widths +* 1 2 3 4 5 6 +* +* 0.000 0 0 0 0 0 0 +* -1.000 - -1 -1 -1 -1 -1 +* 0.123 + E- .12 .123 .123 .123 +* -0.00123 - -. -. -.E- -.001 -.001 +* -12.3 - - -12 -12 -12.3 -12.30 +* 123 + E2 123 123 123.0 123.00 +* +*-*/ +cvtDblToTxt(text, width, value, decPl) +char *text; /* O text representation of value */ +int width; /* I max width of text string (not counting '\0') */ +double value; /* I value to print */ +int decPl; /* I max # of dec places to print */ +{ + double valAbs; /* absolute value of caller's value */ + int wholeNdig; /* number of digits in "whole" part of value */ + double logVal; /* log10 of value */ + int decPlaces; /* number of decimal places to print */ + int expI; /* exponent for frac values */ + double expD; + int expWidth; /* width needed for exponent field */ + int excess; /* number of low order digits which + won't fit into the field */ + char tempText[100]; /* temp for fractional conversions */ + int roomFor; + int minusWidth; /* amount of room for - sign--0 or 1 */ + +/*----------------------------------------------------------------------------- +* special cases +*----------------------------------------------------------------------------*/ + if (value == 0.) { + (void)strcpy(text, "0"); + return; + } + else if (value == 1.) { + (void)strcpy(text, "1"); + return; + } + if (width == 1) { + if (value >= 0) + strcpy(text, "+"); + else + strcpy(text, "-"); + return; + } + else if (width == 2 && value <= -1.) { + if (value == -1.) + strcpy(text, "-1"); + else + strcpy(text, "-"); + return; + } + + valAbs = value>0. ? value : -value; + logVal = log10(valAbs); + if (logVal < 0.) { +/*----------------------------------------------------------------------------- +* numbers with only a fractional part +*----------------------------------------------------------------------------*/ + if (width == 2) { + if (value > 0.) + strcpy(tempText, "0E-"); + else + strcpy(tempText, "0-."); + } + else if (width == 3 && value < 0) + strcpy(tempText, "0-."); + else { + if (value < 0.) + minusWidth = 1; + else + minusWidth = 0; + expI = -1 * (int)logVal; + if (expI < 9) + expWidth = 3; /* need E-n */ + else if (expI < 99) + expWidth = 4; /* need E-nn */ + else if (expI < 999) + expWidth = 5; /* need E-nnn */ + else + expWidth = 6; /* need E-nnnn */ + /* figure out how many sig digit can appear if print "as is" */ + /* expI is the number of leading zeros */ + roomFor = width - expI - 1 - minusWidth; /* -1 for the dot */ + if (roomFor >= 1) { + decPlaces = expI + decPl; + if (decPlaces > width -1 - minusWidth) + decPlaces = roomFor + expI; + (void)sprintf(tempText, "%.*f", decPlaces, value); + if (value < 0.) + tempText[1] = '-'; + } + else { + expD = expI; + value *= exp10(expD); + if (value > 0.) + sprintf(tempText, "0.E-%d", expI); + else + sprintf(tempText, "--.E-%d", expI); + } + } + + strncpy(text, &tempText[1], width); + text[width] = '\0'; + return; + } + +/*----------------------------------------------------------------------------- +* numbers with both an integer and a fractional part +* +* find out how many columns are required to represent the integer part +* of the value. A - is counted as a column; the . isn't. +*----------------------------------------------------------------------------*/ + wholeNdig = 1 + (int)logVal; + if (value < 0.) + wholeNdig++; + if (wholeNdig < width-1) { +/*----------------------------------------------------------------------------- +* the integer part fits well within the field. Find out how many +* decimal places can be printed (honoring caller's decPl limit). +*----------------------------------------------------------------------------*/ + decPlaces = width - wholeNdig - 1; + if (decPl < decPlaces) + decPlaces = decPl; + if (decPl > 0) + (void)sprintf(text, "%.*f", decPlaces, value); + else + (void)sprintf(text, "%d", nint(value)); + } + else if (wholeNdig == width || wholeNdig == width-1) { +/*----------------------------------------------------------------------------- +* The integer part just fits within the field. Print the value as an +* integer, without printing the superfluous decimal point. +*----------------------------------------------------------------------------*/ + (void)sprintf(text, "%d", nint(value)); + } + else { +/*----------------------------------------------------------------------------- +* The integer part is too large to fit within the caller's field. Print +* with an abbreviated E notation. +*----------------------------------------------------------------------------*/ + expWidth = 2; /* assume that En will work */ + excess = wholeNdig - (width - 2); + if (excess > 999) { + expWidth = 5; /* no! it must be Ennnn */ + excess += 3; + } + else if (excess > 99) { + expWidth = 4; /* no! it must be Ennn */ + excess += 2; + } + else if (excess > 9) { + expWidth = 3; /* no! it must be Enn */ + excess += 1; + } +/*----------------------------------------------------------------------------- +* Four progressively worse cases, with all or part of exponent fitting +* into field, but not enough room for any of the value +* Ennn positive value; exponent fits +* -Ennn negative value; exponent fits +* +**** positive value; exponent too big +* -**** negative value; exponent too big +*----------------------------------------------------------------------------*/ + if (value >= 0. && expWidth == width) + (void)sprintf(text, "E%d", nint(logVal)); + else if (value < 0. && expWidth == width-1) + (void)sprintf(text, "-E%d", nint(logVal)); + else if (value > 0. && expWidth > width) + (void)sprintf(text, "%.*s", width, "+*******"); + else if (value < 0. && expWidth > width-1) + (void)sprintf(text, "%.*s", width, "-*******"); + else { +/*----------------------------------------------------------------------------- +* The value can fit, in exponential notation +*----------------------------------------------------------------------------*/ + (void)sprintf(text, "%dE%d", + nint(value/exp10((double)excess)), excess); + } + } +} + +/*+/subr********************************************************************** +* NAME cvtLngToTxt - convert long to text, being STINGY with space +* +* DESCRIPTION +* Convert a long value to text. The main usefulness of this routine +* is that it maximizes the amount of information presented in a +* minimum number of characters. For example, if a 1 column width +* is specified, only the sign of the value is presented. +* +* When an exponent is needed to represent the value, for narrow +* column widths only the exponent appears. If there isn't room +* even for the exponent, large positive exponents will appear as E*. +* +* Negative numbers receive some special treatment. In narrow +* columns, very large negative numbers may be represented as - . +* +* Some example outputs follow: +* +* value printed values for column widths +* 1 2 3 4 5 6 +* +* 0 0 0 0 0 0 0 +* -1 - -1 -1 -1 -1 -1 +* 271453 + E5 2E5 27E4 271E3 271453 +* -22621 - - -E4 -2E4 -22E3 - 22621 +* +*-*/ +cvtLngToTxt(text, width, value) +char *text; /* O text representation of value */ +int width; /* I max width of text string (not counting '\0') */ +long value; /* I value to print */ +{ + char Text[100]; + int nDig, expWidth, expVal, sNcol; + + assert(width > 0); + + sprintf(Text, "%d", value); + if ((nDig = strlen(Text)) <= width) { + strcpy(text, Text); + return; + } + if (width == 1) { + if (value > 0) + strcpy(text, "+"); + else + strcpy(text, "-"); + return; + } + if (width == 2 && value < 0) { + strcpy(text, "-"); + return; + } + if (value < 0) + sNcol = 1; + else + sNcol = 0; + expVal = nDig - width + 2; + if (expVal <= 9) { + if (width-sNcol == 2) + expVal--; + sprintf(&Text[width-2], "E%d", expVal); + } + else { + expVal++; + if (width-sNcol == 2) + sprintf(&Text[sNcol], "E*"); + else { + if (width-sNcol == 3) + expVal--; + sprintf(&Text[width-3], "E%d", expVal); + } + } + strcpy(text, Text); + + return; +}