6 ms·
I think the libstdc++ implementation does indeed have the comparisons ordered in the way that you describe. I stepped into the std::clamp() call in gdb and got
by x1f604 3y ago
I think the libstdc++ implementation does indeed have the comparisons ordered in the way that you describe. I stepped into the std::clamp() call in gdb and got this:
┌─/usr/include/c++/12/bits/stl_algo.h──────────────────────────────────────────────────────────────────────────────────────
│ 3617 \* @pre `_Tp` is LessThanComparable and `(__hi < __lo)` is false.
│ 3618 \*/
│ 3619 template<typename _Tp>
│ 3620 constexpr const _Tp&
│ 3621 clamp(const _Tp& __val, const _Tp& __lo, const _Tp& __hi)
│ 3622 {
│ 3623 __glibcxx_assert(!(__hi < __lo));
│ > 3624 return std::min(std::max(__val, __lo), __hi);
│ 3625 }
│ 3626
- cmovq 3y agoThanks for sharing. I don't know if the C++ standard mandates one behavior or another, it really depends on how you want clamp to behave if the value is NaN. std::clamp returns NaN, while the reverse order returns the min value.
- cornstalks 3y agoFrom §25.8.9 Bounded value [alg.clamp]: > 2 Preconditions: `bool(comp(proj(hi), proj(lo)))` is false. For the first form, type `T` meets the Cpp17LessThanComparable requirements (Table 26). > 3 Returns: `lo` if `bool(comp(proj(v), proj(lo)))` is true, `hi` if `bool(comp(proj(hi), proj(v)))` is true, otherwise `v`. > 4 [Note: If NaN is avoided, `T` can be a floating-point type. — end note] From Table 26: > `<` is a strict weak ordering relation (25.8)
- rahkiin 3y agoDoes that mean NaN is undefined behavior for clamp?
- cornstalks 3y agoMy interpretation is that yes, passing NaN is undefined behavior. Strict weak ordering is defined in 25.8 Sorting and related operations [alg.sorting]: > 4 The term strict refers to the requirement of an irreflexive relation (`!comp(x, x)` for all `x`), and the term weak to requirements that are not as strong as those for a total ordering, but stronger than those for a partial ordering. If we define `equiv(a, b)` as `!comp(a, b) && !comp(b, a)`, then the requirements are that `comp` and `equiv` both be transitive relations: > 4.1 `comp(a, b) && comp(b, c)` implies `comp(a, c)` > 4.2 `equiv(a, b) && equiv(b, c)` implies `equiv(a, c)` NaN breaks these relations, because `equiv(42.0, NaN)` and `equiv(NaN, 3.14)` are both true, which would imply `equiv(42.0, 3.14)` is also true. But clearly that's not true, so floating point numbers do not satisfy the strict weak ordering requirement. The standard doesn't explicitly say that NaN is undefined behavior. But it does not define the behavior for when NaN is used with `std::clamp()`, which I think by definition means it's undefined behavior.
- x1f604 3y agoBased on my reading of cppreference, it is required to return negative zero when you do std::clamp(-0.0f, +0.0f, +0.0f) because when v compares equal to lo and hi the function is required to return v, which the official std::clamp does but my incorrect clamp doesn't.