fcvt.c — floating-point to ASCII conversion in C

[ translations available in: serbo-croatian ]

fcvt.c is an implementation of the (recently-deprecated) POSIX functions ecvt() and fcvt() that are useful in converting IEEE-754 double-precision floating point numbers to human-readable ASCII formats.

These functions are ostensibly replaced by equivalent functionality in sprintf(), although that isn't much consolation at all if you happen to be trying to implement a set of printf()-like functions of your own without recourse to anything in stdio. As I was. Hence this implementation, which should be good as-is, or as a starting point for translation to other programming langauges.

The interface and behaviour are identical, and the names similar, to the functions that they replace. For details see your local ecvt(3) manual page. If you don't have one handy, there might still be one available here.

Two versions are available: "small/fast" and "painfully accurate". Both have been tested on 32- and 64-bit machines of both orientations.

Small, fast and mostly accurate

char *e_cvt(double value, int ndigit, int *decpt, int *sign);
char *f_cvt(double value, int ndigit, int *decpt, int *sign);
This version uses floating-point arithmetic and is accurate to the number of significant decimal digits that can be represented precisely by the fraction part of the stored binary number. This version will not properly convert a precisely-represented scaled binary number whose correct decimal representation exceeds the 6 (or 15) significant decimal digits that correspond to the 24 (or 53) significant bits in the stored representation.
Download the source code: fcvt-1.1.tar.gz
Browse the source code: fcvt-1.1
Sorry, there is no manual page. If you really want one for some reason, send me a note and I'll whip one up.
You will have to link against a math library (e.g., fdlibm or your local libm) to use this version.

Painfully accurate

char *fcvtf(float  value, int ndigit, int *decpt, int *sign);
char *ecvtf(float  value, int ndigit, int *decpt, int *sign);
char *fcvtd(double value, int ndigit, int *decpt, int *sign);
char *ecvtd(double value, int ndigit, int *decpt, int *sign);
This version is larger and slower and uses multiple-precision integer arithmetic to avoid any loss of precision. It will reproduce the exact decimal equivalent of any precisely-stored scaled binary number, in both the integral and fractional parts. It works by converting the floating-point number into a 256-bit (2048-bit for doubles) fixed-point number (by multiplying the "mantissa" by its binary exponent), and then converting that to decimal (retaining arbitary amounts of precision, as required, throughout the process).

(Repeated integer multiplication by ten, used during the conversion of the binary fractional part to decimal, necessitates two additional bits of precision for every multiplication performed. Some versions of fcvt discard these least significant bits, leading to improper rounding at best and random junk in the output at worst.)

This version #includes just those functions it needs from a multiple-precision integer library. You will have to download that library and edit fcvt2's Makefile to tell the compiler where to find the included files.

Download the source code: fcvt2-1.0.tar.gz
Browse the source code: fcvt2-1.0
Sorry, there is no manual page. If you really want one for some reason, send me a note and I'll whip one up.

Epilogue

fcvt and fcvt2 are distributed under the MIT license. Neither will infect you (or your project) with a contagious disease.

If you find bugs or have suggestions, please send them to Ian at the domain name of this web site. Thanks!


Translations

This page has been translated into: