0

I'm currently working through Bjarne Stroustrup's Programming: Principles and Practice Using C++ (3rd Edition).

The book mentions a function named round_to() is provided in PPP_support.h

When, on the other hand, we want rounding, we can use round_to() from PPP_support. For example:

void conv2(double y)
{
    int x = round_to<int>(y); // 4/5 rounding
}

The file provided on Stroustrup's website seems to be missing the definition for round_to().

Does anyone know the official definition for that?

1
  • 3
    round_to was never a standard function and it seems it's not in PPP_support.h (anymore at least). You could use std::round(y); from <cmath> instead. You may get a warning so you could do an explicit cast: int x = static_cast<int>(std::round(y));. You could also define your own round_to like template<class To, class From> To round_to(From y) { return static_cast<To>(std::round(y)); } Commented Oct 21 at 11:32

1 Answer 1

2

Function round_to is not standard and I don't know how it is actually implemented.

In our code base, we use floor_cast, ceil_cast and round_cast that probably are very similar to the mentioned round_to.

To convert floating point numbers to integers, we should use a template function like those. Compared to raw static_cast<int>(std::round(f)), round_cast<int>(f) has the following advantages:

  • Much faster, standard round is typically rather slow
  • No undefined behavior due to integer overflow
  • Cleaner
  • Easier to search in code base
// Adapted from: https://stackoverflow.com/a/30308919
#include <concepts>
template<std::integral I, std::floating_point F> [[nodiscard]] I floor_cast(F value)
{
    int64_t w = static_cast<int64_t>(value);
    return static_cast<I>(w - (value < w));
}
template<std::integral I, std::floating_point F> [[nodiscard]] I ceil_cast(F value)
{
    int64_t w = static_cast<int64_t>(value);
    return static_cast<I>(w + (value > w));
}
template<std::integral I, std::floating_point F> [[nodiscard]] I round_cast(F value)
{
    return floor_cast<I>(value + 0.5);
}

Sign up to request clarification or add additional context in comments.

3 Comments

Interesting that you get faster versions than std::floor, std::ceil and std::round. Do your versions also give the same result as those in the standard library (with a static_cast<I> added)?
For floor and ceil, I am pretty sure the result will be identical for all numerical values inside [-2^54, 2^54]. For round, my version always rounds up for *.5, while most implementations of std::round will do round-to-even. I think this only matters in very rare cases, like precise statistics.
Ok, but how did you come to the conclusion that your versions of floor and ceil are faster? I tried your floor_cast in quick-bench against the libstdc++ version and they seem to be equally fast. The standard version also seems "cleaner" i.m.o. If one uses libc++ instead, the standard version is actually quite a bit faster than your version: quick-bench.com/q/VwaTAKcHgIz_AeiFXVn0Z1Vd99M

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.