[MUD-Dev] Re: [CODE QUESTION] How to encode floats into bytes?

J C Lawrence claw at under.engr.sgi.com
Wed Sep 9 10:26:19 CEST 1998


On Sun, 6 Sep 1998 22:06:47 -0700 (MST) 
Ben Greear<greear at cyberhighway.net> wrote:

> What is the standard way (if there is one) to encode floating point
> numbers (double too I guess) into bytes for transport accross the
> network.

I'm not aware of one.  Certainly Stevens doesn't mention the area in
his TCP/IP or Network Programming books.  

A point you are going to need to be careful of is that the sotrage
format for floating point values (float, double, long double) are only
poorly standardised.  There are acutally _many_ formats (I'm aware of
5 in reasonably common usage) used to store floating point values,
even ignoring the two's complement/one's complement schism.  The ANSI
C++ spec has very little to say on the area:

--<cut>--

3.9.1.8 (Fundamental Types)

There are three floating point types: float, double, and long double.
The type double provides at least as much precision as float, and the
type long double provides at least as much precision as double.  The
set of values of the type float is a subset of the set of values of
the type double; the set of values of the type double is a subset of
the set of values of the type long double.  The value representation
of floating-point types is implementation-defined.  Integral and
floating types are collectively called arithmetic types.  Specializa-
tions of the standard template numeric_limits (_lib.support.limits_)
shall specify the maximum and minimum values of each arithmetic type
for an implementation.

--<cut>--

That all said, the most common floating point format are the IEEE 4,
8, and 12 byte formats.  To give a little overview, the following code
will translate doubles between VAXD and IEEE format doubles, and
should lead you where you need to go:

--<cut>--

double d_vaxd_i3e (struct {
    unsigned uj_right :3;
    unsigned uj_left :4;
    unsigned uj_exponent :8;
    unsigned ub_sign :1;
    struct {
      unsigned uj_right :3;
      unsigned uj_left :13;
    } as_mantissa[3];
  } s_vaxd) /* input -- a VAX D floating point number */
{
  struct {
    struct {
      unsigned uj_right :13;
      unsigned uj_left :3;
    } as_mantissa[3];
    unsigned uj_mantissa :4;
    unsigned uj_exponent :11;
    unsigned ub_sign :1;
  } s_i3e;
  double d_i3e;

/* if input is zero, then return zero */

  if (*((long *)(&s_vaxd)) == 0L && *((long *)(&s_vaxd) + 1) == 0) {
    return (0.);
  }

/* copy the sign bit */

  s_i3e.ub_sign = s_vaxd.ub_sign;

/* copy the exponent */

  s_i3e.uj_exponent = s_vaxd.uj_exponent + 1024 - 130;

/* fill in the first word of the mantissa */

  s_i3e.uj_mantissa = s_vaxd.uj_left;

/* fill in the second word of the mantissa */

  s_i3e.as_mantissa[2].uj_left = s_vaxd.uj_right;
  s_i3e.as_mantissa[2].uj_right = s_vaxd.as_mantissa[0].uj_left;

/* fill in the third word of the mantissa */

  s_i3e.as_mantissa[1].uj_left = s_vaxd.as_mantissa[0].uj_right;
  s_i3e.as_mantissa[1].uj_right = s_vaxd.as_mantissa[1].uj_left;

/* fill in the fourth word of the mantissa */

  s_i3e.as_mantissa[0].uj_left = s_vaxd.as_mantissa[1].uj_right;
  s_i3e.as_mantissa[0].uj_right = s_vaxd.as_mantissa[2].uj_left;

/* return the IEEE */

  memcpy ((char *)&d_i3e, (char *)&s_i3e, 8);
  return (d_i3e);
}



double d_i3e_vaxd (
  struct {
    struct {
      unsigned uj_right :13;
      unsigned uj_left :3;
    } as_mantissa[3];
    unsigned uj_mantissa :4;
    unsigned uj_exponent :11;
    unsigned ub_sign :1;
  } s_i3e) /* input -- an IEEE floating point number */
{
  struct {
    unsigned uj_mantissa :7;
    unsigned uj_exponent :8;
    unsigned ub_sign :1;
    unsigned short auj2_mantissa[3];
  } s_vaxd;
  double d_vaxd;

/* if input is zero, then return zero */

  if (*((double *)(&s_i3e)) == 0.) return (0.);

/* copy the sign bit from I3E to VAXD */

  s_vaxd.ub_sign = s_i3e.ub_sign;

/* copy the exponent from I3E to VAXD */

  s_vaxd.uj_exponent = s_i3e.uj_exponent - 1024 + 130;

/* copy the first part of the mantissa from I3E to VAXD */

  s_vaxd.uj_mantissa = s_i3e.uj_mantissa;
  s_vaxd.uj_mantissa <<= 3;
  s_vaxd.uj_mantissa |= s_i3e.as_mantissa[2].uj_left;

/* copy the second part of the mantissa from I3E to VAXD */

  s_vaxd.auj2_mantissa[0] = s_i3e.as_mantissa[2].uj_right;
  s_vaxd.auj2_mantissa[0] <<= 3;
  s_vaxd.auj2_mantissa[0] |= s_i3e.as_mantissa[1].uj_left;

/* copy the third part of the mantissa from I3E to VAXD */

  s_vaxd.auj2_mantissa[1] = s_i3e.as_mantissa[1].uj_right;
  s_vaxd.auj2_mantissa[1] <<= 3;
  s_vaxd.auj2_mantissa[1] |= s_i3e.as_mantissa[0].uj_left;

/* copy the fourth part of the mantissa from I3E to VAXD */

  s_vaxd.auj2_mantissa[2] = s_i3e.as_mantissa[0].uj_right;
  s_vaxd.auj2_mantissa[2] <<= 3;

/* return the VAXD */

  memcpy ((char *)&d_vaxd, (char *)&s_vaxd, 8);
  return (d_vaxd);
}

--<cut>--

> I'm using c++, on both ends (encode/decode).

Unfortunately that doesn't help a whole lot.

> It would seem like there would be a method to do this somewhere!

Yup: roll your own or rely on everybody using IEEE floats (which in
the microcomputer (as versus mini or host) world is getting close to
universal).

--
J C Lawrence                               Internet: claw at null.net
(Contractor)                               Internet: coder at ibm.net
---------(*)                     Internet: claw at under.engr.sgi.com
...Honourary Member of Clan McFud -- Teamer's Avenging Monolith...




More information about the mud-dev-archive mailing list