Initial revision

This commit is contained in:
Roger Cole
1992-02-25 16:32:51 +00:00
parent e4431f41c5
commit 484d033b89

388
src/libCom/cvtNumbers.c Normal file
View File

@@ -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 <vxWorks.h>
# include <stdioLib.h>
#else
# include <stdio.h>
# include <math.h>
#endif
#include <genDefs.h>
#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;
}