lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi] Code-review request: constexpr ldexp replacement


From: Greg Chicares
Subject: [lmi] Code-review request: constexpr ldexp replacement
Date: Tue, 26 Sep 2017 19:06:17 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.3.0

On 2017-09-26 17:02, Greg Chicares wrote:
[...]
> Or should we write our own function, e.g.:
> 
> -    constexpr From limit = std::ldexp(From(1), to_traits::digits);
> +    constexpr From limit = const_ldexp(From(1), to_traits::digits);
> 
> ? All we're trying to do is raise two to a representable power. Is there
> a clean way to do that within the intersection of both compilers' constexpr
> rules (and perhaps msvc's too, if reasonable)? Iteration? Recursion? Table
> lookup? Bitwise manipulation of an array of sizeof(long double) bits, with
> reinterpret_cast<long double>?

Evidently recursion is the One True Way (TC++PL4, 28.3.2), and this
implementation almost works, but it fails in a way that puzzles me:

---------8<--------8<--------8<--------8<--------8<--------8<--------8<-------
diff --git a/bourn_cast.hpp b/bourn_cast.hpp
index 4453aa22..d39355b8 100644
--- a/bourn_cast.hpp
+++ b/bourn_cast.hpp
@@ -115,6 +115,17 @@ inline To bourn_cast(From from, std::false_type, 
std::true_type)
     return static_cast<To>(from);
 }
 
+namespace lmi
+{
+/// A constexpr alternative to std::ldexp(x, exp).
+
+template<typename T>
+constexpr T ldexp(T x, int exp)
+{
+    return (0 == exp) ? x : T(2) * ldexp(x, exp - 1);
+}
+} // namespace lmi
+
 /// Floating to integral.
 ///
 /// Integral max() must be one less than an integer power of two,
@@ -174,7 +185,7 @@ inline To bourn_cast(From from, std::true_type, 
std::false_type)
     using from_traits = std::numeric_limits<From>;
     static_assert(to_traits::is_integer && !from_traits::is_integer, "");
 
-    constexpr From limit = std::ldexp(From(1), to_traits::digits);
+    constexpr From limit = lmi::ldexp(From(1), to_traits::digits);
 
     constexpr bool is_twos_complement(~To(0) == -To(1));
 
--------->8-------->8-------->8-------->8-------->8-------->8-------->8-------

However, it introduces an error in the regression test (below). But that
error should be impossible: the patch above affects only conversion from
floating to integral, but the observed error arises when converting
from type 'float' to type 'float', i.e., on a path through the code that
should be entirely unaffected by the patch. More specifically, AFAICT, it
arises only when testing the signbit of this conversion:
  (float) (-float(0.0f))
but does not arise with
 - floating conversions other than float <-> float, or
 - conversions involving values other than negative zero.

$make $coefficiency unit_tests unit_test_targets=bourn_cast_test.exe           
make[2]: Nothing to be done for 'build_unit_tests'.
List of unit-test targets that did not build successfully:

List ends.

Running bourn_cast_test:

???? test failed: 
???? test failed: 0
[invoked from file /opt/lmi/src/lmi/bourn_cast_test.cpp, line: 775]
[file /opt/lmi/src/lmi/bourn_cast_test.cpp, line 261]
[...]
???? 1 test errors detected; 598 tests succeeded



reply via email to

[Prev in Thread] Current Thread [Next in Thread]