util: introduce double_compare_nint64()
Utility module (util.h and util.c) offers a function double_compare_uint64() to compare double and uint64_t in a reliable way, without undefined behaviour, without losses, even if values are about 2^53 - 2^64. There was no a similar function to compare double and int64_t, which is needed when the right value is negative. To workaround it the right value (int64_t) was multiplied by -1 when it was negative to be able to use it in double_compare_uint64(). This led to undefined behaviour, when right value was INT64_MIN, because expression (uint64_t)-value did not help. Firstly -value was calculated, and then it was cast to uint64_t. The first step is detected by the sanitizer as undefined behaviour. Not counting, that it was slower than straightforward comparison of negative int64_t and a double value. Because involved additional negation. Besides, there was an expression: assert((uint64_t)(double)rhs == rhs || rhs > (uint64_t)EXP2_53); Rhs is a uint64_t. And there was hidden an undefined behaviour, when rhs is UINT64_MAX. The problem is that UINT64_MAX is 2^64 - 1. And it can't be stored in a double value without precision loss. It is rounded up to 2^64 = UINT64_MAX + 1. This is what happens in "(double)rhs" expression. And when it is cast back to uint64_t: "(uint64_t)(double)rhs", it explodes. The patch fixes it by simply changing check order. If rhs is bigger than 2^53 (below this border all the integers can be represented), then the cast is not done. Part of #4609
Loading
Please register or sign in to comment