message: Use the fcopysign helper in fceil and fnearest
diff: @@ -362,6 +362,25 @@ inline double fneg(double value) noexcept
  return bit_cast<double>(bit_cast<uint64_t>(value) ^ F64SignMask);
  }
  +template <typename T>
  +T fcopysign(T a, T b) noexcept = delete;
  +
  +template <>
  +inline float fcopysign(float a, float b) noexcept
  +{
  + const auto a_u = bit_cast<uint32_t>(a);
  + const auto b_u = bit_cast<uint32_t>(b);
  + return bit_cast<float>((a_u & F32AbsMask) | (b_u & F32SignMask));
  +}
  +
  +template <>
  +inline double fcopysign(double a, double b) noexcept
  +{
  + const auto a_u = bit_cast<uint64_t>(a);
  + const auto b_u = bit_cast<uint64_t>(b);
  + return bit_cast<double>((a_u & F64AbsMask) | (b_u & F64SignMask));
  +}
  +
  template <typename T>
  inline T fceil(T value) noexcept
  {
  @@ -389,7 +408,7 @@ inline T ffloor(T value) noexcept
  // the __builtin_floor() outputs -0 where it should +0.
  // The following workarounds the issue by using the fact that the sign of
  // the output must always match the sign of the input value.
  - return std::copysign(result, value);
  + return fcopysign(result, value);
  }
  template <typename T>
  @@ -420,7 +439,7 @@ T fnearest(T value) noexcept
  // This implementation is based on adjusting the result produced by trunc() by +-1 when needed.
  const auto t = std::trunc(value);
  if (const auto diff = std::abs(value - t); diff > T{0.5} || (diff == T{0.5} && !is_even(t)))
  - return t + std::copysign(T{1}, value);
  + return t + fcopysign(T{1}, value);
  else
  return t;
  }
  @@ -461,24 +480,6 @@ inline T fmax(T a, T b) noexcept
  return a < b ? b : a;
  }
  -template <typename T>
  -T fcopysign(T a, T b) noexcept = delete;
  -
  -template <>
  -inline float fcopysign(float a, float b) noexcept
  -{
  - const auto a_u = bit_cast<uint32_t>(a);
  - const auto b_u = bit_cast<uint32_t>(b);
  - return bit_cast<float>((a_u & F32AbsMask) | (b_u & F32SignMask));
  -}
  -
  -template <>
  -inline double fcopysign(double a, double b) noexcept
  -{
  - const auto a_u = bit_cast<uint64_t>(a);
  - const auto b_u = bit_cast<uint64_t>(b);
  - return bit_cast<double>((a_u & F64AbsMask) | (b_u & F64SignMask));
  -}
  __attribute__((no_sanitize("float-cast-overflow"))) inline constexpr float demote(
  double value) noexcept
  