不久前,我有机会编写了一段类似的代码,您和其他人可能会觉得有用。它将表示浮点数的字符串作为程序的第一个参数,并将字符串转换为其IEEE-754 单精度浮点表示及其等效整数值。看看,如果您有任何问题,请告诉我。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
/* constants for word and double-word size */
#define WDSZ 64
#define DWSZ 128
inline int getmsb (unsigned long x);
char *fmt_binstr (unsigned long n, unsigned char sz, unsigned char szs, char sep);
char *binstr (unsigned long n);
char *fpfrc_bin (float fvalue);
void show_fltmem (float f);
void show_ieee754str (char *s);
void show_ieee754 (float f);
float xstrtof (char *str);
char *form_ieee754SPstr (int sign, char *exp, char *dec, char *frac);
int main (int argc, char** argv) {
if (argc < 2) {
fprintf (stderr, "error: insufficient input. Usage: %s float\n", argv[0]);
return 1;
}
char *dp = strchr (argv[1], '.'); /* pointer to decimal point */
int dec = atoi (argv[1]); /* integer of decimal part */
int frc = (dp) ? atoi (dp + 1) : 0; /* integer of fraction part */
/* output string input values */
printf ("\nString Values:\n");
printf (" string : %s\n whole : %d\n fraction : %d\n\n", argv[1], dec, frc);
float fvalue = xstrtof (argv[1]);
float ffrc = fvalue - dec;
int signbit = (fvalue >= 0) ? 0 : 1;
/* output float input values */
printf ("Float Values:\n");
printf (" decimal : %d\n fraction : %f\n\n", dec, ffrc);
char *fstring = fpfrc_bin (fvalue); /* fraction part in binary */
char *bs = binstr ((unsigned long) dec); /* decimal part in binary */
/* output binary values decimal part/fraction part */
printf ("Binary Values:\n");
printf (" decimal : %s\n fraction : %s\n sign bit : %d\n\n", bs, fstring, signbit);
/* quick hack of exp bias, biased value, conversion to binary */
int bias = (int) strlen (bs) - 1;
int biasexp = 127+bias;
char *binexp = binstr ((unsigned long) biasexp);
/* output summary of biased IEEE-754 exponent */
printf ("Normalization for biased exponent:\n");
printf ("\n %s.%s => %s.%s%s\n\n", bs, fstring, "1", (bs+1), fstring);
printf (" exponent bias: %d\n unbiased exponent: 127\n", bias);
printf (" __________________+____\n\n");
printf (" biased exponent: %3d\n binary exponent: %s\n\n", biasexp, binexp);
/* output summary of IEEE-754 mantissa */
printf ("Conversion to 'hidden bit' format to form mantissa:\n\n");
printf (" %s.%s%s => %s%s\n\n", "1", (bs+1), fstring, (bs+1), fstring);
/* form IEEE-754 binary representation from values computed */
char *ieee754str = form_ieee754SPstr (signbit, binexp, bs, fstring);
/* output formatted complete IEEE-754 binary - from computed values above */
printf ("IEEE-754 Single Precision Floating Point Representation (caclulated value)\n\n");
show_ieee754str (ieee754str);
/* output formatted complete IEEE-754 binary - from float value in memory */
printf ("IEEE-754 Single Precision Floating Point Representation (memory value)\n\n");
show_ieee754 (fvalue);
/* output float, binary and integer equivalent */
show_fltmem (fvalue);
if (bs) free (bs);
if (binexp) free (binexp);
if (ieee754str) free (ieee754str);
return 0;
}
/** single-precision float in memory
* output the float, equivalent unsigned int, and
* binary representation of the number in memory
*/
void show_fltmem (float f)
{
unsigned int i = *(unsigned int *)&f;
printf ("\nRepresentations of float value in memory:\n\n");
printf (" The float value entered : %f\n\n", f);
printf (" binary value in memory : %s\n\n", fmt_binstr (i, 32, 8, '-'));
printf (" bits as unsigned int : %u\n\n", i);
}
/** most significant bit.
* return the 0-based most significant bit for any
* unsigned value using the bit-scan-right assembly
* directive.
*/
inline int getmsb (unsigned long x)
{
#ifdef BUILD_64
asm ("bsrq %0, %0" : "=r" (x) : "0" (x));
#else
asm ("bsr %0, %0" : "=r" (x) : "0" (x));
#endif
return x;
}
/** returns pointer to formatted binary representation of 'n' zero padded to 'sz'.
* returns pointer to string contianing formatted binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits with char
* 'sep' placed every 'szs' digits. (e.g. 10001010 -> 1000-1010).
*/
char *fmt_binstr (unsigned long n, unsigned char sz, unsigned char szs, char sep) {
static char s[DWSZ + 1] = {0};
char *p = s + DWSZ;
unsigned char i;
for (i = 0; i < sz; i++) {
p--;
if (i > 0 && szs > 0 && i % szs == 0)
*p-- = sep;
*p = (n >> i & 1) ? '1' : '0';
}
return p;
}
/** returns an allocated string containing unpadded binary
* representation of the integer value 'n'. This value must
* be assigned to a pointer and freed to prevent leaks.
*/
char *binstr (unsigned long n)
{
unsigned char msb = getmsb (n);
char *s = calloc (msb + 2, sizeof *s);
char *p = s + msb;
unsigned char i;
for (i = 0; i < msb+1; i++) {
*p-- = (n >> i & 1) ? '1' : '0';
}
return s;
}
/** return string containing binary representation of fraction
* The function takes a float as an argument and computes the
* binary representation of the fractional part of the float,
* On success, the function returns a null-terminated string
* containing the binary value, or NULL otherwise. MAXD of 24
* (23 + null-term) for Single-Precision mantissa, 53
* (52 + null-term) for Double-Precision mantissa.
*/
char *fpfrc_bin (float fvalue)
{
float fv = fvalue - (int)fvalue;
int MAXD = 24;
char *fvs = calloc (MAXD, sizeof *fvs);
if (!fvs) {
fprintf (stderr, "%s()_error: allocation failed.\n", __func__);
return NULL;
}
char *p = fvs;
unsigned char it = 0;
while (fv > 0 && it < MAXD)
{
fv = fv * 2.0;
*p++ = ((int)fv) ? '1' : '0';
fv = ((int)fv >= 1) ? fv - 1.0 : fv;
it++;
}
return fvs;
}
/** formatted output of ieee-754 representation of float from binary string.
*/
void show_ieee754str (char *s)
{
printf (" ");
while (*s)
printf (" %c", *s++);
printf ("\n");
printf (" |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|\n");
printf (" |s| exp | mantissa |\n\n");
}
/** formatted output of ieee-754 representation of float from stored value.
*/
void show_ieee754 (float f)
{
printf (" ");
int i = 32;
while (i) {
i--;
printf ("%d ", ((*(int *)&f >> i) & 0x1));
}
printf ("\n");
printf (" |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|\n");
printf (" |s| exp | mantissa |\n\n");
}
/** string to float with error checking. */
float xstrtof (char *str)
{
char *endptr = NULL;
errno = 0;
float val = strtof (str, &endptr);
/* Check for various possible errors */
if ((errno == ERANGE && (val == HUGE_VALF || val == HUGE_VALL)) ||
(errno != 0 && val == 0)) {
perror ("strtof");
exit (EXIT_FAILURE);
}
if (endptr == str) {
fprintf (stderr, "No digits were found\n");
exit (EXIT_FAILURE);
}
return val;
}
/** form IEEE-754 binary representation from computed values for the
* sign bit, biased exponent binary string, decimal binary string, and
* fractional binary string, forming the 23-bit mantissa from the decimal
* and fractional strings, filling with '0' as needed. An allocated
* string containing the IEEE-754 Single-Precision representation is
* returned.
*/
char *form_ieee754SPstr (int sign, char *exp, char *dec, char *frac)
{
char *str = calloc (33, sizeof *str);
char *p = str + 1;
char *sp = dec + 1; /* leading 1 - hidden bit */
size_t fsl = strlen (frac); /* length of fractional str */
size_t manbits = fsl + strlen (sp); /* available mantissa bits */
size_t mdiff = 23 - manbits; /* diff from required 23 */
*str = (sign == 0) ? '0' : '1'; /* set sign bit in string */
memcpy (p, exp, 8); /* set biased exponent */
p += 8;
while (*sp) { *p = *sp++; p++; }; /* mantissa - decimal bits */
if (manbits < 23) /* test < 23 bits available */
{
memcpy (p, frac, fsl); /* copy fractional bits */
p += fsl; /* increment pointer */
register size_t it = 0;
if (mdiff > 0) /* fill remaining mantissa */
for (it = 0; it < mdiff; it++)
{
*p = '0';
p++;
}
}
else
{
memcpy (p, frac, 23); /* fill mantissa w/23 bits */
}
return str;
}
示例使用/输出
$ ./bin/ieee754cvt 123.456
String Values:
string : 123.456
whole : 123
fraction : 456
Float Values:
decimal : 123
fraction : 0.456001
Binary Values:
decimal : 1111011
fraction : 01110100101111001
sign bit : 0
Normalization for biased exponent:
1111011.01110100101111001 => 1.11101101110100101111001
exponent bias: 6
unbiased exponent: 127
__________________+____
biased exponent: 133
binary exponent: 10000101
Conversion to 'hidden bit' format to form mantissa:
1.11101101110100101111001 => 11101101110100101111001
IEEE-754 Single Precision Floating Point Representation (caclulated value)
0 1 0 0 0 0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 0 0 1 0 1 1 1 1 0 0 1
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
|s| exp | mantissa |
IEEE-754 Single Precision Floating Point Representation (memory value)
0 1 0 0 0 0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 0 0 1 0 1 1 1 1 0 0 1
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
|s| exp | mantissa |
Representations of float value in memory:
The float value entered : 123.456001
binary value in memory : 01000010-11110110-11101001-01111001
bits as unsigned int : 1123477881