Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 561daff

Browse files
committedJun 25, 2024
Add more f16 and f128 library functions and constants
This adds everything that was directly or transitively blocked on const arithmetic for these types, which was recently merged. Since const arithmetic is recent, most of these need to be gated by `bootstrap`. Anything that relies on intrinsics that are still missing is excluded.
1 parent 6cb3d34 commit 561daff

File tree

4 files changed

+1309
-2
lines changed

4 files changed

+1309
-2
lines changed
 

‎core/src/num/f128.rs

+639-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
#![unstable(feature = "f128", issue = "116909")]
1313

14+
use crate::convert::FloatToInt;
1415
use crate::mem;
1516

1617
/// Basic mathematical constants.
@@ -220,12 +221,50 @@ impl f128 {
220221
#[unstable(feature = "f128", issue = "116909")]
221222
pub const MAX_10_EXP: i32 = 4_932;
222223

224+
/// Not a Number (NaN).
225+
///
226+
/// Note that IEEE 754 doesn't define just a single NaN value;
227+
/// a plethora of bit patterns are considered to be NaN.
228+
/// Furthermore, the standard makes a difference
229+
/// between a "signaling" and a "quiet" NaN,
230+
/// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
231+
/// This constant isn't guaranteed to equal to any specific NaN bitpattern,
232+
/// and the stability of its representation over Rust versions
233+
/// and target platforms isn't guaranteed.
234+
#[cfg(not(bootstrap))]
235+
#[allow(clippy::eq_op)]
236+
#[rustc_diagnostic_item = "f128_nan"]
237+
#[unstable(feature = "f128", issue = "116909")]
238+
pub const NAN: f128 = 0.0_f128 / 0.0_f128;
239+
240+
/// Infinity (∞).
241+
#[cfg(not(bootstrap))]
242+
#[unstable(feature = "f128", issue = "116909")]
243+
pub const INFINITY: f128 = 1.0_f128 / 0.0_f128;
244+
245+
/// Negative infinity (−∞).
246+
#[cfg(not(bootstrap))]
247+
#[unstable(feature = "f128", issue = "116909")]
248+
pub const NEG_INFINITY: f128 = -1.0_f128 / 0.0_f128;
249+
250+
/// Sign bit
251+
#[cfg(not(bootstrap))]
252+
pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
253+
254+
/// Minimum representable positive value (min subnormal)
255+
#[cfg(not(bootstrap))]
256+
const TINY_BITS: u128 = 0x1;
257+
258+
/// Minimum representable negative value (min negative subnormal)
259+
#[cfg(not(bootstrap))]
260+
const NEG_TINY_BITS: u128 = Self::TINY_BITS | Self::SIGN_MASK;
261+
223262
/// Returns `true` if this value is NaN.
224263
///
225264
/// ```
226265
/// #![feature(f128)]
227266
/// # // FIXME(f16_f128): remove when `unordtf2` is available
228-
/// # #[cfg(target_arch = "x86_64", target_os = "linux")] {
267+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
229268
///
230269
/// let nan = f128::NAN;
231270
/// let f = 7.0_f128;
@@ -243,6 +282,78 @@ impl f128 {
243282
self != self
244283
}
245284

285+
// FIXME(#50145): `abs` is publicly unavailable in core due to
286+
// concerns about portability, so this implementation is for
287+
// private use internally.
288+
#[inline]
289+
#[cfg(not(bootstrap))]
290+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
291+
pub(crate) const fn abs_private(self) -> f128 {
292+
// SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
293+
unsafe {
294+
mem::transmute::<u128, f128>(mem::transmute::<f128, u128>(self) & !Self::SIGN_MASK)
295+
}
296+
}
297+
298+
/// Returns `true` if this value is positive infinity or negative infinity, and
299+
/// `false` otherwise.
300+
///
301+
/// ```
302+
/// #![feature(f128)]
303+
/// # // FIXME(f16_f128): remove when `eqtf2` is available
304+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
305+
///
306+
/// let f = 7.0f128;
307+
/// let inf = f128::INFINITY;
308+
/// let neg_inf = f128::NEG_INFINITY;
309+
/// let nan = f128::NAN;
310+
///
311+
/// assert!(!f.is_infinite());
312+
/// assert!(!nan.is_infinite());
313+
///
314+
/// assert!(inf.is_infinite());
315+
/// assert!(neg_inf.is_infinite());
316+
/// # }
317+
/// ```
318+
#[inline]
319+
#[must_use]
320+
#[cfg(not(bootstrap))]
321+
#[unstable(feature = "f128", issue = "116909")]
322+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
323+
pub const fn is_infinite(self) -> bool {
324+
(self == f128::INFINITY) | (self == f128::NEG_INFINITY)
325+
}
326+
327+
/// Returns `true` if this number is neither infinite nor NaN.
328+
///
329+
/// ```
330+
/// #![feature(f128)]
331+
/// # // FIXME(f16_f128): remove when `lttf2` is available
332+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
333+
///
334+
/// let f = 7.0f128;
335+
/// let inf: f128 = f128::INFINITY;
336+
/// let neg_inf: f128 = f128::NEG_INFINITY;
337+
/// let nan: f128 = f128::NAN;
338+
///
339+
/// assert!(f.is_finite());
340+
///
341+
/// assert!(!nan.is_finite());
342+
/// assert!(!inf.is_finite());
343+
/// assert!(!neg_inf.is_finite());
344+
/// # }
345+
/// ```
346+
#[inline]
347+
#[must_use]
348+
#[cfg(not(bootstrap))]
349+
#[unstable(feature = "f128", issue = "116909")]
350+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
351+
pub const fn is_finite(self) -> bool {
352+
// There's no need to handle NaN separately: if self is NaN,
353+
// the comparison is not true, exactly as desired.
354+
self.abs_private() < Self::INFINITY
355+
}
356+
246357
/// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
247358
/// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
248359
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
@@ -292,6 +403,222 @@ impl f128 {
292403
(self.to_bits() & (1 << 127)) != 0
293404
}
294405

406+
/// Returns the least number greater than `self`.
407+
///
408+
/// Let `TINY` be the smallest representable positive `f128`. Then,
409+
/// - if `self.is_nan()`, this returns `self`;
410+
/// - if `self` is [`NEG_INFINITY`], this returns [`MIN`];
411+
/// - if `self` is `-TINY`, this returns -0.0;
412+
/// - if `self` is -0.0 or +0.0, this returns `TINY`;
413+
/// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`];
414+
/// - otherwise the unique least value greater than `self` is returned.
415+
///
416+
/// The identity `x.next_up() == -(-x).next_down()` holds for all non-NaN `x`. When `x`
417+
/// is finite `x == x.next_up().next_down()` also holds.
418+
///
419+
/// ```rust
420+
/// #![feature(f128)]
421+
/// #![feature(float_next_up_down)]
422+
/// # // FIXME(f16_f128): remove when `eqtf2` is available
423+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
424+
///
425+
/// // f128::EPSILON is the difference between 1.0 and the next number up.
426+
/// assert_eq!(1.0f128.next_up(), 1.0 + f128::EPSILON);
427+
/// // But not for most numbers.
428+
/// assert!(0.1f128.next_up() < 0.1 + f128::EPSILON);
429+
/// assert_eq!(4611686018427387904f128.next_up(), 4611686018427387904.000000000000001);
430+
/// # }
431+
/// ```
432+
///
433+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
434+
/// [`INFINITY`]: Self::INFINITY
435+
/// [`MIN`]: Self::MIN
436+
/// [`MAX`]: Self::MAX
437+
#[inline]
438+
#[cfg(not(bootstrap))]
439+
#[unstable(feature = "f128", issue = "116909")]
440+
// #[unstable(feature = "float_next_up_down", issue = "91399")]
441+
pub fn next_up(self) -> Self {
442+
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
443+
// denormals to zero. This is in general unsound and unsupported, but here
444+
// we do our best to still produce the correct result on such targets.
445+
let bits = self.to_bits();
446+
if self.is_nan() || bits == Self::INFINITY.to_bits() {
447+
return self;
448+
}
449+
450+
let abs = bits & !Self::SIGN_MASK;
451+
let next_bits = if abs == 0 {
452+
Self::TINY_BITS
453+
} else if bits == abs {
454+
bits + 1
455+
} else {
456+
bits - 1
457+
};
458+
Self::from_bits(next_bits)
459+
}
460+
461+
/// Returns the greatest number less than `self`.
462+
///
463+
/// Let `TINY` be the smallest representable positive `f128`. Then,
464+
/// - if `self.is_nan()`, this returns `self`;
465+
/// - if `self` is [`INFINITY`], this returns [`MAX`];
466+
/// - if `self` is `TINY`, this returns 0.0;
467+
/// - if `self` is -0.0 or +0.0, this returns `-TINY`;
468+
/// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`];
469+
/// - otherwise the unique greatest value less than `self` is returned.
470+
///
471+
/// The identity `x.next_down() == -(-x).next_up()` holds for all non-NaN `x`. When `x`
472+
/// is finite `x == x.next_down().next_up()` also holds.
473+
///
474+
/// ```rust
475+
/// #![feature(f128)]
476+
/// #![feature(float_next_up_down)]
477+
/// # // FIXME(f16_f128): remove when `eqtf2` is available
478+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
479+
///
480+
/// let x = 1.0f128;
481+
/// // Clamp value into range [0, 1).
482+
/// let clamped = x.clamp(0.0, 1.0f128.next_down());
483+
/// assert!(clamped < 1.0);
484+
/// assert_eq!(clamped.next_up(), 1.0);
485+
/// # }
486+
/// ```
487+
///
488+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
489+
/// [`INFINITY`]: Self::INFINITY
490+
/// [`MIN`]: Self::MIN
491+
/// [`MAX`]: Self::MAX
492+
#[inline]
493+
#[cfg(not(bootstrap))]
494+
#[unstable(feature = "f128", issue = "116909")]
495+
// #[unstable(feature = "float_next_up_down", issue = "91399")]
496+
pub fn next_down(self) -> Self {
497+
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
498+
// denormals to zero. This is in general unsound and unsupported, but here
499+
// we do our best to still produce the correct result on such targets.
500+
let bits = self.to_bits();
501+
if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() {
502+
return self;
503+
}
504+
505+
let abs = bits & !Self::SIGN_MASK;
506+
let next_bits = if abs == 0 {
507+
Self::NEG_TINY_BITS
508+
} else if bits == abs {
509+
bits - 1
510+
} else {
511+
bits + 1
512+
};
513+
Self::from_bits(next_bits)
514+
}
515+
516+
/// Takes the reciprocal (inverse) of a number, `1/x`.
517+
///
518+
/// ```
519+
/// #![feature(f128)]
520+
/// # // FIXME(f16_f128): remove when `eqtf2` is available
521+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
522+
///
523+
/// let x = 2.0_f128;
524+
/// let abs_difference = (x.recip() - (1.0 / x)).abs();
525+
///
526+
/// assert!(abs_difference <= f128::EPSILON);
527+
/// # }
528+
/// ```
529+
#[inline]
530+
#[cfg(not(bootstrap))]
531+
#[unstable(feature = "f128", issue = "116909")]
532+
#[must_use = "this returns the result of the operation, without modifying the original"]
533+
pub fn recip(self) -> Self {
534+
1.0 / self
535+
}
536+
537+
/// Converts radians to degrees.
538+
///
539+
/// ```
540+
/// #![feature(f128)]
541+
/// # // FIXME(f16_f128): remove when `eqtf2` is available
542+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
543+
///
544+
/// let angle = std::f128::consts::PI;
545+
///
546+
/// let abs_difference = (angle.to_degrees() - 180.0).abs();
547+
/// assert!(abs_difference <= f128::EPSILON);
548+
/// # }
549+
/// ```
550+
#[inline]
551+
#[cfg(not(bootstrap))]
552+
#[unstable(feature = "f128", issue = "116909")]
553+
#[must_use = "this returns the result of the operation, without modifying the original"]
554+
pub fn to_degrees(self) -> Self {
555+
// Use a literal for better precision.
556+
const PIS_IN_180: f128 = 57.2957795130823208767981548141051703324054724665643215491602_f128;
557+
self * PIS_IN_180
558+
}
559+
560+
/// Converts degrees to radians.
561+
///
562+
/// ```
563+
/// #![feature(f128)]
564+
/// # // FIXME(f16_f128): remove when `eqtf2` is available
565+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
566+
///
567+
/// let angle = 180.0f128;
568+
///
569+
/// let abs_difference = (angle.to_radians() - std::f128::consts::PI).abs();
570+
///
571+
/// assert!(abs_difference <= 1e-30);
572+
/// # }
573+
/// ```
574+
#[inline]
575+
#[cfg(not(bootstrap))]
576+
#[unstable(feature = "f128", issue = "116909")]
577+
#[must_use = "this returns the result of the operation, without modifying the original"]
578+
pub fn to_radians(self) -> f128 {
579+
// Use a literal for better precision.
580+
const RADS_PER_DEG: f128 =
581+
0.0174532925199432957692369076848861271344287188854172545609719_f128;
582+
self * RADS_PER_DEG
583+
}
584+
585+
/// Rounds toward zero and converts to any primitive integer type,
586+
/// assuming that the value is finite and fits in that type.
587+
///
588+
/// ```
589+
/// #![feature(f128)]
590+
/// # // FIXME(f16_f128): remove when `float*itf` is available
591+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
592+
///
593+
/// let value = 4.6_f128;
594+
/// let rounded = unsafe { value.to_int_unchecked::<u16>() };
595+
/// assert_eq!(rounded, 4);
596+
///
597+
/// let value = -128.9_f128;
598+
/// let rounded = unsafe { value.to_int_unchecked::<i8>() };
599+
/// assert_eq!(rounded, i8::MIN);
600+
/// # }
601+
/// ```
602+
///
603+
/// # Safety
604+
///
605+
/// The value must:
606+
///
607+
/// * Not be `NaN`
608+
/// * Not be infinite
609+
/// * Be representable in the return type `Int`, after truncating off its fractional part
610+
#[inline]
611+
#[unstable(feature = "f128", issue = "116909")]
612+
#[must_use = "this returns the result of the operation, without modifying the original"]
613+
pub unsafe fn to_int_unchecked<Int>(self) -> Int
614+
where
615+
Self: FloatToInt<Int>,
616+
{
617+
// SAFETY: the caller must uphold the safety contract for
618+
// `FloatToInt::to_int_unchecked`.
619+
unsafe { FloatToInt::<Int>::to_int_unchecked(self) }
620+
}
621+
295622
/// Raw transmutation to `u128`.
296623
///
297624
/// This is currently identical to `transmute::<f128, u128>(self)` on all platforms.
@@ -367,4 +694,315 @@ impl f128 {
367694
// Stability concerns.
368695
unsafe { mem::transmute(v) }
369696
}
697+
698+
/// Return the memory representation of this floating point number as a byte array in
699+
/// big-endian (network) byte order.
700+
///
701+
/// See [`from_bits`](Self::from_bits) for some discussion of the
702+
/// portability of this operation (there are almost no issues).
703+
///
704+
/// # Examples
705+
///
706+
/// ```
707+
/// #![feature(f128)]
708+
///
709+
/// let bytes = 12.5f128.to_be_bytes();
710+
/// assert_eq!(
711+
/// bytes,
712+
/// [0x40, 0x02, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
713+
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
714+
/// );
715+
/// ```
716+
#[inline]
717+
#[unstable(feature = "f128", issue = "116909")]
718+
#[must_use = "this returns the result of the operation, without modifying the original"]
719+
pub fn to_be_bytes(self) -> [u8; 16] {
720+
self.to_bits().to_be_bytes()
721+
}
722+
723+
/// Return the memory representation of this floating point number as a byte array in
724+
/// little-endian byte order.
725+
///
726+
/// See [`from_bits`](Self::from_bits) for some discussion of the
727+
/// portability of this operation (there are almost no issues).
728+
///
729+
/// # Examples
730+
///
731+
/// ```
732+
/// #![feature(f128)]
733+
///
734+
/// let bytes = 12.5f128.to_le_bytes();
735+
/// assert_eq!(
736+
/// bytes,
737+
/// [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
738+
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x02, 0x40]
739+
/// );
740+
/// ```
741+
#[inline]
742+
#[unstable(feature = "f128", issue = "116909")]
743+
#[must_use = "this returns the result of the operation, without modifying the original"]
744+
pub fn to_le_bytes(self) -> [u8; 16] {
745+
self.to_bits().to_le_bytes()
746+
}
747+
748+
/// Return the memory representation of this floating point number as a byte array in
749+
/// native byte order.
750+
///
751+
/// As the target platform's native endianness is used, portable code
752+
/// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead.
753+
///
754+
/// [`to_be_bytes`]: f128::to_be_bytes
755+
/// [`to_le_bytes`]: f128::to_le_bytes
756+
///
757+
/// See [`from_bits`](Self::from_bits) for some discussion of the
758+
/// portability of this operation (there are almost no issues).
759+
///
760+
/// # Examples
761+
///
762+
/// ```
763+
/// #![feature(f128)]
764+
///
765+
/// let bytes = 12.5f128.to_ne_bytes();
766+
/// assert_eq!(
767+
/// bytes,
768+
/// if cfg!(target_endian = "big") {
769+
/// [0x40, 0x02, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
770+
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
771+
/// } else {
772+
/// [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773+
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x02, 0x40]
774+
/// }
775+
/// );
776+
/// ```
777+
#[inline]
778+
#[unstable(feature = "f128", issue = "116909")]
779+
#[must_use = "this returns the result of the operation, without modifying the original"]
780+
pub fn to_ne_bytes(self) -> [u8; 16] {
781+
self.to_bits().to_ne_bytes()
782+
}
783+
784+
/// Create a floating point value from its representation as a byte array in big endian.
785+
///
786+
/// See [`from_bits`](Self::from_bits) for some discussion of the
787+
/// portability of this operation (there are almost no issues).
788+
///
789+
/// # Examples
790+
///
791+
/// ```
792+
/// #![feature(f128)]
793+
/// # // FIXME(f16_f128): remove when `eqtf2` is available
794+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
795+
///
796+
/// let value = f128::from_be_bytes(
797+
/// [0x40, 0x02, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
798+
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
799+
/// );
800+
/// assert_eq!(value, 12.5);
801+
/// # }
802+
/// ```
803+
#[inline]
804+
#[must_use]
805+
#[unstable(feature = "f128", issue = "116909")]
806+
pub fn from_be_bytes(bytes: [u8; 16]) -> Self {
807+
Self::from_bits(u128::from_be_bytes(bytes))
808+
}
809+
810+
/// Create a floating point value from its representation as a byte array in little endian.
811+
///
812+
/// See [`from_bits`](Self::from_bits) for some discussion of the
813+
/// portability of this operation (there are almost no issues).
814+
///
815+
/// # Examples
816+
///
817+
/// ```
818+
/// #![feature(f128)]
819+
/// # // FIXME(f16_f128): remove when `eqtf2` is available
820+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
821+
///
822+
/// let value = f128::from_le_bytes(
823+
/// [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
824+
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x02, 0x40]
825+
/// );
826+
/// assert_eq!(value, 12.5);
827+
/// # }
828+
/// ```
829+
#[inline]
830+
#[must_use]
831+
#[unstable(feature = "f128", issue = "116909")]
832+
pub fn from_le_bytes(bytes: [u8; 16]) -> Self {
833+
Self::from_bits(u128::from_le_bytes(bytes))
834+
}
835+
836+
/// Create a floating point value from its representation as a byte array in native endian.
837+
///
838+
/// As the target platform's native endianness is used, portable code
839+
/// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
840+
/// appropriate instead.
841+
///
842+
/// [`from_be_bytes`]: f128::from_be_bytes
843+
/// [`from_le_bytes`]: f128::from_le_bytes
844+
///
845+
/// See [`from_bits`](Self::from_bits) for some discussion of the
846+
/// portability of this operation (there are almost no issues).
847+
///
848+
/// # Examples
849+
///
850+
/// ```
851+
/// #![feature(f128)]
852+
/// # // FIXME(f16_f128): remove when `eqtf2` is available
853+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
854+
///
855+
/// let value = f128::from_ne_bytes(if cfg!(target_endian = "big") {
856+
/// [0x40, 0x02, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
857+
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
858+
/// } else {
859+
/// [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
860+
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x02, 0x40]
861+
/// });
862+
/// assert_eq!(value, 12.5);
863+
/// # }
864+
/// ```
865+
#[inline]
866+
#[must_use]
867+
#[unstable(feature = "f128", issue = "116909")]
868+
pub fn from_ne_bytes(bytes: [u8; 16]) -> Self {
869+
Self::from_bits(u128::from_ne_bytes(bytes))
870+
}
871+
872+
/// Return the ordering between `self` and `other`.
873+
///
874+
/// Unlike the standard partial comparison between floating point numbers,
875+
/// this comparison always produces an ordering in accordance to
876+
/// the `totalOrder` predicate as defined in the IEEE 754 (2008 revision)
877+
/// floating point standard. The values are ordered in the following sequence:
878+
///
879+
/// - negative quiet NaN
880+
/// - negative signaling NaN
881+
/// - negative infinity
882+
/// - negative numbers
883+
/// - negative subnormal numbers
884+
/// - negative zero
885+
/// - positive zero
886+
/// - positive subnormal numbers
887+
/// - positive numbers
888+
/// - positive infinity
889+
/// - positive signaling NaN
890+
/// - positive quiet NaN.
891+
///
892+
/// The ordering established by this function does not always agree with the
893+
/// [`PartialOrd`] and [`PartialEq`] implementations of `f128`. For example,
894+
/// they consider negative and positive zero equal, while `total_cmp`
895+
/// doesn't.
896+
///
897+
/// The interpretation of the signaling NaN bit follows the definition in
898+
/// the IEEE 754 standard, which may not match the interpretation by some of
899+
/// the older, non-conformant (e.g. MIPS) hardware implementations.
900+
///
901+
/// # Example
902+
///
903+
/// ```
904+
/// #![feature(f128)]
905+
///
906+
/// struct GoodBoy {
907+
/// name: &'static str,
908+
/// weight: f128,
909+
/// }
910+
///
911+
/// let mut bois = vec![
912+
/// GoodBoy { name: "Pucci", weight: 0.1 },
913+
/// GoodBoy { name: "Woofer", weight: 99.0 },
914+
/// GoodBoy { name: "Yapper", weight: 10.0 },
915+
/// GoodBoy { name: "Chonk", weight: f128::INFINITY },
916+
/// GoodBoy { name: "Abs. Unit", weight: f128::NAN },
917+
/// GoodBoy { name: "Floaty", weight: -5.0 },
918+
/// ];
919+
///
920+
/// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
921+
///
922+
/// // `f128::NAN` could be positive or negative, which will affect the sort order.
923+
/// if f128::NAN.is_sign_negative() {
924+
/// bois.into_iter().map(|b| b.weight)
925+
/// .zip([f128::NAN, -5.0, 0.1, 10.0, 99.0, f128::INFINITY].iter())
926+
/// .for_each(|(a, b)| assert_eq!(a.to_bits(), b.to_bits()))
927+
/// } else {
928+
/// bois.into_iter().map(|b| b.weight)
929+
/// .zip([-5.0, 0.1, 10.0, 99.0, f128::INFINITY, f128::NAN].iter())
930+
/// .for_each(|(a, b)| assert_eq!(a.to_bits(), b.to_bits()))
931+
/// }
932+
/// ```
933+
#[inline]
934+
#[must_use]
935+
#[cfg(not(bootstrap))]
936+
#[unstable(feature = "f128", issue = "116909")]
937+
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
938+
let mut left = self.to_bits() as i128;
939+
let mut right = other.to_bits() as i128;
940+
941+
// In case of negatives, flip all the bits except the sign
942+
// to achieve a similar layout as two's complement integers
943+
//
944+
// Why does this work? IEEE 754 floats consist of three fields:
945+
// Sign bit, exponent and mantissa. The set of exponent and mantissa
946+
// fields as a whole have the property that their bitwise order is
947+
// equal to the numeric magnitude where the magnitude is defined.
948+
// The magnitude is not normally defined on NaN values, but
949+
// IEEE 754 totalOrder defines the NaN values also to follow the
950+
// bitwise order. This leads to order explained in the doc comment.
951+
// However, the representation of magnitude is the same for negative
952+
// and positive numbers – only the sign bit is different.
953+
// To easily compare the floats as signed integers, we need to
954+
// flip the exponent and mantissa bits in case of negative numbers.
955+
// We effectively convert the numbers to "two's complement" form.
956+
//
957+
// To do the flipping, we construct a mask and XOR against it.
958+
// We branchlessly calculate an "all-ones except for the sign bit"
959+
// mask from negative-signed values: right shifting sign-extends
960+
// the integer, so we "fill" the mask with sign bits, and then
961+
// convert to unsigned to push one more zero bit.
962+
// On positive values, the mask is all zeros, so it's a no-op.
963+
left ^= (((left >> 127) as u128) >> 1) as i128;
964+
right ^= (((right >> 127) as u128) >> 1) as i128;
965+
966+
left.cmp(&right)
967+
}
968+
969+
/// Restrict a value to a certain interval unless it is NaN.
970+
///
971+
/// Returns `max` if `self` is greater than `max`, and `min` if `self` is
972+
/// less than `min`. Otherwise this returns `self`.
973+
///
974+
/// Note that this function returns NaN if the initial value was NaN as
975+
/// well.
976+
///
977+
/// # Panics
978+
///
979+
/// Panics if `min > max`, `min` is NaN, or `max` is NaN.
980+
///
981+
/// # Examples
982+
///
983+
/// ```
984+
/// #![feature(f128)]
985+
/// # // FIXME(f16_f128): remove when `{eq,gt,unord}tf` are available
986+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
987+
///
988+
/// assert!((-3.0f128).clamp(-2.0, 1.0) == -2.0);
989+
/// assert!((0.0f128).clamp(-2.0, 1.0) == 0.0);
990+
/// assert!((2.0f128).clamp(-2.0, 1.0) == 1.0);
991+
/// assert!((f128::NAN).clamp(-2.0, 1.0).is_nan());
992+
/// # }
993+
/// ```
994+
#[inline]
995+
#[cfg(not(bootstrap))]
996+
#[unstable(feature = "f128", issue = "116909")]
997+
#[must_use = "method returns a new number and does not mutate the original value"]
998+
pub fn clamp(mut self, min: f128, max: f128) -> f128 {
999+
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
1000+
if self < min {
1001+
self = min;
1002+
}
1003+
if self > max {
1004+
self = max;
1005+
}
1006+
self
1007+
}
3701008
}

‎core/src/num/f16.rs

+611-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
#![unstable(feature = "f16", issue = "116909")]
1313

14+
use crate::convert::FloatToInt;
1415
use crate::mem;
1516

1617
/// Basic mathematical constants.
@@ -215,11 +216,49 @@ impl f16 {
215216
#[unstable(feature = "f16", issue = "116909")]
216217
pub const MAX_10_EXP: i32 = 4;
217218

219+
/// Not a Number (NaN).
220+
///
221+
/// Note that IEEE 754 doesn't define just a single NaN value;
222+
/// a plethora of bit patterns are considered to be NaN.
223+
/// Furthermore, the standard makes a difference
224+
/// between a "signaling" and a "quiet" NaN,
225+
/// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
226+
/// This constant isn't guaranteed to equal to any specific NaN bitpattern,
227+
/// and the stability of its representation over Rust versions
228+
/// and target platforms isn't guaranteed.
229+
#[cfg(not(bootstrap))]
230+
#[allow(clippy::eq_op)]
231+
#[rustc_diagnostic_item = "f16_nan"]
232+
#[unstable(feature = "f16", issue = "116909")]
233+
pub const NAN: f16 = 0.0_f16 / 0.0_f16;
234+
235+
/// Infinity (∞).
236+
#[cfg(not(bootstrap))]
237+
#[unstable(feature = "f16", issue = "116909")]
238+
pub const INFINITY: f16 = 1.0_f16 / 0.0_f16;
239+
240+
/// Negative infinity (−∞).
241+
#[cfg(not(bootstrap))]
242+
#[unstable(feature = "f16", issue = "116909")]
243+
pub const NEG_INFINITY: f16 = -1.0_f16 / 0.0_f16;
244+
245+
/// Sign bit
246+
#[cfg(not(bootstrap))]
247+
const SIGN_MASK: u16 = 0x8000;
248+
249+
/// Minimum representable positive value (min subnormal)
250+
#[cfg(not(bootstrap))]
251+
const TINY_BITS: u16 = 0x1;
252+
253+
/// Minimum representable negative value (min negative subnormal)
254+
#[cfg(not(bootstrap))]
255+
const NEG_TINY_BITS: u16 = Self::TINY_BITS | Self::SIGN_MASK;
256+
218257
/// Returns `true` if this value is NaN.
219258
///
220259
/// ```
221260
/// #![feature(f16)]
222-
/// # #[cfg(target_arch = "x86_64")] { // FIXME(f16_f128): remove when ABI bugs are fixed
261+
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
223262
///
224263
/// let nan = f16::NAN;
225264
/// let f = 7.0_f16;
@@ -237,6 +276,74 @@ impl f16 {
237276
self != self
238277
}
239278

279+
// FIXMxE(#50145): `abs` is publicly unavailable in core due to
280+
// concerns about portability, so this implementation is for
281+
// private use internally.
282+
#[inline]
283+
#[cfg(not(bootstrap))]
284+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
285+
pub(crate) const fn abs_private(self) -> f16 {
286+
// SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
287+
unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) }
288+
}
289+
290+
/// Returns `true` if this value is positive infinity or negative infinity, and
291+
/// `false` otherwise.
292+
///
293+
/// ```
294+
/// #![feature(f16)]
295+
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
296+
///
297+
/// let f = 7.0f16;
298+
/// let inf = f16::INFINITY;
299+
/// let neg_inf = f16::NEG_INFINITY;
300+
/// let nan = f16::NAN;
301+
///
302+
/// assert!(!f.is_infinite());
303+
/// assert!(!nan.is_infinite());
304+
///
305+
/// assert!(inf.is_infinite());
306+
/// assert!(neg_inf.is_infinite());
307+
/// # }
308+
/// ```
309+
#[inline]
310+
#[must_use]
311+
#[cfg(not(bootstrap))]
312+
#[unstable(feature = "f16", issue = "116909")]
313+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
314+
pub const fn is_infinite(self) -> bool {
315+
(self == f16::INFINITY) | (self == f16::NEG_INFINITY)
316+
}
317+
318+
/// Returns `true` if this number is neither infinite nor NaN.
319+
///
320+
/// ```
321+
/// #![feature(f16)]
322+
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
323+
///
324+
/// let f = 7.0f16;
325+
/// let inf: f16 = f16::INFINITY;
326+
/// let neg_inf: f16 = f16::NEG_INFINITY;
327+
/// let nan: f16 = f16::NAN;
328+
///
329+
/// assert!(f.is_finite());
330+
///
331+
/// assert!(!nan.is_finite());
332+
/// assert!(!inf.is_finite());
333+
/// assert!(!neg_inf.is_finite());
334+
/// # }
335+
/// ```
336+
#[inline]
337+
#[must_use]
338+
#[cfg(not(bootstrap))]
339+
#[unstable(feature = "f16", issue = "116909")]
340+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
341+
pub const fn is_finite(self) -> bool {
342+
// There's no need to handle NaN separately: if self is NaN,
343+
// the comparison is not true, exactly as desired.
344+
self.abs_private() < Self::INFINITY
345+
}
346+
240347
/// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
241348
/// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
242349
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
@@ -286,6 +393,220 @@ impl f16 {
286393
(self.to_bits() & (1 << 15)) != 0
287394
}
288395

396+
/// Returns the least number greater than `self`.
397+
///
398+
/// Let `TINY` be the smallest representable positive `f16`. Then,
399+
/// - if `self.is_nan()`, this returns `self`;
400+
/// - if `self` is [`NEG_INFINITY`], this returns [`MIN`];
401+
/// - if `self` is `-TINY`, this returns -0.0;
402+
/// - if `self` is -0.0 or +0.0, this returns `TINY`;
403+
/// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`];
404+
/// - otherwise the unique least value greater than `self` is returned.
405+
///
406+
/// The identity `x.next_up() == -(-x).next_down()` holds for all non-NaN `x`. When `x`
407+
/// is finite `x == x.next_up().next_down()` also holds.
408+
///
409+
/// ```rust
410+
/// #![feature(f16)]
411+
/// #![feature(float_next_up_down)]
412+
/// # // FIXME(f16_f128): ABI issues on MSVC
413+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
414+
///
415+
/// // f16::EPSILON is the difference between 1.0 and the next number up.
416+
/// assert_eq!(1.0f16.next_up(), 1.0 + f16::EPSILON);
417+
/// // But not for most numbers.
418+
/// assert!(0.1f16.next_up() < 0.1 + f16::EPSILON);
419+
/// assert_eq!(4356f16.next_up(), 4360.0);
420+
/// # }
421+
/// ```
422+
///
423+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
424+
/// [`INFINITY`]: Self::INFINITY
425+
/// [`MIN`]: Self::MIN
426+
/// [`MAX`]: Self::MAX
427+
#[inline]
428+
#[cfg(not(bootstrap))]
429+
#[unstable(feature = "f16", issue = "116909")]
430+
// #[unstable(feature = "float_next_up_down", issue = "91399")]
431+
pub fn next_up(self) -> Self {
432+
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
433+
// denormals to zero. This is in general unsound and unsupported, but here
434+
// we do our best to still produce the correct result on such targets.
435+
let bits = self.to_bits();
436+
if self.is_nan() || bits == Self::INFINITY.to_bits() {
437+
return self;
438+
}
439+
440+
let abs = bits & !Self::SIGN_MASK;
441+
let next_bits = if abs == 0 {
442+
Self::TINY_BITS
443+
} else if bits == abs {
444+
bits + 1
445+
} else {
446+
bits - 1
447+
};
448+
Self::from_bits(next_bits)
449+
}
450+
451+
/// Returns the greatest number less than `self`.
452+
///
453+
/// Let `TINY` be the smallest representable positive `f16`. Then,
454+
/// - if `self.is_nan()`, this returns `self`;
455+
/// - if `self` is [`INFINITY`], this returns [`MAX`];
456+
/// - if `self` is `TINY`, this returns 0.0;
457+
/// - if `self` is -0.0 or +0.0, this returns `-TINY`;
458+
/// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`];
459+
/// - otherwise the unique greatest value less than `self` is returned.
460+
///
461+
/// The identity `x.next_down() == -(-x).next_up()` holds for all non-NaN `x`. When `x`
462+
/// is finite `x == x.next_down().next_up()` also holds.
463+
///
464+
/// ```rust
465+
/// #![feature(f16)]
466+
/// #![feature(float_next_up_down)]
467+
/// # // FIXME(f16_f128): ABI issues on MSVC
468+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
469+
///
470+
/// let x = 1.0f16;
471+
/// // Clamp value into range [0, 1).
472+
/// let clamped = x.clamp(0.0, 1.0f16.next_down());
473+
/// assert!(clamped < 1.0);
474+
/// assert_eq!(clamped.next_up(), 1.0);
475+
/// # }
476+
/// ```
477+
///
478+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
479+
/// [`INFINITY`]: Self::INFINITY
480+
/// [`MIN`]: Self::MIN
481+
/// [`MAX`]: Self::MAX
482+
#[inline]
483+
#[cfg(not(bootstrap))]
484+
#[unstable(feature = "f16", issue = "116909")]
485+
// #[unstable(feature = "float_next_up_down", issue = "91399")]
486+
pub fn next_down(self) -> Self {
487+
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
488+
// denormals to zero. This is in general unsound and unsupported, but here
489+
// we do our best to still produce the correct result on such targets.
490+
let bits = self.to_bits();
491+
if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() {
492+
return self;
493+
}
494+
495+
let abs = bits & !Self::SIGN_MASK;
496+
let next_bits = if abs == 0 {
497+
Self::NEG_TINY_BITS
498+
} else if bits == abs {
499+
bits - 1
500+
} else {
501+
bits + 1
502+
};
503+
Self::from_bits(next_bits)
504+
}
505+
506+
/// Takes the reciprocal (inverse) of a number, `1/x`.
507+
///
508+
/// ```
509+
/// #![feature(f16)]
510+
/// # // FIXME(f16_f128): remove when `extendhfsf2` and `truncsfhf2` are available
511+
/// # #[cfg(target_os = "linux")] {
512+
///
513+
/// let x = 2.0_f16;
514+
/// let abs_difference = (x.recip() - (1.0 / x)).abs();
515+
///
516+
/// assert!(abs_difference <= f16::EPSILON);
517+
/// # }
518+
/// ```
519+
#[inline]
520+
#[cfg(not(bootstrap))]
521+
#[unstable(feature = "f16", issue = "116909")]
522+
#[must_use = "this returns the result of the operation, without modifying the original"]
523+
pub fn recip(self) -> Self {
524+
1.0 / self
525+
}
526+
527+
/// Converts radians to degrees.
528+
///
529+
/// ```
530+
/// #![feature(f16)]
531+
/// # // FIXME(f16_f128): remove when `extendhfsf2` and `truncsfhf2` are available
532+
/// # #[cfg(target_os = "linux")] {
533+
///
534+
/// let angle = std::f16::consts::PI;
535+
///
536+
/// let abs_difference = (angle.to_degrees() - 180.0).abs();
537+
/// assert!(abs_difference <= 0.5);
538+
/// # }
539+
/// ```
540+
#[inline]
541+
#[cfg(not(bootstrap))]
542+
#[unstable(feature = "f16", issue = "116909")]
543+
#[must_use = "this returns the result of the operation, without modifying the original"]
544+
pub fn to_degrees(self) -> Self {
545+
// Use a literal for better precision.
546+
const PIS_IN_180: f16 = 57.2957795130823208767981548141051703_f16;
547+
self * PIS_IN_180
548+
}
549+
550+
/// Converts degrees to radians.
551+
///
552+
/// ```
553+
/// #![feature(f16)]
554+
/// # // FIXME(f16_f128): remove when `extendhfsf2` and `truncsfhf2` are available
555+
/// # #[cfg(target_os = "linux")] {
556+
///
557+
/// let angle = 180.0f16;
558+
///
559+
/// let abs_difference = (angle.to_radians() - std::f16::consts::PI).abs();
560+
///
561+
/// assert!(abs_difference <= 0.01);
562+
/// # }
563+
/// ```
564+
#[inline]
565+
#[cfg(not(bootstrap))]
566+
#[unstable(feature = "f16", issue = "116909")]
567+
#[must_use = "this returns the result of the operation, without modifying the original"]
568+
pub fn to_radians(self) -> f16 {
569+
// Use a literal for better precision.
570+
const RADS_PER_DEG: f16 = 0.017453292519943295769236907684886_f16;
571+
self * RADS_PER_DEG
572+
}
573+
574+
/// Rounds toward zero and converts to any primitive integer type,
575+
/// assuming that the value is finite and fits in that type.
576+
///
577+
/// ```
578+
/// #![feature(f16)]
579+
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
580+
///
581+
/// let value = 4.6_f16;
582+
/// let rounded = unsafe { value.to_int_unchecked::<u16>() };
583+
/// assert_eq!(rounded, 4);
584+
///
585+
/// let value = -128.9_f16;
586+
/// let rounded = unsafe { value.to_int_unchecked::<i8>() };
587+
/// assert_eq!(rounded, i8::MIN);
588+
/// # }
589+
/// ```
590+
///
591+
/// # Safety
592+
///
593+
/// The value must:
594+
///
595+
/// * Not be `NaN`
596+
/// * Not be infinite
597+
/// * Be representable in the return type `Int`, after truncating off its fractional part
598+
#[inline]
599+
#[unstable(feature = "f16", issue = "116909")]
600+
#[must_use = "this returns the result of the operation, without modifying the original"]
601+
pub unsafe fn to_int_unchecked<Int>(self) -> Int
602+
where
603+
Self: FloatToInt<Int>,
604+
{
605+
// SAFETY: the caller must uphold the safety contract for
606+
// `FloatToInt::to_int_unchecked`.
607+
unsafe { FloatToInt::<Int>::to_int_unchecked(self) }
608+
}
609+
289610
/// Raw transmutation to `u16`.
290611
///
291612
/// This is currently identical to `transmute::<f16, u16>(self)` on all platforms.
@@ -362,4 +683,293 @@ impl f16 {
362683
// Stability concerns.
363684
unsafe { mem::transmute(v) }
364685
}
686+
687+
/// Return the memory representation of this floating point number as a byte array in
688+
/// big-endian (network) byte order.
689+
///
690+
/// See [`from_bits`](Self::from_bits) for some discussion of the
691+
/// portability of this operation (there are almost no issues).
692+
///
693+
/// # Examples
694+
///
695+
/// ```
696+
/// #![feature(f16)]
697+
///
698+
/// let bytes = 12.5f16.to_be_bytes();
699+
/// assert_eq!(bytes, [0x4a, 0x40]);
700+
/// ```
701+
#[inline]
702+
#[unstable(feature = "f16", issue = "116909")]
703+
#[must_use = "this returns the result of the operation, without modifying the original"]
704+
pub fn to_be_bytes(self) -> [u8; 2] {
705+
self.to_bits().to_be_bytes()
706+
}
707+
708+
/// Return the memory representation of this floating point number as a byte array in
709+
/// little-endian byte order.
710+
///
711+
/// See [`from_bits`](Self::from_bits) for some discussion of the
712+
/// portability of this operation (there are almost no issues).
713+
///
714+
/// # Examples
715+
///
716+
/// ```
717+
/// #![feature(f16)]
718+
///
719+
/// let bytes = 12.5f16.to_le_bytes();
720+
/// assert_eq!(bytes, [0x40, 0x4a]);
721+
/// ```
722+
#[inline]
723+
#[unstable(feature = "f16", issue = "116909")]
724+
#[must_use = "this returns the result of the operation, without modifying the original"]
725+
pub fn to_le_bytes(self) -> [u8; 2] {
726+
self.to_bits().to_le_bytes()
727+
}
728+
729+
/// Return the memory representation of this floating point number as a byte array in
730+
/// native byte order.
731+
///
732+
/// As the target platform's native endianness is used, portable code
733+
/// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead.
734+
///
735+
/// [`to_be_bytes`]: f16::to_be_bytes
736+
/// [`to_le_bytes`]: f16::to_le_bytes
737+
///
738+
/// See [`from_bits`](Self::from_bits) for some discussion of the
739+
/// portability of this operation (there are almost no issues).
740+
///
741+
/// # Examples
742+
///
743+
/// ```
744+
/// #![feature(f16)]
745+
///
746+
/// let bytes = 12.5f16.to_ne_bytes();
747+
/// assert_eq!(
748+
/// bytes,
749+
/// if cfg!(target_endian = "big") {
750+
/// [0x4a, 0x40]
751+
/// } else {
752+
/// [0x40, 0x4a]
753+
/// }
754+
/// );
755+
/// ```
756+
#[inline]
757+
#[unstable(feature = "f16", issue = "116909")]
758+
#[must_use = "this returns the result of the operation, without modifying the original"]
759+
pub fn to_ne_bytes(self) -> [u8; 2] {
760+
self.to_bits().to_ne_bytes()
761+
}
762+
763+
/// Create a floating point value from its representation as a byte array in big endian.
764+
///
765+
/// See [`from_bits`](Self::from_bits) for some discussion of the
766+
/// portability of this operation (there are almost no issues).
767+
///
768+
/// # Examples
769+
///
770+
/// ```
771+
/// #![feature(f16)]
772+
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
773+
///
774+
/// let value = f16::from_be_bytes([0x4a, 0x40]);
775+
/// assert_eq!(value, 12.5);
776+
/// # }
777+
/// ```
778+
#[inline]
779+
#[must_use]
780+
#[unstable(feature = "f16", issue = "116909")]
781+
pub fn from_be_bytes(bytes: [u8; 2]) -> Self {
782+
Self::from_bits(u16::from_be_bytes(bytes))
783+
}
784+
785+
/// Create a floating point value from its representation as a byte array in little endian.
786+
///
787+
/// See [`from_bits`](Self::from_bits) for some discussion of the
788+
/// portability of this operation (there are almost no issues).
789+
///
790+
/// # Examples
791+
///
792+
/// ```
793+
/// #![feature(f16)]
794+
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
795+
///
796+
/// let value = f16::from_le_bytes([0x40, 0x4a]);
797+
/// assert_eq!(value, 12.5);
798+
/// # }
799+
/// ```
800+
#[inline]
801+
#[must_use]
802+
#[unstable(feature = "f16", issue = "116909")]
803+
pub fn from_le_bytes(bytes: [u8; 2]) -> Self {
804+
Self::from_bits(u16::from_le_bytes(bytes))
805+
}
806+
807+
/// Create a floating point value from its representation as a byte array in native endian.
808+
///
809+
/// As the target platform's native endianness is used, portable code
810+
/// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
811+
/// appropriate instead.
812+
///
813+
/// [`from_be_bytes`]: f16::from_be_bytes
814+
/// [`from_le_bytes`]: f16::from_le_bytes
815+
///
816+
/// See [`from_bits`](Self::from_bits) for some discussion of the
817+
/// portability of this operation (there are almost no issues).
818+
///
819+
/// # Examples
820+
///
821+
/// ```
822+
/// #![feature(f16)]
823+
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
824+
///
825+
/// let value = f16::from_ne_bytes(if cfg!(target_endian = "big") {
826+
/// [0x4a, 0x40]
827+
/// } else {
828+
/// [0x40, 0x4a]
829+
/// });
830+
/// assert_eq!(value, 12.5);
831+
/// # }
832+
/// ```
833+
#[inline]
834+
#[must_use]
835+
#[unstable(feature = "f16", issue = "116909")]
836+
pub fn from_ne_bytes(bytes: [u8; 2]) -> Self {
837+
Self::from_bits(u16::from_ne_bytes(bytes))
838+
}
839+
840+
/// Return the ordering between `self` and `other`.
841+
///
842+
/// Unlike the standard partial comparison between floating point numbers,
843+
/// this comparison always produces an ordering in accordance to
844+
/// the `totalOrder` predicate as defined in the IEEE 754 (2008 revision)
845+
/// floating point standard. The values are ordered in the following sequence:
846+
///
847+
/// - negative quiet NaN
848+
/// - negative signaling NaN
849+
/// - negative infinity
850+
/// - negative numbers
851+
/// - negative subnormal numbers
852+
/// - negative zero
853+
/// - positive zero
854+
/// - positive subnormal numbers
855+
/// - positive numbers
856+
/// - positive infinity
857+
/// - positive signaling NaN
858+
/// - positive quiet NaN.
859+
///
860+
/// The ordering established by this function does not always agree with the
861+
/// [`PartialOrd`] and [`PartialEq`] implementations of `f16`. For example,
862+
/// they consider negative and positive zero equal, while `total_cmp`
863+
/// doesn't.
864+
///
865+
/// The interpretation of the signaling NaN bit follows the definition in
866+
/// the IEEE 754 standard, which may not match the interpretation by some of
867+
/// the older, non-conformant (e.g. MIPS) hardware implementations.
868+
///
869+
/// # Example
870+
///
871+
/// ```
872+
/// #![feature(f16)]
873+
///
874+
/// struct GoodBoy {
875+
/// name: &'static str,
876+
/// weight: f16,
877+
/// }
878+
///
879+
/// let mut bois = vec![
880+
/// GoodBoy { name: "Pucci", weight: 0.1 },
881+
/// GoodBoy { name: "Woofer", weight: 99.0 },
882+
/// GoodBoy { name: "Yapper", weight: 10.0 },
883+
/// GoodBoy { name: "Chonk", weight: f16::INFINITY },
884+
/// GoodBoy { name: "Abs. Unit", weight: f16::NAN },
885+
/// GoodBoy { name: "Floaty", weight: -5.0 },
886+
/// ];
887+
///
888+
/// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
889+
///
890+
/// // `f16::NAN` could be positive or negative, which will affect the sort order.
891+
/// if f16::NAN.is_sign_negative() {
892+
/// bois.into_iter().map(|b| b.weight)
893+
/// .zip([f16::NAN, -5.0, 0.1, 10.0, 99.0, f16::INFINITY].iter())
894+
/// .for_each(|(a, b)| assert_eq!(a.to_bits(), b.to_bits()))
895+
/// } else {
896+
/// bois.into_iter().map(|b| b.weight)
897+
/// .zip([-5.0, 0.1, 10.0, 99.0, f16::INFINITY, f16::NAN].iter())
898+
/// .for_each(|(a, b)| assert_eq!(a.to_bits(), b.to_bits()))
899+
/// }
900+
/// ```
901+
#[inline]
902+
#[must_use]
903+
#[cfg(not(bootstrap))]
904+
#[unstable(feature = "f16", issue = "116909")]
905+
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
906+
let mut left = self.to_bits() as i16;
907+
let mut right = other.to_bits() as i16;
908+
909+
// In case of negatives, flip all the bits except the sign
910+
// to achieve a similar layout as two's complement integers
911+
//
912+
// Why does this work? IEEE 754 floats consist of three fields:
913+
// Sign bit, exponent and mantissa. The set of exponent and mantissa
914+
// fields as a whole have the property that their bitwise order is
915+
// equal to the numeric magnitude where the magnitude is defined.
916+
// The magnitude is not normally defined on NaN values, but
917+
// IEEE 754 totalOrder defines the NaN values also to follow the
918+
// bitwise order. This leads to order explained in the doc comment.
919+
// However, the representation of magnitude is the same for negative
920+
// and positive numbers – only the sign bit is different.
921+
// To easily compare the floats as signed integers, we need to
922+
// flip the exponent and mantissa bits in case of negative numbers.
923+
// We effectively convert the numbers to "two's complement" form.
924+
//
925+
// To do the flipping, we construct a mask and XOR against it.
926+
// We branchlessly calculate an "all-ones except for the sign bit"
927+
// mask from negative-signed values: right shifting sign-extends
928+
// the integer, so we "fill" the mask with sign bits, and then
929+
// convert to unsigned to push one more zero bit.
930+
// On positive values, the mask is all zeros, so it's a no-op.
931+
left ^= (((left >> 15) as u16) >> 1) as i16;
932+
right ^= (((right >> 15) as u16) >> 1) as i16;
933+
934+
left.cmp(&right)
935+
}
936+
937+
/// Restrict a value to a certain interval unless it is NaN.
938+
///
939+
/// Returns `max` if `self` is greater than `max`, and `min` if `self` is
940+
/// less than `min`. Otherwise this returns `self`.
941+
///
942+
/// Note that this function returns NaN if the initial value was NaN as
943+
/// well.
944+
///
945+
/// # Panics
946+
///
947+
/// Panics if `min > max`, `min` is NaN, or `max` is NaN.
948+
///
949+
/// # Examples
950+
///
951+
/// ```
952+
/// #![feature(f16)]
953+
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
954+
///
955+
/// assert!((-3.0f16).clamp(-2.0, 1.0) == -2.0);
956+
/// assert!((0.0f16).clamp(-2.0, 1.0) == 0.0);
957+
/// assert!((2.0f16).clamp(-2.0, 1.0) == 1.0);
958+
/// assert!((f16::NAN).clamp(-2.0, 1.0).is_nan());
959+
/// # }
960+
/// ```
961+
#[inline]
962+
#[cfg(not(bootstrap))]
963+
#[unstable(feature = "f16", issue = "116909")]
964+
#[must_use = "method returns a new number and does not mutate the original value"]
965+
pub fn clamp(mut self, min: f16, max: f16) -> f16 {
966+
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
967+
if self < min {
968+
self = min;
969+
}
970+
if self > max {
971+
self = max;
972+
}
973+
self
974+
}
365975
}

‎std/src/f128.rs

+30
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,34 @@ impl f128 {
3232
pub fn powi(self, n: i32) -> f128 {
3333
unsafe { intrinsics::powif128(self, n) }
3434
}
35+
36+
/// Computes the absolute value of `self`.
37+
///
38+
/// This function always returns the precise result.
39+
///
40+
/// # Examples
41+
///
42+
/// ```
43+
/// #![feature(f128)]
44+
/// # #[cfg(reliable_f128)] { // FIXME(f16_f128): reliable_f128
45+
///
46+
/// let x = 3.5_f128;
47+
/// let y = -3.5_f128;
48+
///
49+
/// assert_eq!(x.abs(), x);
50+
/// assert_eq!(y.abs(), -y);
51+
///
52+
/// assert!(f128::NAN.abs().is_nan());
53+
/// # }
54+
/// ```
55+
#[inline]
56+
#[cfg(not(bootstrap))]
57+
#[rustc_allow_incoherent_impl]
58+
#[unstable(feature = "f128", issue = "116909")]
59+
#[must_use = "method returns a new number and does not mutate the original value"]
60+
pub fn abs(self) -> Self {
61+
// FIXME(f16_f128): replace with `intrinsics::fabsf128` when available
62+
// We don't do this now because LLVM has lowering bugs for f128 math.
63+
Self::from_bits(self.to_bits() & !(1 << 127))
64+
}
3565
}

‎std/src/f16.rs

+29
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,33 @@ impl f16 {
3232
pub fn powi(self, n: i32) -> f16 {
3333
unsafe { intrinsics::powif16(self, n) }
3434
}
35+
36+
/// Computes the absolute value of `self`.
37+
///
38+
/// This function always returns the precise result.
39+
///
40+
/// # Examples
41+
///
42+
/// ```
43+
/// #![feature(f16)]
44+
/// # #[cfg(reliable_f16)] {
45+
///
46+
/// let x = 3.5_f16;
47+
/// let y = -3.5_f16;
48+
///
49+
/// assert_eq!(x.abs(), x);
50+
/// assert_eq!(y.abs(), -y);
51+
///
52+
/// assert!(f16::NAN.abs().is_nan());
53+
/// # }
54+
/// ```
55+
#[inline]
56+
#[cfg(not(bootstrap))]
57+
#[rustc_allow_incoherent_impl]
58+
#[unstable(feature = "f16", issue = "116909")]
59+
#[must_use = "method returns a new number and does not mutate the original value"]
60+
pub fn abs(self) -> Self {
61+
// FIXME(f16_f128): replace with `intrinsics::fabsf16` when available
62+
Self::from_bits(self.to_bits() & !(1 << 15))
63+
}
3564
}

0 commit comments

Comments
 (0)
Please sign in to comment.