[Xorp-hackers] [PATCH] Support for IEEE754 binary64 format in XRLs

ss at comp.lancs.ac.uk ss at comp.lancs.ac.uk
Wed Aug 31 04:55:03 PDT 2011


From: Steven Simpson <ss at comp.lancs.ac.uk>

* New atom type fp64

* <libxipc/fp64.h> selects alias fp64_t for most compatible
  native C type.  Native type's characteristics are echoed with
  corresponding macros (analogous to DBL_MIN, etc).

* <libxipc/fp64serial.h> (de)serializes fp64_t into
  uint_fast64_t.

* New methods for fp64_t added on XrlAtom and XrlArgs.

* Added fp64 to xif types, mapping to fp64_t in C++ and double
  for Thrift.

* Extended atom and args tests to include fp64_t.

* Added fp64_t serialization test.  (It always succeeds for now,
  but might be useful for diagnostics.)

* Added method to test XIF to demonstrate fp64 type.

Signed-off-by: Steven Simpson <ss at comp.lancs.ac.uk>
---
 xorp/libxipc/SConscript             |    1 +
 xorp/libxipc/fp64.h                 |  198 ++++++++++++++++++++++++++++++
 xorp/libxipc/fp64serial.c           |  184 ++++++++++++++++++++++++++++
 xorp/libxipc/fp64serial.h           |   40 ++++++
 xorp/libxipc/tests/SConscript       |    1 +
 xorp/libxipc/tests/test_fp64.cc     |  226 +++++++++++++++++++++++++++++++++++
 xorp/libxipc/tests/test_xrl_args.cc |    5 +-
 xorp/libxipc/tests/test_xrl_atom.cc |    4 +
 xorp/libxipc/xrl_args.cc            |   28 +++++
 xorp/libxipc/xrl_args.hh            |   24 ++++
 xorp/libxipc/xrl_atom.cc            |   55 +++++++++-
 xorp/libxipc/xrl_atom.hh            |   19 +++-
 xorp/rtrmgr/xorp_client.cc          |    1 +
 xorp/xrl/interfaces/test.xif        |    5 +
 xorp/xrl/scripts/Xif/xiftypes.py    |    3 +-
 15 files changed, 790 insertions(+), 4 deletions(-)
 create mode 100644 xorp/libxipc/fp64.h
 create mode 100644 xorp/libxipc/fp64serial.c
 create mode 100644 xorp/libxipc/fp64serial.h
 create mode 100644 xorp/libxipc/tests/test_fp64.cc

diff --git a/xorp/libxipc/SConscript b/xorp/libxipc/SConscript
index 104bc8e..e7cf973 100644
--- a/xorp/libxipc/SConscript
+++ b/xorp/libxipc/SConscript
@@ -87,6 +87,7 @@ libxipc_sources = [
     'xrl_std_router.cc',
     'xrl_tokens.cc',
     'xuid.cc',				# only for udp (and fea tcpudp mgr)
+    'fp64serial.c',
     ]
 
 # deal with shared objects
diff --git a/xorp/libxipc/fp64.h b/xorp/libxipc/fp64.h
new file mode 100644
index 0000000..8e49a19
--- /dev/null
+++ b/xorp/libxipc/fp64.h
@@ -0,0 +1,198 @@
+// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
+// vim:set sts=4 ts=8:
+
+// Copyright (c) 2001-2011 XORP, Inc and Others
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License, Version
+// 2.1, June 1999 as published by the Free Software Foundation.
+// Redistribution and/or modification of this program under the terms of
+// any other version of the GNU Lesser General Public License is not
+// permitted.
+// 
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+// see the GNU Lesser General Public License, Version 2.1, a copy of
+// which can be found in the XORP LICENSE.lgpl file.
+// 
+// XORP, Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+// http://xorp.net
+
+// $XORP: xorp/libxipc/xrl_atom.hh,v 1.23 2008/10/30 20:49:07 pavlin Exp $
+
+#ifndef __LIBXIPC_FP64_H__
+#define __LIBXIPC_FP64_H__
+
+#include <stdint.h>
+#include <float.h>
+
+/* This header chooses a native real type (float, double, long double)
+   which best matches the IEEE754 binary64 capabilities. */
+
+
+
+/* These are the target characteristics of various IEEE754 types,
+   expressed in terms that make them comparable to the native real
+   types. */
+
+/* TODO: We only need the 64-bit details; the others could be in their
+   own header.  */
+
+#define XORP_IEEE754_BIN16_MANT_DIG 11
+#define XORP_IEEE754_BIN16_MAX_EXP 16
+#define XORP_IEEE754_BIN16_MIN_EXP -13
+
+#define XORP_IEEE754_BIN32_MANT_DIG 24
+#define XORP_IEEE754_BIN32_MAX_EXP 128
+#define XORP_IEEE754_BIN32_MIN_EXP -125
+
+#define XORP_IEEE754_BIN64_MANT_DIG 53
+#define XORP_IEEE754_BIN64_MAX_EXP 1024
+#define XORP_IEEE754_BIN64_MIN_EXP -1021
+
+#define XORP_IEEE754_BIN128_MANT_DIG 113
+#define XORP_IEEE754_BIN128_MAX_EXP 16384
+#define XORP_IEEE754_BIN128_MIN_EXP -16381
+
+
+/* TODO: These ratios and test macros are not binary64-specific.  If
+   other types were to be supported, these macros should be factored
+   out. */
+
+/* These are 100000*log2(FLT_RADIX) for various possible FLT_RADIX
+   values.  In comparing the capabilities of float, double and long
+   double with binary64, we need to account for the slim possibility
+   that our native base is not 2, while binary64's base is 2. */
+
+#define XORP_IEEE754_RADIX_RATIO_2  1000000
+#define XORP_IEEE754_RADIX_RATIO_3  1584963
+#define XORP_IEEE754_RADIX_RATIO_4  2000000
+#define XORP_IEEE754_RADIX_RATIO_5  2321928
+#define XORP_IEEE754_RADIX_RATIO_6  2584963
+#define XORP_IEEE754_RADIX_RATIO_7  2807354
+#define XORP_IEEE754_RADIX_RATIO_8  3000000
+#define XORP_IEEE754_RADIX_RATIO_9  3169925
+#define XORP_IEEE754_RADIX_RATIO_10 3321928
+
+#define XORP_IEEE754_RADIX_RATIO_N(B) (XORP_IEEE754_RADIX_RATIO_ ## B)
+#define XORP_IEEE754_RADIX_RATIO(B) (XORP_IEEE754_RADIX_RATIO_N(B))
+
+
+/* These preprocessor-safe macros test various native types'
+   characteristics against IEEE754 types'. */
+
+#define XORP_IEEE754_TEST_MANT_DIG(T,W) \
+    ( T ## _MANT_DIG * XORP_IEEE754_RADIX_RATIO(FLT_RADIX) >=		\
+      XORP_IEEE754_BIN ## W ## _MANT_DIG * XORP_IEEE754_RADIX_RATIO_2 )
+
+#define XORP_IEEE754_TEST_MAX_EXP(T,W) \
+    ( T ## _MAX_EXP * XORP_IEEE754_RADIX_RATIO(FLT_RADIX) >=		\
+      XORP_IEEE754_BIN ## W ## _MAX_EXP * XORP_IEEE754_RADIX_RATIO_2 )
+
+#define XORP_IEEE754_TEST_MIN_EXP(T,W) \
+    ( T ## _MIN_EXP * XORP_IEEE754_RADIX_RATIO(FLT_RADIX) <=		\
+      XORP_IEEE754_BIN ## W ## _MIN_EXP * XORP_IEEE754_RADIX_RATIO_2)
+
+#define XORP_IEEE754_TEST(T,W)	    \
+    ( XORP_IEEE754_TEST_MANT_DIG(T,W) && \
+      XORP_IEEE754_TEST_MAX_EXP(T,W) &&  \
+      XORP_IEEE754_TEST_MIN_EXP(T,W) )
+
+/* Now we choose a native type to fulfil binary64. */
+
+#if XORP_IEEE754_TEST(DBL,64)
+/* double is sufficient, and is probably the optimal FP type used by
+   this system. */
+#define XORP_IEEE754_BIN64_DBL 1
+#else
+/* We'll have to use long double, and hope that it is adequate.  What
+   other choice do we have? */
+#define XORP_IEEE754_BIN64_LDBL 1
+#endif
+
+
+/* Declare a type alias according to what we've chosen.  Also define
+   some macros (like those in <inttypes.h>) to print and scan the
+   type. */
+
+#if XORP_IEEE754_BIN64_FLT
+typedef float fp64_t;
+#define XORP_PRIaFP64 "a"
+#define XORP_PRIeFP64 "e"
+#define XORP_PRIfFP64 "f"
+#define XORP_PRIgFP64 "g"
+#define XORP_PRIAFP64 "A"
+#define XORP_PRIEFP64 "E"
+#define XORP_PRIFFP64 "F"
+#define XORP_PRIGFP64 "G"
+#define XORP_SCNaFP64 "a"
+#define XORP_SCNeFP64 "e"
+#define XORP_SCNfFP64 "f"
+#define XORP_SCNgFP64 "g"
+#define XORP_FP64(F) F ## f
+#define XORP_FP64_DIG FLT_FP64_DIG
+#define XORP_FP64_EPSILON FLT_FP64_EPSILON
+#define XORP_FP64_MANT_DIG FLT_FP64_MANT_DIG
+#define XORP_FP64_MAX FLT_FP64_MAX
+#define XORP_FP64_MAX_10_EXP FLT_FP64_MAX_10_EXP
+#define XORP_FP64_MAX_EXP FLT_FP64_MAX_EXP
+#define XORP_FP64_MIN FLT_FP64_MIN
+#define XORP_FP64_MIN_10_EXP FLT_FP64_MIN_10_EXP
+#define XORP_FP64_MIN_EXP FLT_FP64_MIN_EXP
+#endif
+
+#if XORP_IEEE754_BIN64_DBL
+typedef double fp64_t;
+#define XORP_PRIaFP64 "a"
+#define XORP_PRIeFP64 "e"
+#define XORP_PRIfFP64 "f"
+#define XORP_PRIgFP64 "g"
+#define XORP_PRIAFP64 "A"
+#define XORP_PRIEFP64 "E"
+#define XORP_PRIFFP64 "F"
+#define XORP_PRIGFP64 "G"
+#define XORP_SCNaFP64 "la"
+#define XORP_SCNeFP64 "le"
+#define XORP_SCNfFP64 "lf"
+#define XORP_SCNgFP64 "lg"
+#define XORP_FP64(F) F
+#define XORP_FP64_DIG DBL_FP64_DIG
+#define XORP_FP64_EPSILON DBL_FP64_EPSILON
+#define XORP_FP64_MANT_DIG DBL_FP64_MANT_DIG
+#define XORP_FP64_MAX DBL_FP64_MAX
+#define XORP_FP64_MAX_10_EXP DBL_FP64_MAX_10_EXP
+#define XORP_FP64_MAX_EXP DBL_FP64_MAX_EXP
+#define XORP_FP64_MIN DBL_FP64_MIN
+#define XORP_FP64_MIN_10_EXP DBL_FP64_MIN_10_EXP
+#define XORP_FP64_MIN_EXP DBL_FP64_MIN_EXP
+#endif
+
+#if XORP_IEEE754_BIN64_LDBL
+typedef long double fp64_t;
+#define XORP_PRIaFP64 "La"
+#define XORP_PRIeFP64 "Le"
+#define XORP_PRIfFP64 "Lf"
+#define XORP_PRIgFP64 "Lg"
+#define XORP_PRIAFP64 "LA"
+#define XORP_PRIEFP64 "LE"
+#define XORP_PRIFFP64 "LF"
+#define XORP_PRIGFP64 "LG"
+#define XORP_SCNaFP64 "La"
+#define XORP_SCNeFP64 "Le"
+#define XORP_SCNfFP64 "Lf"
+#define XORP_SCNgFP64 "Lg"
+#define XORP_FP64(F) F ## l
+#define XORP_FP64_DIG LDBL_FP64_DIG
+#define XORP_FP64_EPSILON LDBL_FP64_EPSILON
+#define XORP_FP64_MANT_DIG LDBL_FP64_MANT_DIG
+#define XORP_FP64_MAX LDBL_FP64_MAX
+#define XORP_FP64_MAX_10_EXP LDBL_FP64_MAX_10_EXP
+#define XORP_FP64_MAX_EXP LDBL_FP64_MAX_EXP
+#define XORP_FP64_MIN LDBL_FP64_MIN
+#define XORP_FP64_MIN_10_EXP LDBL_FP64_MIN_10_EXP
+#define XORP_FP64_MIN_EXP LDBL_FP64_MIN_EXP
+#endif
+
+
+#endif
diff --git a/xorp/libxipc/fp64serial.c b/xorp/libxipc/fp64serial.c
new file mode 100644
index 0000000..e61329f
--- /dev/null
+++ b/xorp/libxipc/fp64serial.c
@@ -0,0 +1,184 @@
+// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
+// vim:set sts=4 ts=8:
+
+// Copyright (c) 2001-2011 XORP, Inc and Others
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License, Version
+// 2.1, June 1999 as published by the Free Software Foundation.
+// Redistribution and/or modification of this program under the terms of
+// any other version of the GNU Lesser General Public License is not
+// permitted.
+// 
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+// see the GNU Lesser General Public License, Version 2.1, a copy of
+// which can be found in the XORP LICENSE.lgpl file.
+// 
+// XORP, Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+// http://xorp.net
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <math.h>
+#include <inttypes.h>
+
+#include "fp64serial.h"
+
+/* How big are the fields of IEEE754 binary64? */
+#define MANTISSA_BIT 52
+#define EXPONENT_BIT 11
+#define SIGN_BIT 1
+
+/* What's the offset for each field? */
+#define MANTISSA_SHIFT 0
+#define EXPONENT_SHIFT (MANTISSA_SHIFT + MANTISSA_BIT)
+#define SIGN_SHIFT (EXPONENT_SHIFT + EXPONENT_BIT)
+
+/* Compute masks for each field. */
+#define MANTISSA_MASK ((UINTMAX_C(1) << MANTISSA_BIT) - 1u)
+#define EXPONENT_MASK ((UINTMAX_C(1) << EXPONENT_BIT) - 1u)
+#define SIGN_MASK ((UINTMAX_C(1) << SIGN_BIT) - 1u)
+
+/* How much is the exponent biased? */
+#define EXPONENT_BIAS ((EXPONENT_MASK >> 1u) - 1u)
+
+
+uint_fast64_t fp64enc(fp64_t input)
+{
+    fp64_t d_mant;
+    unsigned int u_exp;
+    uint_fast64_t u_mant;
+    bool neg;
+    int s_exp;
+    uint_fast64_t bytes;
+
+    switch (fpclassify(input)) {
+    default:
+	abort();
+	break;
+
+    case FP_ZERO:
+	neg = signbit(input);
+	u_mant = 0;
+	u_exp = 0;
+	break;
+
+    case FP_INFINITE:
+	neg = signbit(input);
+	u_mant = 0;
+	u_exp = EXPONENT_MASK;
+	break;
+
+    case FP_NAN:
+	neg = false;
+	u_mant = 1;
+	u_exp = EXPONENT_MASK;
+	break;
+
+    case FP_SUBNORMAL:
+    case FP_NORMAL:
+	/* Handle normal and subnormal together.  The number might be
+	   one class for double, but another for binary64. */
+
+	/* Decompose the input into a significand (mantissa + 1) and
+	   an exponent. */
+	d_mant = XORP_FP64(frexp)(input, &s_exp);
+
+	/* Extract the sign bit from the mantissa. */
+	neg = signbit(input);
+	d_mant = XORP_FP64(fabs)(d_mant);
+
+	/* Offset the exponent so it can be represented as an unsigned
+	   value. */
+	s_exp += EXPONENT_BIAS;
+
+	/* Now we find out whether the number we represent is normal,
+	   subnormal, or overflows binary64. */
+	if (s_exp >= (long) EXPONENT_MASK) {
+	    /* The number is too big for binary64, so use the maximum
+	       value. */
+	    u_mant = MANTISSA_MASK;
+	    u_exp = EXPONENT_MASK - 1u;
+	} else if (s_exp <= 0) {
+	    /* The number is subnormal in binary64. */
+
+	    /* Shift the mantissa so that it's exponent would be 0. */
+	    u_mant = XORP_FP64(ldexp)(d_mant, MANTISSA_BIT);
+
+	    u_mant >>= -s_exp;
+	    u_exp = 0;
+	} else {
+	    /* The number is normal in binary64. */
+
+	    /* Use the suggested exponent. */
+	    u_exp = s_exp;
+
+	    /* Make the mantissa value into a positive integer. */
+	    u_mant = XORP_FP64(ldexp)(d_mant, MANTISSA_BIT + 1);
+	}
+
+	break;
+    }
+
+    /* Transmit the bottom MANTISSA_BITs of u_mant.  The extra top bit
+       will always be one when normalized. */
+
+    bytes = ((uint_fast64_t) u_mant & MANTISSA_MASK) << MANTISSA_SHIFT;
+    bytes |= ((uint_fast64_t) u_exp & EXPONENT_MASK) << EXPONENT_SHIFT;
+    bytes |= ((uint_fast64_t) neg & SIGN_MASK) << SIGN_SHIFT;
+
+    return bytes;
+}
+
+fp64_t fp64dec(uint_fast64_t bytes)
+{
+    int s_exp;
+    unsigned int u_exp;
+    uint_fast64_t u_mant;
+    bool neg;
+    fp64_t output;
+
+    /* Extract the bit fields. */
+    u_exp = (bytes >> EXPONENT_SHIFT) & EXPONENT_MASK;
+    u_mant = (bytes >> MANTISSA_SHIFT) & MANTISSA_MASK;
+    neg = (bytes >> SIGN_SHIFT) & SIGN_MASK;
+
+    if (u_exp == EXPONENT_MASK) {
+	if (u_mant == 0)
+	    return neg ? -INFINITY : +INFINITY;
+	return NAN;
+    }
+
+
+    do {
+	if (u_exp == 0) {
+	    /* Positive or negative zero */
+	    if (u_mant == 0)
+		return XORP_FP64(copysign)(0.0, neg ? -1.0 : +1.0);
+
+	    /* Subnormal value */
+
+	    /* Multiply the mantissa by a power of two. */
+	    output = XORP_FP64(ldexp)
+		(u_mant, -(MANTISSA_BIT + (int) EXPONENT_BIAS));
+	    break;
+	}
+
+	/* Recover the top bit of the mantissa. */
+	u_mant |= MANTISSA_MASK + 1;
+
+	/* Convert offset exponent back into a native signed value. */
+	s_exp = (int) u_exp - EXPONENT_BIAS;
+
+	/* Multiply the mantissa by a power of two. */
+	output = XORP_FP64(ldexp)
+	    (u_mant, s_exp - (MANTISSA_BIT + 1));
+    } while (false);
+
+    if (neg)
+	output = -output;
+
+    return output;
+}
diff --git a/xorp/libxipc/fp64serial.h b/xorp/libxipc/fp64serial.h
new file mode 100644
index 0000000..e07ae73
--- /dev/null
+++ b/xorp/libxipc/fp64serial.h
@@ -0,0 +1,40 @@
+// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
+// vim:set sts=4 ts=8:
+
+// Copyright (c) 2001-2011 XORP, Inc and Others
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License, Version
+// 2.1, June 1999 as published by the Free Software Foundation.
+// Redistribution and/or modification of this program under the terms of
+// any other version of the GNU Lesser General Public License is not
+// permitted.
+// 
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+// see the GNU Lesser General Public License, Version 2.1, a copy of
+// which can be found in the XORP LICENSE.lgpl file.
+// 
+// XORP, Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+// http://xorp.net
+
+// $XORP: xorp/libxipc/xrl_atom.hh,v 1.23 2008/10/30 20:49:07 pavlin Exp $
+
+#ifndef __LIBXIPC_FP64SERIAL_H__
+#define __LIBXIPC_FP64SERIAL_H__
+
+#include "fp64.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern uint_fast64_t fp64enc(fp64_t);
+  extern fp64_t fp64dec(uint_fast64_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/xorp/libxipc/tests/SConscript b/xorp/libxipc/tests/SConscript
index d6d9b8b..4b1d611 100644
--- a/xorp/libxipc/tests/SConscript
+++ b/xorp/libxipc/tests/SConscript
@@ -70,6 +70,7 @@ simple_cpp_tests = [
 	'xrl_error',
 	'xrl_parser',
 	'xrl_router',
+	'fp64',
 ]
 
 xrlrcvr_sources = [
diff --git a/xorp/libxipc/tests/test_fp64.cc b/xorp/libxipc/tests/test_fp64.cc
new file mode 100644
index 0000000..66417d7
--- /dev/null
+++ b/xorp/libxipc/tests/test_fp64.cc
@@ -0,0 +1,226 @@
+// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
+// vim:set sts=4 ts=8:
+
+// Copyright (c) 2001-2009 XORP, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License, Version
+// 2.1, June 1999 as published by the Free Software Foundation.
+// Redistribution and/or modification of this program under the terms of
+// any other version of the GNU Lesser General Public License is not
+// permitted.
+// 
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
+// see the GNU Lesser General Public License, Version 2.1, a copy of
+// which can be found in the XORP LICENSE.lgpl file.
+// 
+// XORP, Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
+// http://xorp.net
+
+
+
+// test_xrl_args: String Serialization Tests
+
+// Needed for PRIXFAST64
+#define __STDC_FORMAT_MACROS 1
+
+#include <cmath>
+#include <inttypes.h>
+
+#include "xrl_module.h"
+
+#include "libxorp/xorp.h"
+#include "libxorp/xlog.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include "xrl_args.hh"
+#include "fp64serial.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Constants
+//
+
+static const char *program_name         = "test_fp64";
+static const char *program_description  = "Test IEEE754-fp64_t conversion";
+static const char *program_version_id   = "0.1";
+static const char *program_date         = "August, 2011";
+static const char *program_copyright    = "See file LICENSE";
+static const char *program_return_value = "0 on success, 1 if test error, "
+					  "2 if internal error";
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Verbosity level control
+//
+
+static bool s_verbose = false;
+bool verbose()                  { return s_verbose; }
+void set_verbose(bool v)        { s_verbose = v; }
+
+#define verbose_log(x...) _verbose_log(__FILE__,__LINE__, x)
+
+#define _verbose_log(file, line, x...)					\
+do {									\
+    if (verbose()) {							\
+	printf("From %s:%d: ", file, line);				\
+	printf(x);							\
+    }									\
+} while(0)
+
+/**
+ * Print program info to output stream.
+ *
+ * @param stream the output stream the print the program info to.
+ */
+static void
+print_program_info(FILE *stream)
+{
+    fprintf(stream, "Name:          %s\n", program_name);
+    fprintf(stream, "Description:   %s\n", program_description);
+    fprintf(stream, "Version:       %s\n", program_version_id);
+    fprintf(stream, "Date:          %s\n", program_date);
+    fprintf(stream, "Copyright:     %s\n", program_copyright);
+    fprintf(stream, "Return:        %s\n", program_return_value);
+}
+
+/**
+ * Print program usage information to the stderr.
+ *
+ * @param progname the name of the program.
+ */
+static void
+usage(const char* progname)
+{
+    print_program_info(stderr);
+    fprintf(stderr, "usage: %s [-v] [-h]\n", progname);
+    fprintf(stderr, "       -h          : usage (this message)\n");
+    fprintf(stderr, "       -v          : verbose output\n");
+}
+
+static double error_threshold;
+
+static int test_conversion(fp64_t input)
+{
+    uint_fast64_t encoded = fp64enc(input);
+    fp64_t output = fp64dec(encoded);
+
+    fp64_t diff = output - input;
+    if (verbose())
+	fprintf(stderr, "%15" XORP_PRIgFP64 " %016" PRIXFAST64
+		" %15" XORP_PRIgFP64 " %15" XORP_PRIgFP64 "\n",
+		input, encoded, output, diff);
+    if (diff > error_threshold) {
+	verbose_log("THRESHOLD EXCEEDED\n");
+	return 1;
+    }
+    return 0;
+}
+
+static int
+run_test()
+{
+    error_threshold = ldexp(1.0, 3 - DBL_MANT_DIG);
+
+
+    verbose_log("\n***** Expanding from DBL_MIN\n");
+    for (double input = DBL_MIN; fpclassify(input) == FP_NORMAL;
+	 input *= rand() * 50.0 / RAND_MAX) {
+	test_conversion(input);
+    }
+
+    verbose_log("\n***** Expanding from -DBL_MIN\n");
+    for (double input = -DBL_MIN; fpclassify(input) == FP_NORMAL;
+	 input *= rand() * 50.0 / RAND_MAX) {
+	test_conversion(input);
+    }
+
+    verbose_log("\n***** Reducinging from largest +ve subnormal\n");
+    for (double input = nextafter(DBL_MIN, 0.0); fpclassify(input) != FP_ZERO;
+	 input /= rand() * 50.0 / RAND_MAX) {
+	test_conversion(input);
+    }
+
+    verbose_log("\n***** Reducinging from largest -ve subnormal\n");
+    for (double input = -nextafter(DBL_MIN, 0.0); fpclassify(input) != FP_ZERO;
+	 input /= rand() * 50.0 / RAND_MAX) {
+	test_conversion(input);
+    }
+
+
+    verbose_log("\n***** Infinities\n");
+    test_conversion(+INFINITY);
+    test_conversion(-INFINITY);
+
+
+    verbose_log("\n***** Zeroes\n");
+    test_conversion(+0.0);
+    test_conversion(-0.0);
+
+#ifdef NAN
+    verbose_log("\n***** NANs\n");
+    test_conversion(NAN);
+#endif
+
+    return 0;
+}
+
+int
+main(int argc, char * const argv[])
+{
+    srand(time(NULL));
+
+    int ret_value;
+    const char* const argv0 = argv[0];
+
+    int ch;
+    while ((ch = getopt(argc, argv, "hv")) != -1) {
+	switch (ch) {
+	case 'v':
+	    set_verbose(true);
+	    break;
+	case 'h':
+	case '?':
+	default:
+	    usage(argv[0]);
+	    if (ch == 'h')
+		return 0;
+	    else
+		return 1;
+	}
+    }
+    argc -= optind;
+    argv += optind;
+
+    //
+    // Initialize and start xlog
+    //
+    xlog_init(argv0, NULL);
+    xlog_set_verbose(XLOG_VERBOSE_LOW);		// Least verbose messages
+    // XXX: verbosity of the error messages temporary increased
+    xlog_level_set_verbose(XLOG_LEVEL_ERROR, XLOG_VERBOSE_HIGH);
+    xlog_add_default_output();
+    xlog_start();
+
+    XorpUnexpectedHandler x(xorp_unexpected_handler);
+    try {
+	ret_value = run_test();
+    }
+    catch (...) {
+	xorp_catch_standard_exceptions();
+	ret_value = 2;
+    }
+    //
+    // Gracefully stop and exit xlog
+    //
+    xlog_stop();
+    xlog_exit();
+
+    return ret_value;
+}
diff --git a/xorp/libxipc/tests/test_xrl_args.cc b/xorp/libxipc/tests/test_xrl_args.cc
index a4afcb4..f929957 100644
--- a/xorp/libxipc/tests/test_xrl_args.cc
+++ b/xorp/libxipc/tests/test_xrl_args.cc
@@ -168,7 +168,8 @@ run_serialization_test()
 	XrlAtom("binary_data",	 test_binary),
 	XrlAtom("a_list",	 test_list),
 	XrlAtom("integer64",	 int64_t(-1234567890123456789LL)),
-	XrlAtom("uinteger64",	 uint64_t(0xabadc0ffee123456ULL))
+	XrlAtom("uinteger64",	 uint64_t(0xabadc0ffee123456ULL)),
+	XrlAtom("fp64",	 	 fp64_t(0.087613017887164087613407))
     };
     uint32_t n_test_args = sizeof(test_args) / sizeof(test_args[0]);
 
@@ -211,6 +212,7 @@ run_test()
     al.add_string("bad_karma", "");
     al.add_int64("a_named_int64", int64_t(-98765432101234LL));
     al.add_uint64("a_named_uint64", uint64_t(123456789012345ULL));
+    al.add_fp64("a_named_fp64", fp64_t(0.087613017887164087613407));
 
     XrlAtomList xal;
     xal.append(XrlAtom("first", string("fooo")));
@@ -260,6 +262,7 @@ run_test()
 	al.get_string("bad_karma");
 	al.get_int64("a_named_int64");
 	al.get_uint64("a_named_uint64");
+	al.get_fp64("a_named_fp64");
     } catch (XrlArgs::BadArgs& e) {
 	verbose_log("Error decoding the argument: %s\n", e.str().c_str());
 	return 1;
diff --git a/xorp/libxipc/tests/test_xrl_atom.cc b/xorp/libxipc/tests/test_xrl_atom.cc
index 280bc6b..dd3beed 100644
--- a/xorp/libxipc/tests/test_xrl_atom.cc
+++ b/xorp/libxipc/tests/test_xrl_atom.cc
@@ -242,6 +242,10 @@ test()
 	    test_atom(XrlAtom("test_uint64_value",
 		uint64_t(0xabadc0ffee123456ULL)));
 	    break;
+	case xrlatom_fp64:
+	    test_atom(XrlAtom("test_fp64_value",
+		fp64_t(0.087613017887164087613407)));
+	    break;
 	}
     }
 }
diff --git a/xorp/libxipc/xrl_args.cc b/xorp/libxipc/xrl_args.cc
index 5ca4a35..0297a49 100644
--- a/xorp/libxipc/xrl_args.cc
+++ b/xorp/libxipc/xrl_args.cc
@@ -536,6 +536,34 @@ XrlArgs::remove_uint64(const char* name) throw (XrlAtomNotFound)
 
 
 // ----------------------------------------------------------------------------
+// XrlArgs add/get/remove fp64
+
+XrlArgs&
+XrlArgs::add_fp64(const char* name, fp64_t val) throw (XrlAtomFound)
+{
+    return add(XrlAtom(name, val));
+}
+
+const fp64_t&
+XrlArgs::get_fp64(const char* name) const throw (BadArgs)
+{
+    try {
+	return get(XrlAtom(name, xrlatom_fp64)).fp64();
+    } catch (const XrlAtom::NoData& e) {
+        xorp_throw(BadArgs, e.why());
+    } catch (const XrlAtom::WrongType& e) {
+        xorp_throw(BadArgs, e.why());
+    }
+}
+
+void
+XrlArgs::remove_fp64(const char* name) throw (XrlAtomNotFound)
+{
+    remove(XrlAtom(name, xrlatom_fp64));
+}
+
+
+// ----------------------------------------------------------------------------
 // Append an existing XrlArgs
 
 XrlArgs&
diff --git a/xorp/libxipc/xrl_args.hh b/xorp/libxipc/xrl_args.hh
index e00338d..6c207aa 100644
--- a/xorp/libxipc/xrl_args.hh
+++ b/xorp/libxipc/xrl_args.hh
@@ -254,6 +254,18 @@ public:
 
     void get(const char* n, uint64_t& t) const throw (BadArgs);
 
+    /* --- fp64 accessors --- */
+
+    XrlArgs& add_fp64(const char* name, fp64_t v) throw (XrlAtomFound);
+
+    const fp64_t& get_fp64(const char* name) const throw (BadArgs);
+
+    void remove_fp64(const char* name) throw (XrlAtomNotFound);
+
+    XrlArgs& add(const char* n, fp64_t v) throw (XrlAtomFound);
+
+    void get(const char* n, fp64_t& t) const throw (BadArgs);
+
 
     // ... Add your type's add, get, remove functions here ...
 
@@ -518,6 +530,18 @@ XrlArgs::get(const char* n, uint64_t& t) const throw (BadArgs)
     t = get_uint64(n);
 }
 
+inline XrlArgs&
+XrlArgs::add(const char* n, fp64_t v) throw (XrlAtomFound)
+{
+    return add_fp64(n, v);
+}
+
+inline void
+XrlArgs::get(const char* n, fp64_t& t) const throw (BadArgs)
+{
+    t = get_fp64(n);
+}
+
 inline const XrlAtom&
 XrlArgs::item(uint32_t index) const
 {
diff --git a/xorp/libxipc/xrl_atom.cc b/xorp/libxipc/xrl_atom.cc
index 2cdc6e1..5106e4a 100644
--- a/xorp/libxipc/xrl_atom.cc
+++ b/xorp/libxipc/xrl_atom.cc
@@ -31,7 +31,7 @@
 #include "libproto/packet.hh"
 
 
-
+#include "fp64serial.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -62,6 +62,7 @@ static const char* xrlatom_list_name	= "list";
 static const char* xrlatom_binary_name	= "binary";
 static const char* xrlatom_int64_name	= "i64";
 static const char* xrlatom_uint64_name	= "u64";
+static const char* xrlatom_fp64_name	= "fp64";
 
 static inline void
 do_pack_uint32(const uint32_t u32val, uint8_t* buffer)
@@ -97,6 +98,7 @@ xrlatom_type_name(const XrlAtomType& t)
 	NAME_CASE(xrlatom_binary);
 	NAME_CASE(xrlatom_int64);
 	NAME_CASE(xrlatom_uint64);
+	NAME_CASE(xrlatom_fp64);
 	// ... Your type here ...
     }
     return xrlatom_no_type_name;
@@ -125,6 +127,7 @@ resolve_xrlatom_name(const char* name)
 	    CHECK_NAME(xrlatom_binary);		/* FALLTHRU */
 	    CHECK_NAME(xrlatom_int64);		/* FALLTHRU */
 	    CHECK_NAME(xrlatom_uint64);		/* FALLTHRU */
+	    CHECK_NAME(xrlatom_fp64);		/* FALLTHRU */
 	    // ... Your type here ...
 	case xrlatom_no_type:
 	    break;
@@ -220,6 +223,9 @@ XrlAtom::data_from_c_str(const char* c_str)
 	_u64val = (uint64_t)strtoull(c_str, (char**)NULL, 10);
 #endif
 	break;
+    case xrlatom_fp64:
+	sscanf(c_str, "%" XORP_SCNgFP64, &_fp64val);
+	break;
 
 	// ... Your types instantiator here ...
     }
@@ -356,6 +362,13 @@ XrlAtom::uint64() const throw (NoData, WrongType)
     return _u64val;
 }
 
+const fp64_t&
+XrlAtom::fp64() const throw (NoData, WrongType)
+{
+    type_and_data_okay(xrlatom_fp64);
+    return _fp64val;
+}
+
 
 // ----------------------------------------------------------------------------
 // XrlAtom dynamic data management functions
@@ -415,6 +428,9 @@ XrlAtom::copy(const XrlAtom& xa)
         case xrlatom_uint64:
             _u64val = xa._u64val;
             break;
+        case xrlatom_fp64:
+            _fp64val = xa._fp64val;
+            break;
 
             // ... Your type's copy operation here ...
         case xrlatom_no_type:
@@ -461,6 +477,7 @@ XrlAtom::discard_dynamic()
 	    break;
         case xrlatom_int64:
         case xrlatom_uint64:
+        case xrlatom_fp64:
 	    break;
 
             // ... Your type should free allocated memory here ...
@@ -608,6 +625,10 @@ XrlAtom::value() const
 		 static_cast<unsigned long long>(_u64val));
 #endif
 	return xrlatom_encode_value(tmp, strlen(tmp));
+    case xrlatom_fp64:
+	snprintf(tmp, sizeof(tmp) / sizeof(tmp[0]),
+		 "%" XORP_PRIAFP64, _fp64val);
+	return xrlatom_encode_value(tmp, strlen(tmp));
 
 	// ... Your type's c_str equivalent here ...
     }
@@ -682,6 +703,9 @@ XrlAtom::operator==(const XrlAtom& other) const
 	case xrlatom_uint64:
 	    mv = (_u64val == other._u64val);
 	    break;
+	case xrlatom_fp64:
+	    mv = (_fp64val == other._fp64val);
+	    break;
 
 	    // ... Your type's equality test here ...
 	}
@@ -765,6 +789,7 @@ XrlAtom::packed_bytes() const
 	break;
     case xrlatom_int64:
     case xrlatom_uint64:
+    case xrlatom_fp64:
 	bytes += 8;
 	break;
 
@@ -790,6 +815,7 @@ XrlAtom::packed_bytes_fixed() const
     case xrlatom_boolean:
     case xrlatom_int64:
     case xrlatom_uint64:
+    case xrlatom_fp64:
 	return true;
     case xrlatom_mac:
     case xrlatom_text:
@@ -1169,6 +1195,27 @@ XrlAtom::unpack_uint64(const uint8_t* buf)
 }
 
 size_t
+XrlAtom::pack_fp64(uint8_t* buffer) const
+{
+    uint_fast64_t bytes = fp64enc(_fp64val);
+
+    do_pack_uint32(bytes >> 32, buffer);
+    do_pack_uint32(bytes & 0xFFFFFFFF, &buffer[4]);
+    return sizeof(_fp64val);
+}
+
+size_t
+XrlAtom::unpack_fp64(const uint8_t* buf)
+{
+    uint_fast64_t bytes;
+    bytes = uint_fast64_t(do_unpack_uint32(buf)) << 32;
+    bytes |= do_unpack_uint32(&buf[4]);
+
+    _fp64val = fp64dec(bytes);
+    return sizeof(_fp64val);
+}
+
+size_t
 XrlAtom::pack(uint8_t* buffer, size_t buffer_bytes) const
 {
     size_t pb = packed_bytes();
@@ -1229,6 +1276,9 @@ XrlAtom::pack(uint8_t* buffer, size_t buffer_bytes) const
 	case xrlatom_uint64:
 	    packed_size += pack_uint64(buffer + packed_size);
 	    break;
+	case xrlatom_fp64:
+	    packed_size += pack_fp64(buffer + packed_size);
+	    break;
 
 	    // ... Your type here ...
 	}
@@ -1330,6 +1380,9 @@ XrlAtom::unpack(const uint8_t* buffer, size_t buffer_bytes)
 	case xrlatom_uint64:
 	    used = unpack_uint64(buffer + unpacked);
 	    break;
+	case xrlatom_fp64:
+	    used = unpack_fp64(buffer + unpacked);
+	    break;
 
 	    // ... Your type here ...
 	}
diff --git a/xorp/libxipc/xrl_atom.hh b/xorp/libxipc/xrl_atom.hh
index d4be38f..50fb4f1 100644
--- a/xorp/libxipc/xrl_atom.hh
+++ b/xorp/libxipc/xrl_atom.hh
@@ -39,6 +39,7 @@
 
 
 #include "xrl_atom_list.hh"
+#include "fp64.h"
 
 
 enum XrlAtomType {
@@ -56,13 +57,14 @@ enum XrlAtomType {
     xrlatom_binary,
     xrlatom_int64,
     xrlatom_uint64,
+    xrlatom_fp64,
     // ... Your type's unique enumerated name here ...
     // Changing order above will break binary compatibility
     // ...Don't forget to update xrlatom_start and xrlatom_end below...
 
     // Bounds for enumerations
     xrlatom_start = xrlatom_int32,	// First valid enumerated value
-    xrlatom_end   = xrlatom_uint64	// Last valid enumerated value
+    xrlatom_end   = xrlatom_fp64	// Last valid enumerated value
 };
 
 inline XrlAtomType& operator++(XrlAtomType& t)
@@ -329,6 +331,16 @@ public:
     }
 
 
+    // fp64 constructors
+    explicit XrlAtom(const fp64_t& value)
+	: _type(xrlatom_fp64), _have_data(true), _own(true), _u64val(value) {}
+
+    XrlAtom(const char* name, fp64_t value) throw (BadName)
+	: _type(xrlatom_fp64), _have_data(true), _own(true), _fp64val(value) {
+	set_name(name);
+    }
+
+
     // ... Your type's constructors here ...
 
     // Copy operations
@@ -368,6 +380,7 @@ public:
     const vector<uint8_t>& binary() const throw (NoData, WrongType);
     const int64_t&	   int64() const throw (NoData, WrongType);
     const uint64_t&	   uint64() const throw (NoData, WrongType);
+    const fp64_t&	   fp64() const throw (NoData, WrongType);
 
     // ... Your type's accessor method here ...
 
@@ -392,6 +405,7 @@ public:
     SET(string, _text, &)
     SET(XrlAtomList, _list, &)
     SET(vector<uint8_t>, _binary, &);
+    SET(fp64_t, _fp64val, )
 #undef SET
 
     void set(const IPv4& v) {
@@ -446,6 +460,7 @@ private:
     size_t pack_list(uint8_t* buffer, size_t buffer_bytes) const;
     size_t pack_binary(uint8_t* buffer) const;
     size_t pack_uint64(uint8_t* buffer) const;
+    size_t pack_fp64(uint8_t* buffer) const;
 
     size_t unpack_name(const uint8_t* buffer, size_t buffer_bytes)
 	throw (BadName);
@@ -460,6 +475,7 @@ private:
     size_t unpack_list(const uint8_t* buffer, size_t buffer_bytes);
     size_t unpack_binary(const uint8_t* buffer, size_t buffer_bytes);
     size_t unpack_uint64(const uint8_t* buffer);
+    size_t unpack_fp64(const uint8_t* buffer);
 
 private:
     XrlAtomType	_type;
@@ -479,6 +495,7 @@ private:
 	vector<uint8_t>* _binary;
         int64_t		 _i64val;
         uint64_t	 _u64val;
+        fp64_t	         _fp64val;
 
         // ... Your type here, if it's more than sizeof(uintptr_t) bytes,
 	// use a pointer ...
diff --git a/xorp/rtrmgr/xorp_client.cc b/xorp/rtrmgr/xorp_client.cc
index e4e01a8..5119ff4 100644
--- a/xorp/rtrmgr/xorp_client.cc
+++ b/xorp/rtrmgr/xorp_client.cc
@@ -143,6 +143,7 @@ XorpClient::fake_return_args(const string& xrl_return_spec)
 	case xrlatom_binary:
 	case xrlatom_uint64:
 	case xrlatom_int64:
+	case xrlatom_fp64:
 	    XLOG_UNFINISHED();
 	    break;
 	}
diff --git a/xorp/xrl/interfaces/test.xif b/xorp/xrl/interfaces/test.xif
index b6e3fe9..bd84ad8 100644
--- a/xorp/xrl/interfaces/test.xif
+++ b/xorp/xrl/interfaces/test.xif
@@ -36,4 +36,9 @@ interface test/1.0 {
 	  * Something that always fails.
 	  */
 	 shoot_foot;
+
+	 /**
+	  * Handle IEEE754 binary64 format.
+	  */
+	 float_my_point ? input:fp64 -> output:fp64;
 }
diff --git a/xorp/xrl/scripts/Xif/xiftypes.py b/xorp/xrl/scripts/Xif/xiftypes.py
index d8d6180..85489f2 100644
--- a/xorp/xrl/scripts/Xif/xiftypes.py
+++ b/xorp/xrl/scripts/Xif/xiftypes.py
@@ -12,7 +12,8 @@ xrl_atom_type = {
     'list' :	('XrlAtomList', 	'list',		'list'),
     'binary' :	('vector<uint8_t>',	'binary',	'binary'),
     'i64' :	('int64_t',		'int64',	'i64'),
-    'u64' :	('uint64_t',		'uint64',	'i64')
+    'u64' :	('uint64_t',		'uint64',	'i64'),
+    'fp64' :	('fp64_t',		'fp64',	        'double')
 }
 
 class XrlArg:
-- 
1.7.4.1



More information about the Xorp-hackers mailing list