num_primitive/
float.rs

1use crate::{PrimitiveNumber, PrimitiveNumberRef, PrimitiveUnsigned};
2
3use core::cmp::Ordering;
4use core::f32::consts as f32_consts;
5use core::f64::consts as f64_consts;
6use core::num::FpCategory;
7
8struct SealedToken;
9
10/// Trait for all primitive [floating-point types], including the supertrait [`PrimitiveNumber`].
11///
12/// This encapsulates trait implementations, constants, and inherent methods that are common among
13/// the primitive floating-point types, [`f32`] and [`f64`]. Unstable types [`f16`] and [`f128`]
14/// will be added once they are stabilized.
15///
16/// See the corresponding items on the individual types for more documentation and examples.
17///
18/// This trait is sealed with a private trait to prevent downstream implementations, so we may
19/// continue to expand along with the standard library without worrying about breaking changes for
20/// implementors.
21///
22/// [floating-point types]: https://doc.rust-lang.org/reference/types/numeric.html#r-type.numeric.float
23///
24/// # Examples
25///
26/// This example requires the `std` feature for [`powi`][Self::powi] and [`sqrt`][Self::sqrt]:
27///
28#[cfg_attr(feature = "std", doc = "```")]
29#[cfg_attr(not(feature = "std"), doc = "```ignore")]
30/// use num_primitive::PrimitiveFloat;
31///
32/// // Euclidean distance, √(∑(aᵢ - bᵢ)²)
33/// fn distance<T: PrimitiveFloat>(a: &[T], b: &[T]) -> T {
34///     assert_eq!(a.len(), b.len());
35///     core::iter::zip(a, b).map(|(a, b)| (*a - b).powi(2)).sum::<T>().sqrt()
36/// }
37///
38/// assert_eq!(distance::<f32>(&[0., 0.], &[3., 4.]), 5.);
39/// assert_eq!(distance::<f64>(&[0., 1., 2.], &[1., 3., 0.]), 3.);
40/// ```
41///
42/// This example works without any features:
43///
44/// ```
45/// use num_primitive::PrimitiveFloat;
46///
47/// // Squared Euclidean distance, ∑(aᵢ - bᵢ)²
48/// fn distance_squared<T: PrimitiveFloat>(a: &[T], b: &[T]) -> T {
49///     assert_eq!(a.len(), b.len());
50///     core::iter::zip(a, b).map(|(a, b)| (*a - b)).map(|x| x * x).sum::<T>()
51/// }
52///
53/// assert_eq!(distance_squared::<f32>(&[0., 0.], &[3., 4.]), 25.);
54/// assert_eq!(distance_squared::<f64>(&[0., 1., 2.], &[1., 3., 0.]), 9.);
55/// ```
56pub trait PrimitiveFloat:
57    PrimitiveNumber + From<i8> + From<u8> + core::ops::Neg<Output = Self>
58{
59    /// Approximate number of significant digits in base 10.
60    const DIGITS: u32;
61
62    /// Machine epsilon value.
63    const EPSILON: Self;
64
65    /// Infinity (∞).
66    const INFINITY: Self;
67
68    /// Number of significant digits in base 2.
69    const MANTISSA_DIGITS: u32;
70
71    /// Largest finite value.
72    const MAX: Self;
73
74    /// Maximum _x_ for which 10<sup>_x_</sup> is normal.
75    const MAX_10_EXP: i32;
76
77    /// Maximum possible power of 2 exponent.
78    const MAX_EXP: i32;
79
80    /// Smallest finite value.
81    const MIN: Self;
82
83    /// Minimum _x_ for which 10<sup>_x_</sup> is normal.
84    const MIN_10_EXP: i32;
85
86    /// One greater than the minimum possible normal power of 2 exponent.
87    const MIN_EXP: i32;
88
89    /// Smallest positive normal value.
90    const MIN_POSITIVE: Self;
91
92    /// Not a Number (NaN).
93    const NAN: Self;
94
95    /// Negative infinity (−∞).
96    const NEG_INFINITY: Self;
97
98    /// The radix or base of the internal representation.
99    const RADIX: u32;
100
101    // The following are not inherent consts, rather from `core::{float}::consts`.
102
103    /// Euler's number (e)
104    const E: Self;
105
106    /// 1/π
107    const FRAC_1_PI: Self;
108
109    /// 1/sqrt(2)
110    const FRAC_1_SQRT_2: Self;
111
112    /// 2/π
113    const FRAC_2_PI: Self;
114
115    /// 2/sqrt(π)
116    const FRAC_2_SQRT_PI: Self;
117
118    /// π/2
119    const FRAC_PI_2: Self;
120
121    /// π/3
122    const FRAC_PI_3: Self;
123
124    /// π/4
125    const FRAC_PI_4: Self;
126
127    /// π/6
128    const FRAC_PI_6: Self;
129
130    /// π/8
131    const FRAC_PI_8: Self;
132
133    /// ln(2)
134    const LN_2: Self;
135
136    /// ln(10)
137    const LN_10: Self;
138
139    /// log₂(10)
140    const LOG2_10: Self;
141
142    /// log₂(e)
143    const LOG2_E: Self;
144
145    /// log₁₀(2)
146    const LOG10_2: Self;
147
148    /// log₁₀(e)
149    const LOG10_E: Self;
150
151    /// Archimedes' constant (π)
152    const PI: Self;
153
154    /// sqrt(2)
155    const SQRT_2: Self;
156
157    /// The full circle constant (τ)
158    const TAU: Self;
159
160    /// An unsigned integer type used by methods [`from_bits`][Self::from_bits] and
161    /// [`to_bits`][Self::to_bits].
162    type Bits: PrimitiveUnsigned;
163
164    /// Computes the absolute value of `self`.
165    fn abs(self) -> Self;
166
167    /// Restrict a value to a certain interval unless it is NaN.
168    fn clamp(self, min: Self, max: Self) -> Self;
169
170    /// Returns the floating point category of the number. If only one property is going to be
171    /// tested, it is generally faster to use the specific predicate instead.
172    fn classify(self) -> FpCategory;
173
174    /// Returns a number composed of the magnitude of `self` and the sign of sign.
175    fn copysign(self, sign: Self) -> Self;
176
177    /// Raw transmutation from `Self::Bits`.
178    fn from_bits(value: Self::Bits) -> Self;
179
180    /// Returns `true` if this number is neither infinite nor NaN.
181    fn is_finite(self) -> bool;
182
183    /// Returns `true` if this value is positive infinity or negative infinity.
184    fn is_infinite(self) -> bool;
185
186    /// Returns `true` if this value is NaN.
187    fn is_nan(self) -> bool;
188
189    /// Returns `true` if the number is neither zero, infinite, subnormal, or NaN.
190    fn is_normal(self) -> bool;
191
192    /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with negative sign bit
193    /// and negative infinity.
194    fn is_sign_negative(self) -> bool;
195
196    /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with positive sign bit
197    /// and positive infinity.
198    fn is_sign_positive(self) -> bool;
199
200    /// Returns `true` if the number is subnormal.
201    fn is_subnormal(self) -> bool;
202
203    /// Returns the maximum of the two numbers, ignoring NaN.
204    fn max(self, other: Self) -> Self;
205
206    /// Calculates the middle point of `self` and `other`.
207    fn midpoint(self, other: Self) -> Self;
208
209    /// Returns the minimum of the two numbers, ignoring NaN.
210    fn min(self, other: Self) -> Self;
211
212    /// Takes the reciprocal (inverse) of a number, `1/x`.
213    fn recip(self) -> Self;
214
215    /// Returns a number that represents the sign of `self`.
216    fn signum(self) -> Self;
217
218    /// Raw transmutation to `Self::Bits`.
219    fn to_bits(self) -> Self::Bits;
220
221    /// Converts radians to degrees.
222    fn to_degrees(self) -> Self;
223
224    /// Converts degrees to radians.
225    fn to_radians(self) -> Self;
226
227    /// Returns the ordering between `self` and `other`.
228    fn total_cmp(&self, other: &Self) -> Ordering;
229
230    /// Rounds toward zero and converts to any primitive integer type, assuming that the value is
231    /// finite and fits in that type.
232    ///
233    /// # Safety
234    ///
235    /// The value must:
236    ///
237    /// * Not be `NaN`
238    /// * Not be infinite
239    /// * Be representable in the return type `Int`, after truncating off its fractional part
240    unsafe fn to_int_unchecked<Int>(self) -> Int
241    where
242        Self: PrimitiveFloatToInt<Int>;
243
244    /// Computes the arccosine of a number. Return value is in radians in the range [0, pi] or NaN
245    /// if the number is outside the range [-1, 1].
246    #[cfg(feature = "std")]
247    fn acos(self) -> Self;
248
249    /// Inverse hyperbolic cosine function.
250    #[cfg(feature = "std")]
251    fn acosh(self) -> Self;
252
253    /// Computes the arcsine of a number. Return value is in radians in the range [-pi/2, pi/2] or
254    /// NaN if the number is outside the range [-1, 1].
255    #[cfg(feature = "std")]
256    fn asin(self) -> Self;
257
258    /// Inverse hyperbolic sine function.
259    #[cfg(feature = "std")]
260    fn asinh(self) -> Self;
261
262    /// Computes the arctangent of a number. Return value is in radians in the range [-pi/2, pi/2];
263    #[cfg(feature = "std")]
264    fn atan(self) -> Self;
265
266    /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
267    #[cfg(feature = "std")]
268    fn atan2(self, other: Self) -> Self;
269
270    /// Inverse hyperbolic tangent function.
271    #[cfg(feature = "std")]
272    fn atanh(self) -> Self;
273
274    /// Returns the cube root of a number.
275    #[cfg(feature = "std")]
276    fn cbrt(self) -> Self;
277
278    /// Returns the smallest integer greater than or equal to `self`.
279    #[cfg(feature = "std")]
280    fn ceil(self) -> Self;
281
282    /// Computes the cosine of a number (in radians).
283    #[cfg(feature = "std")]
284    fn cos(self) -> Self;
285
286    /// Hyperbolic cosine function.
287    #[cfg(feature = "std")]
288    fn cosh(self) -> Self;
289
290    /// Calculates Euclidean division, the matching method for `rem_euclid`.
291    #[cfg(feature = "std")]
292    fn div_euclid(self, rhs: Self) -> Self;
293
294    /// Returns `e^(self)`, (the exponential function).
295    #[cfg(feature = "std")]
296    fn exp(self) -> Self;
297
298    /// Returns `2^(self)`.
299    #[cfg(feature = "std")]
300    fn exp2(self) -> Self;
301
302    /// Returns `e^(self) - 1` in a way that is accurate even if the number is close to zero.
303    #[cfg(feature = "std")]
304    fn exp_m1(self) -> Self;
305
306    /// Returns the largest integer less than or equal to `self`.
307    #[cfg(feature = "std")]
308    fn floor(self) -> Self;
309
310    /// Returns the fractional part of `self`.
311    #[cfg(feature = "std")]
312    fn fract(self) -> Self;
313
314    /// Compute the distance between the origin and a point (`x`, `y`) on the Euclidean plane.
315    /// Equivalently, compute the length of the hypotenuse of a right-angle triangle with other
316    /// sides having length `x.abs()` and `y.abs()`.
317    #[cfg(feature = "std")]
318    fn hypot(self, other: Self) -> Self;
319
320    /// Returns the natural logarithm of the number.
321    #[cfg(feature = "std")]
322    fn ln(self) -> Self;
323
324    /// Returns `ln(1+n)` (natural logarithm) more accurately than if the operations were performed
325    /// separately.
326    #[cfg(feature = "std")]
327    fn ln_1p(self) -> Self;
328
329    /// Returns the logarithm of the number with respect to an arbitrary base.
330    #[cfg(feature = "std")]
331    fn log(self, base: Self) -> Self;
332
333    /// Returns the base 2 logarithm of the number.
334    #[cfg(feature = "std")]
335    fn log2(self) -> Self;
336
337    /// Returns the base 10 logarithm of the number.
338    #[cfg(feature = "std")]
339    fn log10(self) -> Self;
340
341    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error, yielding a more
342    /// accurate result than an unfused multiply-add.
343    #[cfg(feature = "std")]
344    fn mul_add(self, a: Self, b: Self) -> Self;
345
346    /// Raises a number to a floating point power.
347    #[cfg(feature = "std")]
348    fn powf(self, n: Self) -> Self;
349
350    /// Raises a number to an integer power.
351    #[cfg(feature = "std")]
352    fn powi(self, n: i32) -> Self;
353
354    /// Calculates the least nonnegative remainder of `self (mod rhs)`.
355    #[cfg(feature = "std")]
356    fn rem_euclid(self, rhs: Self) -> Self;
357
358    /// Returns the nearest integer to `self`. If a value is half-way between two integers, round
359    /// away from `0.0`.
360    #[cfg(feature = "std")]
361    fn round(self) -> Self;
362
363    /// Returns the nearest integer to a number. Rounds half-way cases to the number with an even
364    /// least significant digit.
365    #[cfg(feature = "std")]
366    fn round_ties_even(self) -> Self;
367
368    /// Computes the sine of a number (in radians).
369    #[cfg(feature = "std")]
370    fn sin(self) -> Self;
371
372    /// Simultaneously computes the sine and cosine of the number, `x`. Returns `(sin(x), cos(x))`.
373    #[cfg(feature = "std")]
374    fn sin_cos(self) -> (Self, Self);
375
376    /// Hyperbolic sine function.
377    #[cfg(feature = "std")]
378    fn sinh(self) -> Self;
379
380    /// Returns the square root of a number.
381    #[cfg(feature = "std")]
382    fn sqrt(self) -> Self;
383
384    /// Computes the tangent of a number (in radians).
385    #[cfg(feature = "std")]
386    fn tan(self) -> Self;
387
388    /// Hyperbolic tangent function.
389    #[cfg(feature = "std")]
390    fn tanh(self) -> Self;
391
392    /// Returns the integer part of `self`. This means that non-integer numbers are always
393    /// truncated towards zero.
394    #[cfg(feature = "std")]
395    fn trunc(self) -> Self;
396}
397
398/// Trait for references to primitive floating-point types ([`PrimitiveFloat`]).
399///
400/// This enables traits like the standard operators in generic code,
401/// e.g. `where &T: PrimitiveFloatRef<T>`.
402pub trait PrimitiveFloatRef<T>: PrimitiveNumberRef<T> + core::ops::Neg<Output = T> {}
403
404/// Trait for conversions supported by [`PrimitiveFloat::to_int_unchecked`].
405///
406/// This is effectively the same as the unstable [`core::convert::FloatToInt`], implemented for all
407/// combinations of [`PrimitiveFloat`] and [`PrimitiveInteger`][crate::PrimitiveInteger].
408pub trait PrimitiveFloatToInt<Int>: PrimitiveFloat {
409    #[doc(hidden)]
410    #[expect(private_interfaces)]
411    unsafe fn __to_int_unchecked(x: Self, _: SealedToken) -> Int;
412}
413
414macro_rules! impl_float {
415    ($Float:ident, $consts:ident, $Bits:ty) => {
416        impl PrimitiveFloat for $Float {
417            use_consts!(Self::{
418                DIGITS: u32,
419                EPSILON: Self,
420                INFINITY: Self,
421                MANTISSA_DIGITS: u32,
422                MAX: Self,
423                MAX_10_EXP: i32,
424                MAX_EXP: i32,
425                MIN: Self,
426                MIN_10_EXP: i32,
427                MIN_EXP: i32,
428                MIN_POSITIVE: Self,
429                NAN: Self,
430                NEG_INFINITY: Self,
431                RADIX: u32,
432            });
433
434            use_consts!($consts::{
435                E: Self,
436                FRAC_1_PI: Self,
437                FRAC_1_SQRT_2: Self,
438                FRAC_2_PI: Self,
439                FRAC_2_SQRT_PI: Self,
440                FRAC_PI_2: Self,
441                FRAC_PI_3: Self,
442                FRAC_PI_4: Self,
443                FRAC_PI_6: Self,
444                FRAC_PI_8: Self,
445                LN_2: Self,
446                LN_10: Self,
447                LOG2_10: Self,
448                LOG2_E: Self,
449                LOG10_2: Self,
450                LOG10_E: Self,
451                PI: Self,
452                SQRT_2: Self,
453                TAU: Self,
454            });
455
456            type Bits = $Bits;
457
458            forward! {
459                fn from_bits(value: Self::Bits) -> Self;
460            }
461            forward! {
462                fn abs(self) -> Self;
463                fn clamp(self, min: Self, max: Self) -> Self;
464                fn classify(self) -> FpCategory;
465                fn copysign(self, sign: Self) -> Self;
466                fn is_finite(self) -> bool;
467                fn is_infinite(self) -> bool;
468                fn is_nan(self) -> bool;
469                fn is_normal(self) -> bool;
470                fn is_sign_negative(self) -> bool;
471                fn is_sign_positive(self) -> bool;
472                fn is_subnormal(self) -> bool;
473                fn max(self, other: Self) -> Self;
474                fn midpoint(self, other: Self) -> Self;
475                fn min(self, other: Self) -> Self;
476                fn recip(self) -> Self;
477                fn signum(self) -> Self;
478                fn to_bits(self) -> Self::Bits;
479                fn to_degrees(self) -> Self;
480                fn to_radians(self) -> Self;
481            }
482            forward! {
483                fn total_cmp(&self, other: &Self) -> Ordering;
484            }
485
486            // NOTE: This is still effectively forwarding, but we need some indirection
487            // to avoid naming the unstable `core::convert::FloatToInt`.
488            #[doc = forward_doc!(to_int_unchecked)]
489            #[inline]
490            unsafe fn to_int_unchecked<Int>(self) -> Int
491            where
492                Self: PrimitiveFloatToInt<Int>,
493            {
494                // SAFETY: we're just passing through here!
495                unsafe { <Self as PrimitiveFloatToInt<Int>>::__to_int_unchecked(self, SealedToken) }
496            }
497
498            // --- std-only methods ---
499
500            #[cfg(feature = "std")]
501            forward! {
502                fn acos(self) -> Self;
503                fn acosh(self) -> Self;
504                fn asin(self) -> Self;
505                fn asinh(self) -> Self;
506                fn atan(self) -> Self;
507                fn atan2(self, other: Self) -> Self;
508                fn atanh(self) -> Self;
509                fn cbrt(self) -> Self;
510                fn ceil(self) -> Self;
511                fn cos(self) -> Self;
512                fn cosh(self) -> Self;
513                fn div_euclid(self, rhs: Self) -> Self;
514                fn exp(self) -> Self;
515                fn exp2(self) -> Self;
516                fn exp_m1(self) -> Self;
517                fn floor(self) -> Self;
518                fn fract(self) -> Self;
519                fn hypot(self, other: Self) -> Self;
520                fn ln(self) -> Self;
521                fn ln_1p(self) -> Self;
522                fn log(self, base: Self) -> Self;
523                fn log2(self) -> Self;
524                fn log10(self) -> Self;
525                fn mul_add(self, a: Self, b: Self) -> Self;
526                fn powf(self, n: Self) -> Self;
527                fn powi(self, n: i32) -> Self;
528                fn rem_euclid(self, rhs: Self) -> Self;
529                fn round(self) -> Self;
530                fn round_ties_even(self) -> Self;
531                fn sin(self) -> Self;
532                fn sin_cos(self) -> (Self, Self);
533                fn sinh(self) -> Self;
534                fn sqrt(self) -> Self;
535                fn tan(self) -> Self;
536                fn tanh(self) -> Self;
537                fn trunc(self) -> Self;
538            }
539        }
540
541        impl PrimitiveFloatRef<$Float> for &$Float {}
542    }
543}
544
545impl_float!(f32, f32_consts, u32);
546impl_float!(f64, f64_consts, u64);
547
548// NOTE: the extra module level here is to make sure that `PrimitiveFloat` isn't in scope, so we
549// can be sure that we're not recursing. Elsewhere we rely on the normal `unconditional-recursion`
550// lint, but that doesn't see through this level of trait indirection.
551mod internal {
552    macro_rules! impl_float_to_int {
553        ($Float:ty => $($Int:ty),+) => {
554            $(
555                impl super::PrimitiveFloatToInt<$Int> for $Float {
556                    #[inline]
557                    #[expect(private_interfaces)]
558                    unsafe fn __to_int_unchecked(x: Self, _: super::SealedToken) -> $Int {
559                        // SAFETY: we're just passing through here!
560                        unsafe { <$Float>::to_int_unchecked::<$Int>(x) }
561                    }
562                }
563            )+
564        }
565    }
566
567    impl_float_to_int!(f32 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
568    impl_float_to_int!(f64 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
569}