|
408 | 408 | /* MSVC log2(float) is returning a double for some reason. */ \
|
409 | 409 | return static_cast<PrimitiveT>(::log2(primitive_value)); \
|
410 | 410 | } \
|
| 411 | + /** Returns the logarithm of the number with respect to an arbitrary base. \ |
| 412 | + * \ |
| 413 | + * The result might not be correctly rounded owing to implementation \ |
| 414 | + * details; self.log2() can produce more accurate results for base 2, and \ |
| 415 | + * self.log10() can produce more accurate results for base 10. \ |
| 416 | + */ \ |
| 417 | + inline T log(const T& base) const& noexcept { return ln() / base.ln(); } \ |
411 | 418 | /** Returns the maximum of the two numbers, ignoring NaN. \
|
412 | 419 | * \
|
413 | 420 | * If one of the arguments is NaN, then the other argument is returned. \
|
|
576 | 583 | } \
|
577 | 584 | static_assert(true)
|
578 | 585 |
|
579 |
| -#define _sus__float_category(T) \ |
580 |
| - /** Returns the floating point category of the number. \ |
581 |
| - * \ |
582 |
| - * If only one property is going to be tested, it is generally faster to use \ |
583 |
| - * the specific predicate instead. \ |
584 |
| - */ \ |
585 |
| - constexpr inline FpCategory classify() const& noexcept { \ |
586 |
| - return __private::float_category(primitive_value); \ |
587 |
| - } \ |
588 |
| - /** Returns true if this number is neither infinite nor NaN. \ |
589 |
| - */ \ |
590 |
| - constexpr inline bool is_finite() const& noexcept { \ |
591 |
| - return !__private::float_is_inf_or_nan(primitive_value); \ |
592 |
| - } \ |
593 |
| - /** Returns true if this value is positive infinity or negative infinity, \ |
594 |
| - * and false otherwise. \ |
595 |
| - */ \ |
596 |
| - constexpr inline bool is_infinite() const& noexcept { \ |
597 |
| - return __private::float_is_inf(primitive_value); \ |
598 |
| - } \ |
599 |
| - /** Returns true if this value is NaN. \ |
600 |
| - */ \ |
601 |
| - constexpr inline bool is_nan() const& noexcept { \ |
602 |
| - return __private::float_is_nan(primitive_value); \ |
603 |
| - } \ |
604 |
| - /** Returns true if the number is neither zero, infinite, subnormal, or NaN. \ |
605 |
| - */ \ |
606 |
| - constexpr inline bool is_normal() const& noexcept { \ |
607 |
| - return __private::float_is_normal(primitive_value); \ |
608 |
| - } \ |
609 |
| - /** Returns true if self has a negative sign, including -0.0, NaNs with \ |
610 |
| - * negative sign bit and negative infinity. \ |
611 |
| - * \ |
612 |
| - * Note that IEEE-745 doesn’t assign any meaning to the sign bit in case of \ |
613 |
| - * a NaN \ |
614 |
| - */ \ |
615 |
| - constexpr inline bool is_sign_negative() const& noexcept { \ |
616 |
| - return __private::float_signbit(primitive_value); \ |
617 |
| - } \ |
618 |
| - /** Returns true if self has a positive sign, including +0.0, NaNs with \ |
619 |
| - * positive sign bit and positive infinity. \ |
620 |
| - * \ |
621 |
| - * Note that IEEE-745 doesn’t assign any meaning to the sign bit in case of \ |
622 |
| - * a NaN. \ |
623 |
| - */ \ |
624 |
| - constexpr inline bool is_sign_positive() const& noexcept { \ |
625 |
| - return !__private::float_signbit(primitive_value); \ |
626 |
| - } \ |
627 |
| - /** Returns true if the number is subnormal. \ |
628 |
| - */ \ |
629 |
| - constexpr inline bool is_subnormal() const& noexcept { \ |
630 |
| - return !__private::float_is_zero(primitive_value) && \ |
631 |
| - __private::float_nonzero_is_subnormal(primitive_value); \ |
632 |
| - } \ |
| 586 | +#define _sus__float_category(T) \ |
| 587 | + /** Returns the floating point category of the number. \ |
| 588 | + * \ |
| 589 | + * If only one property is going to be tested, it is generally faster to use \ |
| 590 | + * the specific predicate instead. \ |
| 591 | + */ \ |
| 592 | + constexpr inline FpCategory classify() const& noexcept { \ |
| 593 | + return __private::float_category(primitive_value); \ |
| 594 | + } \ |
| 595 | + /** Returns true if this number is neither infinite nor NaN. \ |
| 596 | + */ \ |
| 597 | + constexpr inline bool is_finite() const& noexcept { \ |
| 598 | + return !__private::float_is_inf_or_nan(primitive_value); \ |
| 599 | + } \ |
| 600 | + /** Returns true if this value is positive infinity or negative infinity, \ |
| 601 | + * and false otherwise. \ |
| 602 | + */ \ |
| 603 | + constexpr inline bool is_infinite() const& noexcept { \ |
| 604 | + return __private::float_is_inf(primitive_value); \ |
| 605 | + } \ |
| 606 | + /** Returns true if this value is NaN. \ |
| 607 | + */ \ |
| 608 | + constexpr inline bool is_nan() const& noexcept { \ |
| 609 | + return __private::float_is_nan(primitive_value); \ |
| 610 | + } \ |
| 611 | + /** Returns true if the number is neither zero, infinite, subnormal, or NaN. \ |
| 612 | + */ \ |
| 613 | + constexpr inline bool is_normal() const& noexcept { \ |
| 614 | + return __private::float_is_normal(primitive_value); \ |
| 615 | + } \ |
| 616 | + /** Returns true if self has a negative sign, including -0.0, NaNs with \ |
| 617 | + * negative sign bit and negative infinity. \ |
| 618 | + * \ |
| 619 | + * Note that IEEE-745 doesn't assign any meaning to the sign bit in case of \ |
| 620 | + * a NaN \ |
| 621 | + */ \ |
| 622 | + constexpr inline bool is_sign_negative() const& noexcept { \ |
| 623 | + return __private::float_signbit(primitive_value); \ |
| 624 | + } \ |
| 625 | + /** Returns true if self has a positive sign, including +0.0, NaNs with \ |
| 626 | + * positive sign bit and positive infinity. \ |
| 627 | + * \ |
| 628 | + * Note that IEEE-745 doesn't assign any meaning to the sign bit in case of \ |
| 629 | + * a NaN. \ |
| 630 | + */ \ |
| 631 | + constexpr inline bool is_sign_positive() const& noexcept { \ |
| 632 | + return !__private::float_signbit(primitive_value); \ |
| 633 | + } \ |
| 634 | + /** Returns true if the number is subnormal. \ |
| 635 | + */ \ |
| 636 | + constexpr inline bool is_subnormal() const& noexcept { \ |
| 637 | + return !__private::float_is_zero(primitive_value) && \ |
| 638 | + __private::float_nonzero_is_subnormal(primitive_value); \ |
| 639 | + } \ |
633 | 640 | static_assert(true)
|
634 | 641 |
|
635 |
| -// clamp |
636 |
| -// div_euclid, rem_euclid |
| 642 | +#define _sus__float_clamp(T) \ |
| 643 | + /** Restrict a value to a certain interval unless it is NaN. \ |
| 644 | + * \ |
| 645 | + * Returns max if self is greater than max, and min if self is less than \ |
| 646 | + * min. Otherwise this returns self. \ |
| 647 | + * \ |
| 648 | + * Note that this function returns NaN if the initial value was NaN as well. \ |
| 649 | + * \ |
| 650 | + * # Panics \ |
| 651 | + * Panics if min > max, min is NaN, or max is NaN. \ |
| 652 | + */ \ |
| 653 | + constexpr inline T clamp(const T& min, const T& max) const& noexcept { \ |
| 654 | + check(!min.is_nan() && !max.is_nan() && \ |
| 655 | + min.primitive_value <= max.primitive_value); \ |
| 656 | + /* SAFETY: We have verified that the min and max are not NaN and that \ |
| 657 | + * `min <= max`. */ \ |
| 658 | + return __private::float_clamp(unsafe_fn, primitive_value, \ |
| 659 | + min.primitive_value, max.primitive_value); \ |
| 660 | + } |
| 661 | + |
| 662 | +#define _sus__float_euclid(T, PrimitiveT) \ |
| 663 | + /** Calculates Euclidean division, the matching method for `rem_euclid`. \ |
| 664 | + * \ |
| 665 | + * This computes the integer `n` such that `self = n * rhs + \ |
| 666 | + * self.rem_euclid(rhs)`. In other words, the result is `self / rhs` rounded \ |
| 667 | + * to the integer `n` such that `self >= n * rhs`. \ |
| 668 | + */ \ |
| 669 | + T div_euclid(const T& rhs) const& noexcept { \ |
| 670 | + const auto q = (*this / rhs).trunc(); \ |
| 671 | + if (*this % rhs < PrimitiveT{0}) { \ |
| 672 | + if (rhs > T{PrimitiveT{0}}) \ |
| 673 | + return q - T{PrimitiveT{1}}; \ |
| 674 | + else \ |
| 675 | + return q + T{PrimitiveT{1}}; \ |
| 676 | + } \ |
| 677 | + return q; \ |
| 678 | + } \ |
| 679 | + /** Calculates the least nonnegative remainder of `self (mod rhs)`. \ |
| 680 | + * \ |
| 681 | + * In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in \ |
| 682 | + * most cases. However, due to a floating point round-off error it can \ |
| 683 | + * result in `r == rhs.abs()`, violating the mathematical definition, if \ |
| 684 | + * `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. \ |
| 685 | + * This result is not an element of the function's codomain, but it is the \ |
| 686 | + * closest floating point number in the real numbers and thus fulfills the \ |
| 687 | + * property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` \ |
| 688 | + * approximatively. \ |
| 689 | + */ \ |
| 690 | + T rem_euclid(const T& rhs) const& noexcept { \ |
| 691 | + const auto r = *this % rhs; \ |
| 692 | + if (r < T{PrimitiveT{0}}) \ |
| 693 | + return r + rhs.abs(); \ |
| 694 | + else \ |
| 695 | + return r; \ |
| 696 | + } |
| 697 | + |
637 | 698 | // from_be_bytes, from_le_bytes, from_ne_bytes
|
638 | 699 | // to_be_bytes, to_le_bytes, to_ne_bytes
|
639 |
| -// log |
640 | 700 |
|
641 | 701 | #define _sus__float(T, PrimitiveT, UnsignedIntT) \
|
642 | 702 | _sus__float_storage(PrimitiveT); \
|
|
652 | 712 | _sus__float_convert_to(T, PrimitiveT); \
|
653 | 713 | _sus__float_bytes(T, UnsignedIntT); \
|
654 | 714 | _sus__float_category(T); \
|
| 715 | + _sus__float_clamp(T); \ |
| 716 | + _sus__float_euclid(T, PrimitiveT); \ |
655 | 717 | static_assert(true)
|
0 commit comments