From: Steven Simpson <[email protected]> * 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 <[email protected]> --- xorp/libxipc/SConscript | 1 + xorp/libxipc/fp64.h | 196 ++++++++++++++++++++++++++++++ xorp/libxipc/fp64serial.c | 184 ++++++++++++++++++++++++++++ xorp/libxipc/fp64serial.h | 38 ++++++ xorp/libxipc/tests/SConscript | 1 + xorp/libxipc/tests/test_fp64.cc | 224 +++++++++++++++++++++++++++++++++++ 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, 784 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 ec0619b..95d7f4b 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..9ce74a9 --- /dev/null +++ b/xorp/libxipc/fp64.h @@ -0,0 +1,196 @@ +// -*- 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 + +#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..4430f77 --- /dev/null +++ b/xorp/libxipc/fp64serial.h @@ -0,0 +1,38 @@ +// -*- 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 + +#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..9d7788c --- /dev/null +++ b/xorp/libxipc/tests/test_fp64.cc @@ -0,0 +1,224 @@ +// -*- 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 + + + +// 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 e22e03a..0a3ef81 100644 --- a/xorp/libxipc/xrl_args.cc +++ b/xorp/libxipc/xrl_args.cc @@ -533,6 +533,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 8121884..2975cdf 100644 --- a/xorp/libxipc/xrl_args.hh +++ b/xorp/libxipc/xrl_args.hh @@ -251,6 +251,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 ... @@ -515,6 +527,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 _______________________________________________ Xorp-hackers mailing list [email protected] http://mailman.ICSI.Berkeley.EDU/mailman/listinfo/xorp-hackers
