[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi] bourn_cast version 1.0
From: |
Greg Chicares |
Subject: |
[lmi] bourn_cast version 1.0 |
Date: |
Wed, 19 Apr 2017 13:59:55 +0000 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Icedove/45.6.0 |
I've finally found time to finish bourn_cast to my satisfaction. This
has been an interesting exercise: it's the first time I've ever used
std::integral_constant (for what is still called "tag dispatching",
AFAICT, even though no tag struct is needed with C++11), and I hadn't
previously realized that avoiding UB in mixed-mode arithmetic can be
extremely difficult. But our official goal is to keep lmi running for
the next forty years, i.e., until my age equals the 3^3rd prime, and
we won't get there with undefined behavior.
This is a good time to compare the performance of bourn_cast versus
boost::numeric_cast. Here are median-of-three timings with gcc-4.9 on
i686:
Speed tests (Double, Float, Signed, Unsigned):
---ns per 10^6 calls---
---boost--- ---bourn--- -ratio-
/// Integral to integral.
static_cast<U>(S): 319266 317606 99%
bourn_cast<U>(S): 317838 316214 99%
bourn_cast<S>(U): 317233 318479 100%
/// Integral to floating.
static_cast<D>(U): 629020 629113 100%
bourn_cast<D>(U): 631356 1888946 299%
/// Floating to integral.
static_cast<U>(D): 2455119 2455725 100%
bourn_cast<U>(D): 20783153 13123147 63%
bourn_cast<S>(D): 20847704 6310430 30%
/// Floating to floating.
static_cast<F>(D): 1213014 1213738 100%
bourn_cast<F>(D): 2371261 4415004 186%
bourn_cast<D>(F): 1634036 4381516 268%
I'm not sure why bourn_cast is slower in the integral-to-floating
case, but I would guess that boost avoids testing the argument when
the "from" type's limits are within the "to" type's limits. That's an
optimization that bourn_cast might perhaps use, but it involves tricky
mixed-mode arithmetic, and the potential savings of one nanosecond per
invocation is not meaningful for lmi.
For floating-to-floating conversions, the same optimization might give
similar savings. However, bourn_cast is slower also because it takes
greater care with NaNs and infinities.
I'm surprised that bourn_cast is much faster for floating-to-integral
conversions. In this case, boost offers the same truncation semantics
as static_cast, while bourn_cast spends extra cycles to confirm value
preservation. The old method removed in commit 016d173 should be the
same as what boost does, and it was no slower than the new bourn_cast
method. The boost implementation was written in the C++98 dialect;
perhaps that just doesn't optimize as well in cases where bourn_cast
can use constexpr.
This work also gave me reason to study IEEE 754, which I had never
read, although I've studied intel's 287 manual (they sold such things
in bookstores at one time) and numerous books and papers on this
subject. For example, to ascertain that
static_cast<float>(ULLONG_MAX)
returns the nearest representable float as long as
true == std::numeric_limits<float>::is_iec559
I had to follow a chain of references:
C++11 [17.5.1.5]
| the ISO C standard ... is incorporated into this International
| Standard by reference
https://gcc.gnu.org/onlinedocs/gcc/Floating-point-implementation.html#Floating-point-implementation
| The direction of rounding when an integer is converted to a
| floating-point number that cannot exactly represent the original
| value (C90 6.2.1.3, C99 and C11 6.3.1.4).
|
| C99 Annex F is followed.
C99 [F.3]
| The conversions from integer to floating types provide the IEC 60559
| conversions from integer to floating point.
| The conversions from floating to integer types provide IEC 60559-like
| conversions but always round toward zero.
and [F.7.2/1]
| During translation ... The rounding direction mode is rounding to nearest
and [F7.3/1]:
| At program startup ... The rounding direction mode is rounding to nearest
IEEE 754-2008 [5.4.1]
| Integral values are converted exactly from integer formats to
| floating-point formats whenever the value is representable in both
| formats. If the converted value is not exactly representable in the
| destination format, the result is determined according to the
| applicable rounding-direction attribute
and [4.3.3]
| The roundTiesToEven rounding-direction attribute shall be the
| default rounding-direction attribute for results in binary formats.
- [lmi] bourn_cast version 1.0,
Greg Chicares <=