Optimized portable isnan, isfinite, fpclassify etc

I have put together optimized implementations of the following functions: template<class T> int fpclassify(T x); template<class T> bool isfinite(T x); template<class T> bool isinf(T x); template<class T> bool isnan(T x); template<class T> bool isnormal(T x); template<class T> bool signbit(T x); template<class T> T copysign(T x, T y); template<class T> T changesign(T x); Here T is required to be float, double or long double. -------------------- The code has been tested with Windows / VC7.1 / i386 Mac / GCC 4.0 / powerpc Linux / GCC 3.3 / i386, amd64, ia64, powerpc, mips, hppa The code should work with most platforms that support the IEEE754 standard. -------------------- Many of these functions have also been implemented by John Maddock. The difference is that my implementation is optimized for speed. Here are some timing numbers on VC 7.1: float Råde Maddock Native fpclassify 8 57 - isfinite 5 57 - isnormal 6 59 - isinf 5 57 - isnan 6 57 - double Råde Maddock Native fpclassify 13 52 29 isfinite 11 56 17 isnormal 14 56 - isinf 10 52 - isnan 4 52 19 The times are in clock cycles for a single call, based on an average of 10,000,000 calls with random input. -------------------- The code is available in the vault, at "Home/Math - Numerics/fpclassify.zip". Many thanks to Håkan Ardö who tested the code on Linux and Olivier Verdie who tested the code on Mac. --Johan Råde

Johan Råde wrote:
Many of these functions have also been implemented by John Maddock. The difference is that my implementation is optimized for speed.
Here are some timing numbers on VC 7.1:
The times are in clock cycles for a single call, based on an average of 10,000,000 calls with random input.
I think the timings for my latest code should be a bit better than that as I've started forwarding to native versions where applicable. Even so, I think this is a good idea and worth persuing. Unfortunately I don't think your code is as portable as you think it is: I'm attaching below some failed test runs of your code with Intel (Win32 and Linux), HP aCC and g++ (HP-UX). The difficulty is that once you crank up the optimisation levels, code like this tends to break, and since it's reason-for-existance is to improve performance, that's a problem :-( I have some specific comments on the code: 1) I'm a bit uneasy about the #undef's of the std macros: let's say a user includes this header indirectly (because it's used by another Boost header, say my math stuff), they might be a bit miffed if the the macros they were expecting to be defined have been undef'ed like this. 2) I'm a little surprised at seeing memcpy used to shift 4 bytes, given the slightly-hairy nature of what you're doing here, I don't think a reinterpret_cast to uint32 is unreasonable in comparison. But that's just my opinion :-) 3) With respect to the #error Unknown endianness, perhaps we can forward to a slower-but safer alternative in this case? 4) I'm fairly sure the declarations: template<> const boost::uint32_t mask<float>::exponent = 0x7f800000; template<> const boost::uint32_t mask<double>::exponent = 0x7ff00000; template<> const boost::uint32_t mask<long double>::exponent will cause ODR violations / linker errors when the header is used from multiple TU's. 5) isinf needs to handle the situation where T doesn't have infinities, or perhaps even doesn't have / can't have numeric_limits support (NTL::RR for example). 6) Does the implementaton of isnan: template<class T> bool isnan(T x) { return !(x <= std::numeric_limits<T>::infinity()); } work for negative NaN's ? I'm thinking of compilers that perform non-standard-IEEE comparisons using faster comparisons of bit-patterns rather than fully-unordered NaN's. OK where does this leave us. Looks like the way forward might be some kind of merger of our implementations: using the slow-but-safe version as a fallback for where the fast-and-hairy-version doesn't work? The difficulty is doing it without the code turning into a spagetty of #if logic. I wonder if something like: template <class T> T isnan(T x) { return isnan_imp(x, typename classify_traits<T>::type()); } where classify_traits<T>::type is some kind of type that encapsulates: Endianness. Is it a real float. Does it have numeric limits support. Any compiler specific information - like "use fast if possible", or "always use safe version". The we could use compile time dispatch to the right implementation, and all the hairy logic and #if code would be isolated to classify_traits (or whatever it's called). Does this sound plausible, and/or something you might be interested in persuing? Thanks, John. ps heres the failure logs: Intel 9.1, Win32, VC-8 mode: $ icl /O2 /EHs -I../../../develop/boost test.cpp Intel(R) C++ Compiler for 32-bit applications, Version 9.1 Build 20060519Z Copyright (C) 1985-2006 Intel Corporation. All rights reserved. 30 DAY EVALUATION LICENSE icl: NOTE: The evaluation period for this product ends on 11-feb-2008 UTC. test.cpp Microsoft (R) Incremental Linker Version 8.00.50727.42 Copyright (C) Microsoft Corporation. All rights reserved. -out:test.exe test.obj John Maddock@fuji /cygdrive/c/data/boost/fpclassify/fpclassify/test $ ./test little endian sizeof(long double) = 8 mask<long double>::exponent = 7ff00000 Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test !isinf(x) Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test !isinf(x) Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test !isinf(x) Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test !isinf(x) Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(changesign(c)) Failed test isnan(changesign(changesign(c))) Failed test isnan(changesign(c)) Failed test isnan(changesign(changesign(c))) Failed test isnan(changesign(c)) Failed test isnan(changesign(changesign(c))) HP aCC, HP-UX, Itanium: aCC -AA -O3 -I ~ *.cpp maddock@td176> ./a.out little endian sizeof(long double) = 16 mask<long double>::exponent = 0 Failed test fpclassify(x) == FP_ZERO Failed test signbit(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test signbit(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test signbit(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test !signbit(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test !isfinite(x) Failed test fpclassify(x) == FP_INFINITE Failed test signbit(x) Failed test !isfinite(x) Failed test fpclassify(x) == FP_INFINITE Failed test !isfinite(x) Failed test fpclassify(x) == FP_NAN Failed test !isfinite(x) Failed test fpclassify(x) == FP_NAN Failed test !isfinite(x) Failed test fpclassify(x) == FP_NAN Failed test !isfinite(x) Failed test fpclassify(x) == FP_NAN Failed test isfinite(x) Failed test isfinite(x) Failed test fpclassify(x) == FP_ZERO Failed test isfinite(x) Failed test signbit(x) Failed test isfinite(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test signbit(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test signbit(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test !signbit(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test fpclassify(x) == FP_INFINITE Failed test signbit(x) Failed test fpclassify(x) == FP_INFINITE Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(b) == b Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(b) == b G++, HP-UX, Itanium: maddock@td176> g++ g++: no input files maddock@td176> g++ -I ~ -O3 *.cpp maddock@td176> ./a.out little endian sizeof(long double) = 16 mask<long double>::exponent = 0 Failed test fpclassify(x) == FP_ZERO Failed test signbit(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test signbit(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test signbit(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test !signbit(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test !isfinite(x) Failed test fpclassify(x) == FP_INFINITE Failed test signbit(x) Failed test !isfinite(x) Failed test fpclassify(x) == FP_INFINITE Failed test !isfinite(x) Failed test fpclassify(x) == FP_NAN Failed test !isfinite(x) Failed test fpclassify(x) == FP_NAN Failed test !isfinite(x) Failed test fpclassify(x) == FP_NAN Failed test !isfinite(x) Failed test fpclassify(x) == FP_NAN Failed test isfinite(x) Failed test isfinite(x) Failed test fpclassify(x) == FP_ZERO Failed test isfinite(x) Failed test signbit(x) Failed test isfinite(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test signbit(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test signbit(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test !signbit(x) Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isfinite(x) Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test fpclassify(x) == FP_INFINITE Failed test signbit(x) Failed test fpclassify(x) == FP_INFINITE Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, y) == x Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), y) == x Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test copysign(x, changesign(y)) == changesign(x) Failed test copysign(changesign(x), changesign(y)) == changesign(x) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(b) == b Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(a[i]) == -a[i] Failed test changesign(-a[i]) == a[i] Failed test !signbit(changesign(-a[i])) Failed test changesign(b) == b Intel 9.1, Linux, Itanium: maddock@td178.testdrive.hp.com> icc -I ~ -O3 -fast -fp-model fast=2 *.cpp -stat ic IPO: performing single-file optimizations IPO: generating object file /tmp/ipo_iccbMO6qR.o maddock@td178.testdrive.hp.com> ./a.out little endian sizeof(long double) = 16 mask<long double>::exponent = 7fff0000 Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN

Dear John, Thanks for your thoughtful comments. I'm glad you find the project worth persuing. I would be very happy to work with you to merge and improve our solutions to a Boost grade library. Right now I'm very busy but later this week I will have time to study your comments more carefully. Thank you, Johan Råde John Maddock wrote:
Johan Råde wrote:
Many of these functions have also been implemented by John Maddock. The difference is that my implementation is optimized for speed.
[snip]
I think this is a good idea and worth persuing. Unfortunately I don't think your code is as portable as you think it is: I'm attaching below some failed test runs of your code with Intel (Win32 and Linux), HP aCC and g++ (HP-UX). The difficulty is that once you crank up the optimisation levels, code like this tends to break, and since it's reason-for-existance is to improve performance, that's a problem :-(
[snip]
OK where does this leave us.
Looks like the way forward might be some kind of merger of our implementations:
Thanks,
John.

Johan Råde wrote:
Dear John,
Thanks for your thoughtful comments. I'm glad you find the project worth persuing.
I would be very happy to work with you to merge and improve our solutions to a Boost grade library.
Right now I'm very busy but later this week I will have time to study your comments more carefully.
No problem, John.

John Maddock wrote:
Johan Råde wrote:
Many of these functions have also been implemented by John Maddock. The difference is that my implementation is optimized for speed.
Here are some timing numbers on VC 7.1:
The times are in clock cycles for a single call, based on an average of 10,000,000 calls with random input.
I think the timings for my latest code should be a bit better than that as I've started forwarding to native versions where applicable.
Even so, I think this is a good idea and worth persuing. Unfortunately I don't think your code is as portable as you think it is: I'm attaching below some failed test runs of your code with Intel (Win32 and Linux), HP aCC and g++ (HP-UX). The difficulty is that once you crank up the optimisation levels, code like this tends to break, and since it's reason-for-existance is to improve performance, that's a problem :-(
I have some specific comments on the code:
1) I'm a bit uneasy about the #undef's of the std macros: let's say a user includes this header indirectly (because it's used by another Boost header, say my math stuff), they might be a bit miffed if the the macros they were expecting to be defined have been undef'ed like this.
You are obviously right.
2) I'm a little surprised at seeing memcpy used to shift 4 bytes, given the slightly-hairy nature of what you're doing here, I don't think a reinterpret_cast to uint32 is unreasonable in comparison. But that's just my opinion :-)
Sometimes I shift by 6 bytes. For simplicity I handle all the shifts the same way. When we get the stuff to work, we could optimize the 4 byte case.
3) With respect to the #error Unknown endianness, perhaps we can forward to a slower-but safer alternative in this case?
The code should be like this: #include <boost/detail/endian.hpp> ... #if defined BOOST_BIG_ENDIAN ... #elif defined BOOST_LITTLE_ENDIAN ... #elif defined BOOST_PDP_ENDIAN # error PDP-endian platforms are not supported #else # error This can not happen #endif
4) I'm fairly sure the declarations:
template<> const boost::uint32_t mask<float>::exponent = 0x7f800000; template<> const boost::uint32_t mask<double>::exponent = 0x7ff00000; template<> const boost::uint32_t mask<long double>::exponent
will cause ODR violations / linker errors when the header is used from multiple TU's.
You may be right.
5) isinf needs to handle the situation where T doesn't have infinities, or perhaps even doesn't have / can't have numeric_limits support (NTL::RR for example).
This is news to me. I don't know enough about this problem to have an informed opinion.
6) Does the implementaton of isnan:
template<class T> bool isnan(T x) { return !(x <= std::numeric_limits<T>::infinity()); }
work for negative NaN's ? I'm thinking of compilers that perform non-standard-IEEE comparisons using faster comparisons of bit-patterns rather than fully-unordered NaN's.
There are all sorts of problems with the current isnan implementation. I will replace it by one that relies on bit operations instead of comparisons, at the cost of a few extra clock cycles. The new implementation will be immune to optimizing compilers.
OK where does this leave us.
Looks like the way forward might be some kind of merger of our implementations: using the slow-but-safe version as a fallback for where the fast-and-hairy-version doesn't work?
The difficulty is doing it without the code turning into a spagetty of #if logic.
I wonder if something like:
template <class T> T isnan(T x) { return isnan_imp(x, typename classify_traits<T>::type()); }
where classify_traits<T>::type is some kind of type that encapsulates:
Endianness. Is it a real float. Does it have numeric limits support. Any compiler specific information - like "use fast if possible", or "always use safe version".
The we could use compile time dispatch to the right implementation, and all the hairy logic and #if code would be isolated to classify_traits (or whatever it's called).
Does this sound plausible, and/or something you might be interested in persuing?
You are right in principle, but it may be overkill. Let's first see how far we can get with my approach. It is not as hairy as you think. It should work for all processor that are (more or less) IEEE754 compliant.
Thanks,
John.
ps heres the failure logs:
---------------------------------------------------------
Intel 9.1, Win32, VC-8 mode:
$ icl /O2 /EHs -I../../../develop/boost test.cpp Intel(R) C++ Compiler for 32-bit applications, Version 9.1 Build 20060519Z Copyright (C) 1985-2006 Intel Corporation. All rights reserved. 30 DAY EVALUATION LICENSE
icl: NOTE: The evaluation period for this product ends on 11-feb-2008 UTC. test.cpp Microsoft (R) Incremental Linker Version 8.00.50727.42 Copyright (C) Microsoft Corporation. All rights reserved.
-out:test.exe test.obj
John Maddock@fuji /cygdrive/c/data/boost/fpclassify/fpclassify/test $ ./test little endian sizeof(long double) = 8 mask<long double>::exponent = 7ff00000
Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN Failed test isnan(x) Failed test fpclassify(x) == FP_NAN
[snip] New isnan implementation will fix this. ---------------------------------------------------------------
HP aCC, HP-UX, Itanium:
aCC -AA -O3 -I ~ *.cpp maddock@td176> ./a.out little endian sizeof(long double) = 16 mask<long double>::exponent = 0
[snip: lots of failures] Will need more refined logic to detect exponent mask. --------------------------------------------------------------
G++, HP-UX, Itanium:
maddock@td176> g++ g++: no input files maddock@td176> g++ -I ~ -O3 *.cpp maddock@td176> ./a.out little endian sizeof(long double) = 16 mask<long double>::exponent = 0
[snip: lots of failures] Will need more refined logic to determine exponent mask. -------------------------------------------------------
Intel 9.1, Linux, Itanium:
maddock@td178.testdrive.hp.com> icc -I ~ -O3 -fast -fp-model fast=2 *.cpp -stat ic IPO: performing single-file optimizations IPO: generating object file /tmp/ipo_iccbMO6qR.o maddock@td178.testdrive.hp.com> ./a.out little endian sizeof(long double) = 16 mask<long double>::exponent = 7fff0000
Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN Failed test fpclassify(x) == FP_NAN
[snip] New isnan will fix the this.
Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL Failed test isnormal(x) Failed test fpclassify(x) == FP_NORMAL
[snip] What is going on here? Error in <limits>? That would not be the first time. ____________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Johan Råde wrote:
What is going on here? Error in <limits>? That would not be the first time.
I don't know, if that's the Intel/linux failures it's optimizer related, the test passes without the optimizations cranked up. If you have a new revision with fixed isnan logic I'll test them again. John.

John Maddock wrote:
Johan Råde wrote:
What is going on here? Error in <limits>? That would not be the first time.
I don't know, if that's the Intel/linux failures it's optimizer related, the test passes without the optimizations cranked up.
If you have a new revision with fixed isnan logic I'll test them again.
John.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Here is a new version, with a pinch of paranoia added. There are no floating point comparisons at all, except for a few == 0 and != 0. Therefore I expect it to be immune against optimizing compilers. (I have added a cpp file to avoid ODR violations. It may eventually be possible to remove the cpp file, if we can turn the constants into compile time constants. I bit of ifdef logic will be needed for that.) (This version does not undefine any macros either.) --Johan

Johan Råde wrote:
Here is a new version, with a pinch of paranoia added. There are no floating point comparisons at all, except for a few == 0 and != 0. Therefore I expect it to be immune against optimizing compilers.
(I have added a cpp file to avoid ODR violations. It may eventually be possible to remove the cpp file, if we can turn the constants into compile time constants. I bit of ifdef logic will be needed for that.)
(This version does not undefine any macros either.)
It works for Intel/Win32, I haven't been able to build it on either HP or with Intel/Linux due to endless compiler errors inside the system's math.h. I haven't had a chance yet to see what might be wrong. John.

John Maddock wrote:
Johan Råde wrote:
Here is a new version, with a pinch of paranoia added. There are no floating point comparisons at all, except for a few == 0 and != 0. Therefore I expect it to be immune against optimizing compilers.
(I have added a cpp file to avoid ODR violations. It may eventually be possible to remove the cpp file, if we can turn the constants into compile time constants. I bit of ifdef logic will be needed for that.)
(This version does not undefine any macros either.)
It works for Intel/Win32, I haven't been able to build it on either HP or with Intel/Linux due to endless compiler errors inside the system's math.h.
I haven't had a chance yet to see what might be wrong.
John.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
I know what is wrong. I'll send you a new version. --Johan

John Maddock wrote:
Johan Råde wrote:
Here is a new version, with a pinch of paranoia added. There are no floating point comparisons at all, except for a few == 0 and != 0. Therefore I expect it to be immune against optimizing compilers.
(I have added a cpp file to avoid ODR violations. It may eventually be possible to remove the cpp file, if we can turn the constants into compile time constants. I bit of ifdef logic will be needed for that.)
(This version does not undefine any macros either.)
It works for Intel/Win32, I haven't been able to build it on either HP or with Intel/Linux due to endless compiler errors inside the system's math.h.
I haven't had a chance yet to see what might be wrong.
John.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Here it is. --Johan

John, I am a bit baffled with the results from your HP-UX/Itanium tests. Could you run the attached program on that machine? It is just a single cpp file. It prints the byte patterns of various numbers. Below is the output I get with Windows/VC71/x86. Thank you, Johan Råde --------------------------------------------------------------------- little endian float ------------------------------- 0 00 00 00 00 sn. min 00 00 00 01 n. min 00 80 00 00 1 3f 80 00 00 4/3 3f aa aa ab max 7f 7f ff ff inf 7f 80 00 00 q. nan 7f c0 00 00 s. nan 7f 80 00 01 -1 bf 80 00 00 double ------------------------------ 0 00 00 00 00 00 00 00 00 sn. min 00 00 00 00 00 00 00 01 n. min 00 10 00 00 00 00 00 00 1 3f f0 00 00 00 00 00 00 4/3 3f f5 55 55 55 55 55 55 max 7f ef ff ff ff ff ff ff inf 7f f0 00 00 00 00 00 00 q. nan 7f f8 00 00 00 00 00 00 s. nan 7f f8 00 00 00 00 00 01 -1 bf f0 00 00 00 00 00 00 long double ------------------------- 0 00 00 00 00 00 00 00 00 sn. min 00 00 00 00 00 00 00 01 n. min 00 10 00 00 00 00 00 00 1 3f f0 00 00 00 00 00 00 4/3 3f f5 55 55 55 55 55 55 max 7f ef ff ff ff ff ff ff inf 7f f0 00 00 00 00 00 00 q. nan 7f f8 00 00 00 00 00 00 s. nan 7f f8 00 00 00 00 00 01 -1 bf f0 00 00 00 00 00 00 // inspect.cpp // Copyright (c) 2006 Johan Rade // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) //------------------------------------- #include <iomanip> #include <iostream> #include <limits> #include <boost/detail/endian.hpp> //------------------------------------------------------------------------------ template<class T> void print(const char* s, T x, bool ok = true); template<class T> void print_info(); //------------------------------------------------------------------------------ int main() { std::cout << '\n'; #if defined BOOST_BIG_ENDIAN std::cout << "big endian\n\n"; #elif defined BOOST_LITTLE_ENDIAN std::cout << "little endian\n\n"; #elif defined BOOST_PDP_ENDIAN # error PDP-endian platforms are not supported #else # error should not get here #endif std::cout << "float -------------------------------\n\n"; print_info<float>(); std::cout << "double ------------------------------\n\n"; print_info<double>(); std::cout << "long double -------------------------\n\n"; print_info<long double>(); return 0; } //------------------------------------------------------------------------------ template<class T> void print(const char* s, T x, bool ok) { std::cout << std::left << std::setw(10) << s << std::right; std::cout << std::hex << std::setfill('0'); if(ok) { #ifdef BOOST_BIG_ENDIAN for(int i = 0; i < (int)sizeof(T); ++i) #else for(int i = sizeof(T) - 1; i >= 0; --i) #endif std::cout << std::setw(2) << (unsigned int)*((unsigned char*)&x + i) << ' '; } else { for(int i = 0; i < (int)sizeof(T); ++i) std::cout << "-- "; } std::cout << '\n'; std::cout << std::dec << std::setfill(' '); } template<class T> void print_info() { print("0", (T)0); print("sn. min", std::numeric_limits<T>::denorm_min()); print("n. min", std::numeric_limits<T>::min()); print("1", (T)1); print("4/3", (T)4/(T)3); print("max", std::numeric_limits<T>::max()); print("inf", std::numeric_limits<T>::infinity(), std::numeric_limits<T>::has_infinity); print("q. nan", std::numeric_limits<T>::quiet_NaN(), std::numeric_limits<T>::has_quiet_NaN); print("s. nan", std::numeric_limits<T>::signaling_NaN(), std::numeric_limits<T>::has_signaling_NaN); print("-1", (T)-1); std::cout << "\n\n"; }

Markus Schöpflin wrote:
Johan Råde wrote:
Could you run the attached program on that machine? It is just a single cpp file. It prints the byte patterns of various numbers.
Are you interested in test results from a Tru64/Alpha machine?
Markus
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Yes! I have not run any tests on Alphas. --Johan

Johan Råde wrote:
Markus Schöpflin wrote:
Are you interested in test results from a Tru64/Alpha machine?
Yes! I have not run any tests on Alphas.
Here you are: bash-2.05b$ cxx -ieee -std strict_ansi -model ansi -no_pure_cname -I /boost/regression/boost test.cpp -lm ld: Unresolved: boost::math::detail::mask<long double128>::exponent boost::math::detail::mask<long double128>::fraction boost::math::detail::mask<long double128>::significand Seems like there are some specializations missing in boost for long double. When disabling the long double stuff I get the following results: bash-2.05b$ cxx -ieee -std strict_ansi -model ansi -no_pure_cname -I /boost/regression/boost test.cpp -lm && ./a.out little endian sizeof(long double) = 16 Testing float Assertion failed: !(signbit)(x), file test.cpp, line 222 IOT/Abort trap The inspect tool reports: bash-2.05b$ cxx -ieee -std strict_ansi -model ansi -no_pure_cname -I /boost/regression/boost inspect.cpp && ./a.out little endian float ------------------------------- 0 00 00 00 00 sn. min 00 00 00 01 n. min 00 80 00 00 1 3f 80 00 00 4/3 3f aa aa ab max 7f 7f ff ff inf 7f 80 00 00 q. nan ff c0 00 00 s. nan 7f 85 55 55 -1 bf 80 00 00 double ------------------------------ 0 00 00 00 00 00 00 00 00 sn. min 00 00 00 00 00 00 00 01 n. min 00 10 00 00 00 00 00 00 1 3f f0 00 00 00 00 00 00 4/3 3f f5 55 55 55 55 55 55 max 7f ef ff ff ff ff ff ff inf 7f f0 00 00 00 00 00 00 q. nan ff f8 00 00 00 00 00 00 s. nan 7f f5 55 55 55 55 55 55 -1 bf f0 00 00 00 00 00 00 long double ------------------------- 0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sn. min 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 n. min 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1 3f ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4/3 3f ff 55 55 55 55 55 55 55 55 55 55 55 55 55 55 max 7f fe ff ff ff ff ff ff ff ff ff ff ff ff ff ff inf 7f ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 q. nan ff ff 80 00 00 00 00 00 00 00 00 00 00 00 00 00 s. nan 7f ff 55 55 55 55 55 55 55 55 55 55 55 55 55 55 -1 bf ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Markus

Markus Schöpflin wrote:
Johan Råde wrote:
Markus Schöpflin wrote:
Are you interested in test results from a Tru64/Alpha machine?
Yes! I have not run any tests on Alphas.
Here you are:
[snip] There are three problems: 1. The linking problem has been fixed in the latest version. (Or did you have the latest version and just forgot to compile long_double_mask.cpp?) 2. A slightly different binary representation of long double than I had expected. Is there any preprocessor symbol that I can use to detect Alpha processors? 3. Your <limits> header is a bit funny. numeric_limits<T>::quiet_NaN() returns a NaN with the signbit set. This triggered the assertion. (Does it matter? Maybe. According to C99, positive NaN should be written to text files as "nan" or "+nan" and negative NaN as "-nan". And this will probably be part of C++0x as well.) Thank you, Johan Råde

Johan Råde wrote:
There are three problems:
1. The linking problem has been fixed in the latest version. (Or did you have the latest version and just forgot to compile long_double_mask.cpp?)
The latter.
2. A slightly different binary representation of long double than I had expected. Is there any preprocessor symbol that I can use to detect Alpha processors?
Stolen from numeric/interval/detail/alpha_rounding_control.hpp: #if !defined(alpha) && !defined(__alpha__) #error This header only works on Alpha CPUs. #endif This works on GCC and CXX.
3. Your <limits> header is a bit funny. numeric_limits<T>::quiet_NaN() returns a NaN with the signbit set. This triggered the assertion. (Does it matter? Maybe. According to C99, positive NaN should be written to text files as "nan" or "+nan" and negative NaN as "-nan". And this will probably be part of C++0x as well.)
Commenting out the two assert on line 222 and 230 gives: bash-2.05b$ cxx -ieee -std strict_ansi -model ansi -no_pure_cname -I /boost/regression/boost test.cpp ../long_double_mask.cpp -lm && ./a.out test.cpp: ../long_double_mask.cpp: little endian sizeof(long double) = 16 mask<long double>::sign = 80000000 mask<long double>::exponent = 00000000 mask<long double>::significand = 00000000 mask<long double>::fraction = ffffffff Testing float Assertion failed: (copysign)(x, y) == x, file test.cpp, line 281 IOT/Abort trap Seems there is generally something odd with the sign bit handling. Markus

Johan Råde wrote:
3. Your <limits> header is a bit funny. numeric_limits<T>::quiet_NaN() returns a NaN with the signbit set. This triggered the assertion.
You need to allow for the possibility that the sign bit is set anyway.
(Does it matter? Maybe. According to C99, positive NaN should be written to text files as "nan" or "+nan" and negative NaN as "-nan". And this will probably be part of C++0x as well.)
C++ doesn't guarentee any particular format for printing NaN's or Infinities :-( John.

John Maddock wrote:
Johan Råde wrote:
3. Your <limits> header is a bit funny. numeric_limits<T>::quiet_NaN() returns a NaN with the signbit set. This triggered the assertion.
You need to allow for the possibility that the sign bit is set anyway.
I will.
(Does it matter? Maybe. According to C99, positive NaN should be written to text files as "nan" or "+nan" and negative NaN as "-nan". And this will probably be part of C++0x as well.)
C++ doesn't guarentee any particular format for printing NaN's or Infinities :-(
C99 does. And C99 will become part of C++0X, right? --Johan

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Johan Råde | Sent: 12 October 2006 16:40 | To: boost@lists.boost.org | Subject: Re: [boost] Optimized portable isnan, isfinite, | fpclassify etc | | John Maddock wrote: | > Johan Råde wrote: | >> 3. Your <limits> header is a bit funny. | >> numeric_limits<T>::quiet_NaN() returns a NaN with the signbit set. | >> This triggered the assertion. | > | > You need to allow for the possibility that the sign bit is | set anyway. | | I will. | | > | >> (Does it matter? Maybe. According to C99, positive NaN should be | >> written to text files as "nan" or "+nan" and negative | NaN as "-nan". | >> And this will probably be part of C++0x as well.) | > | > C++ doesn't guarentee any particular format for printing | NaN's or Infinities | > :-( | | C99 does. And C99 will become part of C++0X, right? | I have also raised this issue http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2022.pdf and suggest that, with NaNs (like other types), sign bit should be detectable and printed, without implying any mathematical sense. Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

Markus Schöpflin wrote:
Johan Råde wrote:
Markus Schöpflin wrote:
Are you interested in test results from a Tru64/Alpha machine?
Yes! I have not run any tests on Alphas.
Here you are:
[snip] I have uploaded a new version to the Vault. All 3 problems have been fixed, I hope. Please test again. --Johan

Johan Råde wrote:
I have uploaded a new version to the Vault. All 3 problems have been fixed, I hope. Please test again.
No luck: cxx: Error: ../fpclassify.hpp, line 86: identifier "T" is undefined + sizeof(T) - 4, -------------------------^ cxx: Error: ../fpclassify.hpp, line 100: identifier "T" is undefined + sizeof(T) - 4, -------------------------^ cxx: Info: 2 errors detected in the compilation of "test.cpp". ../long_double_mask.cpp: cxx: Error: ../fpclassify.hpp, line 86: identifier "T" is undefined + sizeof(T) - 4, -------------------------^ cxx: Error: ../fpclassify.hpp, line 100: identifier "T" is undefined + sizeof(T) - 4, -------------------------^ cxx: Info: 2 errors detected in the compilation of "../long_double_mask.cpp". Compilation exited abnormally with code 1 at Thu Oct 12 10:37:34 Markus

Markus Schöpflin wrote:
Johan Råde wrote:
I have uploaded a new version to the Vault. All 3 problems have been fixed, I hope. Please test again.
No luck:
cxx: Error: ../fpclassify.hpp, line 86: identifier "T" is undefined + sizeof(T) - 4, -------------------------^ cxx: Error: ../fpclassify.hpp, line 100: identifier "T" is undefined + sizeof(T) - 4, -------------------------^ cxx: Info: 2 errors detected in the compilation of "test.cpp". .../long_double_mask.cpp: cxx: Error: ../fpclassify.hpp, line 86: identifier "T" is undefined + sizeof(T) - 4, -------------------------^ cxx: Error: ../fpclassify.hpp, line 100: identifier "T" is undefined + sizeof(T) - 4, -------------------------^ cxx: Info: 2 errors detected in the compilation of "../long_double_mask.cpp".
Compilation exited abnormally with code 1 at Thu Oct 12 10:37:34
Markus
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
It's a typo. Replace the T on these two lines by long double. I have fixed it in the Vault too. --Johan

Johan Råde wrote:
It's a typo. Replace the T on these two lines by long double.
Better now. bash-2.05b$ cxx -ieee -std strict_ansi -model ansi -no_pure_cname -I /boost/regression/boost test.cpp ../long_double_mask.cpp -lm && ./a.out test.cpp: ../long_double_mask.cpp: little endian Testing float Testing double Testing long double Works regardless of the optimization level used. I tried -O0 up to -O4. Markus

Markus Schöpflin wrote:
Johan Råde wrote:
It's a typo. Replace the T on these two lines by long double.
Better now.
bash-2.05b$ cxx -ieee -std strict_ansi -model ansi -no_pure_cname -I /boost/regression/boost test.cpp ../long_double_mask.cpp -lm && ./a.out test.cpp: .../long_double_mask.cpp: little endian
Testing float Testing double Testing long double
Works regardless of the optimization level used. I tried -O0 up to -O4.
Markus
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Mission accomplished. Thanks a lot. --Johan

Johan Råde wrote:
John,
I am a bit baffled with the results from your HP-UX/Itanium tests.
Could you run the attached program on that machine? It is just a single cpp file. It prints the byte patterns of various numbers.
Here we go, HP-UX on itanium: maddock@td176> aCC -AA -I ~ *.cpp maddock@td176> ./a.out little endian float ------------------------------- 0 00 00 00 00 sn. min 01 00 00 00 n. min 00 00 80 00 1 00 00 80 3f 4/3 ab aa aa 3f max ff ff 7f 7f inf 00 00 80 7f q. nan 00 00 c0 7f s. nan 00 00 a0 7f -1 00 00 80 bf double ------------------------------ 0 00 00 00 00 00 00 00 00 sn. min 01 00 00 00 00 00 00 00 n. min 00 00 00 00 00 00 10 00 1 00 00 00 00 00 00 f0 3f 4/3 55 55 55 55 55 55 f5 3f max ff ff ff ff ff ff ef 7f inf 00 00 00 00 00 00 f0 7f q. nan 00 00 00 00 00 00 f8 7f s. nan 00 00 00 00 00 00 f4 7f -1 00 00 00 00 00 00 f0 bf long double ------------------------- 0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sn. min 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 n. min 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 3f 4/3 55 55 55 55 55 55 55 55 55 55 55 55 55 55 ff 3f max ff ff ff ff ff ff ff ff ff ff ff ff ff ff fe 7f inf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 7f q. nan 00 00 00 00 00 00 00 00 00 00 00 00 00 80 ff 7f s. nan 00 00 00 00 00 00 00 00 00 00 00 00 00 40 ff 7f -1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff bf And for completeness, HP-UX on PA-RISC: maddock@td191> aCC -AA -I ~ *.cpp maddock@td191> ./a.out big endian float ------------------------------- 0 00 00 00 00 sn. min 00 00 00 01 n. min 00 80 00 00 1 3f 80 00 00 4/3 3f aa aa ab max 7f 7f ff ff inf 7f 80 00 00 q. nan 7f a0 00 00 s. nan 7f c0 00 00 -1 bf 80 00 00 double ------------------------------ 0 00 00 00 00 00 00 00 00 sn. min 00 00 00 00 00 00 00 01 n. min 00 10 00 00 00 00 00 00 1 3f f0 00 00 00 00 00 00 4/3 3f f5 55 55 55 55 55 55 max 7f ef ff ff ff ff ff ff inf 7f f0 00 00 00 00 00 00 q. nan 7f f4 00 00 00 00 00 00 s. nan 7f f8 00 00 00 00 00 00 -1 bf f0 00 00 00 00 00 00 long double ------------------------- 0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sn. min 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 n. min 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1 3f ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4/3 3f ff 55 55 55 55 55 55 55 55 55 55 55 55 55 55 max 7f fe ff ff ff ff ff ff ff ff ff ff ff ff ff ff inf 7f ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 q. nan 7f ff 40 00 00 00 00 00 00 00 00 00 00 00 00 00 s. nan 7f ff 80 00 00 00 00 00 00 00 00 00 00 00 00 00 -1 bf ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 HTH, John.

John Maddock wrote:
Johan Råde wrote:
John,
I am a bit baffled with the results from your HP-UX/Itanium tests.
Could you run the attached program on that machine? It is just a single cpp file. It prints the byte patterns of various numbers.
Here we go, HP-UX on itanium:
maddock@td176> aCC -AA -I ~ *.cpp maddock@td176> ./a.out
little endian
float -------------------------------
0 00 00 00 00 sn. min 01 00 00 00 n. min 00 00 80 00 1 00 00 80 3f 4/3 ab aa aa 3f max ff ff 7f 7f inf 00 00 80 7f q. nan 00 00 c0 7f s. nan 00 00 a0 7f -1 00 00 80 bf
The problem is <boost/endian.hpp>. According to <boost/detail/endian.hpp> the platform is little endian. But it is clearly big endian. --Johan

Johan Råde wrote:
The problem is <boost/endian.hpp>. According to <boost/detail/endian.hpp> the platform is little endian. But it is clearly big endian.
One thing you've got to watch here is that the endianness of ints and pointers isn't necessarily the same as that for reals. And just to throw a spanner in the works, I believe the Itanium can have it's endianness altered at runtime. Whether any OS's will let you do that without crashing your program, I don't know, but I could certainly see uses for changing the endianness of reals at runtime (think big distributed applications, running over mixed hardware). John.

John Maddock wrote:
Johan Råde wrote:
The problem is <boost/endian.hpp>. According to <boost/detail/endian.hpp> the platform is little endian. But it is clearly big endian.
One thing you've got to watch here is that the endianness of ints and pointers isn't necessarily the same as that for reals.
And just to throw a spanner in the works, I believe the Itanium can have it's endianness altered at runtime. Whether any OS's will let you do that without crashing your program, I don't know, but I could certainly see uses for changing the endianness of reals at runtime (think big distributed applications, running over mixed hardware).
Some searching around the web seems to confirm this, indeed it appears that Linux on Itanium is LE, but HP-UX on Itanium is BE. And HP-UX on either Itanium or PA-RISC appears to be able to handle data in either BE or LE depending on the setting of one hardware bit. John.

Here is a new version. I have fixed name conflicts with std::isnan etc. (I tried to upload it to the vault, but the vault did not work.) -------------------------------- There are two remaining problems: 1. The header <boost/detail/endian.hpp> sometimes gives incorrect results. As John Maddock has pointed out, some processors can be operated in both BE and LE mode. So it may be difficult to fix this problem. 2. There are some problems with long double on little endian platforms with sizeof(long double) > 8. This can probably be fixed. --Johan

Johan Råde wrote: [snip]
1. The header <boost/detail/endian.hpp> sometimes gives incorrect results. As John Maddock has pointed out, some processors can be operated in both BE and LE mode. So it may be difficult to fix this problem.
[snip] Note that the Alpha processor can operate in big or little endian mode, too. AFAIK, Tru64/Alpha always uses little endian. But I have no idea about Linux/Alpha, for example. Anyway, I think it's fairly safe to assume fixed endianess given a specific CPU _and_ OS. Markus

Markus Schöpflin wrote:
Johan Råde wrote:
[snip]
1. The header <boost/detail/endian.hpp> sometimes gives incorrect results. As John Maddock has pointed out, some processors can be operated in both BE and LE mode. So it may be difficult to fix this problem.
[snip]
Note that the Alpha processor can operate in big or little endian mode, too. AFAIK, Tru64/Alpha always uses little endian. But I have no idea about Linux/Alpha, for example. Anyway, I think it's fairly safe to assume fixed endianess given a specific CPU _and_ OS.
Markus
The header <boost/detail/endian.hpp> should be revised. Now it only looks at the processor type. If the processor is Itanium or Alpha, then it defines BOOST_LITTLE_ENDIAN. It may need to look at both processor type and O/S. But according to John, Itanium can be operated in both BE and LE mode under HP-UX. So the header may have to define a symbol BOOST_UNKNOWN_ENDIAN when it can not deduce the endianness. --Johan

While you're looking at boost/detail/endian.hpp, could you please add _M_X64 to the list of little endian platforms? _M_X64 is the Microsoft define for the AMD64/INTEL64(EM64T) platform and definitely signals a little endian platform. (I didn't have any luck with my previous two requests concerning this matter on the list.) Thank you, Stephan John Maddock wrote:
John Maddock wrote:
The problem is <boost/endian.hpp>. According to <boost/detail/endian.hpp> the platform is little endian. But it is clearly big endian. One thing you've got to watch here is that the endianness of ints and
Johan Råde wrote: pointers isn't necessarily the same as that for reals.

Stephan Tolksdorf wrote:
While you're looking at boost/detail/endian.hpp, could you please add _M_X64 to the list of little endian platforms? _M_X64 is the Microsoft define for the AMD64/INTEL64(EM64T) platform and definitely signals a little endian platform.
(I didn't have any luck with my previous two requests concerning this matter on the list.)
Thank you, Stephan
You are right. The macros __amd64 __amd64__ _M_AMD64 __x86_64 __x86_64__ _M_X64 should be added to the little endian platforms. But I'm not the right person to ask. I do not have developper access to Boost. John, could you fix this? --Johan

John Maddock wrote:
Done.
John, sorry to bother you with this, but I just thought, that while we are at it, it makes sense to fix endian.hpp for HP-UX/ia64 also. Currently, endian.hpp is using the __hppa macro which is defined on PA-RISC, but not on HP-UX/ia64. It makes PA-RISC a big endian platform, which is correct, and leaves HP-UX/ia64 a little endian platform, which is wrong. The correct macro defined on both PA-RISC and HP-UX/ia64 is __hpux. Attached the patch. Could you, please, apply it to both the HEAD and the RC branch? Thanks in advance, Boris Index: endian.hpp =================================================================== RCS file: /cvsroot/boost/boost/boost/detail/endian.hpp,v retrieving revision 1.3 diff -r1.3 endian.hpp 42c42 < || defined(__ppc__) || defined(__hppa) \ ---
|| defined(__ppc__) || defined(__hpux) \
----- Original Message ----- From: "John Maddock" <john@johnmaddock.co.uk> To: <boost@lists.boost.org> Sent: Friday, October 13, 2006 8:41 AM Subject: Re: [boost] Optimized portable isnan, isfinite, fpclassify etc Johan Råde wrote:
You are right. The macros
__amd64 __amd64__ _M_AMD64 __x86_64 __x86_64__ _M_X64
should be added to the little endian platforms.
But I'm not the right person to ask. I do not have developper access to Boost.
John, could you fix this?
Done. John. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Here is a new version. I have removed the cpp file. It is now a single header file only. The static initializations have been replaced by preprocessor stuff. It relies on <boost/detail/endian.hpp> to determine endianness, so if that does not work, then nothing works. I can not log in to the vault. What is the problem? --Johan

Johan Råde wrote:
I can not log in to the vault. What is the problem?
No clue, as it seems to work for me. What error did you get? -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - grafikrobot/yahoo

Rene Rivera wrote:
Johan Råde wrote:
I can not log in to the vault. What is the problem?
No clue, as it seems to work for me. What error did you get?
"You entered an invalid account name or password. Please, go back and try again." I thought I might had forgotten the password, so I tried to get a new password. When I entered my user name "rade" and my e-mail adress "rade@maths.lth.se" I got the error message " The entered e-mail address is not valid". It seems the Vault has forgotten that I exist.

Johan Råde wrote:
Rene Rivera wrote:
Johan Råde wrote:
I can not log in to the vault. What is the problem? No clue, as it seems to work for me. What error did you get?
"You entered an invalid account name or password. Please, go back and try again."
I thought I might had forgotten the password, so I tried to get a new password. When I entered my user name "rade" and my e-mail adress "rade@maths.lth.se" I got the error message
" The entered e-mail address is not valid". It seems the Vault has forgotten that I exist.
Well it didn't forget, but it did somehow scramble your user info. Unfortunately I don't know which parts it scrambled. So instead I deleted it, you should be able to recreate it now. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - grafikrobot/yahoo

Rene Rivera wrote:
Johan Råde wrote:
" The entered e-mail address is not valid". It seems the Vault has forgotten that I exist.
Well it didn't forget, but it did somehow scramble your user info. Unfortunately I don't know which parts it scrambled. So instead I deleted it, you should be able to recreate it now.
PS. The same happened to Andy Littles' account. So I also deleted that one. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - grafikrobot/yahoo

Rene Rivera wrote:
Johan Råde wrote:
It seems the Vault has forgotten that I exist.
Well it didn't forget, but it did somehow scramble your user info. Unfortunately I don't know which parts it scrambled. So instead I deleted it, you should be able to recreate it now.
Thanks, now I can get into the vault again. I have uploaded the latest version of fpclassify. New features: 1. No cpp file. A single header only. 2. No use of <limits>. (The test program uses <limits> though.) 3. The test program checks that <boost/detail/endian.hpp> gives the correct endianness. --Johan

Some more results: Intel on Linux/Itanium: maddock@td178.testdrive.hp.com> icc -I ~ -O3 -fast -fp-model fast=2 *.cpp ../*. cpp 2>&1 | less IPO: performing multi-file optimizations IPO: generating object file /tmp/ipo_iccEKNWIV.o maddock@td178.testdrive.hp.com> ./a.out Testing float Testing double Testing long double a.out: test.cpp:133: void test_basic() [with T = long double]: Assertion `(isnor mal)(x)' failed. Aborted HP aCC on HP-UX on itanium: maddock@td176> aCC -AA -O3 -I ~ *.cpp ../*.cpp test.cpp: "test.cpp", line 32: error #2735: using-declaration of function "boost::math::isinf(float)" conflicts with function "isinf(float)" (declared at line 1380 of "/opt/aCC/include_std/cmath") using boost::math::isinf; ^ "test.cpp", line 33: error #2735: using-declaration of function "boost::math::isnan(float)" conflicts with function "isnan(float)" (declared at line 1379 of "/opt/aCC/include_std/cmath") using boost::math::isnan; ^ 2 errors detected in the compilation of "test.cpp". ../long_double_mask.cpp: Intel/Linux/Xeon: maddock@td185.testdrive.hp.com> icc -I ~ -O3 -fp-model fast=2 *.cpp ../*.cpp -s tatic maddock@td185.testdrive.hp.com> ./a.out Testing float Testing double Testing long double a.out: test.cpp:133: void test_basic() [with T = long double]: Assertion `(isnor mal)(x)' failed. Aborted John.

John Maddock wrote:
2) I'm a little surprised at seeing memcpy used to shift 4 bytes, given the slightly-hairy nature of what you're doing here, I don't think a reinterpret_cast to uint32 is unreasonable in comparison. But that's just my opinion :-)
Here's little tip about that. Some compilers (GCC 3.x, for example) don't perform dataflow analysis between certain pairs of types. Therefore, reading the bits of a float as an unsigned int by a construct like: unsigned int x_bits = *reinterpret_cast< unsigned int * >( &x ) (or the reverse) may not generate all of the proper data dependencies. What's really pernicious about this is that because the bug is scheduling-dependent, inline functions which use these constructs may only fail in some cases. The reason compilers do this is because always making conservative decisions about aliasing yields slow code (lots of extra loads & stores). Because certain classes of aliasing are extremely rare (such as the same memory being accessed through both an int * and float *), such cases are excluded from alias analysis. In the case of GCC 3.x, it seems unions avoid this problem. You can also use __attribute__((__may_alias__)). Here's what I used, in my optimized floating-point operations: #define MAY_ALIAS __attribute__ ((may_alias)) typedef unsigned int uint32; typedef uint32 MAY_ALIAS FloatBits; //! Returns the binary representation of a single-precision float as a uint32. inline FloatBits Float_GetBits( const float *p_f //!< Address of value to return. ) { return *reinterpret_cast< const FloatBits * >( p_f ); } Yes, I learned all of this the hard way. ...and was that ever a fun bug to track down! The odd thing is that the error seemed to be not only context-dependent, but also non-deterministic (perhaps based on the value of a not-yet-written memory location?)! :-/ References: http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Type-Attributes.html http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html#Optimize-O... Matt Gruenke

Matt Gruenke wrote:
John Maddock wrote: Yes, I learned all of this the hard way. ...and was that ever a fun bug to track down! The odd thing is that the error seemed to be not only context-dependent, but also non-deterministic (perhaps based on the value of a not-yet-written memory location?)! :-/
Thanks for the information! John.

Matt Gruenke wrote:
Here's little tip about that. Some compilers (GCC 3.x, for example) don't perform dataflow analysis between certain pairs of types. Therefore, reading the bits of a float as an unsigned int by a construct like:
unsigned int x_bits = *reinterpret_cast< unsigned int * >( &x )
(or the reverse) may not generate all of the proper data dependencies. What's really pernicious about this is that because the bug is scheduling-dependent, inline functions which use these constructs may only fail in some cases.
The reason compilers do this is because always making conservative decisions about aliasing yields slow code (lots of extra loads & stores). Because certain classes of aliasing are extremely rare (such as the same memory being accessed through both an int * and float *), such cases are excluded from alias analysis.
No, the reason compilers do this is because the standard labels accessing a float as an int undefined behavior. You can legitimately access it as an unsigned char[], though, and memcpy'ing a float into an int (under the assumption that both are the same size) is also well-defined, although the result may have its bytes swapped/reordered if the endianness of the two doesn't match. (In practice. In theory it's more complicated.)

Peter Dimov wrote:
No, the reason compilers do this is because the standard labels accessing a float as an int undefined behavior. You can legitimately access it as an unsigned char[], though, and memcpy'ing a float into an int (under the assumption that both are the same size) is also well-defined, although the result may have its bytes swapped/reordered if the endianness of the two doesn't match. (In practice. In theory it's more complicated.)
Thanks for the information. I'm a bit worried about the whole endianness issue. There are three approaches: 1. Check endianness during compile time (using boost/detail/endian.hpp) 2. Check endianness during static initialization (by inspecting the binary representation of some suitable number) 3. Check endianness each time a function in the library is called (by inspecting the binary representation of some suitable number) Alternative 1 is the current approach. Alternative 2 requires a cpp file and means that the library can not be used during static initialization. Alternative 3 is very safe, but slower. It would be nice to get 1 to work. There are some problems, but are they real or theoretical? Any comments on this? I have uploaded a new version to the vault. It has more well commented, and it comes bundled with the RC 1.34 version of endian.hpp. And many thanks to Stephan Tolksdorf, Boris Gubenko and John Maddock for their improvements to endian.hpp. --Johan

From: Johan Råde
I'm a bit worried about the whole endianness issue. There are three approaches:
1. Check endianness during compile time (using boost/detail/endian.hpp)
[snip]
It would be nice to get 1 to work. There are some problems, but are they real or theoretical?
Two problems I know of: 1. The endianness of int and that of float is not necessarily the same (the classic example of this is the Vax). Does Boost support Vax? Are there any other platforms out there that Boost supports which have the same problem? Of course, this is not a particularly difficult problem to solve. endian.hpp can set another symbol to signal the endiannes of floating point nubmers. By default this would be set to the same as the endianness of int on the platform, but problem platforms could set it seperately. 2. Processors which can switch endianness at runtime. Are there any operating systems which actually allow this, or is a given processor/os combination a fixed endianness? One solution that you did not suggest: - Have a global variable that indicates the endianness. - Initialize it to zero. - At the start of each function, have the code: if (endianness == 0) calculate endianness ... use endianness (I think this is safe in practise for multi-threaded operations. It just means that two threads might end up setting the endianness, but as they would both calculate the same value, that hardly matters). Is this the sort of problem which Fusion can solve? Use a compile-time solution where available, or a run-time solution where not. -- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB24 6WZ, ENGLAND Tel: +44 (0)1223 203894

Johan Råde wrote:
Martin Bonner wrote:
Are there any operating systems which actually allow this, or is a given processor/os combination a fixed endianness?
That is an important question. Does anyone know of any OS / processor combination that does not have fixed endianness?
I'm not completely certain, but I believe HP-UX falls into this category: the idea is that you can pass binary data from one platform to another, and just switch the endianness bit to access it natively (think distributed applications). John.

John Maddock wrote:
I'm not completely certain, but I believe HP-UX falls into this category: the idea is that you can pass binary data from one platform to another, and just switch the endianness bit to access it natively (think distributed applications).
Now endian.hpp defines BOOST_BIG_ENDIAN on HP-UX. This was suggested by Boris Gubenko. If you are right John, then this seems to be incorrect. Shouldn't endian.hpp then define something like BOOST_UNKNOWN_ENDIAN on HP-UX? Boris, do you have any comments on this? Then my fpclassify could use a fast implementation when BOOST_BIG_ENDIAN or BOOST_LITTLE_ENDIAN is defined and a slower implementation when BOOST_UNKNOWN_ENDIAN is defined. --Johan

Now endian.hpp defines BOOST_BIG_ENDIAN on HP-UX. This was suggested by Boris Gubenko.
If you are right John, then this seems to be incorrect. Shouldn't endian.hpp then define something like BOOST_UNKNOWN_ENDIAN on HP-UX?
Boris, do you have any comments on this?
I'm checking with the OS folks and will report back here, for both HP-UX/ia64 and Tru64 Alpha. Thanks, Boris ----- Original Message ----- From: "Johan Råde" <rade@maths.lth.se> To: <boost@lists.boost.org> Sent: Tuesday, October 17, 2006 9:00 AM Subject: Re: [boost] Optimized portable isnan, isfinite, fpclassify etc
John Maddock wrote:
I'm not completely certain, but I believe HP-UX falls into this category: the idea is that you can pass binary data from one platform to another, and just switch the endianness bit to access it natively (think distributed applications).
Now endian.hpp defines BOOST_BIG_ENDIAN on HP-UX. This was suggested by Boris Gubenko.
If you are right John, then this seems to be incorrect. Shouldn't endian.hpp then define something like BOOST_UNKNOWN_ENDIAN on HP-UX?
Boris, do you have any comments on this?
Then my fpclassify could use a fast implementation when BOOST_BIG_ENDIAN or BOOST_LITTLE_ENDIAN is defined and a slower implementation when BOOST_UNKNOWN_ENDIAN is defined.
--Johan
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (10)
-
Boris Gubenko
-
Johan Råde
-
John Maddock
-
Markus Schöpflin
-
Martin Bonner
-
Matt Gruenke
-
Paul A Bristow
-
Peter Dimov
-
Rene Rivera
-
Stephan Tolksdorf