/* $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 # 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.))) #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; }