3

Surely rounding is (one of) the mostly asked and resolved questions. With any pre-defined precision after decimal point e.g. 10 ^ N, one could easily do

double round(double input) {
    static constexpr double DIVISOR = std::pow(10, N); 
    return std::round(value * DIVISOR) / DIVISOR;
}

However, this would potentially give values like e.g. 15.1499999999999 when the value I want is 15.15; As the nearest double number to the desired value it makes sense. But my application needs to make sure the result is always strictly larger than 15.15.

To achieve this, the easiest way is to change the std::round() to std::ceil() as above; but a N must be chosen. Given the IEEE standard for double, is there any elegant way to round up and make sure the number is always e.g. 15.1500000000000001 and achieve the highest accuracy?

I read up gtest ASSERT_DOUBLE_EQ which goes:

Verifies that the two double values val1 and val2 are approximately equal, to within 4 ULPs from each other.

But am not sure if within 4 ULPs I would surely have the above result.

Thank you in advance.

Alex Suo
  • 2,977
  • 1
  • 14
  • 22
  • "Is there any elegant way" - this is opinion. Still, I don't understand the question. – Something Something Jan 30 '23 at 05:34
  • Using `fenv` (in my suggested duplicate link) you can set the rounding direction to `FE_UPWARD`. That will get you the smallest double greater than or equal to your desired value. – JohnFilleau Jan 30 '23 at 05:36
  • If you want to round at _compile time_ then you can't rely on the floating point environment. FENV is purely runtime. – JohnFilleau Jan 30 '23 at 05:39
  • @JohnFilleau Your link seems great and exactly what I need. But 2 additional quetions: 1. Is the fenv.h available in Linux environment? 2. Would setting this flag affecting other threads in the same process? – Alex Suo Jan 30 '23 at 05:52
  • 1
    @AlexSuo according to docs it should be thread-local, see [here](https://en.cppreference.com/w/cpp/numeric/fenv). As for compliance with the standard you'll need to consult your platform-specific docs I'm afraid. – alagner Jan 30 '23 at 06:19
  • The linked duplicate does not answer this question. Not even a tiny bit. – A M Jan 30 '23 at 09:08
  • @Peter I might be making a logical jump. It sounds like OP wants to round either up or down after floating point operations. Setting the floating point environment will do that. With that knowledge, does the duplicate still not answer OP's question? – JohnFilleau Jan 30 '23 at 13:04
  • @AlexSuo it's thread local but if you're doing everything in the same thread you'll still need to get the current state, set the state to what you need, and then set it back when you're done. Most compiler apparently ignore the `#pragma` to enable access and just give you access _anyway_ without the pragma. I would include a test to make sure rounding works as you expect (pick a value that you know should round down, and test that it actually rounds up). – JohnFilleau Jan 30 '23 at 13:09
  • Here's an example https://godbolt.org/z/8Knf8Paoa – JohnFilleau Jan 30 '23 at 13:23
  • @JohnFilleau Thanks for the extra color. I've taken and implemented as desired :) Just a note that I also found this setting ultimately goes to a register on the CPU - and it's worth noting that on some certain combination of CPU + OS (e.g. Intel + Win) such flag might **NOT** be set and reset properly during context switching, and the value of the register turns our undeterministic. But if things go consistent with the spec, this is indeed the best solution. Thank you :) – Alex Suo Jan 31 '23 at 02:43

0 Answers0