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