lmi
[Top][All Lists]
Advanced

[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.




reply via email to

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