[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