Files
epics-base/src/libCom/cvtFast/cvtFast.c
Andrew Johnson cffa2e8f46 Fix typo in cvtFast.c
Probably only affects MEDM
2017-09-19 16:38:27 -05:00

524 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Fast numeric to string conversions
*
* Original Authors:
* Bob Dalesio, Mark Anderson and Marty Kraimer
* Date: 12 January 1993
*/
#include <string.h>
#include <limits.h>
#define epicsExportSharedSymbols
#include "cvtFast.h"
#include "epicsMath.h"
#include "epicsStdio.h"
/*
* These routines convert numbers up to +/- 10,000,000.
* They defer to sprintf() for numbers requiring more than
* 8 places of precision.
*/
static epicsInt32 frac_multiplier[] =
{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
int cvtFloatToString(float flt_value, char *pdest,
epicsUInt16 precision)
{
int got_one, i;
epicsInt32 whole, iplace, number, fraction, fplace;
float ftemp;
char *startAddr;
/* can this routine handle this conversion */
if (isnan(flt_value) || precision > 8 ||
flt_value > 10000000.0 || flt_value < -10000000.0) {
if (precision > 8 || flt_value >= 1e8 || flt_value <= -1e8) {
if (precision > 12) precision = 12; /* FIXME */
sprintf(pdest, "%*.*e", precision+6, precision, (double) flt_value);
} else {
if (precision > 3) precision = 3; /* FIXME */
sprintf(pdest, "%.*f", precision, (double) flt_value);
}
return((int)strlen(pdest));
}
startAddr = pdest;
/* determine the sign */
if (flt_value < 0){
*pdest++ = '-';
flt_value = -flt_value;
};
/* remove the whole number portion */
whole = (epicsInt32)flt_value;
ftemp = flt_value - whole;
/* multiplier to convert fractional portion to integer */
fplace = frac_multiplier[precision];
fraction = (epicsInt32)(ftemp * fplace * 10);
fraction = (fraction + 5) / 10; /* round up */
/* determine rounding into the whole number portion */
if ((fraction / fplace) >= 1){
whole++;
fraction -= fplace;
}
/* whole numbers */
got_one = 0;
for (iplace = 10000000; iplace >= 1; iplace /= 10){
if (whole >= iplace){
got_one = 1;
number = whole / iplace;
whole = whole - (number * iplace);
*pdest = number + '0';
pdest++;
}else if (got_one){
*pdest = '0';
pdest++;
}
}
if (!got_one){
*pdest = '0';
pdest++;
}
/* fraction */
if (precision > 0){
/* convert fractional portional to ASCII */
*pdest = '.';
pdest++;
for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){
number = fraction / fplace;
fraction -= number * fplace;
*pdest = number + '0';
pdest++;
}
}
*pdest = 0;
return((int)(pdest - startAddr));
}
int cvtDoubleToString(
double flt_value,
char *pdest,
epicsUInt16 precision)
{
epicsUInt16 got_one,i;
epicsInt32 whole,iplace,number,fraction,fplace;
double ftemp;
char *startAddr;
/* can this routine handle this conversion */
if (isnan(flt_value) || precision > 8 || flt_value > 10000000.0 || flt_value < -10000000.0) {
if (precision > 8 || flt_value > 1e16 || flt_value < -1e16) {
if(precision>17) precision=17;
sprintf(pdest,"%*.*e",precision+7,precision,
flt_value);
} else {
if(precision>3) precision=3;
sprintf(pdest,"%.*f",precision,flt_value);
}
return((int)strlen(pdest));
}
startAddr = pdest;
/* determine the sign */
if (flt_value < 0){
*pdest++ = '-';
flt_value = -flt_value;
};
/* remove the whole number portion */
whole = (epicsInt32)flt_value;
ftemp = flt_value - whole;
/* multiplier to convert fractional portion to integer */
fplace = frac_multiplier[precision];
fraction = (epicsInt32)(ftemp * fplace * 10);
fraction = (fraction + 5) / 10; /* round up */
/* determine rounding into the whole number portion */
if ((fraction / fplace) >= 1){
whole++;
fraction -= fplace;
}
/* whole numbers */
got_one = 0;
for (iplace = 10000000; iplace >= 1; iplace /= 10){
if (whole >= iplace){
got_one = 1;
number = whole / iplace;
whole = whole - (number * iplace);
*pdest = number + '0';
pdest++;
}else if (got_one){
*pdest = '0';
pdest++;
}
}
if (!got_one){
*pdest = '0';
pdest++;
}
/* fraction */
if (precision > 0){
/* convert fractional portional to ASCII */
*pdest = '.';
pdest++;
for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){
number = fraction / fplace;
fraction -= number * fplace;
*pdest = number + '0';
pdest++;
}
}
*pdest = 0;
return((int)(pdest - startAddr));
}
/*
* These routines are provided for backwards compatibility,
* extensions such as MEDM, edm and histtool use them.
*/
/*
* cvtFloatToExpString
*
* Converts a float to a %e formatted string
*/
int cvtFloatToExpString(float val, char *pdest, epicsUInt16 precision)
{
return epicsSnprintf(pdest, MAX_STRING_SIZE, "%.*e", precision, val);
}
/*
* cvtFloatToCompactString
*
* Converts a float to a %g formatted string.
* The result uses %f notation for 10e-4 < |value| < 10e+4,
* otherwise %e notation.
*/
int cvtFloatToCompactString(float val, char *pdest, epicsUInt16 precision)
{
if ((val < 1.e4 && val > 1.e-4) ||
(val > -1.e4 && val < -1.e-4) ||
val == 0.0)
return cvtFloatToString(val, pdest, precision);
return cvtFloatToExpString(val, pdest, precision);
}
/*
* cvtDoubleToExpString
*
* Converts a double to a %e formatted string
*/
int cvtDoubleToExpString(double val, char *pdest, epicsUInt16 precision)
{
return epicsSnprintf(pdest, MAX_STRING_SIZE, "%.*e", precision, val);
}
/*
* cvtDoubleToCompactString
*
* Converts a double to %g formatted string.
* The result uses %f notation for 10e-4 < |value| < 10e+4,
* otherwise %e notation.
*/
int cvtDoubleToCompactString(double val, char *pdest, epicsUInt16 precision)
{
if ((val < 1.e4 && val > 1.e-4) ||
(val > -1.e4 && val < -1.e-4) ||
val == 0.0)
return cvtDoubleToString(val, pdest, precision);
return cvtDoubleToExpString(val, pdest, precision);
}
/* Integer conversion primitives */
static size_t
UInt32ToDec(epicsUInt32 val, char *pdest)
{
int i;
char digit[10];
size_t len;
for (i = 0; val; i++) {
epicsUInt32 tenth = val / 10;
digit[i] = val - tenth * 10 + '0';
val = tenth;
}
len = i;
while (i > 0)
*pdest++ = digit[--i];
*pdest = 0;
return len;
}
static size_t
UInt32ToBase(epicsUInt32 val, char *pdest, int base)
{
int i;
char digit, digits[32];
size_t len;
for (i = 0; val; i++) {
epicsUInt32 tenth = val / base;
digit = val - tenth * base;
digits[i] = digit < 10 ? digit + '0' : digit - 10 + 'a';
val = tenth;
}
len = i;
while (i > 0)
*pdest++ = digits[--i];
*pdest = 0;
return len;
}
static size_t
UInt64ToDec(epicsUInt64 val, char *pdest)
{
int i;
char digit[20];
size_t len;
for (i = 0; val; i++) {
epicsUInt64 tenth = val / 10;
digit[i] = val - tenth * 10 + '0';
val = tenth;
}
len = i;
while (i > 0)
*pdest++ = digit[--i];
*pdest = 0;
return len;
}
static size_t
UInt64ToBase(epicsUInt64 val, char *pdest, int base)
{
int i;
char digit, digits[64];
size_t len;
for (i = 0; val; i++) {
epicsUInt64 tenth = val / base;
digit = val - tenth * base;
digits[i] = digit < 10 ? digit + '0' : digit - 10 + 'a';
val = tenth;
}
len = i;
while (i > 0)
*pdest++ = digits[--i];
*pdest = 0;
return len;
}
/* Integer conversion routines */
size_t
cvtUInt32ToString(epicsUInt32 val, char *pdest)
{
if (val == 0) {
*pdest++ = '0';
*pdest = 0;
return 1;
}
return UInt32ToDec(val, pdest);
}
size_t
cvtInt32ToString(epicsInt32 val, char *pdest)
{
if (val == 0) {
*pdest++ = '0';
*pdest = 0;
return 1;
}
if (val > 0)
return UInt32ToDec(val, pdest);
if (val == -0x80000000) {
strcpy(pdest, "-2147483648");
return strlen(pdest);
}
*pdest++ = '-';
return 1 + UInt32ToDec(-val, pdest);
}
size_t
cvtUInt64ToString(epicsUInt64 val, char *pdest)
{
if (val == 0) {
*pdest++ = '0';
*pdest = 0;
return 1;
}
return UInt64ToDec(val, pdest);
}
size_t
cvtInt64ToString(epicsInt64 val, char *pdest)
{
if (val == 0) {
*pdest++ = '0';
*pdest = 0;
return 1;
}
if (val > 0)
return UInt64ToDec(val, pdest);
if (val == -0x8000000000000000LL) {
strcpy(pdest, "-9223372036854775808");
return strlen(pdest);
}
*pdest++ = '-';
return 1 + UInt64ToDec(-val, pdest);
}
size_t
cvtInt32ToHexString(epicsInt32 val, char *pdest)
{
if (val < 0)
*pdest++ = '-';
*pdest++ = '0';
*pdest++ = 'x';
if (val == 0) {
*pdest++ = '0';
*pdest = 0;
return 3;
}
if (val > 0)
return 2 + UInt32ToBase(val, pdest, 16);
if (val == -0x80000000) {
strcpy(pdest, "80000000");
return 11;
}
return 3 + UInt32ToBase(-val, pdest, 16);
}
size_t
cvtUInt32ToHexString(epicsUInt32 val, char *pdest)
{
*pdest++ = '0';
*pdest++ = 'x';
if (val == 0) {
*pdest++ = '0';
*pdest = 0;
return 3;
}
return 2 + UInt32ToBase(val, pdest, 16);
}
size_t
cvtInt32ToOctalString(epicsInt32 val, char *pdest)
{
if (val == 0) {
*pdest++ = '0';
*pdest = 0;
return 1;
}
if (val > 0) {
*pdest++ = '0';
return 1 + UInt32ToBase(val, pdest, 8);
}
if (val == -0x80000000) {
strcpy(pdest, "-020000000000");
return strlen(pdest);
}
*pdest++ = '-';
*pdest++ = '0';
return 2 + UInt32ToBase(-val, pdest, 8);
}
size_t
cvtInt64ToHexString(epicsInt64 val, char *pdest)
{
if (val < 0)
*pdest++ = '-';
*pdest++ = '0';
*pdest++ = 'x';
if (val == 0) {
*pdest++ = '0';
*pdest = 0;
return 3;
}
if (val > 0)
return 2 + UInt64ToBase(val, pdest, 16);
if (val == -0x8000000000000000LL) {
strcpy(pdest, "8000000000000000");
return 19;
}
return 3 + UInt64ToBase(-val, pdest, 16);
}
size_t
cvtUInt64ToHexString(epicsUInt64 val, char *pdest)
{
*pdest++ = '0';
*pdest++ = 'x';
if (val == 0) {
*pdest++ = '0';
*pdest = 0;
return 3;
}
return 2 + UInt64ToBase(val, pdest, 16);
}