398 lines
12 KiB
C
398 lines
12 KiB
C
/* $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
|
||
* .03 03-09-92 rac fix bug where decPl was sometimes ignored
|
||
*
|
||
* 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.)))
|
||
#else
|
||
/* really nint and exp10 aren't ANSI-C or POSIX */
|
||
# ifndef sun
|
||
# define nint(value) (value>=0 ? (int)((value)+.5) : (int)((value)-.5))
|
||
# define exp10(value) (exp(value * log(10.)))
|
||
# endif
|
||
#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;
|
||
if (decPlaces > decPl)
|
||
decPlaces = decPl;
|
||
(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;
|
||
}
|