[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
- [lmi] New clang errors fixes, Vadim Zeitlin, 2017/09/17
- Re: [lmi] New clang errors fixes, Greg Chicares, 2017/09/26
- Re: [lmi] New clang errors fixes, Greg Chicares, 2017/09/27
- Re: [lmi] New clang errors fixes, Vadim Zeitlin, 2017/09/27
- [lmi] Enabling '-Wshadow' [Was: New clang errors fixes], Greg Chicares, 2017/09/27
- Re: [lmi] Enabling '-Wshadow' [Was: New clang errors fixes], Greg Chicares, 2017/09/28
- Re: [lmi] Enabling '-Wshadow', Vadim Zeitlin, 2017/09/28