diff options
143 files changed, 5682 insertions, 4321 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 159c17b0af7..c5792da2678 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -768,7 +768,7 @@ fn link_natively( && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-fuse-ld=lld") { info!("linker output: {:?}", out); - warn!("The linker driver does not support `-fuse-ld=lld`. Retrying without it."); + info!("The linker driver does not support `-fuse-ld=lld`. Retrying without it."); for arg in cmd.take_args() { if arg.to_string_lossy() != "-fuse-ld=lld" { cmd.arg(arg); diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 216800717fd..405208e94f4 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -353,8 +353,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if caller_fn_abi.conv != callee_fn_abi.conv { throw_ub_custom!( fluent::const_eval_incompatible_calling_conventions, - callee_conv = format!("{:?}", callee_fn_abi.conv), - caller_conv = format!("{:?}", caller_fn_abi.conv), + callee_conv = format!("{}", callee_fn_abi.conv), + caller_conv = format!("{}", caller_fn_abi.conv), ) } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f92b2aea160..da94331aa26 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1754,17 +1754,19 @@ pub(super) fn check_coroutine_obligations( debug!(?typeck_results.coroutine_stalled_predicates); let mode = if tcx.next_trait_solver_globally() { - TypingMode::post_borrowck_analysis(tcx, def_id) + // This query is conceptually between HIR typeck and + // MIR borrowck. We use the opaque types defined by HIR + // and ignore region constraints. + TypingMode::borrowck(tcx, def_id) } else { TypingMode::analysis_in_body(tcx, def_id) }; - let infcx = tcx - .infer_ctxt() - // typeck writeback gives us predicates with their regions erased. - // As borrowck already has checked lifetimes, we do not need to do it again. - .ignoring_regions() - .build(mode); + // Typeck writeback gives us predicates with their regions erased. + // We only need to check the goals while ignoring lifetimes to give good + // error message and to avoid breaking the assumption of `mir_borrowck` + // that all obligations already hold modulo regions. + let infcx = tcx.infer_ctxt().ignoring_regions().build(mode); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, cause) in &typeck_results.coroutine_stalled_predicates { @@ -1785,6 +1787,10 @@ pub(super) fn check_coroutine_obligations( let key = infcx.resolve_vars_if_possible(key); sanity_check_found_hidden_type(tcx, key, hidden_type)?; } + } else { + // We're not checking region constraints here, so we can simply drop the + // added opaque type uses in `TypingMode::Borrowck`. + let _ = infcx.take_opaque_types(); } Ok(()) diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 52656fc2d90..b92d1d7104f 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -214,11 +214,9 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() let span = tcx.def_span(impl_did); let trait_name = "DispatchFromDyn"; - let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span)); - let source = trait_ref.self_ty(); let target = { - assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait); + assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn)); trait_ref.args.type_at(1) }; @@ -339,7 +337,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() tcx, cause.clone(), param_env, - ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]), + ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]), )); let errors = ocx.select_all_or_error(); if !errors.is_empty() { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 4937eb73a8b..010c6c376fe 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -194,17 +194,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(()); }); - if tcx.features().rustc_attrs() { - tcx.sess.time("dumping_rustc_attr_data", || { - outlives::dump::inferred_outlives(tcx); - variance::dump::variances(tcx); - collect::dump::opaque_hidden_types(tcx); - collect::dump::predicates_and_item_bounds(tcx); - collect::dump::def_parents(tcx); - collect::dump::vtables(tcx); - }); - } - // Make sure we evaluate all static and (non-associated) const items, even if unused. // If any of these fail to evaluate, we do not want this crate to pass compilation. tcx.par_hir_body_owners(|item_def_id| { @@ -228,6 +217,17 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } }); + if tcx.features().rustc_attrs() { + tcx.sess.time("dumping_rustc_attr_data", || { + outlives::dump::inferred_outlives(tcx); + variance::dump::variances(tcx); + collect::dump::opaque_hidden_types(tcx); + collect::dump::predicates_and_item_bounds(tcx); + collect::dump::def_parents(tcx); + collect::dump::vtables(tcx); + }); + } + tcx.ensure_ok().check_unused_traits(()); } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 8fd59999fce..b1cb3ef4d79 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -1080,15 +1080,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check that this is a projection from the `Future` trait. let trait_def_id = predicate.projection_term.trait_def_id(self.tcx); - let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span)); - if trait_def_id != future_trait { + if !self.tcx.is_lang_item(trait_def_id, LangItem::Future) { debug!("deduce_future_output_from_projection: not a future"); return None; } // The `Future` trait has only one associated item, `Output`, // so check that this is what we see. - let output_assoc_item = self.tcx.associated_item_def_ids(future_trait)[0]; + let output_assoc_item = self.tcx.associated_item_def_ids(trait_def_id)[0]; if output_assoc_item != predicate.projection_term.def_id { span_bug!( cause_span, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index b554cc715fe..e28639576f0 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1001,10 +1001,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { tcx.ensure_ok().check_unsafety(def_id); tcx.ensure_ok().mir_borrowck(def_id) } - }); - }); - sess.time("MIR_effect_checking", || { - tcx.par_hir_body_owners(|def_id| { tcx.ensure_ok().has_ffi_unwind_calls(def_id); // If we need to codegen, ensure that we emit all errors from diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 33fb13e23bf..ee377277017 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -267,6 +267,18 @@ fn add_query_desc_cached_impl( ) { let Query { name, key, modifiers, .. } = &query; + // This dead code exists to instruct rust-analyzer about the link between the `rustc_queries` + // query names and the corresponding produced provider. The issue is that by nature of this + // macro producing a higher order macro that has all its token in the macro declaration we lose + // any meaningful spans, resulting in rust-analyzer being unable to make the connection between + // the query name and the corresponding providers field. The trick to fix this is to have + // `rustc_queries` emit a field access with the given name's span which allows it to succesfully + // show references / go to definition to the correspondig provider assignment which is usually + // the more interesting place. + let ra_hint = quote! { + let crate::query::Providers { #name: _, .. }; + }; + // Find out if we should cache the query on disk let cache = if let Some((args, expr)) = modifiers.cache.as_ref() { let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ }); @@ -277,6 +289,7 @@ fn add_query_desc_cached_impl( #[allow(unused_variables, unused_braces, rustc::pass_by_value)] #[inline] pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::queries::#name::Key<'tcx>) -> bool { + #ra_hint #expr } } @@ -286,6 +299,7 @@ fn add_query_desc_cached_impl( #[allow(rustc::pass_by_value)] #[inline] pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::queries::#name::Key<'tcx>) -> bool { + #ra_hint false } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c31ce1bc630..ab1f3d6099f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1260,8 +1260,7 @@ impl<'tcx> Ty<'tcx> { return true; }; alloc.expect_ty().ty_adt_def().is_some_and(|alloc_adt| { - let global_alloc = tcx.require_lang_item(LangItem::GlobalAlloc, None); - alloc_adt.did() == global_alloc + tcx.is_lang_item(alloc_adt.did(), LangItem::GlobalAlloc) }) } _ => false, diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index f63d8b2d79f..2b85d7b26ce 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -6,7 +6,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![allow(unused_crate_dependencies)] -#![cfg_attr(all(feature = "rustc", bootstrap), feature(let_chains))] // tidy-alphabetical-end pub mod constructor; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 0b16983c2c7..d09750fa281 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2493,7 +2493,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else { return None; }; - let module_name = crate_module.kind.name().unwrap_or(kw::Empty); + let module_name = crate_module.kind.name().unwrap_or(kw::Crate); let import_snippet = match import.kind { ImportKind::Single { source, target, .. } if source != target => { format!("{source} as {target}") diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index ae366e29e32..907614520a2 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -1,3 +1,4 @@ +use std::fmt::Display; use std::str::FromStr; use std::{fmt, iter}; @@ -895,6 +896,37 @@ impl FromStr for Conv { } } +fn conv_to_externabi(conv: &Conv) -> ExternAbi { + match conv { + Conv::C => ExternAbi::C { unwind: false }, + Conv::Rust => ExternAbi::Rust, + Conv::PreserveMost => ExternAbi::RustCold, + Conv::ArmAapcs => ExternAbi::Aapcs { unwind: false }, + Conv::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, + Conv::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, + Conv::Msp430Intr => ExternAbi::Msp430Interrupt, + Conv::GpuKernel => ExternAbi::GpuKernel, + Conv::X86Fastcall => ExternAbi::Fastcall { unwind: false }, + Conv::X86Intr => ExternAbi::X86Interrupt, + Conv::X86Stdcall => ExternAbi::Stdcall { unwind: false }, + Conv::X86ThisCall => ExternAbi::Thiscall { unwind: false }, + Conv::X86VectorCall => ExternAbi::Vectorcall { unwind: false }, + Conv::X86_64SysV => ExternAbi::SysV64 { unwind: false }, + Conv::X86_64Win64 => ExternAbi::Win64 { unwind: false }, + Conv::AvrInterrupt => ExternAbi::AvrInterrupt, + Conv::AvrNonBlockingInterrupt => ExternAbi::AvrNonBlockingInterrupt, + Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => ExternAbi::RiscvInterruptM, + Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor } => ExternAbi::RiscvInterruptS, + Conv::Cold | Conv::PreserveAll => unreachable!(), + } +} + +impl Display for Conv { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", conv_to_externabi(self)) + } +} + // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs index c5704c57448..f1b6fa123de 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs @@ -1,4 +1,4 @@ -use crate::spec::{FramePointer, LinkerFlavor, Lld, Target, TargetMetadata, base}; +use crate::spec::{FramePointer, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { let mut base = base::windows_msvc::opts(); @@ -11,11 +11,6 @@ pub(crate) fn target() -> Target { // and other services. It must point to the previous {x29, x30} pair on the stack." base.frame_pointer = FramePointer::NonLeaf; - // MSVC emits a warning about code that may trip "Cortex-A53 MPCore processor bug #843419" (see - // https://developer.arm.com/documentation/epm048406/latest) which is sometimes emitted by LLVM. - // Since Arm64 Windows 10+ isn't supported on that processor, it's safe to disable the warning. - base.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/arm64hazardfree"]); - Target { llvm_target: "aarch64-pc-windows-msvc".into(), metadata: TargetMetadata { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 4738a538b29..31b075db04b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -701,9 +701,15 @@ pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate); ocx.register_obligation(obligation); } - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { + // Use `select_where_possible` to only return impossible for true errors, + // and not ambiguities or overflows. Since the new trait solver forces + // some currently undetected overlap between `dyn Trait: Trait` built-in + // vs user-written impls to AMBIGUOUS, this may return ambiguity even + // with no infer vars. There may also be ways to encounter ambiguity due + // to post-mono overflow. + let true_errors = ocx.select_where_possible(); + if !true_errors.is_empty() { return true; } diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 7423a156a21..c929de11624 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -8,15 +8,6 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout}; pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { let tcx = cx.tcx(); - // Type-level uninhabitedness should always imply ABI uninhabitedness. - if layout.ty.is_privately_uninhabited(tcx, cx.typing_env) { - assert!( - layout.is_uninhabited(), - "{:?} is type-level uninhabited but not ABI-uninhabited?", - layout.ty - ); - } - if layout.size.bytes() % layout.align.abi.bytes() != 0 { bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); } @@ -29,6 +20,19 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou return; } + // Type-level uninhabitedness should always imply ABI uninhabitedness. This can be expensive on + // big non-exhaustive types, and is [hard to + // fix](https://github.com/rust-lang/rust/issues/141006#issuecomment-2883415000) in general. + // Only doing this sanity check when debug assertions are turned on avoids the issue for the + // very specific case of #140944. + if layout.ty.is_privately_uninhabited(tcx, cx.typing_env) { + assert!( + layout.is_uninhabited(), + "{:?} is type-level uninhabited but not ABI-uninhabited?", + layout.ty + ); + } + /// Yields non-ZST fields of the type fn non_zst_fields<'tcx, 'a>( cx: &'a LayoutCx<'tcx>, diff --git a/library/Cargo.lock b/library/Cargo.lock index 97ca3cb06b2..02018057ed5 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -196,7 +196,6 @@ name = "panic_abort" version = "0.0.0" dependencies = [ "alloc", - "cfg-if", "compiler_builtins", "core", "libc", diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 99e52d0ada0..83ba17b93f5 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -35,4 +35,10 @@ check-cfg = [ # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg 'cfg(feature, values(any()))', + # Internal features aren't marked known config by default, we use these to + # gate tests. + 'cfg(target_has_reliable_f16)', + 'cfg(target_has_reliable_f16_math)', + 'cfg(target_has_reliable_f128)', + 'cfg(target_has_reliable_f128_math)', ] diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 042925a352f..af2edf141b2 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -4,6 +4,7 @@ use super::*; use crate::panic::const_panic; use crate::slice; use crate::str::from_utf8_unchecked_mut; +use crate::ub_checks::assert_unsafe_precondition; use crate::unicode::printable::is_printable; use crate::unicode::{self, conversions}; @@ -1202,6 +1203,26 @@ impl char { } } + /// Converts this char into an [ASCII character](`ascii::Char`), without + /// checking whether it is valid. + /// + /// # Safety + /// + /// This char must be within the ASCII range, or else this is UB. + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char { + assert_unsafe_precondition!( + check_library_ub, + "as_ascii_unchecked requires that the char is valid ASCII", + (it: &char = self) => it.is_ascii() + ); + + // SAFETY: the caller promised that this char is ASCII. + unsafe { ascii::Char::from_u8_unchecked(*self as u8) } + } + /// Makes a copy of the value in its ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 64a7ec8906b..4e8d1dc1152 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -111,7 +111,6 @@ #![feature(is_ascii_octdigit)] #![feature(lazy_get)] #![feature(link_cfg)] -#![feature(non_null_from_ref)] #![feature(offset_of_enum)] #![feature(panic_internals)] #![feature(ptr_alignment_type)] diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 7e470185c86..0c2c4155d66 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1415,3 +1415,413 @@ impl f128 { intrinsics::frem_algebraic(self, rhs) } } + +// Functions in this module fall into `core_float_math` +// FIXME(f16_f128): all doctests must be gated to platforms that have `long double` === `_Float128` +// due to https://github.com/llvm/llvm-project/issues/44744. aarch64 linux matches this. +// #[unstable(feature = "core_float_math", issue = "137578")] +#[cfg(not(test))] +impl f128 { + /// Returns the largest integer less than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.7_f128; + /// let g = 3.0_f128; + /// let h = -3.7_f128; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// assert_eq!(h.floor(), -4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn floor(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf128(self) } + } + + /// Returns the smallest integer greater than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.01_f128; + /// let g = 4.0_f128; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "ceiling")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ceil(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf128(self) } + } + + /// Returns the nearest integer to `self`. If a value is half-way between two + /// integers, round away from `0.0`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.3_f128; + /// let g = -3.3_f128; + /// let h = -3.7_f128; + /// let i = 3.5_f128; + /// let j = 4.5_f128; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// assert_eq!(h.round(), -4.0); + /// assert_eq!(i.round(), 4.0); + /// assert_eq!(j.round(), 5.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf128(self) } + } + + /// Returns the nearest integer to a number. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.3_f128; + /// let g = -3.3_f128; + /// let h = 3.5_f128; + /// let i = 4.5_f128; + /// + /// assert_eq!(f.round_ties_even(), 3.0); + /// assert_eq!(g.round_ties_even(), -3.0); + /// assert_eq!(h.round_ties_even(), 4.0); + /// assert_eq!(i.round_ties_even(), 4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round_ties_even(self) -> f128 { + intrinsics::round_ties_even_f128(self) + } + + /// Returns the integer part of `self`. + /// This means that non-integer numbers are always truncated towards zero. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let f = 3.7_f128; + /// let g = 3.0_f128; + /// let h = -3.7_f128; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), 3.0); + /// assert_eq!(h.trunc(), -3.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "truncate")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn trunc(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf128(self) } + } + + /// Returns the fractional part of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let x = 3.6_f128; + /// let y = -3.6_f128; + /// let abs_difference_x = (x.fract() - 0.6).abs(); + /// let abs_difference_y = (y.fract() - (-0.6)).abs(); + /// + /// assert!(abs_difference_x <= f128::EPSILON); + /// assert!(abs_difference_y <= f128::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn fract(self) -> f128 { + self - self.trunc() + } + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as + /// `fusedMultiplyAdd` and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let m = 10.0_f128; + /// let x = 4.0_f128; + /// let b = 60.0_f128; + /// + /// assert_eq!(m.mul_add(x, b), 100.0); + /// assert_eq!(m * x + b, 100.0); + /// + /// let one_plus_eps = 1.0_f128 + f128::EPSILON; + /// let one_minus_eps = 1.0_f128 - f128::EPSILON; + /// let minus_one = -1.0_f128; + /// + /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. + /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f128::EPSILON * f128::EPSILON); + /// // Different rounding with the non-fused multiply and add. + /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn mul_add(self, a: f128, b: f128) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf128(self, a, b) } + } + + /// Calculates Euclidean division, the matching method for `rem_euclid`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.rem_euclid(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let a: f128 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn div_euclid(self, rhs: f128) -> f128 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` + /// approximately. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let a: f128 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.rem_euclid(b), 3.0); + /// assert_eq!((-a).rem_euclid(b), 1.0); + /// assert_eq!(a.rem_euclid(-b), 3.0); + /// assert_eq!((-a).rem_euclid(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-f128::EPSILON).rem_euclid(3.0) != 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[doc(alias = "modulo", alias = "mod")] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn rem_euclid(self, rhs: f128) -> f128 { + let r = self % rhs; + if r < 0.0 { r + rhs.abs() } else { r } + } + + /// Raises a number to an integer power. + /// + /// Using this function is generally faster than using `powf`. + /// It might have a different sequence of rounding operations than `powf`, + /// so the results are not guaranteed to agree. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let x = 2.0_f128; + /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f128::EPSILON); + /// + /// assert_eq!(f128::powi(f128::NAN, 0), 1.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn powi(self, n: i32) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif128(self, n) } + } + + /// Returns the square root of a number. + /// + /// Returns NaN if `self` is a negative number other than `-0.0`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` + /// and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f128_math)] { + /// + /// let positive = 4.0_f128; + /// let negative = -4.0_f128; + /// let negative_zero = -0.0_f128; + /// + /// assert_eq!(positive.sqrt(), 2.0); + /// assert!(negative.sqrt().is_nan()); + /// assert!(negative_zero.sqrt() == negative_zero); + /// # } + /// ``` + #[inline] + #[doc(alias = "squareRoot")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f128", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sqrt(self) -> f128 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf128(self) } + } +} diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index e47900cba55..1a859f2277f 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -13,6 +13,8 @@ use crate::convert::FloatToInt; use crate::num::FpCategory; +#[cfg(not(test))] +use crate::num::libm; use crate::panic::const_assert; use crate::{intrinsics, mem}; @@ -1391,3 +1393,446 @@ impl f16 { intrinsics::frem_algebraic(self, rhs) } } + +// Functions in this module fall into `core_float_math` +// #[unstable(feature = "core_float_math", issue = "137578")] +#[cfg(not(test))] +impl f16 { + /// Returns the largest integer less than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.7_f16; + /// let g = 3.0_f16; + /// let h = -3.7_f16; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// assert_eq!(h.floor(), -4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn floor(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf16(self) } + } + + /// Returns the smallest integer greater than or equal to `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.01_f16; + /// let g = 4.0_f16; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "ceiling")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn ceil(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf16(self) } + } + + /// Returns the nearest integer to `self`. If a value is half-way between two + /// integers, round away from `0.0`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.3_f16; + /// let g = -3.3_f16; + /// let h = -3.7_f16; + /// let i = 3.5_f16; + /// let j = 4.5_f16; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// assert_eq!(h.round(), -4.0); + /// assert_eq!(i.round(), 4.0); + /// assert_eq!(j.round(), 5.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf16(self) } + } + + /// Returns the nearest integer to a number. Rounds half-way cases to the number + /// with an even least significant digit. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.3_f16; + /// let g = -3.3_f16; + /// let h = 3.5_f16; + /// let i = 4.5_f16; + /// + /// assert_eq!(f.round_ties_even(), 3.0); + /// assert_eq!(g.round_ties_even(), -3.0); + /// assert_eq!(h.round_ties_even(), 4.0); + /// assert_eq!(i.round_ties_even(), 4.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn round_ties_even(self) -> f16 { + intrinsics::round_ties_even_f16(self) + } + + /// Returns the integer part of `self`. + /// This means that non-integer numbers are always truncated towards zero. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let f = 3.7_f16; + /// let g = 3.0_f16; + /// let h = -3.7_f16; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), 3.0); + /// assert_eq!(h.trunc(), -3.0); + /// # } + /// ``` + #[inline] + #[doc(alias = "truncate")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn trunc(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf16(self) } + } + + /// Returns the fractional part of `self`. + /// + /// This function always returns the precise result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let x = 3.6_f16; + /// let y = -3.6_f16; + /// let abs_difference_x = (x.fract() - 0.6).abs(); + /// let abs_difference_y = (y.fract() - (-0.6)).abs(); + /// + /// assert!(abs_difference_x <= f16::EPSILON); + /// assert!(abs_difference_y <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn fract(self) -> f16 { + self - self.trunc() + } + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` *may* be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. However, + /// this is not always true, and will be heavily dependant on designing + /// algorithms with specific target hardware in mind. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as + /// `fusedMultiplyAdd` and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let m = 10.0_f16; + /// let x = 4.0_f16; + /// let b = 60.0_f16; + /// + /// assert_eq!(m.mul_add(x, b), 100.0); + /// assert_eq!(m * x + b, 100.0); + /// + /// let one_plus_eps = 1.0_f16 + f16::EPSILON; + /// let one_minus_eps = 1.0_f16 - f16::EPSILON; + /// let minus_one = -1.0_f16; + /// + /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. + /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f16::EPSILON * f16::EPSILON); + /// // Different rounding with the non-fused multiply and add. + /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn mul_add(self, a: f16, b: f16) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf16(self, a, b) } + } + + /// Calculates Euclidean division, the matching method for `rem_euclid`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.rem_euclid(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let a: f16 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn div_euclid(self, rhs: f16) -> f16 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q + } + + /// Calculates the least nonnegative remainder of `self (mod rhs)`. + /// + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` + /// approximately. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let a: f16 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.rem_euclid(b), 3.0); + /// assert_eq!((-a).rem_euclid(b), 1.0); + /// assert_eq!(a.rem_euclid(-b), 3.0); + /// assert_eq!((-a).rem_euclid(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-f16::EPSILON).rem_euclid(3.0) != 0.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[doc(alias = "modulo", alias = "mod")] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn rem_euclid(self, rhs: f16) -> f16 { + let r = self % rhs; + if r < 0.0 { r + rhs.abs() } else { r } + } + + /// Raises a number to an integer power. + /// + /// Using this function is generally faster than using `powf`. + /// It might have a different sequence of rounding operations than `powf`, + /// so the results are not guaranteed to agree. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let x = 2.0_f16; + /// let abs_difference = (x.powi(2) - (x * x)).abs(); + /// assert!(abs_difference <= f16::EPSILON); + /// + /// assert_eq!(f16::powi(f16::NAN, 0), 1.0); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn powi(self, n: i32) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif16(self, n) } + } + + /// Returns the square root of a number. + /// + /// Returns NaN if `self` is a negative number other than `-0.0`. + /// + /// # Precision + /// + /// The result of this operation is guaranteed to be the rounded + /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` + /// and guaranteed not to change. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let positive = 4.0_f16; + /// let negative = -4.0_f16; + /// let negative_zero = -0.0_f16; + /// + /// assert_eq!(positive.sqrt(), 2.0); + /// assert!(negative.sqrt().is_nan()); + /// assert!(negative_zero.sqrt() == negative_zero); + /// # } + /// ``` + #[inline] + #[doc(alias = "squareRoot")] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn sqrt(self) -> f16 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf16(self) } + } + + /// Returns the cube root of a number. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `cbrtf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// # #![feature(cfg_target_has_reliable_f16_f128)] + /// # #![expect(internal_features)] + /// # #[cfg(not(miri))] + /// # #[cfg(target_has_reliable_f16_math)] { + /// + /// let x = 8.0f16; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// # } + /// ``` + #[inline] + #[rustc_allow_incoherent_impl] + #[unstable(feature = "f16", issue = "116909")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub fn cbrt(self) -> f16 { + libm::cbrtf(self as f32) as f16 + } +} diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 5fbc6eb33f1..9525bdb6762 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::convert::FloatToInt; -use crate::num::FpCategory; +use crate::num::{FpCategory, libm}; use crate::panic::const_assert; use crate::{cfg_match, intrinsics, mem}; @@ -1556,3 +1556,414 @@ impl f32 { intrinsics::frem_algebraic(self, rhs) } } + +/// Experimental version of `floor` in `core`. See [`f32::floor`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.7_f32; +/// let g = 3.0_f32; +/// let h = -3.7_f32; +/// +/// assert_eq!(f32::floor(f), 3.0); +/// assert_eq!(f32::floor(g), 3.0); +/// assert_eq!(f32::floor(h), -4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::floor`]: ../../std/primitive.f32.html#method.floor +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn floor(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf32(x) } +} + +/// Experimental version of `ceil` in `core`. See [`f32::ceil`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.01_f32; +/// let g = 4.0_f32; +/// +/// assert_eq!(f32::ceil(f), 4.0); +/// assert_eq!(f32::ceil(g), 4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::ceil`]: ../../std/primitive.f32.html#method.ceil +#[inline] +#[doc(alias = "ceiling")] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn ceil(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf32(x) } +} + +/// Experimental version of `round` in `core`. See [`f32::round`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.3_f32; +/// let g = -3.3_f32; +/// let h = -3.7_f32; +/// let i = 3.5_f32; +/// let j = 4.5_f32; +/// +/// assert_eq!(f32::round(f), 3.0); +/// assert_eq!(f32::round(g), -3.0); +/// assert_eq!(f32::round(h), -4.0); +/// assert_eq!(f32::round(i), 4.0); +/// assert_eq!(f32::round(j), 5.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::round`]: ../../std/primitive.f32.html#method.round +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn round(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf32(x) } +} + +/// Experimental version of `round_ties_even` in `core`. See [`f32::round_ties_even`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.3_f32; +/// let g = -3.3_f32; +/// let h = 3.5_f32; +/// let i = 4.5_f32; +/// +/// assert_eq!(f32::round_ties_even(f), 3.0); +/// assert_eq!(f32::round_ties_even(g), -3.0); +/// assert_eq!(f32::round_ties_even(h), 4.0); +/// assert_eq!(f32::round_ties_even(i), 4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::round_ties_even`]: ../../std/primitive.f32.html#method.round_ties_even +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn round_ties_even(x: f32) -> f32 { + intrinsics::round_ties_even_f32(x) +} + +/// Experimental version of `trunc` in `core`. See [`f32::trunc`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let f = 3.7_f32; +/// let g = 3.0_f32; +/// let h = -3.7_f32; +/// +/// assert_eq!(f32::trunc(f), 3.0); +/// assert_eq!(f32::trunc(g), 3.0); +/// assert_eq!(f32::trunc(h), -3.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::trunc`]: ../../std/primitive.f32.html#method.trunc +#[inline] +#[doc(alias = "truncate")] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn trunc(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf32(x) } +} + +/// Experimental version of `fract` in `core`. See [`f32::fract`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let x = 3.6_f32; +/// let y = -3.6_f32; +/// let abs_difference_x = (f32::fract(x) - 0.6).abs(); +/// let abs_difference_y = (f32::fract(y) - (-0.6)).abs(); +/// +/// assert!(abs_difference_x <= f32::EPSILON); +/// assert!(abs_difference_y <= f32::EPSILON); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::fract`]: ../../std/primitive.f32.html#method.fract +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn fract(x: f32) -> f32 { + x - trunc(x) +} + +/// Experimental version of `mul_add` in `core`. See [`f32::mul_add`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// # // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ +/// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] { +/// use core::f32; +/// +/// let m = 10.0_f32; +/// let x = 4.0_f32; +/// let b = 60.0_f32; +/// +/// assert_eq!(f32::mul_add(m, x, b), 100.0); +/// assert_eq!(m * x + b, 100.0); +/// +/// let one_plus_eps = 1.0_f32 + f32::EPSILON; +/// let one_minus_eps = 1.0_f32 - f32::EPSILON; +/// let minus_one = -1.0_f32; +/// +/// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. +/// assert_eq!(f32::mul_add(one_plus_eps, one_minus_eps, minus_one), -f32::EPSILON * f32::EPSILON); +/// // Different rounding with the non-fused multiply and add. +/// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); +/// # } +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::mul_add`]: ../../std/primitive.f32.html#method.mul_add +#[inline] +#[doc(alias = "fmaf", alias = "fusedMultiplyAdd")] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn mul_add(x: f32, y: f32, z: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf32(x, y, z) } +} + +/// Experimental version of `div_euclid` in `core`. See [`f32::div_euclid`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let a: f32 = 7.0; +/// let b = 4.0; +/// assert_eq!(f32::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0 +/// assert_eq!(f32::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0 +/// assert_eq!(f32::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0 +/// assert_eq!(f32::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0 +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::div_euclid`]: ../../std/primitive.f32.html#method.div_euclid +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn div_euclid(x: f32, rhs: f32) -> f32 { + let q = trunc(x / rhs); + if x % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q +} + +/// Experimental version of `rem_euclid` in `core`. See [`f32::rem_euclid`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let a: f32 = 7.0; +/// let b = 4.0; +/// assert_eq!(f32::rem_euclid(a, b), 3.0); +/// assert_eq!(f32::rem_euclid(-a, b), 1.0); +/// assert_eq!(f32::rem_euclid(a, -b), 3.0); +/// assert_eq!(f32::rem_euclid(-a, -b), 1.0); +/// // limitation due to round-off error +/// assert!(f32::rem_euclid(-f32::EPSILON, 3.0) != 0.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::rem_euclid`]: ../../std/primitive.f32.html#method.rem_euclid +#[inline] +#[doc(alias = "modulo", alias = "mod")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn rem_euclid(x: f32, rhs: f32) -> f32 { + let r = x % rhs; + if r < 0.0 { r + rhs.abs() } else { r } +} + +/// Experimental version of `powi` in `core`. See [`f32::powi`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let x = 2.0_f32; +/// let abs_difference = (f32::powi(x, 2) - (x * x)).abs(); +/// assert!(abs_difference <= f32::EPSILON); +/// +/// assert_eq!(f32::powi(f32::NAN, 0), 1.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::powi`]: ../../std/primitive.f32.html#method.powi +#[inline] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn powi(x: f32, n: i32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif32(x, n) } +} + +/// Experimental version of `sqrt` in `core`. See [`f32::sqrt`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let positive = 4.0_f32; +/// let negative = -4.0_f32; +/// let negative_zero = -0.0_f32; +/// +/// assert_eq!(f32::sqrt(positive), 2.0); +/// assert!(f32::sqrt(negative).is_nan()); +/// assert_eq!(f32::sqrt(negative_zero), negative_zero); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::sqrt`]: ../../std/primitive.f32.html#method.sqrt +#[inline] +#[doc(alias = "squareRoot")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn sqrt(x: f32) -> f32 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf32(x) } +} + +/// Experimental version of `abs_sub` in `core`. See [`f32::abs_sub`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let x = 3.0f32; +/// let y = -3.0f32; +/// +/// let abs_difference_x = (f32::abs_sub(x, 1.0) - 2.0).abs(); +/// let abs_difference_y = (f32::abs_sub(y, 1.0) - 0.0).abs(); +/// +/// assert!(abs_difference_x <= f32::EPSILON); +/// assert!(abs_difference_y <= f32::EPSILON); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::abs_sub`]: ../../std/primitive.f32.html#method.abs_sub +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated( + since = "1.10.0", + note = "you probably meant `(self - other).abs()`: \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ + known as `fdimf` in C). If you truly need the positive \ + difference, consider using that expression or the C function \ + `fdimf`, depending on how you wish to handle NaN (please consider \ + filing an issue describing your use-case too)." +)] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn abs_sub(x: f32, other: f32) -> f32 { + libm::fdimf(x, other) +} + +/// Experimental version of `cbrt` in `core`. See [`f32::cbrt`] for details. +/// +/// # Unspecified precision +/// +/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and +/// can even differ within the same execution from one invocation to the next. +/// This function currently corresponds to the `cbrtf` from libc on Unix +/// and Windows. Note that this might change in the future. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f32; +/// +/// let x = 8.0f32; +/// +/// // x^(1/3) - 2 == 0 +/// let abs_difference = (f32::cbrt(x) - 2.0).abs(); +/// +/// assert!(abs_difference <= f32::EPSILON); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f32::cbrt`]: ../../std/primitive.f32.html#method.cbrt +#[inline] +#[must_use = "method returns a new number and does not mutate the original value"] +#[unstable(feature = "core_float_math", issue = "137578")] +pub fn cbrt(x: f32) -> f32 { + libm::cbrtf(x) +} diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 81ab0f14c2b..76c4e5d1a6f 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::convert::FloatToInt; -use crate::num::FpCategory; +use crate::num::{FpCategory, libm}; use crate::panic::const_assert; use crate::{intrinsics, mem}; @@ -1555,3 +1555,407 @@ impl f64 { intrinsics::frem_algebraic(self, rhs) } } + +/// Experimental version of `floor` in `core`. See [`f64::floor`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.7_f64; +/// let g = 3.0_f64; +/// let h = -3.7_f64; +/// +/// assert_eq!(f64::floor(f), 3.0); +/// assert_eq!(f64::floor(g), 3.0); +/// assert_eq!(f64::floor(h), -4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::floor`]: ../../std/primitive.f64.html#method.floor +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn floor(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::floorf64(x) } +} + +/// Experimental version of `ceil` in `core`. See [`f64::ceil`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.01_f64; +/// let g = 4.0_f64; +/// +/// assert_eq!(f64::ceil(f), 4.0); +/// assert_eq!(f64::ceil(g), 4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::ceil`]: ../../std/primitive.f64.html#method.ceil +#[inline] +#[doc(alias = "ceiling")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn ceil(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::ceilf64(x) } +} + +/// Experimental version of `round` in `core`. See [`f64::round`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.3_f64; +/// let g = -3.3_f64; +/// let h = -3.7_f64; +/// let i = 3.5_f64; +/// let j = 4.5_f64; +/// +/// assert_eq!(f64::round(f), 3.0); +/// assert_eq!(f64::round(g), -3.0); +/// assert_eq!(f64::round(h), -4.0); +/// assert_eq!(f64::round(i), 4.0); +/// assert_eq!(f64::round(j), 5.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::round`]: ../../std/primitive.f64.html#method.round +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn round(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::roundf64(x) } +} + +/// Experimental version of `round_ties_even` in `core`. See [`f64::round_ties_even`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.3_f64; +/// let g = -3.3_f64; +/// let h = 3.5_f64; +/// let i = 4.5_f64; +/// +/// assert_eq!(f64::round_ties_even(f), 3.0); +/// assert_eq!(f64::round_ties_even(g), -3.0); +/// assert_eq!(f64::round_ties_even(h), 4.0); +/// assert_eq!(f64::round_ties_even(i), 4.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::round_ties_even`]: ../../std/primitive.f64.html#method.round_ties_even +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn round_ties_even(x: f64) -> f64 { + intrinsics::round_ties_even_f64(x) +} + +/// Experimental version of `trunc` in `core`. See [`f64::trunc`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let f = 3.7_f64; +/// let g = 3.0_f64; +/// let h = -3.7_f64; +/// +/// assert_eq!(f64::trunc(f), 3.0); +/// assert_eq!(f64::trunc(g), 3.0); +/// assert_eq!(f64::trunc(h), -3.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::trunc`]: ../../std/primitive.f64.html#method.trunc +#[inline] +#[doc(alias = "truncate")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn trunc(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::truncf64(x) } +} + +/// Experimental version of `fract` in `core`. See [`f64::fract`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let x = 3.6_f64; +/// let y = -3.6_f64; +/// let abs_difference_x = (f64::fract(x) - 0.6).abs(); +/// let abs_difference_y = (f64::fract(y) - (-0.6)).abs(); +/// +/// assert!(abs_difference_x < 1e-10); +/// assert!(abs_difference_y < 1e-10); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::fract`]: ../../std/primitive.f64.html#method.fract +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn fract(x: f64) -> f64 { + x - trunc(x) +} + +/// Experimental version of `mul_add` in `core`. See [`f64::mul_add`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// # // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ +/// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] { +/// use core::f64; +/// +/// let m = 10.0_f64; +/// let x = 4.0_f64; +/// let b = 60.0_f64; +/// +/// assert_eq!(f64::mul_add(m, x, b), 100.0); +/// assert_eq!(m * x + b, 100.0); +/// +/// let one_plus_eps = 1.0_f64 + f64::EPSILON; +/// let one_minus_eps = 1.0_f64 - f64::EPSILON; +/// let minus_one = -1.0_f64; +/// +/// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. +/// assert_eq!(f64::mul_add(one_plus_eps, one_minus_eps, minus_one), -f64::EPSILON * f64::EPSILON); +/// // Different rounding with the non-fused multiply and add. +/// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); +/// # } +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::mul_add`]: ../../std/primitive.f64.html#method.mul_add +#[inline] +#[doc(alias = "fma", alias = "fusedMultiplyAdd")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn mul_add(x: f64, a: f64, b: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::fmaf64(x, a, b) } +} + +/// Experimental version of `div_euclid` in `core`. See [`f64::div_euclid`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let a: f64 = 7.0; +/// let b = 4.0; +/// assert_eq!(f64::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0 +/// assert_eq!(f64::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0 +/// assert_eq!(f64::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0 +/// assert_eq!(f64::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0 +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::div_euclid`]: ../../std/primitive.f64.html#method.div_euclid +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn div_euclid(x: f64, rhs: f64) -> f64 { + let q = trunc(x / rhs); + if x % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; + } + q +} + +/// Experimental version of `rem_euclid` in `core`. See [`f64::rem_euclid`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let a: f64 = 7.0; +/// let b = 4.0; +/// assert_eq!(f64::rem_euclid(a, b), 3.0); +/// assert_eq!(f64::rem_euclid(-a, b), 1.0); +/// assert_eq!(f64::rem_euclid(a, -b), 3.0); +/// assert_eq!(f64::rem_euclid(-a, -b), 1.0); +/// // limitation due to round-off error +/// assert!(f64::rem_euclid(-f64::EPSILON, 3.0) != 0.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::rem_euclid`]: ../../std/primitive.f64.html#method.rem_euclid +#[inline] +#[doc(alias = "modulo", alias = "mod")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn rem_euclid(x: f64, rhs: f64) -> f64 { + let r = x % rhs; + if r < 0.0 { r + rhs.abs() } else { r } +} + +/// Experimental version of `powi` in `core`. See [`f64::powi`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let x = 2.0_f64; +/// let abs_difference = (f64::powi(x, 2) - (x * x)).abs(); +/// assert!(abs_difference <= f64::EPSILON); +/// +/// assert_eq!(f64::powi(f64::NAN, 0), 1.0); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::powi`]: ../../std/primitive.f64.html#method.powi +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn powi(x: f64, n: i32) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::powif64(x, n) } +} + +/// Experimental version of `sqrt` in `core`. See [`f64::sqrt`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let positive = 4.0_f64; +/// let negative = -4.0_f64; +/// let negative_zero = -0.0_f64; +/// +/// assert_eq!(f64::sqrt(positive), 2.0); +/// assert!(f64::sqrt(negative).is_nan()); +/// assert_eq!(f64::sqrt(negative_zero), negative_zero); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::sqrt`]: ../../std/primitive.f64.html#method.sqrt +#[inline] +#[doc(alias = "squareRoot")] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn sqrt(x: f64) -> f64 { + // SAFETY: intrinsic with no preconditions + unsafe { intrinsics::sqrtf64(x) } +} + +/// Experimental version of `abs_sub` in `core`. See [`f64::abs_sub`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let x = 3.0_f64; +/// let y = -3.0_f64; +/// +/// let abs_difference_x = (f64::abs_sub(x, 1.0) - 2.0).abs(); +/// let abs_difference_y = (f64::abs_sub(y, 1.0) - 0.0).abs(); +/// +/// assert!(abs_difference_x < 1e-10); +/// assert!(abs_difference_y < 1e-10); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::abs_sub`]: ../../std/primitive.f64.html#method.abs_sub +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[deprecated( + since = "1.10.0", + note = "you probably meant `(self - other).abs()`: \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ + known as `fdim` in C). If you truly need the positive \ + difference, consider using that expression or the C function \ + `fdim`, depending on how you wish to handle NaN (please consider \ + filing an issue describing your use-case too)." +)] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn abs_sub(x: f64, other: f64) -> f64 { + libm::fdim(x, other) +} + +/// Experimental version of `cbrt` in `core`. See [`f64::cbrt`] for details. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_float_math)] +/// +/// use core::f64; +/// +/// let x = 8.0_f64; +/// +/// // x^(1/3) - 2 == 0 +/// let abs_difference = (f64::cbrt(x) - 2.0).abs(); +/// +/// assert!(abs_difference < 1e-10); +/// ``` +/// +/// _This standalone function is for testing only. It will be stabilized as an inherent method._ +/// +/// [`f64::cbrt`]: ../../std/primitive.f64.html#method.cbrt +#[inline] +#[unstable(feature = "core_float_math", issue = "137578")] +#[must_use = "method returns a new number and does not mutate the original value"] +pub fn cbrt(x: f64) -> f64 { + libm::cbrt(x) +} diff --git a/library/core/src/num/libm.rs b/library/core/src/num/libm.rs new file mode 100644 index 00000000000..aeabb087230 --- /dev/null +++ b/library/core/src/num/libm.rs @@ -0,0 +1,11 @@ +//! Bindings to math functions provided by the system `libm` or by the `libm` crate, exposed +//! via `compiler-builtins`. + +// SAFETY: These symbols have standard interfaces in C and are defined by `libm`, or are +// provided by `compiler-builtins` on unsupported platforms. +unsafe extern "C" { + pub(crate) safe fn cbrt(n: f64) -> f64; + pub(crate) safe fn cbrtf(n: f32) -> f32; + pub(crate) safe fn fdim(a: f64, b: f64) -> f64; + pub(crate) safe fn fdimf(a: f32, b: f32) -> f32; +} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index ecc1c7bf902..5c73bddbef2 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -46,6 +46,7 @@ mod uint_macros; // import uint_impl! mod error; mod int_log10; mod int_sqrt; +pub(crate) mod libm; mod nonzero; mod overflow_panic; mod saturating; @@ -492,6 +493,26 @@ impl u8 { ascii::Char::from_u8(*self) } + /// Converts this byte to an [ASCII character](ascii::Char), without + /// checking whether or not it's valid. + /// + /// # Safety + /// + /// This byte must be valid ASCII, or else this is UB. + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char { + assert_unsafe_precondition!( + check_library_ub, + "as_ascii_unchecked requires that the byte is valid ASCII", + (it: &u8 = self) => it.is_ascii() + ); + + // SAFETY: the caller promised that this byte is ASCII. + unsafe { ascii::Char::from_u8_unchecked(*self) } + } + /// Makes a copy of the value in its ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index d05fb6a6d31..8b31328de04 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -262,7 +262,8 @@ impl<T: ?Sized> NonNull<T> { } /// Converts a reference to a `NonNull` pointer. - #[unstable(feature = "non_null_from_ref", issue = "130823")] + #[stable(feature = "non_null_from_ref", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_from_ref", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn from_ref(r: &T) -> Self { // SAFETY: A reference cannot be null. @@ -270,7 +271,8 @@ impl<T: ?Sized> NonNull<T> { } /// Converts a mutable reference to a `NonNull` pointer. - #[unstable(feature = "non_null_from_ref", issue = "130823")] + #[stable(feature = "non_null_from_ref", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "non_null_from_ref", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn from_mut(r: &mut T) -> Self { // SAFETY: A mutable reference cannot be null. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 9e7e949b722..e505e228095 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -17,6 +17,7 @@ use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use crate::char::{self, EscapeDebugExtArgs}; use crate::ops::Range; use crate::slice::{self, SliceIndex}; +use crate::ub_checks::assert_unsafe_precondition; use crate::{ascii, mem}; pub mod pattern; @@ -2634,6 +2635,27 @@ impl str { self.as_bytes().as_ascii() } + /// Converts this string slice into a slice of [ASCII characters](ascii::Char), + /// without checking whether they are valid. + /// + /// # Safety + /// + /// Every character in this string must be ASCII, or else this is UB. + #[unstable(feature = "ascii_char", issue = "110998")] + #[must_use] + #[inline] + pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char] { + assert_unsafe_precondition!( + check_library_ub, + "as_ascii_unchecked requires that the string is valid ASCII", + (it: &str = self) => it.is_ascii() + ); + + // SAFETY: the caller promised that every byte of this string slice + // is ASCII. + unsafe { self.as_bytes().as_ascii_unchecked() } + } + /// Checks that two strings are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, diff --git a/library/coretests/Cargo.toml b/library/coretests/Cargo.toml index 7656388d24b..e0ddcd466ae 100644 --- a/library/coretests/Cargo.toml +++ b/library/coretests/Cargo.toml @@ -26,3 +26,14 @@ test = true [dev-dependencies] rand = { version = "0.9.0", default-features = false } rand_xorshift = { version = "0.4.0", default-features = false } + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + # Internal features aren't marked known config by default, we use these to + # gate tests. + 'cfg(target_has_reliable_f16)', + 'cfg(target_has_reliable_f16_math)', + 'cfg(target_has_reliable_f128)', + 'cfg(target_has_reliable_f128_math)', +] diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs new file mode 100644 index 00000000000..12cf651f03f --- /dev/null +++ b/library/coretests/tests/floats/f128.rs @@ -0,0 +1,790 @@ +// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy +#![cfg(target_has_reliable_f128)] + +use std::f128::consts; +use std::num::FpCategory as Fp; +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +use std::ops::Rem; +use std::ops::{Add, Div, Mul, Sub}; + +// Note these tolerances make sense around zero, but not for more extreme exponents. + +/// Default tolerances. Works for values that should be near precise but not exact. Roughly +/// the precision carried by `100 * 100`. +const TOL: f128 = 1e-12; + +/// For operations that are near exact, usually not involving math of different +/// signs. +const TOL_PRECISE: f128 = 1e-28; + +/// Smallest number +const TINY_BITS: u128 = 0x1; + +/// Next smallest number +const TINY_UP_BITS: u128 = 0x2; + +/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 +const MAX_DOWN_BITS: u128 = 0x7ffefffffffffffffffffffffffffffe; + +/// Zeroed exponent, full significant +const LARGEST_SUBNORMAL_BITS: u128 = 0x0000ffffffffffffffffffffffffffff; + +/// Exponent = 0b1, zeroed significand +const SMALLEST_NORMAL_BITS: u128 = 0x00010000000000000000000000000000; + +/// First pattern over the mantissa +const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; + +/// Second pattern over the mantissa +const NAN_MASK2: u128 = 0x00005555555555555555555555555555; + +/// Compare by representation +#[allow(unused_macros)] +macro_rules! assert_f128_biteq { + ($a:expr, $b:expr) => { + let (l, r): (&f128, &f128) = (&$a, &$b); + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {l:?} is not bitequal to {r:?}.\na: {lb:#034x}\nb: {rb:#034x}"); + }; +} + +#[test] +fn test_num_f128() { + // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` + // function is available on all platforms. + let ten = 10f128; + let two = 2f128; + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); +} + +// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support +// the intrinsics. + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_num_f128_rem() { + let ten = 10f128; + let two = 2f128; + assert_eq!(ten.rem(two), ten % two); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_min_nan() { + assert_eq!(f128::NAN.min(2.0), 2.0); + assert_eq!(2.0f128.min(f128::NAN), 2.0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_max_nan() { + assert_eq!(f128::NAN.max(2.0), 2.0); + assert_eq!(2.0f128.max(f128::NAN), 2.0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_minimum() { + assert!(f128::NAN.minimum(2.0).is_nan()); + assert!(2.0f128.minimum(f128::NAN).is_nan()); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_maximum() { + assert!(f128::NAN.maximum(2.0).is_nan()); + assert!(2.0f128.maximum(f128::NAN).is_nan()); +} + +#[test] +fn test_nan() { + let nan: f128 = f128::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert!(!nan.is_normal()); + assert_eq!(Fp::Nan, nan.classify()); + // Ensure the quiet bit is set. + assert!(nan.to_bits() & (1 << (f128::MANTISSA_DIGITS - 2)) != 0); +} + +#[test] +fn test_infinity() { + let inf: f128 = f128::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); +} + +#[test] +fn test_neg_infinity() { + let neg_inf: f128 = f128::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); +} + +#[test] +fn test_zero() { + let zero: f128 = 0.0f128; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); +} + +#[test] +fn test_neg_zero() { + let neg_zero: f128 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); +} + +#[test] +fn test_one() { + let one: f128 = 1.0f128; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); +} + +#[test] +fn test_is_nan() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f128.is_nan()); + assert!(!5.3f128.is_nan()); + assert!(!(-10.732f128).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); +} + +#[test] +fn test_is_infinite() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f128.is_infinite()); + assert!(!42.8f128.is_infinite()); + assert!(!(-109.2f128).is_infinite()); +} + +#[test] +fn test_is_finite() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f128.is_finite()); + assert!(42.8f128.is_finite()); + assert!((-109.2f128).is_finite()); +} + +#[test] +fn test_is_normal() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let zero: f128 = 0.0f128; + let neg_zero: f128 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f128.is_normal()); + assert!(1e-4931f128.is_normal()); + assert!(!1e-4932f128.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + let zero: f128 = 0.0f128; + let neg_zero: f128 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f128.classify(), Fp::Normal); + assert_eq!(1e-4931f128.classify(), Fp::Normal); + assert_eq!(1e-4932f128.classify(), Fp::Subnormal); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_floor() { + assert_approx_eq!(1.0f128.floor(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.floor(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.floor(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.floor(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.floor(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).floor(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).floor(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).floor(), -2.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).floor(), -2.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).floor(), -2.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_ceil() { + assert_approx_eq!(1.0f128.ceil(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.ceil(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.ceil(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.ceil(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.ceil(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).ceil(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).ceil(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).ceil(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).ceil(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).ceil(), -1.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_round() { + assert_approx_eq!(2.5f128.round(), 3.0f128, TOL_PRECISE); + assert_approx_eq!(1.0f128.round(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.round(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.round(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.round(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.round(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).round(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).round(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).round(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).round(), -2.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).round(), -2.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_round_ties_even() { + assert_approx_eq!(2.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.0f128.round_ties_even(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.round_ties_even(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.round_ties_even(), 2.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.round_ties_even(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).round_ties_even(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).round_ties_even(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).round_ties_even(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).round_ties_even(), -2.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).round_ties_even(), -2.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_trunc() { + assert_approx_eq!(1.0f128.trunc(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.trunc(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.trunc(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.trunc(), 1.0f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.trunc(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).trunc(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).trunc(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).trunc(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).trunc(), -1.0f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).trunc(), -1.0f128, TOL_PRECISE); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_fract() { + assert_approx_eq!(1.0f128.fract(), 0.0f128, TOL_PRECISE); + assert_approx_eq!(1.3f128.fract(), 0.3f128, TOL_PRECISE); + assert_approx_eq!(1.5f128.fract(), 0.5f128, TOL_PRECISE); + assert_approx_eq!(1.7f128.fract(), 0.7f128, TOL_PRECISE); + assert_approx_eq!(0.0f128.fract(), 0.0f128, TOL_PRECISE); + assert_approx_eq!((-0.0f128).fract(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.0f128).fract(), -0.0f128, TOL_PRECISE); + assert_approx_eq!((-1.3f128).fract(), -0.3f128, TOL_PRECISE); + assert_approx_eq!((-1.5f128).fract(), -0.5f128, TOL_PRECISE); + assert_approx_eq!((-1.7f128).fract(), -0.7f128, TOL_PRECISE); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_abs() { + assert_eq!(f128::INFINITY.abs(), f128::INFINITY); + assert_eq!(1f128.abs(), 1f128); + assert_eq!(0f128.abs(), 0f128); + assert_eq!((-0f128).abs(), 0f128); + assert_eq!((-1f128).abs(), 1f128); + assert_eq!(f128::NEG_INFINITY.abs(), f128::INFINITY); + assert_eq!((1f128 / f128::NEG_INFINITY).abs(), 0f128); + assert!(f128::NAN.abs().is_nan()); +} + +#[test] +fn test_is_sign_positive() { + assert!(f128::INFINITY.is_sign_positive()); + assert!(1f128.is_sign_positive()); + assert!(0f128.is_sign_positive()); + assert!(!(-0f128).is_sign_positive()); + assert!(!(-1f128).is_sign_positive()); + assert!(!f128::NEG_INFINITY.is_sign_positive()); + assert!(!(1f128 / f128::NEG_INFINITY).is_sign_positive()); + assert!(f128::NAN.is_sign_positive()); + assert!(!(-f128::NAN).is_sign_positive()); +} + +#[test] +fn test_is_sign_negative() { + assert!(!f128::INFINITY.is_sign_negative()); + assert!(!1f128.is_sign_negative()); + assert!(!0f128.is_sign_negative()); + assert!((-0f128).is_sign_negative()); + assert!((-1f128).is_sign_negative()); + assert!(f128::NEG_INFINITY.is_sign_negative()); + assert!((1f128 / f128::NEG_INFINITY).is_sign_negative()); + assert!(!f128::NAN.is_sign_negative()); + assert!((-f128::NAN).is_sign_negative()); +} + +#[test] +fn test_next_up() { + let tiny = f128::from_bits(TINY_BITS); + let tiny_up = f128::from_bits(TINY_UP_BITS); + let max_down = f128::from_bits(MAX_DOWN_BITS); + let largest_subnormal = f128::from_bits(LARGEST_SUBNORMAL_BITS); + let smallest_normal = f128::from_bits(SMALLEST_NORMAL_BITS); + assert_f128_biteq!(f128::NEG_INFINITY.next_up(), f128::MIN); + assert_f128_biteq!(f128::MIN.next_up(), -max_down); + assert_f128_biteq!((-1.0 - f128::EPSILON).next_up(), -1.0); + assert_f128_biteq!((-smallest_normal).next_up(), -largest_subnormal); + assert_f128_biteq!((-tiny_up).next_up(), -tiny); + assert_f128_biteq!((-tiny).next_up(), -0.0f128); + assert_f128_biteq!((-0.0f128).next_up(), tiny); + assert_f128_biteq!(0.0f128.next_up(), tiny); + assert_f128_biteq!(tiny.next_up(), tiny_up); + assert_f128_biteq!(largest_subnormal.next_up(), smallest_normal); + assert_f128_biteq!(1.0f128.next_up(), 1.0 + f128::EPSILON); + assert_f128_biteq!(f128::MAX.next_up(), f128::INFINITY); + assert_f128_biteq!(f128::INFINITY.next_up(), f128::INFINITY); + + // Check that NaNs roundtrip. + let nan0 = f128::NAN; + let nan1 = f128::from_bits(f128::NAN.to_bits() ^ 0x002a_aaaa); + let nan2 = f128::from_bits(f128::NAN.to_bits() ^ 0x0055_5555); + assert_f128_biteq!(nan0.next_up(), nan0); + assert_f128_biteq!(nan1.next_up(), nan1); + assert_f128_biteq!(nan2.next_up(), nan2); +} + +#[test] +fn test_next_down() { + let tiny = f128::from_bits(TINY_BITS); + let tiny_up = f128::from_bits(TINY_UP_BITS); + let max_down = f128::from_bits(MAX_DOWN_BITS); + let largest_subnormal = f128::from_bits(LARGEST_SUBNORMAL_BITS); + let smallest_normal = f128::from_bits(SMALLEST_NORMAL_BITS); + assert_f128_biteq!(f128::NEG_INFINITY.next_down(), f128::NEG_INFINITY); + assert_f128_biteq!(f128::MIN.next_down(), f128::NEG_INFINITY); + assert_f128_biteq!((-max_down).next_down(), f128::MIN); + assert_f128_biteq!((-1.0f128).next_down(), -1.0 - f128::EPSILON); + assert_f128_biteq!((-largest_subnormal).next_down(), -smallest_normal); + assert_f128_biteq!((-tiny).next_down(), -tiny_up); + assert_f128_biteq!((-0.0f128).next_down(), -tiny); + assert_f128_biteq!((0.0f128).next_down(), -tiny); + assert_f128_biteq!(tiny.next_down(), 0.0f128); + assert_f128_biteq!(tiny_up.next_down(), tiny); + assert_f128_biteq!(smallest_normal.next_down(), largest_subnormal); + assert_f128_biteq!((1.0 + f128::EPSILON).next_down(), 1.0f128); + assert_f128_biteq!(f128::MAX.next_down(), max_down); + assert_f128_biteq!(f128::INFINITY.next_down(), f128::MAX); + + // Check that NaNs roundtrip. + let nan0 = f128::NAN; + let nan1 = f128::from_bits(f128::NAN.to_bits() ^ 0x002a_aaaa); + let nan2 = f128::from_bits(f128::NAN.to_bits() ^ 0x0055_5555); + assert_f128_biteq!(nan0.next_down(), nan0); + assert_f128_biteq!(nan1.next_down(), nan1); + assert_f128_biteq!(nan2.next_down(), nan2); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_mul_add() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_approx_eq!(12.3f128.mul_add(4.5, 6.7), 62.05, TOL_PRECISE); + assert_approx_eq!((-12.3f128).mul_add(-4.5, -6.7), 48.65, TOL_PRECISE); + assert_approx_eq!(0.0f128.mul_add(8.9, 1.2), 1.2, TOL_PRECISE); + assert_approx_eq!(3.4f128.mul_add(-0.0, 5.6), 5.6, TOL_PRECISE); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f128.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_recip() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(1.0f128.recip(), 1.0); + assert_eq!(2.0f128.recip(), 0.5); + assert_eq!((-0.4f128).recip(), -2.5); + assert_eq!(0.0f128.recip(), inf); + assert_approx_eq!( + f128::MAX.recip(), + 8.40525785778023376565669454330438228902076605e-4933, + 1e-4900 + ); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_powi() { + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(1.0f128.powi(1), 1.0); + assert_approx_eq!((-3.1f128).powi(2), 9.6100000000000005506706202140776519387, TOL); + assert_approx_eq!(5.9f128.powi(-2), 0.028727377190462507313100483690639638451, TOL); + assert_eq!(8.3f128.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] +fn test_sqrt_domain() { + assert!(f128::NAN.sqrt().is_nan()); + assert!(f128::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f128).sqrt().is_nan()); + assert_eq!((-0.0f128).sqrt(), -0.0); + assert_eq!(0.0f128.sqrt(), 0.0); + assert_eq!(1.0f128.sqrt(), 1.0); + assert_eq!(f128::INFINITY.sqrt(), f128::INFINITY); +} + +#[test] +fn test_to_degrees() { + let pi: f128 = consts::PI; + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(0.0f128.to_degrees(), 0.0); + assert_approx_eq!((-5.8f128).to_degrees(), -332.31552117587745090765431723855668471, TOL); + assert_approx_eq!(pi.to_degrees(), 180.0, TOL); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); + assert_eq!(1_f128.to_degrees(), 57.2957795130823208767981548141051703); +} + +#[test] +fn test_to_radians() { + let pi: f128 = consts::PI; + let nan: f128 = f128::NAN; + let inf: f128 = f128::INFINITY; + let neg_inf: f128 = f128::NEG_INFINITY; + assert_eq!(0.0f128.to_radians(), 0.0); + assert_approx_eq!(154.6f128.to_radians(), 2.6982790235832334267135442069489767804, TOL); + assert_approx_eq!((-332.31f128).to_radians(), -5.7999036373023566567593094812182763013, TOL); + // check approx rather than exact because round trip for pi doesn't fall on an exactly + // representable value (unlike `f32` and `f64`). + assert_approx_eq!(180.0f128.to_radians(), pi, TOL_PRECISE); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); +} + +#[test] +fn test_float_bits_conv() { + assert_eq!((1f128).to_bits(), 0x3fff0000000000000000000000000000); + assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000); + assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000); + assert_eq!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); + assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0, TOL_PRECISE); + assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5, TOL_PRECISE); + assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0, TOL_PRECISE); + assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25, TOL_PRECISE); + + // Check that NaNs roundtrip their bits regardless of signaling-ness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + let masked_nan1 = f128::NAN.to_bits() ^ NAN_MASK1; + let masked_nan2 = f128::NAN.to_bits() ^ NAN_MASK2; + assert!(f128::from_bits(masked_nan1).is_nan()); + assert!(f128::from_bits(masked_nan2).is_nan()); + + assert_eq!(f128::from_bits(masked_nan1).to_bits(), masked_nan1); + assert_eq!(f128::from_bits(masked_nan2).to_bits(), masked_nan2); +} + +#[test] +#[should_panic] +fn test_clamp_min_greater_than_max() { + let _ = 1.0f128.clamp(3.0, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_min_is_nan() { + let _ = 1.0f128.clamp(f128::NAN, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_max_is_nan() { + let _ = 1.0f128.clamp(3.0, f128::NAN); +} + +#[test] +fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u128 { + 1 << (f128::MANTISSA_DIGITS - 2) + } + + // FIXME(f16_f128): test subnormals when powf is available + // fn min_subnorm() -> f128 { + // f128::MIN_POSITIVE / f128::powf(2.0, f128::MANTISSA_DIGITS as f128 - 1.0) + // } + + // fn max_subnorm() -> f128 { + // f128::MIN_POSITIVE - min_subnorm() + // } + + fn q_nan() -> f128 { + f128::from_bits(f128::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f128 { + f128::from_bits((f128::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f128::INFINITY).total_cmp(&-f128::INFINITY)); + assert_eq!(Ordering::Equal, (-f128::MAX).total_cmp(&-f128::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f128).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f128).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f128).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f128).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f128::MIN_POSITIVE).total_cmp(&-f128::MIN_POSITIVE)); + // assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + // assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f128).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f128.total_cmp(&0.0)); + // assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + // assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f128::MIN_POSITIVE.total_cmp(&f128::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f128.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f128.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f128.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f128.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f128::MAX.total_cmp(&f128::MAX)); + assert_eq!(Ordering::Equal, f128::INFINITY.total_cmp(&f128::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::INFINITY)); + assert_eq!(Ordering::Less, (-f128::INFINITY).total_cmp(&-f128::MAX)); + assert_eq!(Ordering::Less, (-f128::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f128).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f128).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f128).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f128).total_cmp(&-f128::MIN_POSITIVE)); + // assert_eq!(Ordering::Less, (-f128::MIN_POSITIVE).total_cmp(&-max_subnorm())); + // assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + // assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f128).total_cmp(&0.0)); + // assert_eq!(Ordering::Less, 0.0_f128.total_cmp(&min_subnorm())); + // assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + // assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f128::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f128::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f128.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f128.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f128.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f128.total_cmp(&f128::MAX)); + assert_eq!(Ordering::Less, f128::MAX.total_cmp(&f128::INFINITY)); + assert_eq!(Ordering::Less, f128::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f128::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f128::MAX).total_cmp(&-f128::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f128).total_cmp(&-f128::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f128).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f128).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f128).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f128::MIN_POSITIVE).total_cmp(&-0.5)); + // assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f128::MIN_POSITIVE)); + // assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + // assert_eq!(Ordering::Greater, (-0.0_f128).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f128.total_cmp(&-0.0)); + // assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + // assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + // assert_eq!(Ordering::Greater, f128::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f128.total_cmp(&f128::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f128.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f128.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f128.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f128::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f128::INFINITY.total_cmp(&f128::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f128::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f128::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f128::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f128::MIN_POSITIVE)); + // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f128::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f128::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f128::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::MIN_POSITIVE)); + // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); +} + +#[test] +fn test_algebraic() { + let a: f128 = 123.0; + let b: f128 = 456.0; + + // Check that individual operations match their primitive counterparts. + // + // This is a check of current implementations and does NOT imply any form of + // guarantee about future behavior. The compiler reserves the right to make + // these operations inexact matches in the future. + let eps = if cfg!(miri) { 1e-6 } else { 0.0 }; + + assert_approx_eq!(a.algebraic_add(b), a + b, eps); + assert_approx_eq!(a.algebraic_sub(b), a - b, eps); + assert_approx_eq!(a.algebraic_mul(b), a * b, eps); + assert_approx_eq!(a.algebraic_div(b), a / b, eps); + assert_approx_eq!(a.algebraic_rem(b), a % b, eps); +} + +#[test] +fn test_from() { + assert_eq!(f128::from(false), 0.0); + assert_eq!(f128::from(true), 1.0); + assert_eq!(f128::from(u8::MIN), 0.0); + assert_eq!(f128::from(42_u8), 42.0); + assert_eq!(f128::from(u8::MAX), 255.0); + assert_eq!(f128::from(i8::MIN), -128.0); + assert_eq!(f128::from(42_i8), 42.0); + assert_eq!(f128::from(i8::MAX), 127.0); + assert_eq!(f128::from(u16::MIN), 0.0); + assert_eq!(f128::from(42_u16), 42.0); + assert_eq!(f128::from(u16::MAX), 65535.0); + assert_eq!(f128::from(i16::MIN), -32768.0); + assert_eq!(f128::from(42_i16), 42.0); + assert_eq!(f128::from(i16::MAX), 32767.0); + assert_eq!(f128::from(u32::MIN), 0.0); + assert_eq!(f128::from(42_u32), 42.0); + assert_eq!(f128::from(u32::MAX), 4294967295.0); + assert_eq!(f128::from(i32::MIN), -2147483648.0); + assert_eq!(f128::from(42_i32), 42.0); + assert_eq!(f128::from(i32::MAX), 2147483647.0); + // FIXME(f16_f128): Uncomment these tests once the From<{u64,i64}> impls are added. + // assert_eq!(f128::from(u64::MIN), 0.0); + // assert_eq!(f128::from(42_u64), 42.0); + // assert_eq!(f128::from(u64::MAX), 18446744073709551615.0); + // assert_eq!(f128::from(i64::MIN), -9223372036854775808.0); + // assert_eq!(f128::from(42_i64), 42.0); + // assert_eq!(f128::from(i64::MAX), 9223372036854775807.0); +} diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs new file mode 100644 index 00000000000..db98181226c --- /dev/null +++ b/library/coretests/tests/floats/f16.rs @@ -0,0 +1,753 @@ +// FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy +#![cfg(target_has_reliable_f16)] + +use std::f16::consts; +use std::num::FpCategory as Fp; + +/// Tolerance for results on the order of 10.0e-2 +#[allow(unused)] +const TOL_N2: f16 = 0.0001; + +/// Tolerance for results on the order of 10.0e+0 +#[allow(unused)] +const TOL_0: f16 = 0.01; + +/// Tolerance for results on the order of 10.0e+2 +#[allow(unused)] +const TOL_P2: f16 = 0.5; + +/// Tolerance for results on the order of 10.0e+4 +#[allow(unused)] +const TOL_P4: f16 = 10.0; + +/// Smallest number +const TINY_BITS: u16 = 0x1; + +/// Next smallest number +const TINY_UP_BITS: u16 = 0x2; + +/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 +const MAX_DOWN_BITS: u16 = 0x7bfe; + +/// Zeroed exponent, full significant +const LARGEST_SUBNORMAL_BITS: u16 = 0x03ff; + +/// Exponent = 0b1, zeroed significand +const SMALLEST_NORMAL_BITS: u16 = 0x0400; + +/// First pattern over the mantissa +const NAN_MASK1: u16 = 0x02aa; + +/// Second pattern over the mantissa +const NAN_MASK2: u16 = 0x0155; + +/// Compare by representation +#[allow(unused_macros)] +macro_rules! assert_f16_biteq { + ($a:expr, $b:expr) => { + let (l, r): (&f16, &f16) = (&$a, &$b); + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {l:?} ({lb:#04x}) is not bitequal to {r:?} ({rb:#04x})"); + }; +} + +#[test] +fn test_num_f16() { + super::test_num(10f16, 2f16); +} + +// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support +// the intrinsics. + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_min_nan() { + assert_eq!(f16::NAN.min(2.0), 2.0); + assert_eq!(2.0f16.min(f16::NAN), 2.0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_max_nan() { + assert_eq!(f16::NAN.max(2.0), 2.0); + assert_eq!(2.0f16.max(f16::NAN), 2.0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_minimum() { + assert!(f16::NAN.minimum(2.0).is_nan()); + assert!(2.0f16.minimum(f16::NAN).is_nan()); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_maximum() { + assert!(f16::NAN.maximum(2.0).is_nan()); + assert!(2.0f16.maximum(f16::NAN).is_nan()); +} + +#[test] +fn test_nan() { + let nan: f16 = f16::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert!(!nan.is_normal()); + assert_eq!(Fp::Nan, nan.classify()); + // Ensure the quiet bit is set. + assert!(nan.to_bits() & (1 << (f16::MANTISSA_DIGITS - 2)) != 0); +} + +#[test] +fn test_infinity() { + let inf: f16 = f16::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); +} + +#[test] +fn test_neg_infinity() { + let neg_inf: f16 = f16::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); +} + +#[test] +fn test_zero() { + let zero: f16 = 0.0f16; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); +} + +#[test] +fn test_neg_zero() { + let neg_zero: f16 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); +} + +#[test] +fn test_one() { + let one: f16 = 1.0f16; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); +} + +#[test] +fn test_is_nan() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f16.is_nan()); + assert!(!5.3f16.is_nan()); + assert!(!(-10.732f16).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); +} + +#[test] +fn test_is_infinite() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f16.is_infinite()); + assert!(!42.8f16.is_infinite()); + assert!(!(-109.2f16).is_infinite()); +} + +#[test] +fn test_is_finite() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f16.is_finite()); + assert!(42.8f16.is_finite()); + assert!((-109.2f16).is_finite()); +} + +#[test] +fn test_is_normal() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let zero: f16 = 0.0f16; + let neg_zero: f16 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f16.is_normal()); + assert!(1e-4f16.is_normal()); + assert!(!1e-5f16.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + let zero: f16 = 0.0f16; + let neg_zero: f16 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f16.classify(), Fp::Normal); + assert_eq!(1e-4f16.classify(), Fp::Normal); + assert_eq!(1e-5f16.classify(), Fp::Subnormal); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_floor() { + assert_approx_eq!(1.0f16.floor(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.floor(), 1.0f16, TOL_0); + assert_approx_eq!(1.5f16.floor(), 1.0f16, TOL_0); + assert_approx_eq!(1.7f16.floor(), 1.0f16, TOL_0); + assert_approx_eq!(0.0f16.floor(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).floor(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).floor(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).floor(), -2.0f16, TOL_0); + assert_approx_eq!((-1.5f16).floor(), -2.0f16, TOL_0); + assert_approx_eq!((-1.7f16).floor(), -2.0f16, TOL_0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_ceil() { + assert_approx_eq!(1.0f16.ceil(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.ceil(), 2.0f16, TOL_0); + assert_approx_eq!(1.5f16.ceil(), 2.0f16, TOL_0); + assert_approx_eq!(1.7f16.ceil(), 2.0f16, TOL_0); + assert_approx_eq!(0.0f16.ceil(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).ceil(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).ceil(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).ceil(), -1.0f16, TOL_0); + assert_approx_eq!((-1.5f16).ceil(), -1.0f16, TOL_0); + assert_approx_eq!((-1.7f16).ceil(), -1.0f16, TOL_0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_round() { + assert_approx_eq!(2.5f16.round(), 3.0f16, TOL_0); + assert_approx_eq!(1.0f16.round(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.round(), 1.0f16, TOL_0); + assert_approx_eq!(1.5f16.round(), 2.0f16, TOL_0); + assert_approx_eq!(1.7f16.round(), 2.0f16, TOL_0); + assert_approx_eq!(0.0f16.round(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).round(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).round(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).round(), -1.0f16, TOL_0); + assert_approx_eq!((-1.5f16).round(), -2.0f16, TOL_0); + assert_approx_eq!((-1.7f16).round(), -2.0f16, TOL_0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_round_ties_even() { + assert_approx_eq!(2.5f16.round_ties_even(), 2.0f16, TOL_0); + assert_approx_eq!(1.0f16.round_ties_even(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.round_ties_even(), 1.0f16, TOL_0); + assert_approx_eq!(1.5f16.round_ties_even(), 2.0f16, TOL_0); + assert_approx_eq!(1.7f16.round_ties_even(), 2.0f16, TOL_0); + assert_approx_eq!(0.0f16.round_ties_even(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).round_ties_even(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).round_ties_even(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).round_ties_even(), -1.0f16, TOL_0); + assert_approx_eq!((-1.5f16).round_ties_even(), -2.0f16, TOL_0); + assert_approx_eq!((-1.7f16).round_ties_even(), -2.0f16, TOL_0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_trunc() { + assert_approx_eq!(1.0f16.trunc(), 1.0f16, TOL_0); + assert_approx_eq!(1.3f16.trunc(), 1.0f16, TOL_0); + assert_approx_eq!(1.5f16.trunc(), 1.0f16, TOL_0); + assert_approx_eq!(1.7f16.trunc(), 1.0f16, TOL_0); + assert_approx_eq!(0.0f16.trunc(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).trunc(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).trunc(), -1.0f16, TOL_0); + assert_approx_eq!((-1.3f16).trunc(), -1.0f16, TOL_0); + assert_approx_eq!((-1.5f16).trunc(), -1.0f16, TOL_0); + assert_approx_eq!((-1.7f16).trunc(), -1.0f16, TOL_0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_fract() { + assert_approx_eq!(1.0f16.fract(), 0.0f16, TOL_0); + assert_approx_eq!(1.3f16.fract(), 0.3f16, TOL_0); + assert_approx_eq!(1.5f16.fract(), 0.5f16, TOL_0); + assert_approx_eq!(1.7f16.fract(), 0.7f16, TOL_0); + assert_approx_eq!(0.0f16.fract(), 0.0f16, TOL_0); + assert_approx_eq!((-0.0f16).fract(), -0.0f16, TOL_0); + assert_approx_eq!((-1.0f16).fract(), -0.0f16, TOL_0); + assert_approx_eq!((-1.3f16).fract(), -0.3f16, TOL_0); + assert_approx_eq!((-1.5f16).fract(), -0.5f16, TOL_0); + assert_approx_eq!((-1.7f16).fract(), -0.7f16, TOL_0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_abs() { + assert_eq!(f16::INFINITY.abs(), f16::INFINITY); + assert_eq!(1f16.abs(), 1f16); + assert_eq!(0f16.abs(), 0f16); + assert_eq!((-0f16).abs(), 0f16); + assert_eq!((-1f16).abs(), 1f16); + assert_eq!(f16::NEG_INFINITY.abs(), f16::INFINITY); + assert_eq!((1f16 / f16::NEG_INFINITY).abs(), 0f16); + assert!(f16::NAN.abs().is_nan()); +} + +#[test] +fn test_is_sign_positive() { + assert!(f16::INFINITY.is_sign_positive()); + assert!(1f16.is_sign_positive()); + assert!(0f16.is_sign_positive()); + assert!(!(-0f16).is_sign_positive()); + assert!(!(-1f16).is_sign_positive()); + assert!(!f16::NEG_INFINITY.is_sign_positive()); + assert!(!(1f16 / f16::NEG_INFINITY).is_sign_positive()); + assert!(f16::NAN.is_sign_positive()); + assert!(!(-f16::NAN).is_sign_positive()); +} + +#[test] +fn test_is_sign_negative() { + assert!(!f16::INFINITY.is_sign_negative()); + assert!(!1f16.is_sign_negative()); + assert!(!0f16.is_sign_negative()); + assert!((-0f16).is_sign_negative()); + assert!((-1f16).is_sign_negative()); + assert!(f16::NEG_INFINITY.is_sign_negative()); + assert!((1f16 / f16::NEG_INFINITY).is_sign_negative()); + assert!(!f16::NAN.is_sign_negative()); + assert!((-f16::NAN).is_sign_negative()); +} + +#[test] +fn test_next_up() { + let tiny = f16::from_bits(TINY_BITS); + let tiny_up = f16::from_bits(TINY_UP_BITS); + let max_down = f16::from_bits(MAX_DOWN_BITS); + let largest_subnormal = f16::from_bits(LARGEST_SUBNORMAL_BITS); + let smallest_normal = f16::from_bits(SMALLEST_NORMAL_BITS); + assert_f16_biteq!(f16::NEG_INFINITY.next_up(), f16::MIN); + assert_f16_biteq!(f16::MIN.next_up(), -max_down); + assert_f16_biteq!((-1.0 - f16::EPSILON).next_up(), -1.0); + assert_f16_biteq!((-smallest_normal).next_up(), -largest_subnormal); + assert_f16_biteq!((-tiny_up).next_up(), -tiny); + assert_f16_biteq!((-tiny).next_up(), -0.0f16); + assert_f16_biteq!((-0.0f16).next_up(), tiny); + assert_f16_biteq!(0.0f16.next_up(), tiny); + assert_f16_biteq!(tiny.next_up(), tiny_up); + assert_f16_biteq!(largest_subnormal.next_up(), smallest_normal); + assert_f16_biteq!(1.0f16.next_up(), 1.0 + f16::EPSILON); + assert_f16_biteq!(f16::MAX.next_up(), f16::INFINITY); + assert_f16_biteq!(f16::INFINITY.next_up(), f16::INFINITY); + + // Check that NaNs roundtrip. + let nan0 = f16::NAN; + let nan1 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK1); + let nan2 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK2); + assert_f16_biteq!(nan0.next_up(), nan0); + assert_f16_biteq!(nan1.next_up(), nan1); + assert_f16_biteq!(nan2.next_up(), nan2); +} + +#[test] +fn test_next_down() { + let tiny = f16::from_bits(TINY_BITS); + let tiny_up = f16::from_bits(TINY_UP_BITS); + let max_down = f16::from_bits(MAX_DOWN_BITS); + let largest_subnormal = f16::from_bits(LARGEST_SUBNORMAL_BITS); + let smallest_normal = f16::from_bits(SMALLEST_NORMAL_BITS); + assert_f16_biteq!(f16::NEG_INFINITY.next_down(), f16::NEG_INFINITY); + assert_f16_biteq!(f16::MIN.next_down(), f16::NEG_INFINITY); + assert_f16_biteq!((-max_down).next_down(), f16::MIN); + assert_f16_biteq!((-1.0f16).next_down(), -1.0 - f16::EPSILON); + assert_f16_biteq!((-largest_subnormal).next_down(), -smallest_normal); + assert_f16_biteq!((-tiny).next_down(), -tiny_up); + assert_f16_biteq!((-0.0f16).next_down(), -tiny); + assert_f16_biteq!((0.0f16).next_down(), -tiny); + assert_f16_biteq!(tiny.next_down(), 0.0f16); + assert_f16_biteq!(tiny_up.next_down(), tiny); + assert_f16_biteq!(smallest_normal.next_down(), largest_subnormal); + assert_f16_biteq!((1.0 + f16::EPSILON).next_down(), 1.0f16); + assert_f16_biteq!(f16::MAX.next_down(), max_down); + assert_f16_biteq!(f16::INFINITY.next_down(), f16::MAX); + + // Check that NaNs roundtrip. + let nan0 = f16::NAN; + let nan1 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK1); + let nan2 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK2); + assert_f16_biteq!(nan0.next_down(), nan0); + assert_f16_biteq!(nan1.next_down(), nan1); + assert_f16_biteq!(nan2.next_down(), nan2); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_mul_add() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_approx_eq!(12.3f16.mul_add(4.5, 6.7), 62.05, TOL_P2); + assert_approx_eq!((-12.3f16).mul_add(-4.5, -6.7), 48.65, TOL_P2); + assert_approx_eq!(0.0f16.mul_add(8.9, 1.2), 1.2, TOL_0); + assert_approx_eq!(3.4f16.mul_add(-0.0, 5.6), 5.6, TOL_0); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f16.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_recip() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(1.0f16.recip(), 1.0); + assert_eq!(2.0f16.recip(), 0.5); + assert_eq!((-0.4f16).recip(), -2.5); + assert_eq!(0.0f16.recip(), inf); + assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_powi() { + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(1.0f16.powi(1), 1.0); + assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0); + assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2); + assert_eq!(8.3f16.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_sqrt_domain() { + assert!(f16::NAN.sqrt().is_nan()); + assert!(f16::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f16).sqrt().is_nan()); + assert_eq!((-0.0f16).sqrt(), -0.0); + assert_eq!(0.0f16.sqrt(), 0.0); + assert_eq!(1.0f16.sqrt(), 1.0); + assert_eq!(f16::INFINITY.sqrt(), f16::INFINITY); +} + +#[test] +fn test_to_degrees() { + let pi: f16 = consts::PI; + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(0.0f16.to_degrees(), 0.0); + assert_approx_eq!((-5.8f16).to_degrees(), -332.315521, TOL_P2); + assert_approx_eq!(pi.to_degrees(), 180.0, TOL_P2); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); + assert_eq!(1_f16.to_degrees(), 57.2957795130823208767981548141051703); +} + +#[test] +fn test_to_radians() { + let pi: f16 = consts::PI; + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(0.0f16.to_radians(), 0.0); + assert_approx_eq!(154.6f16.to_radians(), 2.698279, TOL_0); + assert_approx_eq!((-332.31f16).to_radians(), -5.799903, TOL_0); + assert_approx_eq!(180.0f16.to_radians(), pi, TOL_0); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); +} + +#[test] +fn test_float_bits_conv() { + assert_eq!((1f16).to_bits(), 0x3c00); + assert_eq!((12.5f16).to_bits(), 0x4a40); + assert_eq!((1337f16).to_bits(), 0x6539); + assert_eq!((-14.25f16).to_bits(), 0xcb20); + assert_approx_eq!(f16::from_bits(0x3c00), 1.0, TOL_0); + assert_approx_eq!(f16::from_bits(0x4a40), 12.5, TOL_0); + assert_approx_eq!(f16::from_bits(0x6539), 1337.0, TOL_P4); + assert_approx_eq!(f16::from_bits(0xcb20), -14.25, TOL_0); + + // Check that NaNs roundtrip their bits regardless of signaling-ness + let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1; + let masked_nan2 = f16::NAN.to_bits() ^ NAN_MASK2; + assert!(f16::from_bits(masked_nan1).is_nan()); + assert!(f16::from_bits(masked_nan2).is_nan()); + + assert_eq!(f16::from_bits(masked_nan1).to_bits(), masked_nan1); + assert_eq!(f16::from_bits(masked_nan2).to_bits(), masked_nan2); +} + +#[test] +#[should_panic] +fn test_clamp_min_greater_than_max() { + let _ = 1.0f16.clamp(3.0, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_min_is_nan() { + let _ = 1.0f16.clamp(f16::NAN, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_max_is_nan() { + let _ = 1.0f16.clamp(3.0, f16::NAN); +} + +#[test] +#[cfg(not(miri))] +#[cfg(target_has_reliable_f16_math)] +fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u16 { + 1 << (f16::MANTISSA_DIGITS - 2) + } + + fn min_subnorm() -> f16 { + f16::MIN_POSITIVE / f16::powf(2.0, f16::MANTISSA_DIGITS as f16 - 1.0) + } + + fn max_subnorm() -> f16 { + f16::MIN_POSITIVE - min_subnorm() + } + + fn q_nan() -> f16 { + f16::from_bits(f16::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f16 { + f16::from_bits((f16::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f16::INFINITY).total_cmp(&-f16::INFINITY)); + assert_eq!(Ordering::Equal, (-f16::MAX).total_cmp(&-f16::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f16).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f16).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f16).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f16).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f16::MIN_POSITIVE).total_cmp(&-f16::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f16).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f16.total_cmp(&0.0)); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f16::MIN_POSITIVE.total_cmp(&f16::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f16.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f16.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f16.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f16.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f16::MAX.total_cmp(&f16::MAX)); + assert_eq!(Ordering::Equal, f16::INFINITY.total_cmp(&f16::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::INFINITY)); + assert_eq!(Ordering::Less, (-f16::INFINITY).total_cmp(&-f16::MAX)); + assert_eq!(Ordering::Less, (-f16::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f16).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f16).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f16).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f16).total_cmp(&-f16::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-f16::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f16).total_cmp(&0.0)); + assert_eq!(Ordering::Less, 0.0_f16.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f16::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f16::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f16.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f16.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f16.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f16.total_cmp(&f16::MAX)); + assert_eq!(Ordering::Less, f16::MAX.total_cmp(&f16::INFINITY)); + assert_eq!(Ordering::Less, f16::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f16::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f16::MAX).total_cmp(&-f16::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f16).total_cmp(&-f16::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f16).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f16).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f16).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f16::MIN_POSITIVE).total_cmp(&-0.5)); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f16::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f16).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f16.total_cmp(&-0.0)); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f16::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f16.total_cmp(&f16::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f16.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f16.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f16.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f16::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f16::INFINITY.total_cmp(&f16::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f16::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f16::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f16::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f16::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f16::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f16::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f16::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); +} + +#[test] +fn test_algebraic() { + let a: f16 = 123.0; + let b: f16 = 456.0; + + // Check that individual operations match their primitive counterparts. + // + // This is a check of current implementations and does NOT imply any form of + // guarantee about future behavior. The compiler reserves the right to make + // these operations inexact matches in the future. + let eps_add = if cfg!(miri) { 1e1 } else { 0.0 }; + let eps_mul = if cfg!(miri) { 1e3 } else { 0.0 }; + let eps_div = if cfg!(miri) { 1e0 } else { 0.0 }; + + assert_approx_eq!(a.algebraic_add(b), a + b, eps_add); + assert_approx_eq!(a.algebraic_sub(b), a - b, eps_add); + assert_approx_eq!(a.algebraic_mul(b), a * b, eps_mul); + assert_approx_eq!(a.algebraic_div(b), a / b, eps_div); + assert_approx_eq!(a.algebraic_rem(b), a % b, eps_div); +} + +#[test] +fn test_from() { + assert_eq!(f16::from(false), 0.0); + assert_eq!(f16::from(true), 1.0); + assert_eq!(f16::from(u8::MIN), 0.0); + assert_eq!(f16::from(42_u8), 42.0); + assert_eq!(f16::from(u8::MAX), 255.0); + assert_eq!(f16::from(i8::MIN), -128.0); + assert_eq!(f16::from(42_i8), 42.0); + assert_eq!(f16::from(i8::MAX), 127.0); +} diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs new file mode 100644 index 00000000000..9b551643bae --- /dev/null +++ b/library/coretests/tests/floats/f32.rs @@ -0,0 +1,702 @@ +use core::f32; +use core::f32::consts; +use core::num::FpCategory as Fp; + +/// Smallest number +const TINY_BITS: u32 = 0x1; + +/// Next smallest number +const TINY_UP_BITS: u32 = 0x2; + +/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 +const MAX_DOWN_BITS: u32 = 0x7f7f_fffe; + +/// Zeroed exponent, full significant +const LARGEST_SUBNORMAL_BITS: u32 = 0x007f_ffff; + +/// Exponent = 0b1, zeroed significand +const SMALLEST_NORMAL_BITS: u32 = 0x0080_0000; + +/// First pattern over the mantissa +const NAN_MASK1: u32 = 0x002a_aaaa; + +/// Second pattern over the mantissa +const NAN_MASK2: u32 = 0x0055_5555; + +#[allow(unused_macros)] +macro_rules! assert_f32_biteq { + ($left : expr, $right : expr) => { + let l: &f32 = &$left; + let r: &f32 = &$right; + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {l} ({lb:#010x}) is not bitequal to {r} ({rb:#010x})"); + }; +} + +#[test] +fn test_num_f32() { + super::test_num(10f32, 2f32); +} + +#[test] +fn test_min_nan() { + assert_eq!(f32::NAN.min(2.0), 2.0); + assert_eq!(2.0f32.min(f32::NAN), 2.0); +} + +#[test] +fn test_max_nan() { + assert_eq!(f32::NAN.max(2.0), 2.0); + assert_eq!(2.0f32.max(f32::NAN), 2.0); +} + +#[test] +fn test_minimum() { + assert!(f32::NAN.minimum(2.0).is_nan()); + assert!(2.0f32.minimum(f32::NAN).is_nan()); +} + +#[test] +fn test_maximum() { + assert!(f32::NAN.maximum(2.0).is_nan()); + assert!(2.0f32.maximum(f32::NAN).is_nan()); +} + +#[test] +fn test_nan() { + let nan: f32 = f32::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(!nan.is_normal()); + assert!(nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert_eq!(Fp::Nan, nan.classify()); + // Ensure the quiet bit is set. + assert!(nan.to_bits() & (1 << (f32::MANTISSA_DIGITS - 2)) != 0); +} + +#[test] +fn test_infinity() { + let inf: f32 = f32::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); +} + +#[test] +fn test_neg_infinity() { + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); +} + +#[test] +fn test_zero() { + let zero: f32 = 0.0f32; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); +} + +#[test] +fn test_neg_zero() { + let neg_zero: f32 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); +} + +#[test] +fn test_one() { + let one: f32 = 1.0f32; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); +} + +#[test] +fn test_is_nan() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f32.is_nan()); + assert!(!5.3f32.is_nan()); + assert!(!(-10.732f32).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); +} + +#[test] +fn test_is_infinite() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f32.is_infinite()); + assert!(!42.8f32.is_infinite()); + assert!(!(-109.2f32).is_infinite()); +} + +#[test] +fn test_is_finite() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f32.is_finite()); + assert!(42.8f32.is_finite()); + assert!((-109.2f32).is_finite()); +} + +#[test] +fn test_is_normal() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f32.is_normal()); + assert!(1e-37f32.is_normal()); + assert!(!1e-38f32.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f32.classify(), Fp::Normal); + assert_eq!(1e-37f32.classify(), Fp::Normal); + assert_eq!(1e-38f32.classify(), Fp::Subnormal); +} + +#[test] +fn test_floor() { + assert_approx_eq!(f32::floor(1.0f32), 1.0f32); + assert_approx_eq!(f32::floor(1.3f32), 1.0f32); + assert_approx_eq!(f32::floor(1.5f32), 1.0f32); + assert_approx_eq!(f32::floor(1.7f32), 1.0f32); + assert_approx_eq!(f32::floor(0.0f32), 0.0f32); + assert_approx_eq!(f32::floor(-0.0f32), -0.0f32); + assert_approx_eq!(f32::floor(-1.0f32), -1.0f32); + assert_approx_eq!(f32::floor(-1.3f32), -2.0f32); + assert_approx_eq!(f32::floor(-1.5f32), -2.0f32); + assert_approx_eq!(f32::floor(-1.7f32), -2.0f32); +} + +#[test] +fn test_ceil() { + assert_approx_eq!(f32::ceil(1.0f32), 1.0f32); + assert_approx_eq!(f32::ceil(1.3f32), 2.0f32); + assert_approx_eq!(f32::ceil(1.5f32), 2.0f32); + assert_approx_eq!(f32::ceil(1.7f32), 2.0f32); + assert_approx_eq!(f32::ceil(0.0f32), 0.0f32); + assert_approx_eq!(f32::ceil(-0.0f32), -0.0f32); + assert_approx_eq!(f32::ceil(-1.0f32), -1.0f32); + assert_approx_eq!(f32::ceil(-1.3f32), -1.0f32); + assert_approx_eq!(f32::ceil(-1.5f32), -1.0f32); + assert_approx_eq!(f32::ceil(-1.7f32), -1.0f32); +} + +#[test] +fn test_round() { + assert_approx_eq!(f32::round(2.5f32), 3.0f32); + assert_approx_eq!(f32::round(1.0f32), 1.0f32); + assert_approx_eq!(f32::round(1.3f32), 1.0f32); + assert_approx_eq!(f32::round(1.5f32), 2.0f32); + assert_approx_eq!(f32::round(1.7f32), 2.0f32); + assert_approx_eq!(f32::round(0.0f32), 0.0f32); + assert_approx_eq!(f32::round(-0.0f32), -0.0f32); + assert_approx_eq!(f32::round(-1.0f32), -1.0f32); + assert_approx_eq!(f32::round(-1.3f32), -1.0f32); + assert_approx_eq!(f32::round(-1.5f32), -2.0f32); + assert_approx_eq!(f32::round(-1.7f32), -2.0f32); +} + +#[test] +fn test_round_ties_even() { + assert_approx_eq!(f32::round_ties_even(2.5f32), 2.0f32); + assert_approx_eq!(f32::round_ties_even(1.0f32), 1.0f32); + assert_approx_eq!(f32::round_ties_even(1.3f32), 1.0f32); + assert_approx_eq!(f32::round_ties_even(1.5f32), 2.0f32); + assert_approx_eq!(f32::round_ties_even(1.7f32), 2.0f32); + assert_approx_eq!(f32::round_ties_even(0.0f32), 0.0f32); + assert_approx_eq!(f32::round_ties_even(-0.0f32), -0.0f32); + assert_approx_eq!(f32::round_ties_even(-1.0f32), -1.0f32); + assert_approx_eq!(f32::round_ties_even(-1.3f32), -1.0f32); + assert_approx_eq!(f32::round_ties_even(-1.5f32), -2.0f32); + assert_approx_eq!(f32::round_ties_even(-1.7f32), -2.0f32); +} + +#[test] +fn test_trunc() { + assert_approx_eq!(f32::trunc(1.0f32), 1.0f32); + assert_approx_eq!(f32::trunc(1.3f32), 1.0f32); + assert_approx_eq!(f32::trunc(1.5f32), 1.0f32); + assert_approx_eq!(f32::trunc(1.7f32), 1.0f32); + assert_approx_eq!(f32::trunc(0.0f32), 0.0f32); + assert_approx_eq!(f32::trunc(-0.0f32), -0.0f32); + assert_approx_eq!(f32::trunc(-1.0f32), -1.0f32); + assert_approx_eq!(f32::trunc(-1.3f32), -1.0f32); + assert_approx_eq!(f32::trunc(-1.5f32), -1.0f32); + assert_approx_eq!(f32::trunc(-1.7f32), -1.0f32); +} + +#[test] +fn test_fract() { + assert_approx_eq!(f32::fract(1.0f32), 0.0f32); + assert_approx_eq!(f32::fract(1.3f32), 0.3f32); + assert_approx_eq!(f32::fract(1.5f32), 0.5f32); + assert_approx_eq!(f32::fract(1.7f32), 0.7f32); + assert_approx_eq!(f32::fract(0.0f32), 0.0f32); + assert_approx_eq!(f32::fract(-0.0f32), -0.0f32); + assert_approx_eq!(f32::fract(-1.0f32), -0.0f32); + assert_approx_eq!(f32::fract(-1.3f32), -0.3f32); + assert_approx_eq!(f32::fract(-1.5f32), -0.5f32); + assert_approx_eq!(f32::fract(-1.7f32), -0.7f32); +} + +#[test] +fn test_abs() { + assert_eq!(f32::INFINITY.abs(), f32::INFINITY); + assert_eq!(1f32.abs(), 1f32); + assert_eq!(0f32.abs(), 0f32); + assert_eq!((-0f32).abs(), 0f32); + assert_eq!((-1f32).abs(), 1f32); + assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY); + assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32); + assert!(f32::NAN.abs().is_nan()); +} + +#[test] +fn test_signum() { + assert_eq!(f32::INFINITY.signum(), 1f32); + assert_eq!(1f32.signum(), 1f32); + assert_eq!(0f32.signum(), 1f32); + assert_eq!((-0f32).signum(), -1f32); + assert_eq!((-1f32).signum(), -1f32); + assert_eq!(f32::NEG_INFINITY.signum(), -1f32); + assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32); + assert!(f32::NAN.signum().is_nan()); +} + +#[test] +fn test_is_sign_positive() { + assert!(f32::INFINITY.is_sign_positive()); + assert!(1f32.is_sign_positive()); + assert!(0f32.is_sign_positive()); + assert!(!(-0f32).is_sign_positive()); + assert!(!(-1f32).is_sign_positive()); + assert!(!f32::NEG_INFINITY.is_sign_positive()); + assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive()); + assert!(f32::NAN.is_sign_positive()); + assert!(!(-f32::NAN).is_sign_positive()); +} + +#[test] +fn test_is_sign_negative() { + assert!(!f32::INFINITY.is_sign_negative()); + assert!(!1f32.is_sign_negative()); + assert!(!0f32.is_sign_negative()); + assert!((-0f32).is_sign_negative()); + assert!((-1f32).is_sign_negative()); + assert!(f32::NEG_INFINITY.is_sign_negative()); + assert!((1f32 / f32::NEG_INFINITY).is_sign_negative()); + assert!(!f32::NAN.is_sign_negative()); + assert!((-f32::NAN).is_sign_negative()); +} + +#[test] +fn test_next_up() { + let tiny = f32::from_bits(TINY_BITS); + let tiny_up = f32::from_bits(TINY_UP_BITS); + let max_down = f32::from_bits(MAX_DOWN_BITS); + let largest_subnormal = f32::from_bits(LARGEST_SUBNORMAL_BITS); + let smallest_normal = f32::from_bits(SMALLEST_NORMAL_BITS); + assert_f32_biteq!(f32::NEG_INFINITY.next_up(), f32::MIN); + assert_f32_biteq!(f32::MIN.next_up(), -max_down); + assert_f32_biteq!((-1.0 - f32::EPSILON).next_up(), -1.0); + assert_f32_biteq!((-smallest_normal).next_up(), -largest_subnormal); + assert_f32_biteq!((-tiny_up).next_up(), -tiny); + assert_f32_biteq!((-tiny).next_up(), -0.0f32); + assert_f32_biteq!((-0.0f32).next_up(), tiny); + assert_f32_biteq!(0.0f32.next_up(), tiny); + assert_f32_biteq!(tiny.next_up(), tiny_up); + assert_f32_biteq!(largest_subnormal.next_up(), smallest_normal); + assert_f32_biteq!(1.0f32.next_up(), 1.0 + f32::EPSILON); + assert_f32_biteq!(f32::MAX.next_up(), f32::INFINITY); + assert_f32_biteq!(f32::INFINITY.next_up(), f32::INFINITY); + + // Check that NaNs roundtrip. + let nan0 = f32::NAN; + let nan1 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK1); + let nan2 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK2); + assert_f32_biteq!(nan0.next_up(), nan0); + assert_f32_biteq!(nan1.next_up(), nan1); + assert_f32_biteq!(nan2.next_up(), nan2); +} + +#[test] +fn test_next_down() { + let tiny = f32::from_bits(TINY_BITS); + let tiny_up = f32::from_bits(TINY_UP_BITS); + let max_down = f32::from_bits(MAX_DOWN_BITS); + let largest_subnormal = f32::from_bits(LARGEST_SUBNORMAL_BITS); + let smallest_normal = f32::from_bits(SMALLEST_NORMAL_BITS); + assert_f32_biteq!(f32::NEG_INFINITY.next_down(), f32::NEG_INFINITY); + assert_f32_biteq!(f32::MIN.next_down(), f32::NEG_INFINITY); + assert_f32_biteq!((-max_down).next_down(), f32::MIN); + assert_f32_biteq!((-1.0f32).next_down(), -1.0 - f32::EPSILON); + assert_f32_biteq!((-largest_subnormal).next_down(), -smallest_normal); + assert_f32_biteq!((-tiny).next_down(), -tiny_up); + assert_f32_biteq!((-0.0f32).next_down(), -tiny); + assert_f32_biteq!((0.0f32).next_down(), -tiny); + assert_f32_biteq!(tiny.next_down(), 0.0f32); + assert_f32_biteq!(tiny_up.next_down(), tiny); + assert_f32_biteq!(smallest_normal.next_down(), largest_subnormal); + assert_f32_biteq!((1.0 + f32::EPSILON).next_down(), 1.0f32); + assert_f32_biteq!(f32::MAX.next_down(), max_down); + assert_f32_biteq!(f32::INFINITY.next_down(), f32::MAX); + + // Check that NaNs roundtrip. + let nan0 = f32::NAN; + let nan1 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK1); + let nan2 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK2); + assert_f32_biteq!(nan0.next_down(), nan0); + assert_f32_biteq!(nan1.next_down(), nan1); + assert_f32_biteq!(nan2.next_down(), nan2); +} + +// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ +#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] +#[test] +fn test_mul_add() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(f32::mul_add(12.3f32, 4.5, 6.7), 62.05); + assert_approx_eq!(f32::mul_add(-12.3f32, -4.5, -6.7), 48.65); + assert_approx_eq!(f32::mul_add(0.0f32, 8.9, 1.2), 1.2); + assert_approx_eq!(f32::mul_add(3.4f32, -0.0, 5.6), 5.6); + assert!(f32::mul_add(nan, 7.8, 9.0).is_nan()); + assert_eq!(f32::mul_add(inf, 7.8, 9.0), inf); + assert_eq!(f32::mul_add(neg_inf, 7.8, 9.0), neg_inf); + assert_eq!(f32::mul_add(8.9f32, inf, 3.2), inf); + assert_eq!(f32::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); +} + +#[test] +fn test_recip() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.recip(), 1.0); + assert_eq!(2.0f32.recip(), 0.5); + assert_eq!((-0.4f32).recip(), -2.5); + assert_eq!(0.0f32.recip(), inf); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); +} + +#[test] +fn test_powi() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.powi(1), 1.0); + assert_approx_eq!((-3.1f32).powi(2), 9.61); + assert_approx_eq!(5.9f32.powi(-2), 0.028727); + assert_eq!(8.3f32.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +fn test_sqrt_domain() { + assert!(f32::NAN.sqrt().is_nan()); + assert!(f32::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f32).sqrt().is_nan()); + assert_eq!((-0.0f32).sqrt(), -0.0); + assert_eq!(0.0f32.sqrt(), 0.0); + assert_eq!(1.0f32.sqrt(), 1.0); + assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); +} + +#[test] +fn test_to_degrees() { + let pi: f32 = consts::PI; + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(0.0f32.to_degrees(), 0.0); + assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); + assert_eq!(pi.to_degrees(), 180.0); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); + assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); +} + +#[test] +fn test_to_radians() { + let pi: f32 = consts::PI; + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(0.0f32.to_radians(), 0.0); + assert_approx_eq!(154.6f32.to_radians(), 2.698279); + assert_approx_eq!((-332.31f32).to_radians(), -5.799903); + assert_eq!(180.0f32.to_radians(), pi); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); +} + +#[test] +fn test_float_bits_conv() { + assert_eq!((1f32).to_bits(), 0x3f800000); + assert_eq!((12.5f32).to_bits(), 0x41480000); + assert_eq!((1337f32).to_bits(), 0x44a72000); + assert_eq!((-14.25f32).to_bits(), 0xc1640000); + assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); + assert_approx_eq!(f32::from_bits(0x41480000), 12.5); + assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); + assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signaling-ness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + let masked_nan1 = f32::NAN.to_bits() ^ NAN_MASK1; + let masked_nan2 = f32::NAN.to_bits() ^ NAN_MASK2; + assert!(f32::from_bits(masked_nan1).is_nan()); + assert!(f32::from_bits(masked_nan2).is_nan()); + + assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1); + assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2); +} + +#[test] +#[should_panic] +fn test_clamp_min_greater_than_max() { + let _ = 1.0f32.clamp(3.0, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_min_is_nan() { + let _ = 1.0f32.clamp(f32::NAN, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_max_is_nan() { + let _ = 1.0f32.clamp(3.0, f32::NAN); +} + +#[test] +fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u32 { + 1 << (f32::MANTISSA_DIGITS - 2) + } + + fn min_subnorm() -> f32 { + f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0) + } + + fn max_subnorm() -> f32 { + f32::MIN_POSITIVE - min_subnorm() + } + + fn q_nan() -> f32 { + f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f32 { + f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0)); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0)); + assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5)); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0)); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); +} + +#[test] +fn test_algebraic() { + let a: f32 = 123.0; + let b: f32 = 456.0; + + // Check that individual operations match their primitive counterparts. + // + // This is a check of current implementations and does NOT imply any form of + // guarantee about future behavior. The compiler reserves the right to make + // these operations inexact matches in the future. + let eps_add = if cfg!(miri) { 1e-3 } else { 0.0 }; + let eps_mul = if cfg!(miri) { 1e-1 } else { 0.0 }; + let eps_div = if cfg!(miri) { 1e-4 } else { 0.0 }; + + assert_approx_eq!(a.algebraic_add(b), a + b, eps_add); + assert_approx_eq!(a.algebraic_sub(b), a - b, eps_add); + assert_approx_eq!(a.algebraic_mul(b), a * b, eps_mul); + assert_approx_eq!(a.algebraic_div(b), a / b, eps_div); + assert_approx_eq!(a.algebraic_rem(b), a % b, eps_div); +} diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs new file mode 100644 index 00000000000..988108371d7 --- /dev/null +++ b/library/coretests/tests/floats/f64.rs @@ -0,0 +1,682 @@ +use std::f64::consts; +use std::num::FpCategory as Fp; + +/// Smallest number +const TINY_BITS: u64 = 0x1; + +/// Next smallest number +const TINY_UP_BITS: u64 = 0x2; + +/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 +const MAX_DOWN_BITS: u64 = 0x7fef_ffff_ffff_fffe; + +/// Zeroed exponent, full significant +const LARGEST_SUBNORMAL_BITS: u64 = 0x000f_ffff_ffff_ffff; + +/// Exponent = 0b1, zeroed significand +const SMALLEST_NORMAL_BITS: u64 = 0x0010_0000_0000_0000; + +/// First pattern over the mantissa +const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; + +/// Second pattern over the mantissa +const NAN_MASK2: u64 = 0x0005_5555_5555_5555; + +#[allow(unused_macros)] +macro_rules! assert_f64_biteq { + ($left : expr, $right : expr) => { + let l: &f64 = &$left; + let r: &f64 = &$right; + let lb = l.to_bits(); + let rb = r.to_bits(); + assert_eq!(lb, rb, "float {l} ({lb:#018x}) is not bitequal to {r} ({rb:#018x})"); + }; +} + +#[test] +fn test_num_f64() { + super::test_num(10f64, 2f64); +} + +#[test] +fn test_min_nan() { + assert_eq!(f64::NAN.min(2.0), 2.0); + assert_eq!(2.0f64.min(f64::NAN), 2.0); +} + +#[test] +fn test_max_nan() { + assert_eq!(f64::NAN.max(2.0), 2.0); + assert_eq!(2.0f64.max(f64::NAN), 2.0); +} + +#[test] +fn test_nan() { + let nan: f64 = f64::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(!nan.is_normal()); + assert!(nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert_eq!(Fp::Nan, nan.classify()); + // Ensure the quiet bit is set. + assert!(nan.to_bits() & (1 << (f64::MANTISSA_DIGITS - 2)) != 0); +} + +#[test] +fn test_infinity() { + let inf: f64 = f64::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); +} + +#[test] +fn test_neg_infinity() { + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); +} + +#[test] +fn test_zero() { + let zero: f64 = 0.0f64; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); +} + +#[test] +fn test_neg_zero() { + let neg_zero: f64 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); +} + +#[test] +fn test_one() { + let one: f64 = 1.0f64; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); +} + +#[test] +fn test_is_nan() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f64.is_nan()); + assert!(!5.3f64.is_nan()); + assert!(!(-10.732f64).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); +} + +#[test] +fn test_is_infinite() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f64.is_infinite()); + assert!(!42.8f64.is_infinite()); + assert!(!(-109.2f64).is_infinite()); +} + +#[test] +fn test_is_finite() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f64.is_finite()); + assert!(42.8f64.is_finite()); + assert!((-109.2f64).is_finite()); +} + +#[test] +fn test_is_normal() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f64.is_normal()); + assert!(1e-307f64.is_normal()); + assert!(!1e-308f64.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1e-307f64.classify(), Fp::Normal); + assert_eq!(1e-308f64.classify(), Fp::Subnormal); +} + +#[test] +fn test_floor() { + assert_approx_eq!(f64::floor(1.0f64), 1.0f64); + assert_approx_eq!(f64::floor(1.3f64), 1.0f64); + assert_approx_eq!(f64::floor(1.5f64), 1.0f64); + assert_approx_eq!(f64::floor(1.7f64), 1.0f64); + assert_approx_eq!(f64::floor(0.0f64), 0.0f64); + assert_approx_eq!(f64::floor(-0.0f64), -0.0f64); + assert_approx_eq!(f64::floor(-1.0f64), -1.0f64); + assert_approx_eq!(f64::floor(-1.3f64), -2.0f64); + assert_approx_eq!(f64::floor(-1.5f64), -2.0f64); + assert_approx_eq!(f64::floor(-1.7f64), -2.0f64); +} + +#[test] +fn test_ceil() { + assert_approx_eq!(f64::ceil(1.0f64), 1.0f64); + assert_approx_eq!(f64::ceil(1.3f64), 2.0f64); + assert_approx_eq!(f64::ceil(1.5f64), 2.0f64); + assert_approx_eq!(f64::ceil(1.7f64), 2.0f64); + assert_approx_eq!(f64::ceil(0.0f64), 0.0f64); + assert_approx_eq!(f64::ceil(-0.0f64), -0.0f64); + assert_approx_eq!(f64::ceil(-1.0f64), -1.0f64); + assert_approx_eq!(f64::ceil(-1.3f64), -1.0f64); + assert_approx_eq!(f64::ceil(-1.5f64), -1.0f64); + assert_approx_eq!(f64::ceil(-1.7f64), -1.0f64); +} + +#[test] +fn test_round() { + assert_approx_eq!(f64::round(2.5f64), 3.0f64); + assert_approx_eq!(f64::round(1.0f64), 1.0f64); + assert_approx_eq!(f64::round(1.3f64), 1.0f64); + assert_approx_eq!(f64::round(1.5f64), 2.0f64); + assert_approx_eq!(f64::round(1.7f64), 2.0f64); + assert_approx_eq!(f64::round(0.0f64), 0.0f64); + assert_approx_eq!(f64::round(-0.0f64), -0.0f64); + assert_approx_eq!(f64::round(-1.0f64), -1.0f64); + assert_approx_eq!(f64::round(-1.3f64), -1.0f64); + assert_approx_eq!(f64::round(-1.5f64), -2.0f64); + assert_approx_eq!(f64::round(-1.7f64), -2.0f64); +} + +#[test] +fn test_round_ties_even() { + assert_approx_eq!(f64::round_ties_even(2.5f64), 2.0f64); + assert_approx_eq!(f64::round_ties_even(1.0f64), 1.0f64); + assert_approx_eq!(f64::round_ties_even(1.3f64), 1.0f64); + assert_approx_eq!(f64::round_ties_even(1.5f64), 2.0f64); + assert_approx_eq!(f64::round_ties_even(1.7f64), 2.0f64); + assert_approx_eq!(f64::round_ties_even(0.0f64), 0.0f64); + assert_approx_eq!(f64::round_ties_even(-0.0f64), -0.0f64); + assert_approx_eq!(f64::round_ties_even(-1.0f64), -1.0f64); + assert_approx_eq!(f64::round_ties_even(-1.3f64), -1.0f64); + assert_approx_eq!(f64::round_ties_even(-1.5f64), -2.0f64); + assert_approx_eq!(f64::round_ties_even(-1.7f64), -2.0f64); +} + +#[test] +fn test_trunc() { + assert_approx_eq!(f64::trunc(1.0f64), 1.0f64); + assert_approx_eq!(f64::trunc(1.3f64), 1.0f64); + assert_approx_eq!(f64::trunc(1.5f64), 1.0f64); + assert_approx_eq!(f64::trunc(1.7f64), 1.0f64); + assert_approx_eq!(f64::trunc(0.0f64), 0.0f64); + assert_approx_eq!(f64::trunc(-0.0f64), -0.0f64); + assert_approx_eq!(f64::trunc(-1.0f64), -1.0f64); + assert_approx_eq!(f64::trunc(-1.3f64), -1.0f64); + assert_approx_eq!(f64::trunc(-1.5f64), -1.0f64); + assert_approx_eq!(f64::trunc(-1.7f64), -1.0f64); +} + +#[test] +fn test_fract() { + assert_approx_eq!(f64::fract(1.0f64), 0.0f64); + assert_approx_eq!(f64::fract(1.3f64), 0.3f64); + assert_approx_eq!(f64::fract(1.5f64), 0.5f64); + assert_approx_eq!(f64::fract(1.7f64), 0.7f64); + assert_approx_eq!(f64::fract(0.0f64), 0.0f64); + assert_approx_eq!(f64::fract(-0.0f64), -0.0f64); + assert_approx_eq!(f64::fract(-1.0f64), -0.0f64); + assert_approx_eq!(f64::fract(-1.3f64), -0.3f64); + assert_approx_eq!(f64::fract(-1.5f64), -0.5f64); + assert_approx_eq!(f64::fract(-1.7f64), -0.7f64); +} + +#[test] +fn test_abs() { + assert_eq!(f64::INFINITY.abs(), f64::INFINITY); + assert_eq!(1f64.abs(), 1f64); + assert_eq!(0f64.abs(), 0f64); + assert_eq!((-0f64).abs(), 0f64); + assert_eq!((-1f64).abs(), 1f64); + assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY); + assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64); + assert!(f64::NAN.abs().is_nan()); +} + +#[test] +fn test_signum() { + assert_eq!(f64::INFINITY.signum(), 1f64); + assert_eq!(1f64.signum(), 1f64); + assert_eq!(0f64.signum(), 1f64); + assert_eq!((-0f64).signum(), -1f64); + assert_eq!((-1f64).signum(), -1f64); + assert_eq!(f64::NEG_INFINITY.signum(), -1f64); + assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64); + assert!(f64::NAN.signum().is_nan()); +} + +#[test] +fn test_is_sign_positive() { + assert!(f64::INFINITY.is_sign_positive()); + assert!(1f64.is_sign_positive()); + assert!(0f64.is_sign_positive()); + assert!(!(-0f64).is_sign_positive()); + assert!(!(-1f64).is_sign_positive()); + assert!(!f64::NEG_INFINITY.is_sign_positive()); + assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive()); + assert!(f64::NAN.is_sign_positive()); + assert!(!(-f64::NAN).is_sign_positive()); +} + +#[test] +fn test_is_sign_negative() { + assert!(!f64::INFINITY.is_sign_negative()); + assert!(!1f64.is_sign_negative()); + assert!(!0f64.is_sign_negative()); + assert!((-0f64).is_sign_negative()); + assert!((-1f64).is_sign_negative()); + assert!(f64::NEG_INFINITY.is_sign_negative()); + assert!((1f64 / f64::NEG_INFINITY).is_sign_negative()); + assert!(!f64::NAN.is_sign_negative()); + assert!((-f64::NAN).is_sign_negative()); +} + +#[test] +fn test_next_up() { + let tiny = f64::from_bits(TINY_BITS); + let tiny_up = f64::from_bits(TINY_UP_BITS); + let max_down = f64::from_bits(MAX_DOWN_BITS); + let largest_subnormal = f64::from_bits(LARGEST_SUBNORMAL_BITS); + let smallest_normal = f64::from_bits(SMALLEST_NORMAL_BITS); + assert_f64_biteq!(f64::NEG_INFINITY.next_up(), f64::MIN); + assert_f64_biteq!(f64::MIN.next_up(), -max_down); + assert_f64_biteq!((-1.0 - f64::EPSILON).next_up(), -1.0); + assert_f64_biteq!((-smallest_normal).next_up(), -largest_subnormal); + assert_f64_biteq!((-tiny_up).next_up(), -tiny); + assert_f64_biteq!((-tiny).next_up(), -0.0f64); + assert_f64_biteq!((-0.0f64).next_up(), tiny); + assert_f64_biteq!(0.0f64.next_up(), tiny); + assert_f64_biteq!(tiny.next_up(), tiny_up); + assert_f64_biteq!(largest_subnormal.next_up(), smallest_normal); + assert_f64_biteq!(1.0f64.next_up(), 1.0 + f64::EPSILON); + assert_f64_biteq!(f64::MAX.next_up(), f64::INFINITY); + assert_f64_biteq!(f64::INFINITY.next_up(), f64::INFINITY); + + let nan0 = f64::NAN; + let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1); + let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2); + assert_f64_biteq!(nan0.next_up(), nan0); + assert_f64_biteq!(nan1.next_up(), nan1); + assert_f64_biteq!(nan2.next_up(), nan2); +} + +#[test] +fn test_next_down() { + let tiny = f64::from_bits(TINY_BITS); + let tiny_up = f64::from_bits(TINY_UP_BITS); + let max_down = f64::from_bits(MAX_DOWN_BITS); + let largest_subnormal = f64::from_bits(LARGEST_SUBNORMAL_BITS); + let smallest_normal = f64::from_bits(SMALLEST_NORMAL_BITS); + assert_f64_biteq!(f64::NEG_INFINITY.next_down(), f64::NEG_INFINITY); + assert_f64_biteq!(f64::MIN.next_down(), f64::NEG_INFINITY); + assert_f64_biteq!((-max_down).next_down(), f64::MIN); + assert_f64_biteq!((-1.0f64).next_down(), -1.0 - f64::EPSILON); + assert_f64_biteq!((-largest_subnormal).next_down(), -smallest_normal); + assert_f64_biteq!((-tiny).next_down(), -tiny_up); + assert_f64_biteq!((-0.0f64).next_down(), -tiny); + assert_f64_biteq!((0.0f64).next_down(), -tiny); + assert_f64_biteq!(tiny.next_down(), 0.0f64); + assert_f64_biteq!(tiny_up.next_down(), tiny); + assert_f64_biteq!(smallest_normal.next_down(), largest_subnormal); + assert_f64_biteq!((1.0 + f64::EPSILON).next_down(), 1.0f64); + assert_f64_biteq!(f64::MAX.next_down(), max_down); + assert_f64_biteq!(f64::INFINITY.next_down(), f64::MAX); + + let nan0 = f64::NAN; + let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1); + let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2); + assert_f64_biteq!(nan0.next_down(), nan0); + assert_f64_biteq!(nan1.next_down(), nan1); + assert_f64_biteq!(nan2.next_down(), nan2); +} + +// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ +#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] +#[test] +fn test_mul_add() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); + assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); + assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); + assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f64.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); +} + +#[test] +fn test_recip() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(1.0f64.recip(), 1.0); + assert_eq!(2.0f64.recip(), 0.5); + assert_eq!((-0.4f64).recip(), -2.5); + assert_eq!(0.0f64.recip(), inf); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); +} + +#[test] +fn test_powi() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(1.0f64.powi(1), 1.0); + assert_approx_eq!((-3.1f64).powi(2), 9.61); + assert_approx_eq!(5.9f64.powi(-2), 0.028727); + assert_eq!(8.3f64.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +fn test_sqrt_domain() { + assert!(f64::NAN.sqrt().is_nan()); + assert!(f64::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f64).sqrt().is_nan()); + assert_eq!((-0.0f64).sqrt(), -0.0); + assert_eq!(0.0f64.sqrt(), 0.0); + assert_eq!(1.0f64.sqrt(), 1.0); + assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); +} + +#[test] +fn test_to_degrees() { + let pi: f64 = consts::PI; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(0.0f64.to_degrees(), 0.0); + assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); + assert_eq!(pi.to_degrees(), 180.0); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); +} + +#[test] +fn test_to_radians() { + let pi: f64 = consts::PI; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(0.0f64.to_radians(), 0.0); + assert_approx_eq!(154.6f64.to_radians(), 2.698279); + assert_approx_eq!((-332.31f64).to_radians(), -5.799903); + assert_eq!(180.0f64.to_radians(), pi); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); +} + +#[test] +fn test_float_bits_conv() { + assert_eq!((1f64).to_bits(), 0x3ff0000000000000); + assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + assert_eq!((1337f64).to_bits(), 0x4094e40000000000); + assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); + assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); + assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); + assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); + assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signaling-ness + let masked_nan1 = f64::NAN.to_bits() ^ NAN_MASK1; + let masked_nan2 = f64::NAN.to_bits() ^ NAN_MASK2; + assert!(f64::from_bits(masked_nan1).is_nan()); + assert!(f64::from_bits(masked_nan2).is_nan()); + + assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1); + assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2); +} + +#[test] +#[should_panic] +fn test_clamp_min_greater_than_max() { + let _ = 1.0f64.clamp(3.0, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_min_is_nan() { + let _ = 1.0f64.clamp(f64::NAN, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_max_is_nan() { + let _ = 1.0f64.clamp(3.0, f64::NAN); +} + +#[test] +fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u64 { + 1 << (f64::MANTISSA_DIGITS - 2) + } + + fn min_subnorm() -> f64 { + f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0) + } + + fn max_subnorm() -> f64 { + f64::MIN_POSITIVE - min_subnorm() + } + + fn q_nan() -> f64 { + f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f64 { + f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0)); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0)); + assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5)); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0)); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); +} + +#[test] +fn test_algebraic() { + let a: f64 = 123.0; + let b: f64 = 456.0; + + // Check that individual operations match their primitive counterparts. + // + // This is a check of current implementations and does NOT imply any form of + // guarantee about future behavior. The compiler reserves the right to make + // these operations inexact matches in the future. + let eps = if cfg!(miri) { 1e-6 } else { 0.0 }; + + assert_approx_eq!(a.algebraic_add(b), a + b, eps); + assert_approx_eq!(a.algebraic_sub(b), a - b, eps); + assert_approx_eq!(a.algebraic_mul(b), a * b, eps); + assert_approx_eq!(a.algebraic_div(b), a / b, eps); + assert_approx_eq!(a.algebraic_rem(b), a % b, eps); +} diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs new file mode 100644 index 00000000000..7de34271ad0 --- /dev/null +++ b/library/coretests/tests/floats/mod.rs @@ -0,0 +1,40 @@ +use std::fmt; +use std::ops::{Add, Div, Mul, Rem, Sub}; + +/// Verify that floats are within a tolerance of each other, 1.0e-6 by default. +macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; + ($a:expr, $b:expr, $lim:expr) => {{ + let (a, b) = (&$a, &$b); + let diff = (*a - *b).abs(); + assert!( + diff <= $lim, + "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})", + lim = $lim + ); + }}; +} + +/// Helper function for testing numeric operations +pub fn test_num<T>(ten: T, two: T) +where + T: PartialEq + + Add<Output = T> + + Sub<Output = T> + + Mul<Output = T> + + Div<Output = T> + + Rem<Output = T> + + fmt::Debug + + Copy, +{ + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); + assert_eq!(ten.rem(two), ten % two); +} + +mod f128; +mod f16; +mod f32; +mod f64; diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0575375cf4f..b98e52718f6 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -12,10 +12,12 @@ #![feature(async_iterator)] #![feature(bigint_helper_methods)] #![feature(bstr)] +#![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(const_eval_select)] #![feature(const_trait_impl)] +#![feature(core_float_math)] #![feature(core_intrinsics)] #![feature(core_intrinsics_fallbacks)] #![feature(core_io_borrowed_buf)] @@ -29,6 +31,10 @@ #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(extern_types)] +#![feature(f128)] +#![feature(f16)] +#![feature(float_algebraic)] +#![feature(float_gamma)] #![feature(float_minimum_maximum)] #![feature(flt2dec)] #![feature(fmt_internals)] @@ -144,6 +150,7 @@ mod cmp; mod const_ptr; mod convert; mod ffi; +mod floats; mod fmt; mod future; mod hash; diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index 0add9a01e68..a6b75f70266 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -732,157 +732,157 @@ assume_usize_width! { } macro_rules! test_float { - ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => { + ($modname: ident, $fassert: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => { mod $modname { #[test] fn min() { - assert_eq!((0.0 as $fty).min(0.0), 0.0); - assert!((0.0 as $fty).min(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).min(-0.0), -0.0); - assert!((-0.0 as $fty).min(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).min(9.0), 9.0); - assert_eq!((-9.0 as $fty).min(0.0), -9.0); - assert_eq!((0.0 as $fty).min(9.0), 0.0); - assert!((0.0 as $fty).min(9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).min(9.0), -0.0); - assert!((-0.0 as $fty).min(9.0).is_sign_negative()); - assert_eq!((-0.0 as $fty).min(-9.0), -9.0); - assert_eq!(($inf as $fty).min(9.0), 9.0); - assert_eq!((9.0 as $fty).min($inf), 9.0); - assert_eq!(($inf as $fty).min(-9.0), -9.0); - assert_eq!((-9.0 as $fty).min($inf), -9.0); - assert_eq!(($neginf as $fty).min(9.0), $neginf); - assert_eq!((9.0 as $fty).min($neginf), $neginf); - assert_eq!(($neginf as $fty).min(-9.0), $neginf); - assert_eq!((-9.0 as $fty).min($neginf), $neginf); - assert_eq!(($nan as $fty).min(9.0), 9.0); - assert_eq!(($nan as $fty).min(-9.0), -9.0); - assert_eq!((9.0 as $fty).min($nan), 9.0); - assert_eq!((-9.0 as $fty).min($nan), -9.0); - assert!(($nan as $fty).min($nan).is_nan()); + $fassert!((0.0 as $fty).min(0.0), 0.0); + $fassert!((0.0 as $fty).min(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).min(-0.0), -0.0); + $fassert!((-0.0 as $fty).min(-0.0).is_sign_negative()); + $fassert!((9.0 as $fty).min(9.0), 9.0); + $fassert!((-9.0 as $fty).min(0.0), -9.0); + $fassert!((0.0 as $fty).min(9.0), 0.0); + $fassert!((0.0 as $fty).min(9.0).is_sign_positive()); + $fassert!((-0.0 as $fty).min(9.0), -0.0); + $fassert!((-0.0 as $fty).min(9.0).is_sign_negative()); + $fassert!((-0.0 as $fty).min(-9.0), -9.0); + $fassert!(($inf as $fty).min(9.0), 9.0); + $fassert!((9.0 as $fty).min($inf), 9.0); + $fassert!(($inf as $fty).min(-9.0), -9.0); + $fassert!((-9.0 as $fty).min($inf), -9.0); + $fassert!(($neginf as $fty).min(9.0), $neginf); + $fassert!((9.0 as $fty).min($neginf), $neginf); + $fassert!(($neginf as $fty).min(-9.0), $neginf); + $fassert!((-9.0 as $fty).min($neginf), $neginf); + $fassert!(($nan as $fty).min(9.0), 9.0); + $fassert!(($nan as $fty).min(-9.0), -9.0); + $fassert!((9.0 as $fty).min($nan), 9.0); + $fassert!((-9.0 as $fty).min($nan), -9.0); + $fassert!(($nan as $fty).min($nan).is_nan()); } #[test] fn max() { - assert_eq!((0.0 as $fty).max(0.0), 0.0); - assert!((0.0 as $fty).max(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).max(-0.0), -0.0); - assert!((-0.0 as $fty).max(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).max(9.0), 9.0); - assert_eq!((-9.0 as $fty).max(0.0), 0.0); - assert!((-9.0 as $fty).max(0.0).is_sign_positive()); - assert_eq!((-9.0 as $fty).max(-0.0), -0.0); - assert!((-9.0 as $fty).max(-0.0).is_sign_negative()); - assert_eq!((0.0 as $fty).max(9.0), 9.0); - assert_eq!((0.0 as $fty).max(-9.0), 0.0); - assert!((0.0 as $fty).max(-9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).max(-9.0), -0.0); - assert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - assert_eq!(($inf as $fty).max(9.0), $inf); - assert_eq!((9.0 as $fty).max($inf), $inf); - assert_eq!(($inf as $fty).max(-9.0), $inf); - assert_eq!((-9.0 as $fty).max($inf), $inf); - assert_eq!(($neginf as $fty).max(9.0), 9.0); - assert_eq!((9.0 as $fty).max($neginf), 9.0); - assert_eq!(($neginf as $fty).max(-9.0), -9.0); - assert_eq!((-9.0 as $fty).max($neginf), -9.0); - assert_eq!(($nan as $fty).max(9.0), 9.0); - assert_eq!(($nan as $fty).max(-9.0), -9.0); - assert_eq!((9.0 as $fty).max($nan), 9.0); - assert_eq!((-9.0 as $fty).max($nan), -9.0); - assert!(($nan as $fty).max($nan).is_nan()); + $fassert!((0.0 as $fty).max(0.0), 0.0); + $fassert!((0.0 as $fty).max(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).max(-0.0), -0.0); + $fassert!((-0.0 as $fty).max(-0.0).is_sign_negative()); + $fassert!((9.0 as $fty).max(9.0), 9.0); + $fassert!((-9.0 as $fty).max(0.0), 0.0); + $fassert!((-9.0 as $fty).max(0.0).is_sign_positive()); + $fassert!((-9.0 as $fty).max(-0.0), -0.0); + $fassert!((-9.0 as $fty).max(-0.0).is_sign_negative()); + $fassert!((0.0 as $fty).max(9.0), 9.0); + $fassert!((0.0 as $fty).max(-9.0), 0.0); + $fassert!((0.0 as $fty).max(-9.0).is_sign_positive()); + $fassert!((-0.0 as $fty).max(-9.0), -0.0); + $fassert!((-0.0 as $fty).max(-9.0).is_sign_negative()); + $fassert!(($inf as $fty).max(9.0), $inf); + $fassert!((9.0 as $fty).max($inf), $inf); + $fassert!(($inf as $fty).max(-9.0), $inf); + $fassert!((-9.0 as $fty).max($inf), $inf); + $fassert!(($neginf as $fty).max(9.0), 9.0); + $fassert!((9.0 as $fty).max($neginf), 9.0); + $fassert!(($neginf as $fty).max(-9.0), -9.0); + $fassert!((-9.0 as $fty).max($neginf), -9.0); + $fassert!(($nan as $fty).max(9.0), 9.0); + $fassert!(($nan as $fty).max(-9.0), -9.0); + $fassert!((9.0 as $fty).max($nan), 9.0); + $fassert!((-9.0 as $fty).max($nan), -9.0); + $fassert!(($nan as $fty).max($nan).is_nan()); } #[test] fn minimum() { - assert_eq!((0.0 as $fty).minimum(0.0), 0.0); - assert!((0.0 as $fty).minimum(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).minimum(0.0), -0.0); - assert!((-0.0 as $fty).minimum(0.0).is_sign_negative()); - assert_eq!((-0.0 as $fty).minimum(-0.0), -0.0); - assert!((-0.0 as $fty).minimum(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).minimum(9.0), 9.0); - assert_eq!((-9.0 as $fty).minimum(0.0), -9.0); - assert_eq!((0.0 as $fty).minimum(9.0), 0.0); - assert!((0.0 as $fty).minimum(9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).minimum(9.0), -0.0); - assert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); - assert_eq!((-0.0 as $fty).minimum(-9.0), -9.0); - assert_eq!(($inf as $fty).minimum(9.0), 9.0); - assert_eq!((9.0 as $fty).minimum($inf), 9.0); - assert_eq!(($inf as $fty).minimum(-9.0), -9.0); - assert_eq!((-9.0 as $fty).minimum($inf), -9.0); - assert_eq!(($neginf as $fty).minimum(9.0), $neginf); - assert_eq!((9.0 as $fty).minimum($neginf), $neginf); - assert_eq!(($neginf as $fty).minimum(-9.0), $neginf); - assert_eq!((-9.0 as $fty).minimum($neginf), $neginf); - assert!(($nan as $fty).minimum(9.0).is_nan()); - assert!(($nan as $fty).minimum(-9.0).is_nan()); - assert!((9.0 as $fty).minimum($nan).is_nan()); - assert!((-9.0 as $fty).minimum($nan).is_nan()); - assert!(($nan as $fty).minimum($nan).is_nan()); + $fassert!((0.0 as $fty).minimum(0.0), 0.0); + $fassert!((0.0 as $fty).minimum(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).minimum(0.0), -0.0); + $fassert!((-0.0 as $fty).minimum(0.0).is_sign_negative()); + $fassert!((-0.0 as $fty).minimum(-0.0), -0.0); + $fassert!((-0.0 as $fty).minimum(-0.0).is_sign_negative()); + $fassert!((9.0 as $fty).minimum(9.0), 9.0); + $fassert!((-9.0 as $fty).minimum(0.0), -9.0); + $fassert!((0.0 as $fty).minimum(9.0), 0.0); + $fassert!((0.0 as $fty).minimum(9.0).is_sign_positive()); + $fassert!((-0.0 as $fty).minimum(9.0), -0.0); + $fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); + $fassert!((-0.0 as $fty).minimum(-9.0), -9.0); + $fassert!(($inf as $fty).minimum(9.0), 9.0); + $fassert!((9.0 as $fty).minimum($inf), 9.0); + $fassert!(($inf as $fty).minimum(-9.0), -9.0); + $fassert!((-9.0 as $fty).minimum($inf), -9.0); + $fassert!(($neginf as $fty).minimum(9.0), $neginf); + $fassert!((9.0 as $fty).minimum($neginf), $neginf); + $fassert!(($neginf as $fty).minimum(-9.0), $neginf); + $fassert!((-9.0 as $fty).minimum($neginf), $neginf); + $fassert!(($nan as $fty).minimum(9.0).is_nan()); + $fassert!(($nan as $fty).minimum(-9.0).is_nan()); + $fassert!((9.0 as $fty).minimum($nan).is_nan()); + $fassert!((-9.0 as $fty).minimum($nan).is_nan()); + $fassert!(($nan as $fty).minimum($nan).is_nan()); } #[test] fn maximum() { - assert_eq!((0.0 as $fty).maximum(0.0), 0.0); - assert!((0.0 as $fty).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).maximum(0.0), 0.0); - assert!((-0.0 as $fty).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).maximum(-0.0), -0.0); - assert!((-0.0 as $fty).maximum(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).maximum(9.0), 9.0); - assert_eq!((-9.0 as $fty).maximum(0.0), 0.0); - assert!((-9.0 as $fty).maximum(0.0).is_sign_positive()); - assert_eq!((-9.0 as $fty).maximum(-0.0), -0.0); - assert!((-9.0 as $fty).maximum(-0.0).is_sign_negative()); - assert_eq!((0.0 as $fty).maximum(9.0), 9.0); - assert_eq!((0.0 as $fty).maximum(-9.0), 0.0); - assert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).maximum(-9.0), -0.0); - assert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - assert_eq!(($inf as $fty).maximum(9.0), $inf); - assert_eq!((9.0 as $fty).maximum($inf), $inf); - assert_eq!(($inf as $fty).maximum(-9.0), $inf); - assert_eq!((-9.0 as $fty).maximum($inf), $inf); - assert_eq!(($neginf as $fty).maximum(9.0), 9.0); - assert_eq!((9.0 as $fty).maximum($neginf), 9.0); - assert_eq!(($neginf as $fty).maximum(-9.0), -9.0); - assert_eq!((-9.0 as $fty).maximum($neginf), -9.0); - assert!(($nan as $fty).maximum(9.0).is_nan()); - assert!(($nan as $fty).maximum(-9.0).is_nan()); - assert!((9.0 as $fty).maximum($nan).is_nan()); - assert!((-9.0 as $fty).maximum($nan).is_nan()); - assert!(($nan as $fty).maximum($nan).is_nan()); + $fassert!((0.0 as $fty).maximum(0.0), 0.0); + $fassert!((0.0 as $fty).maximum(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).maximum(0.0), 0.0); + $fassert!((-0.0 as $fty).maximum(0.0).is_sign_positive()); + $fassert!((-0.0 as $fty).maximum(-0.0), -0.0); + $fassert!((-0.0 as $fty).maximum(-0.0).is_sign_negative()); + $fassert!((9.0 as $fty).maximum(9.0), 9.0); + $fassert!((-9.0 as $fty).maximum(0.0), 0.0); + $fassert!((-9.0 as $fty).maximum(0.0).is_sign_positive()); + $fassert!((-9.0 as $fty).maximum(-0.0), -0.0); + $fassert!((-9.0 as $fty).maximum(-0.0).is_sign_negative()); + $fassert!((0.0 as $fty).maximum(9.0), 9.0); + $fassert!((0.0 as $fty).maximum(-9.0), 0.0); + $fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); + $fassert!((-0.0 as $fty).maximum(-9.0), -0.0); + $fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); + $fassert!(($inf as $fty).maximum(9.0), $inf); + $fassert!((9.0 as $fty).maximum($inf), $inf); + $fassert!(($inf as $fty).maximum(-9.0), $inf); + $fassert!((-9.0 as $fty).maximum($inf), $inf); + $fassert!(($neginf as $fty).maximum(9.0), 9.0); + $fassert!((9.0 as $fty).maximum($neginf), 9.0); + $fassert!(($neginf as $fty).maximum(-9.0), -9.0); + $fassert!((-9.0 as $fty).maximum($neginf), -9.0); + $fassert!(($nan as $fty).maximum(9.0).is_nan()); + $fassert!(($nan as $fty).maximum(-9.0).is_nan()); + $fassert!((9.0 as $fty).maximum($nan).is_nan()); + $fassert!((-9.0 as $fty).maximum($nan).is_nan()); + $fassert!(($nan as $fty).maximum($nan).is_nan()); } #[test] fn midpoint() { - assert_eq!((0.5 as $fty).midpoint(0.5), 0.5); - assert_eq!((0.5 as $fty).midpoint(2.5), 1.5); - assert_eq!((3.0 as $fty).midpoint(4.0), 3.5); - assert_eq!((-3.0 as $fty).midpoint(4.0), 0.5); - assert_eq!((3.0 as $fty).midpoint(-4.0), -0.5); - assert_eq!((-3.0 as $fty).midpoint(-4.0), -3.5); - assert_eq!((0.0 as $fty).midpoint(0.0), 0.0); - assert_eq!((-0.0 as $fty).midpoint(-0.0), -0.0); - assert_eq!((-5.0 as $fty).midpoint(5.0), 0.0); - assert_eq!(($max as $fty).midpoint($min), 0.0); - assert_eq!(($min as $fty).midpoint($max), -0.0); - assert_eq!(($max as $fty).midpoint($min_pos), $max / 2.); - assert_eq!((-$max as $fty).midpoint($min_pos), -$max / 2.); - assert_eq!(($max as $fty).midpoint(-$min_pos), $max / 2.); - assert_eq!((-$max as $fty).midpoint(-$min_pos), -$max / 2.); - assert_eq!(($min_pos as $fty).midpoint($max), $max / 2.); - assert_eq!(($min_pos as $fty).midpoint(-$max), -$max / 2.); - assert_eq!((-$min_pos as $fty).midpoint($max), $max / 2.); - assert_eq!((-$min_pos as $fty).midpoint(-$max), -$max / 2.); - assert_eq!(($max as $fty).midpoint($max), $max); - assert_eq!(($min_pos as $fty).midpoint($min_pos), $min_pos); - assert_eq!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos); - assert_eq!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5); - assert_eq!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5); - assert_eq!(($inf as $fty).midpoint($inf), $inf); - assert_eq!(($neginf as $fty).midpoint($neginf), $neginf); - assert!(($nan as $fty).midpoint(1.0).is_nan()); - assert!((1.0 as $fty).midpoint($nan).is_nan()); - assert!(($nan as $fty).midpoint($nan).is_nan()); + $fassert!((0.5 as $fty).midpoint(0.5), 0.5); + $fassert!((0.5 as $fty).midpoint(2.5), 1.5); + $fassert!((3.0 as $fty).midpoint(4.0), 3.5); + $fassert!((-3.0 as $fty).midpoint(4.0), 0.5); + $fassert!((3.0 as $fty).midpoint(-4.0), -0.5); + $fassert!((-3.0 as $fty).midpoint(-4.0), -3.5); + $fassert!((0.0 as $fty).midpoint(0.0), 0.0); + $fassert!((-0.0 as $fty).midpoint(-0.0), -0.0); + $fassert!((-5.0 as $fty).midpoint(5.0), 0.0); + $fassert!(($max as $fty).midpoint($min), 0.0); + $fassert!(($min as $fty).midpoint($max), -0.0); + $fassert!(($max as $fty).midpoint($min_pos), $max / 2.); + $fassert!((-$max as $fty).midpoint($min_pos), -$max / 2.); + $fassert!(($max as $fty).midpoint(-$min_pos), $max / 2.); + $fassert!((-$max as $fty).midpoint(-$min_pos), -$max / 2.); + $fassert!(($min_pos as $fty).midpoint($max), $max / 2.); + $fassert!(($min_pos as $fty).midpoint(-$max), -$max / 2.); + $fassert!((-$min_pos as $fty).midpoint($max), $max / 2.); + $fassert!((-$min_pos as $fty).midpoint(-$max), -$max / 2.); + $fassert!(($max as $fty).midpoint($max), $max); + $fassert!(($min_pos as $fty).midpoint($min_pos), $min_pos); + $fassert!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos); + $fassert!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5); + $fassert!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5); + $fassert!(($inf as $fty).midpoint($inf), $inf); + $fassert!(($neginf as $fty).midpoint($neginf), $neginf); + $fassert!(($nan as $fty).midpoint(1.0).is_nan()); + $fassert!((1.0 as $fty).midpoint($nan).is_nan()); + $fassert!(($nan as $fty).midpoint($nan).is_nan()); // test if large differences in magnitude are still correctly computed. // NOTE: that because of how small x and y are, x + y can never overflow @@ -907,19 +907,19 @@ macro_rules! test_float { } #[test] fn rem_euclid() { - let a: $fty = 42.0; - assert!($inf.rem_euclid(a).is_nan()); - assert_eq!(a.rem_euclid($inf), a); - assert!(a.rem_euclid($nan).is_nan()); + // FIXME: Use $fassert when rem_euclid becomes const + assert!($inf.rem_euclid((42.0 as $fty)).is_nan()); + assert_eq!((42.0 as $fty).rem_euclid($inf), (42.0 as $fty)); + assert!((42.0 as $fty).rem_euclid($nan).is_nan()); assert!($inf.rem_euclid($inf).is_nan()); assert!($inf.rem_euclid($nan).is_nan()); assert!($nan.rem_euclid($inf).is_nan()); } #[test] fn div_euclid() { - let a: $fty = 42.0; - assert_eq!(a.div_euclid($inf), 0.0); - assert!(a.div_euclid($nan).is_nan()); + // FIXME: Use $fassert when div_euclid becomes const + assert_eq!((42.0 as $fty).div_euclid($inf), 0.0); + assert!((42.0 as $fty).div_euclid($nan).is_nan()); assert!($inf.div_euclid($inf).is_nan()); assert!($inf.div_euclid($nan).is_nan()); assert!($nan.div_euclid($inf).is_nan()); @@ -928,8 +928,41 @@ macro_rules! test_float { }; } +// Custom assert macro that distribute between assert! and assert_eq! in a non-const context +macro_rules! float_assert { + ($b:expr) => { + assert!($b); + }; + ($left:expr, $right:expr) => { + assert_eq!($left, $right); + }; +} + +// Custom assert macro that only uses assert! in a const context +macro_rules! float_const_assert { + ($b:expr) => { + assert!(const { $b }); + }; + ($left:expr, $right:expr) => { + assert!(const { $left == $right }); + }; +} + test_float!( f32, + float_assert, + f32, + f32::INFINITY, + f32::NEG_INFINITY, + f32::NAN, + f32::MIN, + f32::MAX, + f32::MIN_POSITIVE, + f32::MAX_EXP +); +test_float!( + f32_const, + float_const_assert, f32, f32::INFINITY, f32::NEG_INFINITY, @@ -941,6 +974,19 @@ test_float!( ); test_float!( f64, + float_assert, + f64, + f64::INFINITY, + f64::NEG_INFINITY, + f64::NAN, + f64::MIN, + f64::MAX, + f64::MIN_POSITIVE, + f64::MAX_EXP +); +test_float!( + f64_const, + float_const_assert, f64, f64::INFINITY, f64::NEG_INFINITY, diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index 6f43ac4809a..d7d169671f0 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -12,10 +12,11 @@ bench = false doc = false [dependencies] -alloc = { path = "../alloc" } -cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } core = { path = "../core" } compiler_builtins = "0.1.0" -[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] +[target.'cfg(target_os = "android")'.dependencies] libc = { version = "0.2", default-features = false } + +[target.'cfg(any(target_os = "android", target_os = "zkvm"))'.dependencies] +alloc = { path = "../alloc" } diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index b2ad0f4ac3d..d1706b65252 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -7,15 +7,11 @@ #![unstable(feature = "panic_abort", issue = "32837")] #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![panic_runtime] -#![allow(unused_features)] -#![feature(asm_experimental_arch)] -#![feature(core_intrinsics)] #![feature(panic_runtime)] #![feature(std_internals)] #![feature(staged_api)] #![feature(rustc_attrs)] #![allow(internal_features)] -#![deny(unsafe_op_in_unsafe_fn)] #[cfg(target_os = "android")] mod android; @@ -45,75 +41,13 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { zkvm::zkvm_set_abort_message(_payload); } - unsafe { - abort(); + unsafe extern "Rust" { + // This is defined in std::rt. + #[rustc_std_internal_symbol] + safe fn __rust_abort() -> !; } - cfg_if::cfg_if! { - if #[cfg(any(unix, target_os = "solid_asp3"))] { - unsafe fn abort() -> ! { - unsafe { libc::abort(); } - } - } else if #[cfg(any(target_os = "hermit", - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "xous", - target_os = "uefi", - ))] { - unsafe fn abort() -> ! { - // call std::sys::abort_internal - unsafe extern "C" { - pub fn __rust_abort() -> !; - } - unsafe { __rust_abort(); } - } - } else if #[cfg(all(windows, not(miri)))] { - // On Windows, use the processor-specific __fastfail mechanism. In Windows 8 - // and later, this will terminate the process immediately without running any - // in-process exception handlers. In earlier versions of Windows, this - // sequence of instructions will be treated as an access violation, - // terminating the process but without necessarily bypassing all exception - // handlers. - // - // https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail - // - // Note: this is the same implementation as in std's `abort_internal` - unsafe fn abort() -> ! { - #[allow(unused)] - const FAST_FAIL_FATAL_APP_EXIT: usize = 7; - cfg_if::cfg_if! { - if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - unsafe { - core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); - } - } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { - unsafe { - core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); - } - } else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { - unsafe { - core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); - } - } else { - core::intrinsics::abort(); - } - } - } - } else if #[cfg(target_os = "teeos")] { - mod teeos { - unsafe extern "C" { - pub fn TEE_Panic(code: u32) -> !; - } - } - - unsafe fn abort() -> ! { - unsafe { teeos::TEE_Panic(1); } - } - } else { - unsafe fn abort() -> ! { - core::intrinsics::abort(); - } - } - } + __rust_abort() } // This... is a bit of an oddity. The tl;dr; is that this is required to link diff --git a/library/panic_unwind/src/hermit.rs b/library/panic_unwind/src/hermit.rs index 8f4562d07fc..b36d1a019fd 100644 --- a/library/panic_unwind/src/hermit.rs +++ b/library/panic_unwind/src/hermit.rs @@ -5,20 +5,16 @@ use alloc::boxed::Box; use core::any::Any; +unsafe extern "Rust" { + // This is defined in std::rt + #[rustc_std_internal_symbol] + safe fn __rust_abort() -> !; +} + pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> { - unsafe extern "C" { - fn __rust_abort() -> !; - } - unsafe { - __rust_abort(); - } + __rust_abort() } pub(crate) unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 { - unsafe extern "C" { - fn __rust_abort() -> !; - } - unsafe { - __rust_abort(); - } + __rust_abort() } diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index 6b2ba2e714c..bb4acde4822 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -14,365 +14,6 @@ use crate::sys::cmath; #[cfg(not(test))] impl f128 { - /// Returns the largest integer less than or equal to `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.7_f128; - /// let g = 3.0_f128; - /// let h = -3.7_f128; - /// - /// assert_eq!(f.floor(), 3.0); - /// assert_eq!(g.floor(), 3.0); - /// assert_eq!(h.floor(), -4.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn floor(self) -> f128 { - unsafe { intrinsics::floorf128(self) } - } - - /// Returns the smallest integer greater than or equal to `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.01_f128; - /// let g = 4.0_f128; - /// - /// assert_eq!(f.ceil(), 4.0); - /// assert_eq!(g.ceil(), 4.0); - /// # } - /// ``` - #[inline] - #[doc(alias = "ceiling")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn ceil(self) -> f128 { - unsafe { intrinsics::ceilf128(self) } - } - - /// Returns the nearest integer to `self`. If a value is half-way between two - /// integers, round away from `0.0`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.3_f128; - /// let g = -3.3_f128; - /// let h = -3.7_f128; - /// let i = 3.5_f128; - /// let j = 4.5_f128; - /// - /// assert_eq!(f.round(), 3.0); - /// assert_eq!(g.round(), -3.0); - /// assert_eq!(h.round(), -4.0); - /// assert_eq!(i.round(), 4.0); - /// assert_eq!(j.round(), 5.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round(self) -> f128 { - unsafe { intrinsics::roundf128(self) } - } - - /// Returns the nearest integer to a number. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.3_f128; - /// let g = -3.3_f128; - /// let h = 3.5_f128; - /// let i = 4.5_f128; - /// - /// assert_eq!(f.round_ties_even(), 3.0); - /// assert_eq!(g.round_ties_even(), -3.0); - /// assert_eq!(h.round_ties_even(), 4.0); - /// assert_eq!(i.round_ties_even(), 4.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round_ties_even(self) -> f128 { - intrinsics::round_ties_even_f128(self) - } - - /// Returns the integer part of `self`. - /// This means that non-integer numbers are always truncated towards zero. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let f = 3.7_f128; - /// let g = 3.0_f128; - /// let h = -3.7_f128; - /// - /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), 3.0); - /// assert_eq!(h.trunc(), -3.0); - /// # } - /// ``` - #[inline] - #[doc(alias = "truncate")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn trunc(self) -> f128 { - unsafe { intrinsics::truncf128(self) } - } - - /// Returns the fractional part of `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let x = 3.6_f128; - /// let y = -3.6_f128; - /// let abs_difference_x = (x.fract() - 0.6).abs(); - /// let abs_difference_y = (y.fract() - (-0.6)).abs(); - /// - /// assert!(abs_difference_x <= f128::EPSILON); - /// assert!(abs_difference_y <= f128::EPSILON); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn fract(self) -> f128 { - self - self.trunc() - } - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error, yielding a more accurate result than an unfused multiply-add. - /// - /// Using `mul_add` *may* be more performant than an unfused multiply-add if - /// the target architecture has a dedicated `fma` CPU instruction. However, - /// this is not always true, and will be heavily dependant on designing - /// algorithms with specific target hardware in mind. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. It is specified by IEEE 754 as - /// `fusedMultiplyAdd` and guaranteed not to change. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let m = 10.0_f128; - /// let x = 4.0_f128; - /// let b = 60.0_f128; - /// - /// assert_eq!(m.mul_add(x, b), 100.0); - /// assert_eq!(m * x + b, 100.0); - /// - /// let one_plus_eps = 1.0_f128 + f128::EPSILON; - /// let one_minus_eps = 1.0_f128 - f128::EPSILON; - /// let minus_one = -1.0_f128; - /// - /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. - /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f128::EPSILON * f128::EPSILON); - /// // Different rounding with the non-fused multiply and add. - /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(self, a: f128, b: f128) -> f128 { - unsafe { intrinsics::fmaf128(self, a, b) } - } - - /// Calculates Euclidean division, the matching method for `rem_euclid`. - /// - /// This computes the integer `n` such that - /// `self = n * rhs + self.rem_euclid(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer `n` - /// such that `self >= n * rhs`. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let a: f128 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 - /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 - /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 - /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn div_euclid(self, rhs: f128) -> f128 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q - } - - /// Calculates the least nonnegative remainder of `self (mod rhs)`. - /// - /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in - /// most cases. However, due to a floating point round-off error it can - /// result in `r == rhs.abs()`, violating the mathematical definition, if - /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. - /// This result is not an element of the function's codomain, but it is the - /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` - /// approximately. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let a: f128 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.rem_euclid(b), 3.0); - /// assert_eq!((-a).rem_euclid(b), 1.0); - /// assert_eq!(a.rem_euclid(-b), 3.0); - /// assert_eq!((-a).rem_euclid(-b), 1.0); - /// // limitation due to round-off error - /// assert!((-f128::EPSILON).rem_euclid(3.0) != 0.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[doc(alias = "modulo", alias = "mod")] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn rem_euclid(self, rhs: f128) -> f128 { - let r = self % rhs; - if r < 0.0 { r + rhs.abs() } else { r } - } - - /// Raises a number to an integer power. - /// - /// Using this function is generally faster than using `powf`. - /// It might have a different sequence of rounding operations than `powf`, - /// so the results are not guaranteed to agree. - /// - /// # Unspecified precision - /// - /// The precision of this function is non-deterministic. This means it varies by platform, - /// Rust version, and can even differ within the same execution from one invocation to the next. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let x = 2.0_f128; - /// let abs_difference = (x.powi(2) - (x * x)).abs(); - /// assert!(abs_difference <= f128::EPSILON); - /// - /// assert_eq!(f128::powi(f128::NAN, 0), 1.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn powi(self, n: i32) -> f128 { - unsafe { intrinsics::powif128(self, n) } - } - /// Raises a number to a floating point power. /// /// # Unspecified precision @@ -405,43 +46,6 @@ impl f128 { unsafe { intrinsics::powf128(self, n) } } - /// Returns the square root of a number. - /// - /// Returns NaN if `self` is a negative number other than `-0.0`. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` - /// and guaranteed not to change. - /// - /// # Examples - /// - /// ``` - /// #![feature(f128)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f128_math)] { - /// - /// let positive = 4.0_f128; - /// let negative = -4.0_f128; - /// let negative_zero = -0.0_f128; - /// - /// assert_eq!(positive.sqrt(), 2.0); - /// assert!(negative.sqrt().is_nan()); - /// assert!(negative_zero.sqrt() == negative_zero); - /// # } - /// ``` - #[inline] - #[doc(alias = "squareRoot")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f128", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn sqrt(self) -> f128 { - unsafe { intrinsics::sqrtf128(self) } - } - /// Returns `e^(self)`, (the exponential function). /// /// # Unspecified precision diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index d6bc1d3118a..4792eac1f9e 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -14,365 +14,6 @@ use crate::sys::cmath; #[cfg(not(test))] impl f16 { - /// Returns the largest integer less than or equal to `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.7_f16; - /// let g = 3.0_f16; - /// let h = -3.7_f16; - /// - /// assert_eq!(f.floor(), 3.0); - /// assert_eq!(g.floor(), 3.0); - /// assert_eq!(h.floor(), -4.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn floor(self) -> f16 { - unsafe { intrinsics::floorf16(self) } - } - - /// Returns the smallest integer greater than or equal to `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.01_f16; - /// let g = 4.0_f16; - /// - /// assert_eq!(f.ceil(), 4.0); - /// assert_eq!(g.ceil(), 4.0); - /// # } - /// ``` - #[inline] - #[doc(alias = "ceiling")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn ceil(self) -> f16 { - unsafe { intrinsics::ceilf16(self) } - } - - /// Returns the nearest integer to `self`. If a value is half-way between two - /// integers, round away from `0.0`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.3_f16; - /// let g = -3.3_f16; - /// let h = -3.7_f16; - /// let i = 3.5_f16; - /// let j = 4.5_f16; - /// - /// assert_eq!(f.round(), 3.0); - /// assert_eq!(g.round(), -3.0); - /// assert_eq!(h.round(), -4.0); - /// assert_eq!(i.round(), 4.0); - /// assert_eq!(j.round(), 5.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round(self) -> f16 { - unsafe { intrinsics::roundf16(self) } - } - - /// Returns the nearest integer to a number. Rounds half-way cases to the number - /// with an even least significant digit. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.3_f16; - /// let g = -3.3_f16; - /// let h = 3.5_f16; - /// let i = 4.5_f16; - /// - /// assert_eq!(f.round_ties_even(), 3.0); - /// assert_eq!(g.round_ties_even(), -3.0); - /// assert_eq!(h.round_ties_even(), 4.0); - /// assert_eq!(i.round_ties_even(), 4.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn round_ties_even(self) -> f16 { - intrinsics::round_ties_even_f16(self) - } - - /// Returns the integer part of `self`. - /// This means that non-integer numbers are always truncated towards zero. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let f = 3.7_f16; - /// let g = 3.0_f16; - /// let h = -3.7_f16; - /// - /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), 3.0); - /// assert_eq!(h.trunc(), -3.0); - /// # } - /// ``` - #[inline] - #[doc(alias = "truncate")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn trunc(self) -> f16 { - unsafe { intrinsics::truncf16(self) } - } - - /// Returns the fractional part of `self`. - /// - /// This function always returns the precise result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let x = 3.6_f16; - /// let y = -3.6_f16; - /// let abs_difference_x = (x.fract() - 0.6).abs(); - /// let abs_difference_y = (y.fract() - (-0.6)).abs(); - /// - /// assert!(abs_difference_x <= f16::EPSILON); - /// assert!(abs_difference_y <= f16::EPSILON); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn fract(self) -> f16 { - self - self.trunc() - } - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error, yielding a more accurate result than an unfused multiply-add. - /// - /// Using `mul_add` *may* be more performant than an unfused multiply-add if - /// the target architecture has a dedicated `fma` CPU instruction. However, - /// this is not always true, and will be heavily dependant on designing - /// algorithms with specific target hardware in mind. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. It is specified by IEEE 754 as - /// `fusedMultiplyAdd` and guaranteed not to change. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let m = 10.0_f16; - /// let x = 4.0_f16; - /// let b = 60.0_f16; - /// - /// assert_eq!(m.mul_add(x, b), 100.0); - /// assert_eq!(m * x + b, 100.0); - /// - /// let one_plus_eps = 1.0_f16 + f16::EPSILON; - /// let one_minus_eps = 1.0_f16 - f16::EPSILON; - /// let minus_one = -1.0_f16; - /// - /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps. - /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f16::EPSILON * f16::EPSILON); - /// // Different rounding with the non-fused multiply and add. - /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn mul_add(self, a: f16, b: f16) -> f16 { - unsafe { intrinsics::fmaf16(self, a, b) } - } - - /// Calculates Euclidean division, the matching method for `rem_euclid`. - /// - /// This computes the integer `n` such that - /// `self = n * rhs + self.rem_euclid(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer `n` - /// such that `self >= n * rhs`. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let a: f16 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 - /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 - /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 - /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn div_euclid(self, rhs: f16) -> f16 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q - } - - /// Calculates the least nonnegative remainder of `self (mod rhs)`. - /// - /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in - /// most cases. However, due to a floating point round-off error it can - /// result in `r == rhs.abs()`, violating the mathematical definition, if - /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. - /// This result is not an element of the function's codomain, but it is the - /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` - /// approximately. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let a: f16 = 7.0; - /// let b = 4.0; - /// assert_eq!(a.rem_euclid(b), 3.0); - /// assert_eq!((-a).rem_euclid(b), 1.0); - /// assert_eq!(a.rem_euclid(-b), 3.0); - /// assert_eq!((-a).rem_euclid(-b), 1.0); - /// // limitation due to round-off error - /// assert!((-f16::EPSILON).rem_euclid(3.0) != 0.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[doc(alias = "modulo", alias = "mod")] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn rem_euclid(self, rhs: f16) -> f16 { - let r = self % rhs; - if r < 0.0 { r + rhs.abs() } else { r } - } - - /// Raises a number to an integer power. - /// - /// Using this function is generally faster than using `powf`. - /// It might have a different sequence of rounding operations than `powf`, - /// so the results are not guaranteed to agree. - /// - /// # Unspecified precision - /// - /// The precision of this function is non-deterministic. This means it varies by platform, - /// Rust version, and can even differ within the same execution from one invocation to the next. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let x = 2.0_f16; - /// let abs_difference = (x.powi(2) - (x * x)).abs(); - /// assert!(abs_difference <= f16::EPSILON); - /// - /// assert_eq!(f16::powi(f16::NAN, 0), 1.0); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn powi(self, n: i32) -> f16 { - unsafe { intrinsics::powif16(self, n) } - } - /// Raises a number to a floating point power. /// /// # Unspecified precision @@ -405,43 +46,6 @@ impl f16 { unsafe { intrinsics::powf16(self, n) } } - /// Returns the square root of a number. - /// - /// Returns NaN if `self` is a negative number other than `-0.0`. - /// - /// # Precision - /// - /// The result of this operation is guaranteed to be the rounded - /// infinite-precision result. It is specified by IEEE 754 as `squareRoot` - /// and guaranteed not to change. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let positive = 4.0_f16; - /// let negative = -4.0_f16; - /// let negative_zero = -0.0_f16; - /// - /// assert_eq!(positive.sqrt(), 2.0); - /// assert!(negative.sqrt().is_nan()); - /// assert!(negative_zero.sqrt() == negative_zero); - /// # } - /// ``` - #[inline] - #[doc(alias = "squareRoot")] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn sqrt(self) -> f16 { - unsafe { intrinsics::sqrtf16(self) } - } - /// Returns `e^(self)`, (the exponential function). /// /// # Unspecified precision @@ -702,41 +306,6 @@ impl f16 { unsafe { intrinsics::log10f16(self) } } - /// Returns the cube root of a number. - /// - /// # Unspecified precision - /// - /// The precision of this function is non-deterministic. This means it varies by platform, - /// Rust version, and can even differ within the same execution from one invocation to the next. - /// - /// This function currently corresponds to the `cbrtf` from libc on Unix - /// and Windows. Note that this might change in the future. - /// - /// # Examples - /// - /// ``` - /// #![feature(f16)] - /// # #![feature(cfg_target_has_reliable_f16_f128)] - /// # #![expect(internal_features)] - /// # #[cfg(not(miri))] - /// # #[cfg(target_has_reliable_f16_math)] { - /// - /// let x = 8.0f16; - /// - /// // x^(1/3) - 2 == 0 - /// let abs_difference = (x.cbrt() - 2.0).abs(); - /// - /// assert!(abs_difference <= f16::EPSILON); - /// # } - /// ``` - #[inline] - #[rustc_allow_incoherent_impl] - #[unstable(feature = "f16", issue = "116909")] - #[must_use = "method returns a new number and does not mutate the original value"] - pub fn cbrt(self) -> f16 { - cmath::cbrtf(self as f32) as f16 - } - /// Compute the distance between the origin and a point (`x`, `y`) on the /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a /// right-angle triangle with other sides having length `x.abs()` and diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index baf7002f380..94140d01d8b 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -46,7 +46,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn floor(self) -> f32 { - unsafe { intrinsics::floorf32(self) } + core::f32::floor(self) } /// Returns the smallest integer greater than or equal to `self`. @@ -68,7 +68,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ceil(self) -> f32 { - unsafe { intrinsics::ceilf32(self) } + core::f32::ceil(self) } /// Returns the nearest integer to `self`. If a value is half-way between two @@ -96,7 +96,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn round(self) -> f32 { - unsafe { intrinsics::roundf32(self) } + core::f32::round(self) } /// Returns the nearest integer to a number. Rounds half-way cases to the number @@ -122,7 +122,7 @@ impl f32 { #[stable(feature = "round_ties_even", since = "1.77.0")] #[inline] pub fn round_ties_even(self) -> f32 { - intrinsics::round_ties_even_f32(self) + core::f32::round_ties_even(self) } /// Returns the integer part of `self`. @@ -147,7 +147,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn trunc(self) -> f32 { - unsafe { intrinsics::truncf32(self) } + core::f32::trunc(self) } /// Returns the fractional part of `self`. @@ -170,7 +170,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn fract(self) -> f32 { - self - self.trunc() + core::f32::fract(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding @@ -212,7 +212,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn mul_add(self, a: f32, b: f32) -> f32 { - unsafe { intrinsics::fmaf32(self, a, b) } + core::f32::mul_add(self, a, b) } /// Calculates Euclidean division, the matching method for `rem_euclid`. @@ -242,11 +242,7 @@ impl f32 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn div_euclid(self, rhs: f32) -> f32 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q + core::f32::div_euclid(self, rhs) } /// Calculates the least nonnegative remainder of `self (mod rhs)`. @@ -283,8 +279,7 @@ impl f32 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn rem_euclid(self, rhs: f32) -> f32 { - let r = self % rhs; - if r < 0.0 { r + rhs.abs() } else { r } + core::f32::rem_euclid(self, rhs) } /// Raises a number to an integer power. @@ -312,7 +307,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powi(self, n: i32) -> f32 { - unsafe { intrinsics::powif32(self, n) } + core::f32::powi(self, n) } /// Raises a number to a floating point power. @@ -367,7 +362,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sqrt(self) -> f32 { - unsafe { intrinsics::sqrtf32(self) } + core::f32::sqrt(self) } /// Returns `e^(self)`, (the exponential function). @@ -599,7 +594,8 @@ impl f32 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f32) -> f32 { - cmath::fdimf(self, other) + #[allow(deprecated)] + core::f32::abs_sub(self, other) } /// Returns the cube root of a number. @@ -626,7 +622,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f32 { - cmath::cbrtf(self) + core::f32::cbrt(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 84fd9bfb7b6..051061ae605 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -46,7 +46,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn floor(self) -> f64 { - unsafe { intrinsics::floorf64(self) } + core::f64::floor(self) } /// Returns the smallest integer greater than or equal to `self`. @@ -68,7 +68,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ceil(self) -> f64 { - unsafe { intrinsics::ceilf64(self) } + core::f64::ceil(self) } /// Returns the nearest integer to `self`. If a value is half-way between two @@ -96,7 +96,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn round(self) -> f64 { - unsafe { intrinsics::roundf64(self) } + core::f64::round(self) } /// Returns the nearest integer to a number. Rounds half-way cases to the number @@ -122,7 +122,7 @@ impl f64 { #[stable(feature = "round_ties_even", since = "1.77.0")] #[inline] pub fn round_ties_even(self) -> f64 { - intrinsics::round_ties_even_f64(self) + core::f64::round_ties_even(self) } /// Returns the integer part of `self`. @@ -147,7 +147,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn trunc(self) -> f64 { - unsafe { intrinsics::truncf64(self) } + core::f64::trunc(self) } /// Returns the fractional part of `self`. @@ -170,7 +170,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn fract(self) -> f64 { - self - self.trunc() + core::f64::fract(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding @@ -212,7 +212,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn mul_add(self, a: f64, b: f64) -> f64 { - unsafe { intrinsics::fmaf64(self, a, b) } + core::f64::mul_add(self, a, b) } /// Calculates Euclidean division, the matching method for `rem_euclid`. @@ -242,11 +242,7 @@ impl f64 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn div_euclid(self, rhs: f64) -> f64 { - let q = (self / rhs).trunc(); - if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; - } - q + core::f64::div_euclid(self, rhs) } /// Calculates the least nonnegative remainder of `self (mod rhs)`. @@ -283,8 +279,7 @@ impl f64 { #[inline] #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn rem_euclid(self, rhs: f64) -> f64 { - let r = self % rhs; - if r < 0.0 { r + rhs.abs() } else { r } + core::f64::rem_euclid(self, rhs) } /// Raises a number to an integer power. @@ -312,7 +307,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powi(self, n: i32) -> f64 { - unsafe { intrinsics::powif64(self, n) } + core::f64::powi(self, n) } /// Raises a number to a floating point power. @@ -367,7 +362,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sqrt(self) -> f64 { - unsafe { intrinsics::sqrtf64(self) } + core::f64::sqrt(self) } /// Returns `e^(self)`, (the exponential function). @@ -599,7 +594,8 @@ impl f64 { filing an issue describing your use-case too)." )] pub fn abs_sub(self, other: f64) -> f64 { - cmath::fdim(self, other) + #[allow(deprecated)] + core::f64::abs_sub(self, other) } /// Returns the cube root of a number. @@ -626,7 +622,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cbrt(self) -> f64 { - cmath::cbrt(self) + core::f64::cbrt(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0bb40ee4b31..ca04a381271 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -287,6 +287,7 @@ #![feature(cfi_encoding)] #![feature(char_max_len)] #![feature(concat_idents)] +#![feature(core_float_math)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] @@ -304,7 +305,6 @@ #![feature(iter_advance_by)] #![feature(iter_next_chunk)] #![feature(lang_items)] -#![feature(let_chains)] #![feature(link_cfg)] #![feature(linkage)] #![feature(macro_metavar_expr_concat)] diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 9737b2f5bfe..b3f3b301e3d 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -26,6 +26,13 @@ use crate::sync::Once; use crate::thread::{self, main_thread}; use crate::{mem, panic, sys}; +// This function is needed by the panic runtime. +#[cfg(not(test))] +#[rustc_std_internal_symbol] +fn __rust_abort() { + crate::process::abort(); +} + // Prints to the "panic output", depending on the platform this may be: // - the standard error output // - some dedicated platform specific output @@ -47,7 +54,7 @@ macro_rules! rtabort { ($($t:tt)*) => { { rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*)); - crate::sys::abort_internal(); + crate::process::abort(); } } } diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs index 668fd928534..299ce1a6ff0 100644 --- a/library/std/src/sys/cmath.rs +++ b/library/std/src/sys/cmath.rs @@ -7,13 +7,9 @@ unsafe extern "C" { pub safe fn asin(n: f64) -> f64; pub safe fn atan(n: f64) -> f64; pub safe fn atan2(a: f64, b: f64) -> f64; - pub safe fn cbrt(n: f64) -> f64; - pub safe fn cbrtf(n: f32) -> f32; pub safe fn cosh(n: f64) -> f64; pub safe fn expm1(n: f64) -> f64; pub safe fn expm1f(n: f32) -> f32; - pub safe fn fdim(a: f64, b: f64) -> f64; - pub safe fn fdimf(a: f32, b: f32) -> f32; #[cfg_attr(target_env = "msvc", link_name = "_hypot")] pub safe fn hypot(x: f64, y: f64) -> f64; #[cfg_attr(target_env = "msvc", link_name = "_hypotf")] diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index ea636938d70..fb8d69b7375 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -43,15 +43,6 @@ pub fn abort_internal() -> ! { unsafe { hermit_abi::abort() } } -// This function is needed by the panic runtime. The symbol is named in -// pre-link args for the target specification, so keep that in sync. -#[cfg(not(test))] -#[unsafe(no_mangle)] -// NB. used by both libunwind and libpanic_abort -pub extern "C" fn __rust_abort() { - abort_internal(); -} - // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 3932f64c0ef..6e43a79ddec 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -112,11 +112,14 @@ pub fn abort_internal() -> ! { abi::usercalls::exit(true) } -// This function is needed by the panic runtime. The symbol is named in +// This function is needed by libunwind. The symbol is named in // pre-link args for the target specification, so keep that in sync. +// Note: contrary to the `__rust_abort` in `crate::rt`, this uses `no_mangle` +// because it is actually used from C code. Because symbols annotated with +// #[rustc_std_internal_symbol] get mangled, this will not lead to linker +// conflicts. #[cfg(not(test))] #[unsafe(no_mangle)] -// NB. used by both libunwind and libpanic_abort pub extern "C" fn __rust_abort() { abort_internal(); } diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 78fcfcb3b77..8911a2ee519 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -161,14 +161,6 @@ pub fn abort_internal() -> ! { core::intrinsics::abort(); } -// This function is needed by the panic runtime. The symbol is named in -// pre-link args for the target specification, so keep that in sync. -#[cfg(not(test))] -#[unsafe(no_mangle)] -pub extern "C" fn __rust_abort() { - abort_internal(); -} - /// Disable access to BootServices if `EVT_SIGNAL_EXIT_BOOT_SERVICES` is signaled extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut crate::ffi::c_void) { uefi::env::disable_boot_services(); diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 4f18c4009ab..8f54e2376eb 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -328,8 +328,12 @@ pub fn dur2timeout(dur: Duration) -> u32 { /// Use `__fastfail` to abort the process /// -/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See -/// that function for more information on `__fastfail` +/// In Windows 8 and later, this will terminate the process immediately without +/// running any in-process exception handlers. In earlier versions of Windows, +/// this sequence of instructions will be treated as an access violation, which +/// will still terminate the process but might run some exception handlers. +/// +/// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail #[cfg(not(miri))] // inline assembly does not work in Miri pub fn abort_internal() -> ! { unsafe { diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 383d031ed43..042c4ff862f 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -1,5 +1,7 @@ #![forbid(unsafe_op_in_unsafe_fn)] +use crate::os::xous::ffi::exit; + pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; @@ -9,3 +11,7 @@ pub mod time; #[path = "../unsupported/common.rs"] mod common; pub use common::*; + +pub fn abort_internal() -> ! { + exit(101); +} diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs index 2230dabe096..d612a27d2bd 100644 --- a/library/std/src/sys/pal/xous/os.rs +++ b/library/std/src/sys/pal/xous/os.rs @@ -62,14 +62,6 @@ mod c_compat { } exit(unsafe { main() }); } - - // This function is needed by the panic runtime. The symbol is named in - // pre-link args for the target specification, so keep that in sync. - #[unsafe(no_mangle)] - // NB. used by both libunwind and libpanic_abort - pub extern "C" fn __rust_abort() -> ! { - exit(101); - } } pub fn errno() -> i32 { diff --git a/library/std/tests/floats/f128.rs b/library/std/tests/floats/f128.rs index c2618f3b315..e7c90faa05c 100644 --- a/library/std/tests/floats/f128.rs +++ b/library/std/tests/floats/f128.rs @@ -2,49 +2,26 @@ #![cfg(target_has_reliable_f128)] use std::f128::consts; -use std::num::FpCategory as Fp; -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -use std::ops::Rem; use std::ops::{Add, Div, Mul, Sub}; // Note these tolerances make sense around zero, but not for more extreme exponents. -/// For operations that are near exact, usually not involving math of different -/// signs. -const TOL_PRECISE: f128 = 1e-28; - /// Default tolerances. Works for values that should be near precise but not exact. Roughly /// the precision carried by `100 * 100`. +#[cfg(not(miri))] +#[cfg(target_has_reliable_f128_math)] const TOL: f128 = 1e-12; +/// For operations that are near exact, usually not involving math of different +/// signs. +const TOL_PRECISE: f128 = 1e-28; + /// Tolerances for math that is allowed to be imprecise, usually due to multiple chained /// operations. #[cfg(not(miri))] #[cfg(target_has_reliable_f128_math)] const TOL_IMPR: f128 = 1e-10; -/// Smallest number -const TINY_BITS: u128 = 0x1; - -/// Next smallest number -const TINY_UP_BITS: u128 = 0x2; - -/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -const MAX_DOWN_BITS: u128 = 0x7ffefffffffffffffffffffffffffffe; - -/// Zeroed exponent, full significant -const LARGEST_SUBNORMAL_BITS: u128 = 0x0000ffffffffffffffffffffffffffff; - -/// Exponent = 0b1, zeroed significand -const SMALLEST_NORMAL_BITS: u128 = 0x00010000000000000000000000000000; - -/// First pattern over the mantissa -const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; - -/// Second pattern over the mantissa -const NAN_MASK2: u128 = 0x00005555555555555555555555555555; - /// Compare by representation #[allow(unused_macros)] macro_rules! assert_f128_biteq { @@ -68,459 +45,11 @@ fn test_num_f128() { assert_eq!(ten.div(two), ten / two); } -// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support -// the intrinsics. - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_num_f128_rem() { - let ten = 10f128; - let two = 2f128; - assert_eq!(ten.rem(two), ten % two); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_min_nan() { - assert_eq!(f128::NAN.min(2.0), 2.0); - assert_eq!(2.0f128.min(f128::NAN), 2.0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_max_nan() { - assert_eq!(f128::NAN.max(2.0), 2.0); - assert_eq!(2.0f128.max(f128::NAN), 2.0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_minimum() { - assert!(f128::NAN.minimum(2.0).is_nan()); - assert!(2.0f128.minimum(f128::NAN).is_nan()); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_maximum() { - assert!(f128::NAN.maximum(2.0).is_nan()); - assert!(2.0f128.maximum(f128::NAN).is_nan()); -} - -#[test] -fn test_nan() { - let nan: f128 = f128::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert!(!nan.is_normal()); - assert_eq!(Fp::Nan, nan.classify()); - // Ensure the quiet bit is set. - assert!(nan.to_bits() & (1 << (f128::MANTISSA_DIGITS - 2)) != 0); -} - -#[test] -fn test_infinity() { - let inf: f128 = f128::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f128 = 0.0f128; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f128 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f128 = 1.0f128; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f128.is_nan()); - assert!(!5.3f128.is_nan()); - assert!(!(-10.732f128).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f128.is_infinite()); - assert!(!42.8f128.is_infinite()); - assert!(!(-109.2f128).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f128.is_finite()); - assert!(42.8f128.is_finite()); - assert!((-109.2f128).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f128.is_normal()); - assert!(1e-4931f128.is_normal()); - assert!(!1e-4932f128.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f128.classify(), Fp::Normal); - assert_eq!(1e-4931f128.classify(), Fp::Normal); - assert_eq!(1e-4932f128.classify(), Fp::Subnormal); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_floor() { - assert_approx_eq!(1.0f128.floor(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.floor(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.floor(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.floor(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.floor(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).floor(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).floor(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).floor(), -2.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).floor(), -2.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).floor(), -2.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_ceil() { - assert_approx_eq!(1.0f128.ceil(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.ceil(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.ceil(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.ceil(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.ceil(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).ceil(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).ceil(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).ceil(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).ceil(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).ceil(), -1.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_round() { - assert_approx_eq!(2.5f128.round(), 3.0f128, TOL_PRECISE); - assert_approx_eq!(1.0f128.round(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.round(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.round(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.round(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.round(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).round(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).round(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).round(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).round(), -2.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).round(), -2.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_round_ties_even() { - assert_approx_eq!(2.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.0f128.round_ties_even(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.round_ties_even(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.round_ties_even(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.round_ties_even(), 2.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.round_ties_even(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).round_ties_even(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).round_ties_even(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).round_ties_even(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).round_ties_even(), -2.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).round_ties_even(), -2.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_trunc() { - assert_approx_eq!(1.0f128.trunc(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.trunc(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.trunc(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.trunc(), 1.0f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.trunc(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).trunc(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).trunc(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).trunc(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).trunc(), -1.0f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).trunc(), -1.0f128, TOL_PRECISE); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_fract() { - assert_approx_eq!(1.0f128.fract(), 0.0f128, TOL_PRECISE); - assert_approx_eq!(1.3f128.fract(), 0.3f128, TOL_PRECISE); - assert_approx_eq!(1.5f128.fract(), 0.5f128, TOL_PRECISE); - assert_approx_eq!(1.7f128.fract(), 0.7f128, TOL_PRECISE); - assert_approx_eq!(0.0f128.fract(), 0.0f128, TOL_PRECISE); - assert_approx_eq!((-0.0f128).fract(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.0f128).fract(), -0.0f128, TOL_PRECISE); - assert_approx_eq!((-1.3f128).fract(), -0.3f128, TOL_PRECISE); - assert_approx_eq!((-1.5f128).fract(), -0.5f128, TOL_PRECISE); - assert_approx_eq!((-1.7f128).fract(), -0.7f128, TOL_PRECISE); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_abs() { - assert_eq!(f128::INFINITY.abs(), f128::INFINITY); - assert_eq!(1f128.abs(), 1f128); - assert_eq!(0f128.abs(), 0f128); - assert_eq!((-0f128).abs(), 0f128); - assert_eq!((-1f128).abs(), 1f128); - assert_eq!(f128::NEG_INFINITY.abs(), f128::INFINITY); - assert_eq!((1f128 / f128::NEG_INFINITY).abs(), 0f128); - assert!(f128::NAN.abs().is_nan()); -} - -#[test] -fn test_is_sign_positive() { - assert!(f128::INFINITY.is_sign_positive()); - assert!(1f128.is_sign_positive()); - assert!(0f128.is_sign_positive()); - assert!(!(-0f128).is_sign_positive()); - assert!(!(-1f128).is_sign_positive()); - assert!(!f128::NEG_INFINITY.is_sign_positive()); - assert!(!(1f128 / f128::NEG_INFINITY).is_sign_positive()); - assert!(f128::NAN.is_sign_positive()); - assert!(!(-f128::NAN).is_sign_positive()); -} - -#[test] -fn test_is_sign_negative() { - assert!(!f128::INFINITY.is_sign_negative()); - assert!(!1f128.is_sign_negative()); - assert!(!0f128.is_sign_negative()); - assert!((-0f128).is_sign_negative()); - assert!((-1f128).is_sign_negative()); - assert!(f128::NEG_INFINITY.is_sign_negative()); - assert!((1f128 / f128::NEG_INFINITY).is_sign_negative()); - assert!(!f128::NAN.is_sign_negative()); - assert!((-f128::NAN).is_sign_negative()); -} - -#[test] -fn test_next_up() { - let tiny = f128::from_bits(TINY_BITS); - let tiny_up = f128::from_bits(TINY_UP_BITS); - let max_down = f128::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f128::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f128::from_bits(SMALLEST_NORMAL_BITS); - assert_f128_biteq!(f128::NEG_INFINITY.next_up(), f128::MIN); - assert_f128_biteq!(f128::MIN.next_up(), -max_down); - assert_f128_biteq!((-1.0 - f128::EPSILON).next_up(), -1.0); - assert_f128_biteq!((-smallest_normal).next_up(), -largest_subnormal); - assert_f128_biteq!((-tiny_up).next_up(), -tiny); - assert_f128_biteq!((-tiny).next_up(), -0.0f128); - assert_f128_biteq!((-0.0f128).next_up(), tiny); - assert_f128_biteq!(0.0f128.next_up(), tiny); - assert_f128_biteq!(tiny.next_up(), tiny_up); - assert_f128_biteq!(largest_subnormal.next_up(), smallest_normal); - assert_f128_biteq!(1.0f128.next_up(), 1.0 + f128::EPSILON); - assert_f128_biteq!(f128::MAX.next_up(), f128::INFINITY); - assert_f128_biteq!(f128::INFINITY.next_up(), f128::INFINITY); - - // Check that NaNs roundtrip. - let nan0 = f128::NAN; - let nan1 = f128::from_bits(f128::NAN.to_bits() ^ 0x002a_aaaa); - let nan2 = f128::from_bits(f128::NAN.to_bits() ^ 0x0055_5555); - assert_f128_biteq!(nan0.next_up(), nan0); - assert_f128_biteq!(nan1.next_up(), nan1); - assert_f128_biteq!(nan2.next_up(), nan2); -} - -#[test] -fn test_next_down() { - let tiny = f128::from_bits(TINY_BITS); - let tiny_up = f128::from_bits(TINY_UP_BITS); - let max_down = f128::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f128::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f128::from_bits(SMALLEST_NORMAL_BITS); - assert_f128_biteq!(f128::NEG_INFINITY.next_down(), f128::NEG_INFINITY); - assert_f128_biteq!(f128::MIN.next_down(), f128::NEG_INFINITY); - assert_f128_biteq!((-max_down).next_down(), f128::MIN); - assert_f128_biteq!((-1.0f128).next_down(), -1.0 - f128::EPSILON); - assert_f128_biteq!((-largest_subnormal).next_down(), -smallest_normal); - assert_f128_biteq!((-tiny).next_down(), -tiny_up); - assert_f128_biteq!((-0.0f128).next_down(), -tiny); - assert_f128_biteq!((0.0f128).next_down(), -tiny); - assert_f128_biteq!(tiny.next_down(), 0.0f128); - assert_f128_biteq!(tiny_up.next_down(), tiny); - assert_f128_biteq!(smallest_normal.next_down(), largest_subnormal); - assert_f128_biteq!((1.0 + f128::EPSILON).next_down(), 1.0f128); - assert_f128_biteq!(f128::MAX.next_down(), max_down); - assert_f128_biteq!(f128::INFINITY.next_down(), f128::MAX); - - // Check that NaNs roundtrip. - let nan0 = f128::NAN; - let nan1 = f128::from_bits(f128::NAN.to_bits() ^ 0x002a_aaaa); - let nan2 = f128::from_bits(f128::NAN.to_bits() ^ 0x0055_5555); - assert_f128_biteq!(nan0.next_down(), nan0); - assert_f128_biteq!(nan1.next_down(), nan1); - assert_f128_biteq!(nan2.next_down(), nan2); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_mul_add() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_approx_eq!(12.3f128.mul_add(4.5, 6.7), 62.05, TOL_PRECISE); - assert_approx_eq!((-12.3f128).mul_add(-4.5, -6.7), 48.65, TOL_PRECISE); - assert_approx_eq!(0.0f128.mul_add(8.9, 1.2), 1.2, TOL_PRECISE); - assert_approx_eq!(3.4f128.mul_add(-0.0, 5.6), 5.6, TOL_PRECISE); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f128.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_recip() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(1.0f128.recip(), 1.0); - assert_eq!(2.0f128.recip(), 0.5); - assert_eq!((-0.4f128).recip(), -2.5); - assert_eq!(0.0f128.recip(), inf); - assert_approx_eq!( - f128::MAX.recip(), - 8.40525785778023376565669454330438228902076605e-4933, - 1e-4900 - ); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); -} - // Many math functions allow for less accurate results, so the next tolerance up is used #[test] #[cfg(not(miri))] #[cfg(target_has_reliable_f128_math)] -fn test_powi() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(1.0f128.powi(1), 1.0); - assert_approx_eq!((-3.1f128).powi(2), 9.6100000000000005506706202140776519387, TOL); - assert_approx_eq!(5.9f128.powi(-2), 0.028727377190462507313100483690639638451, TOL); - assert_eq!(8.3f128.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] fn test_powf() { let nan: f128 = f128::NAN; let inf: f128 = f128::INFINITY; @@ -539,19 +68,6 @@ fn test_powf() { #[test] #[cfg(not(miri))] #[cfg(target_has_reliable_f128_math)] -fn test_sqrt_domain() { - assert!(f128::NAN.sqrt().is_nan()); - assert!(f128::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f128).sqrt().is_nan()); - assert_eq!((-0.0f128).sqrt(), -0.0); - assert_eq!(0.0f128.sqrt(), 0.0); - assert_eq!(1.0f128.sqrt(), 1.0); - assert_eq!(f128::INFINITY.sqrt(), f128::INFINITY); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] fn test_exp() { assert_eq!(1.0, 0.0f128.exp()); assert_approx_eq!(consts::E, 1.0f128.exp(), TOL); @@ -655,38 +171,6 @@ fn test_log10() { } #[test] -fn test_to_degrees() { - let pi: f128 = consts::PI; - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(0.0f128.to_degrees(), 0.0); - assert_approx_eq!((-5.8f128).to_degrees(), -332.31552117587745090765431723855668471, TOL); - assert_approx_eq!(pi.to_degrees(), 180.0, TOL); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - assert_eq!(1_f128.to_degrees(), 57.2957795130823208767981548141051703); -} - -#[test] -fn test_to_radians() { - let pi: f128 = consts::PI; - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_eq!(0.0f128.to_radians(), 0.0); - assert_approx_eq!(154.6f128.to_radians(), 2.6982790235832334267135442069489767804, TOL); - assert_approx_eq!((-332.31f128).to_radians(), -5.7999036373023566567593094812182763013, TOL); - // check approx rather than exact because round trip for pi doesn't fall on an exactly - // representable value (unlike `f32` and `f64`). - assert_approx_eq!(180.0f128.to_radians(), pi, TOL_PRECISE); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); -} - -#[test] #[cfg(not(miri))] #[cfg(target_has_reliable_f128_math)] fn test_asinh() { @@ -835,237 +319,3 @@ fn test_real_consts() { assert_approx_eq!(ln_10, 10f128.ln(), TOL_PRECISE); } } - -#[test] -fn test_float_bits_conv() { - assert_eq!((1f128).to_bits(), 0x3fff0000000000000000000000000000); - assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000); - assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000); - assert_eq!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); - assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0, TOL_PRECISE); - assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5, TOL_PRECISE); - assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0, TOL_PRECISE); - assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25, TOL_PRECISE); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f128::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f128::NAN.to_bits() ^ NAN_MASK2; - assert!(f128::from_bits(masked_nan1).is_nan()); - assert!(f128::from_bits(masked_nan2).is_nan()); - - assert_eq!(f128::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f128::from_bits(masked_nan2).to_bits(), masked_nan2); -} - -#[test] -#[should_panic] -fn test_clamp_min_greater_than_max() { - let _ = 1.0f128.clamp(3.0, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_min_is_nan() { - let _ = 1.0f128.clamp(f128::NAN, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_max_is_nan() { - let _ = 1.0f128.clamp(3.0, f128::NAN); -} - -#[test] -fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u128 { - 1 << (f128::MANTISSA_DIGITS - 2) - } - - // FIXME(f16_f128): test subnormals when powf is available - // fn min_subnorm() -> f128 { - // f128::MIN_POSITIVE / f128::powf(2.0, f128::MANTISSA_DIGITS as f128 - 1.0) - // } - - // fn max_subnorm() -> f128 { - // f128::MIN_POSITIVE - min_subnorm() - // } - - fn q_nan() -> f128 { - f128::from_bits(f128::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f128 { - f128::from_bits((f128::NAN.to_bits() & !quiet_bit_mask()) + 42) - } - - assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Equal, (-f128::INFINITY).total_cmp(&-f128::INFINITY)); - assert_eq!(Ordering::Equal, (-f128::MAX).total_cmp(&-f128::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f128).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f128).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f128).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f128).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f128::MIN_POSITIVE).total_cmp(&-f128::MIN_POSITIVE)); - // assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Equal, (-0.0_f128).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f128.total_cmp(&0.0)); - // assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Equal, f128::MIN_POSITIVE.total_cmp(&f128::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f128.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f128.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f128.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f128.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f128::MAX.total_cmp(&f128::MAX)); - assert_eq!(Ordering::Equal, f128::INFINITY.total_cmp(&f128::INFINITY)); - assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); - assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::INFINITY)); - assert_eq!(Ordering::Less, (-f128::INFINITY).total_cmp(&-f128::MAX)); - assert_eq!(Ordering::Less, (-f128::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f128).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f128).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f128).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f128).total_cmp(&-f128::MIN_POSITIVE)); - // assert_eq!(Ordering::Less, (-f128::MIN_POSITIVE).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); - // assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-0.0_f128).total_cmp(&0.0)); - // assert_eq!(Ordering::Less, 0.0_f128.total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - // assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f128::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f128::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f128.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f128.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f128.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f128.total_cmp(&f128::MAX)); - assert_eq!(Ordering::Less, f128::MAX.total_cmp(&f128::INFINITY)); - assert_eq!(Ordering::Less, f128::INFINITY.total_cmp(&s_nan())); - assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Greater, (-f128::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f128::MAX).total_cmp(&-f128::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f128).total_cmp(&-f128::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f128).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f128).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f128).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f128::MIN_POSITIVE).total_cmp(&-0.5)); - // assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f128::MIN_POSITIVE)); - // assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Greater, (-0.0_f128).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f128.total_cmp(&-0.0)); - // assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); - // assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Greater, f128::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f128.total_cmp(&f128::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f128.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f128.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f128.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f128::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f128::INFINITY.total_cmp(&f128::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f128::INFINITY)); - assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f128::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f128::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f128::MIN_POSITIVE)); - // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); - // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f128::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f128::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f128::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f128::MIN_POSITIVE)); - // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); - // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); -} - -#[test] -fn test_algebraic() { - let a: f128 = 123.0; - let b: f128 = 456.0; - - // Check that individual operations match their primitive counterparts. - // - // This is a check of current implementations and does NOT imply any form of - // guarantee about future behavior. The compiler reserves the right to make - // these operations inexact matches in the future. - let eps = if cfg!(miri) { 1e-6 } else { 0.0 }; - - assert_approx_eq!(a.algebraic_add(b), a + b, eps); - assert_approx_eq!(a.algebraic_sub(b), a - b, eps); - assert_approx_eq!(a.algebraic_mul(b), a * b, eps); - assert_approx_eq!(a.algebraic_div(b), a / b, eps); - assert_approx_eq!(a.algebraic_rem(b), a % b, eps); -} - -#[test] -fn test_from() { - assert_eq!(f128::from(false), 0.0); - assert_eq!(f128::from(true), 1.0); - assert_eq!(f128::from(u8::MIN), 0.0); - assert_eq!(f128::from(42_u8), 42.0); - assert_eq!(f128::from(u8::MAX), 255.0); - assert_eq!(f128::from(i8::MIN), -128.0); - assert_eq!(f128::from(42_i8), 42.0); - assert_eq!(f128::from(i8::MAX), 127.0); - assert_eq!(f128::from(u16::MIN), 0.0); - assert_eq!(f128::from(42_u16), 42.0); - assert_eq!(f128::from(u16::MAX), 65535.0); - assert_eq!(f128::from(i16::MIN), -32768.0); - assert_eq!(f128::from(42_i16), 42.0); - assert_eq!(f128::from(i16::MAX), 32767.0); - assert_eq!(f128::from(u32::MIN), 0.0); - assert_eq!(f128::from(42_u32), 42.0); - assert_eq!(f128::from(u32::MAX), 4294967295.0); - assert_eq!(f128::from(i32::MIN), -2147483648.0); - assert_eq!(f128::from(42_i32), 42.0); - assert_eq!(f128::from(i32::MAX), 2147483647.0); - // FIXME(f16_f128): Uncomment these tests once the From<{u64,i64}> impls are added. - // assert_eq!(f128::from(u64::MIN), 0.0); - // assert_eq!(f128::from(42_u64), 42.0); - // assert_eq!(f128::from(u64::MAX), 18446744073709551615.0); - // assert_eq!(f128::from(i64::MIN), -9223372036854775808.0); - // assert_eq!(f128::from(42_i64), 42.0); - // assert_eq!(f128::from(i64::MAX), 9223372036854775807.0); -} diff --git a/library/std/tests/floats/f16.rs b/library/std/tests/floats/f16.rs index 70bbcd07160..0f8b4138d22 100644 --- a/library/std/tests/floats/f16.rs +++ b/library/std/tests/floats/f16.rs @@ -2,7 +2,6 @@ #![cfg(target_has_reliable_f16)] use std::f16::consts; -use std::num::FpCategory as Fp; /// Tolerance for results on the order of 10.0e-2 #[allow(unused)] @@ -20,27 +19,6 @@ const TOL_P2: f16 = 0.5; #[allow(unused)] const TOL_P4: f16 = 10.0; -/// Smallest number -const TINY_BITS: u16 = 0x1; - -/// Next smallest number -const TINY_UP_BITS: u16 = 0x2; - -/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -const MAX_DOWN_BITS: u16 = 0x7bfe; - -/// Zeroed exponent, full significant -const LARGEST_SUBNORMAL_BITS: u16 = 0x03ff; - -/// Exponent = 0b1, zeroed significand -const SMALLEST_NORMAL_BITS: u16 = 0x0400; - -/// First pattern over the mantissa -const NAN_MASK1: u16 = 0x02aa; - -/// Second pattern over the mantissa -const NAN_MASK2: u16 = 0x0155; - /// Compare by representation #[allow(unused_macros)] macro_rules! assert_f16_biteq { @@ -53,446 +31,6 @@ macro_rules! assert_f16_biteq { } #[test] -fn test_num_f16() { - crate::test_num(10f16, 2f16); -} - -// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support -// the intrinsics. - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_min_nan() { - assert_eq!(f16::NAN.min(2.0), 2.0); - assert_eq!(2.0f16.min(f16::NAN), 2.0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_max_nan() { - assert_eq!(f16::NAN.max(2.0), 2.0); - assert_eq!(2.0f16.max(f16::NAN), 2.0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_minimum() { - assert!(f16::NAN.minimum(2.0).is_nan()); - assert!(2.0f16.minimum(f16::NAN).is_nan()); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_maximum() { - assert!(f16::NAN.maximum(2.0).is_nan()); - assert!(2.0f16.maximum(f16::NAN).is_nan()); -} - -#[test] -fn test_nan() { - let nan: f16 = f16::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert!(!nan.is_normal()); - assert_eq!(Fp::Nan, nan.classify()); - // Ensure the quiet bit is set. - assert!(nan.to_bits() & (1 << (f16::MANTISSA_DIGITS - 2)) != 0); -} - -#[test] -fn test_infinity() { - let inf: f16 = f16::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f16 = 0.0f16; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f16 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f16 = 1.0f16; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f16.is_nan()); - assert!(!5.3f16.is_nan()); - assert!(!(-10.732f16).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f16.is_infinite()); - assert!(!42.8f16.is_infinite()); - assert!(!(-109.2f16).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f16.is_finite()); - assert!(42.8f16.is_finite()); - assert!((-109.2f16).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f16.is_normal()); - assert!(1e-4f16.is_normal()); - assert!(!1e-5f16.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f16.classify(), Fp::Normal); - assert_eq!(1e-4f16.classify(), Fp::Normal); - assert_eq!(1e-5f16.classify(), Fp::Subnormal); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_floor() { - assert_approx_eq!(1.0f16.floor(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.floor(), 1.0f16, TOL_0); - assert_approx_eq!(1.5f16.floor(), 1.0f16, TOL_0); - assert_approx_eq!(1.7f16.floor(), 1.0f16, TOL_0); - assert_approx_eq!(0.0f16.floor(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).floor(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).floor(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).floor(), -2.0f16, TOL_0); - assert_approx_eq!((-1.5f16).floor(), -2.0f16, TOL_0); - assert_approx_eq!((-1.7f16).floor(), -2.0f16, TOL_0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_ceil() { - assert_approx_eq!(1.0f16.ceil(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.ceil(), 2.0f16, TOL_0); - assert_approx_eq!(1.5f16.ceil(), 2.0f16, TOL_0); - assert_approx_eq!(1.7f16.ceil(), 2.0f16, TOL_0); - assert_approx_eq!(0.0f16.ceil(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).ceil(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).ceil(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).ceil(), -1.0f16, TOL_0); - assert_approx_eq!((-1.5f16).ceil(), -1.0f16, TOL_0); - assert_approx_eq!((-1.7f16).ceil(), -1.0f16, TOL_0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_round() { - assert_approx_eq!(2.5f16.round(), 3.0f16, TOL_0); - assert_approx_eq!(1.0f16.round(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.round(), 1.0f16, TOL_0); - assert_approx_eq!(1.5f16.round(), 2.0f16, TOL_0); - assert_approx_eq!(1.7f16.round(), 2.0f16, TOL_0); - assert_approx_eq!(0.0f16.round(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).round(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).round(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).round(), -1.0f16, TOL_0); - assert_approx_eq!((-1.5f16).round(), -2.0f16, TOL_0); - assert_approx_eq!((-1.7f16).round(), -2.0f16, TOL_0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_round_ties_even() { - assert_approx_eq!(2.5f16.round_ties_even(), 2.0f16, TOL_0); - assert_approx_eq!(1.0f16.round_ties_even(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.round_ties_even(), 1.0f16, TOL_0); - assert_approx_eq!(1.5f16.round_ties_even(), 2.0f16, TOL_0); - assert_approx_eq!(1.7f16.round_ties_even(), 2.0f16, TOL_0); - assert_approx_eq!(0.0f16.round_ties_even(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).round_ties_even(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).round_ties_even(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).round_ties_even(), -1.0f16, TOL_0); - assert_approx_eq!((-1.5f16).round_ties_even(), -2.0f16, TOL_0); - assert_approx_eq!((-1.7f16).round_ties_even(), -2.0f16, TOL_0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_trunc() { - assert_approx_eq!(1.0f16.trunc(), 1.0f16, TOL_0); - assert_approx_eq!(1.3f16.trunc(), 1.0f16, TOL_0); - assert_approx_eq!(1.5f16.trunc(), 1.0f16, TOL_0); - assert_approx_eq!(1.7f16.trunc(), 1.0f16, TOL_0); - assert_approx_eq!(0.0f16.trunc(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).trunc(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).trunc(), -1.0f16, TOL_0); - assert_approx_eq!((-1.3f16).trunc(), -1.0f16, TOL_0); - assert_approx_eq!((-1.5f16).trunc(), -1.0f16, TOL_0); - assert_approx_eq!((-1.7f16).trunc(), -1.0f16, TOL_0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_fract() { - assert_approx_eq!(1.0f16.fract(), 0.0f16, TOL_0); - assert_approx_eq!(1.3f16.fract(), 0.3f16, TOL_0); - assert_approx_eq!(1.5f16.fract(), 0.5f16, TOL_0); - assert_approx_eq!(1.7f16.fract(), 0.7f16, TOL_0); - assert_approx_eq!(0.0f16.fract(), 0.0f16, TOL_0); - assert_approx_eq!((-0.0f16).fract(), -0.0f16, TOL_0); - assert_approx_eq!((-1.0f16).fract(), -0.0f16, TOL_0); - assert_approx_eq!((-1.3f16).fract(), -0.3f16, TOL_0); - assert_approx_eq!((-1.5f16).fract(), -0.5f16, TOL_0); - assert_approx_eq!((-1.7f16).fract(), -0.7f16, TOL_0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_abs() { - assert_eq!(f16::INFINITY.abs(), f16::INFINITY); - assert_eq!(1f16.abs(), 1f16); - assert_eq!(0f16.abs(), 0f16); - assert_eq!((-0f16).abs(), 0f16); - assert_eq!((-1f16).abs(), 1f16); - assert_eq!(f16::NEG_INFINITY.abs(), f16::INFINITY); - assert_eq!((1f16 / f16::NEG_INFINITY).abs(), 0f16); - assert!(f16::NAN.abs().is_nan()); -} - -#[test] -fn test_is_sign_positive() { - assert!(f16::INFINITY.is_sign_positive()); - assert!(1f16.is_sign_positive()); - assert!(0f16.is_sign_positive()); - assert!(!(-0f16).is_sign_positive()); - assert!(!(-1f16).is_sign_positive()); - assert!(!f16::NEG_INFINITY.is_sign_positive()); - assert!(!(1f16 / f16::NEG_INFINITY).is_sign_positive()); - assert!(f16::NAN.is_sign_positive()); - assert!(!(-f16::NAN).is_sign_positive()); -} - -#[test] -fn test_is_sign_negative() { - assert!(!f16::INFINITY.is_sign_negative()); - assert!(!1f16.is_sign_negative()); - assert!(!0f16.is_sign_negative()); - assert!((-0f16).is_sign_negative()); - assert!((-1f16).is_sign_negative()); - assert!(f16::NEG_INFINITY.is_sign_negative()); - assert!((1f16 / f16::NEG_INFINITY).is_sign_negative()); - assert!(!f16::NAN.is_sign_negative()); - assert!((-f16::NAN).is_sign_negative()); -} - -#[test] -fn test_next_up() { - let tiny = f16::from_bits(TINY_BITS); - let tiny_up = f16::from_bits(TINY_UP_BITS); - let max_down = f16::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f16::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f16::from_bits(SMALLEST_NORMAL_BITS); - assert_f16_biteq!(f16::NEG_INFINITY.next_up(), f16::MIN); - assert_f16_biteq!(f16::MIN.next_up(), -max_down); - assert_f16_biteq!((-1.0 - f16::EPSILON).next_up(), -1.0); - assert_f16_biteq!((-smallest_normal).next_up(), -largest_subnormal); - assert_f16_biteq!((-tiny_up).next_up(), -tiny); - assert_f16_biteq!((-tiny).next_up(), -0.0f16); - assert_f16_biteq!((-0.0f16).next_up(), tiny); - assert_f16_biteq!(0.0f16.next_up(), tiny); - assert_f16_biteq!(tiny.next_up(), tiny_up); - assert_f16_biteq!(largest_subnormal.next_up(), smallest_normal); - assert_f16_biteq!(1.0f16.next_up(), 1.0 + f16::EPSILON); - assert_f16_biteq!(f16::MAX.next_up(), f16::INFINITY); - assert_f16_biteq!(f16::INFINITY.next_up(), f16::INFINITY); - - // Check that NaNs roundtrip. - let nan0 = f16::NAN; - let nan1 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK2); - assert_f16_biteq!(nan0.next_up(), nan0); - assert_f16_biteq!(nan1.next_up(), nan1); - assert_f16_biteq!(nan2.next_up(), nan2); -} - -#[test] -fn test_next_down() { - let tiny = f16::from_bits(TINY_BITS); - let tiny_up = f16::from_bits(TINY_UP_BITS); - let max_down = f16::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f16::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f16::from_bits(SMALLEST_NORMAL_BITS); - assert_f16_biteq!(f16::NEG_INFINITY.next_down(), f16::NEG_INFINITY); - assert_f16_biteq!(f16::MIN.next_down(), f16::NEG_INFINITY); - assert_f16_biteq!((-max_down).next_down(), f16::MIN); - assert_f16_biteq!((-1.0f16).next_down(), -1.0 - f16::EPSILON); - assert_f16_biteq!((-largest_subnormal).next_down(), -smallest_normal); - assert_f16_biteq!((-tiny).next_down(), -tiny_up); - assert_f16_biteq!((-0.0f16).next_down(), -tiny); - assert_f16_biteq!((0.0f16).next_down(), -tiny); - assert_f16_biteq!(tiny.next_down(), 0.0f16); - assert_f16_biteq!(tiny_up.next_down(), tiny); - assert_f16_biteq!(smallest_normal.next_down(), largest_subnormal); - assert_f16_biteq!((1.0 + f16::EPSILON).next_down(), 1.0f16); - assert_f16_biteq!(f16::MAX.next_down(), max_down); - assert_f16_biteq!(f16::INFINITY.next_down(), f16::MAX); - - // Check that NaNs roundtrip. - let nan0 = f16::NAN; - let nan1 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f16::from_bits(f16::NAN.to_bits() ^ NAN_MASK2); - assert_f16_biteq!(nan0.next_down(), nan0); - assert_f16_biteq!(nan1.next_down(), nan1); - assert_f16_biteq!(nan2.next_down(), nan2); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_mul_add() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_approx_eq!(12.3f16.mul_add(4.5, 6.7), 62.05, TOL_P2); - assert_approx_eq!((-12.3f16).mul_add(-4.5, -6.7), 48.65, TOL_P2); - assert_approx_eq!(0.0f16.mul_add(8.9, 1.2), 1.2, TOL_0); - assert_approx_eq!(3.4f16.mul_add(-0.0, 5.6), 5.6, TOL_0); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f16.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_recip() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(1.0f16.recip(), 1.0); - assert_eq!(2.0f16.recip(), 0.5); - assert_eq!((-0.4f16).recip(), -2.5); - assert_eq!(0.0f16.recip(), inf); - assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_powi() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(1.0f16.powi(1), 1.0); - assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0); - assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2); - assert_eq!(8.3f16.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); -} - -#[test] #[cfg(not(miri))] #[cfg(target_has_reliable_f16_math)] fn test_powf() { @@ -513,19 +51,6 @@ fn test_powf() { #[test] #[cfg(not(miri))] #[cfg(target_has_reliable_f16_math)] -fn test_sqrt_domain() { - assert!(f16::NAN.sqrt().is_nan()); - assert!(f16::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f16).sqrt().is_nan()); - assert_eq!((-0.0f16).sqrt(), -0.0); - assert_eq!(0.0f16.sqrt(), 0.0); - assert_eq!(1.0f16.sqrt(), 1.0); - assert_eq!(f16::INFINITY.sqrt(), f16::INFINITY); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] fn test_exp() { assert_eq!(1.0, 0.0f16.exp()); assert_approx_eq!(2.718282, 1.0f16.exp(), TOL_0); @@ -629,36 +154,6 @@ fn test_log10() { } #[test] -fn test_to_degrees() { - let pi: f16 = consts::PI; - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(0.0f16.to_degrees(), 0.0); - assert_approx_eq!((-5.8f16).to_degrees(), -332.315521, TOL_P2); - assert_approx_eq!(pi.to_degrees(), 180.0, TOL_P2); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - assert_eq!(1_f16.to_degrees(), 57.2957795130823208767981548141051703); -} - -#[test] -fn test_to_radians() { - let pi: f16 = consts::PI; - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_eq!(0.0f16.to_radians(), 0.0); - assert_approx_eq!(154.6f16.to_radians(), 2.698279, TOL_0); - assert_approx_eq!((-332.31f16).to_radians(), -5.799903, TOL_0); - assert_approx_eq!(180.0f16.to_radians(), pi, TOL_0); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); -} - -#[test] #[cfg(not(miri))] #[cfg(target_has_reliable_f16_math)] fn test_asinh() { @@ -803,220 +298,3 @@ fn test_real_consts() { assert_approx_eq!(ln_10, 10f16.ln(), TOL_0); } } - -#[test] -fn test_float_bits_conv() { - assert_eq!((1f16).to_bits(), 0x3c00); - assert_eq!((12.5f16).to_bits(), 0x4a40); - assert_eq!((1337f16).to_bits(), 0x6539); - assert_eq!((-14.25f16).to_bits(), 0xcb20); - assert_approx_eq!(f16::from_bits(0x3c00), 1.0, TOL_0); - assert_approx_eq!(f16::from_bits(0x4a40), 12.5, TOL_0); - assert_approx_eq!(f16::from_bits(0x6539), 1337.0, TOL_P4); - assert_approx_eq!(f16::from_bits(0xcb20), -14.25, TOL_0); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f16::NAN.to_bits() ^ NAN_MASK2; - assert!(f16::from_bits(masked_nan1).is_nan()); - assert!(f16::from_bits(masked_nan2).is_nan()); - - assert_eq!(f16::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f16::from_bits(masked_nan2).to_bits(), masked_nan2); -} - -#[test] -#[should_panic] -fn test_clamp_min_greater_than_max() { - let _ = 1.0f16.clamp(3.0, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_min_is_nan() { - let _ = 1.0f16.clamp(f16::NAN, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_max_is_nan() { - let _ = 1.0f16.clamp(3.0, f16::NAN); -} - -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u16 { - 1 << (f16::MANTISSA_DIGITS - 2) - } - - fn min_subnorm() -> f16 { - f16::MIN_POSITIVE / f16::powf(2.0, f16::MANTISSA_DIGITS as f16 - 1.0) - } - - fn max_subnorm() -> f16 { - f16::MIN_POSITIVE - min_subnorm() - } - - fn q_nan() -> f16 { - f16::from_bits(f16::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f16 { - f16::from_bits((f16::NAN.to_bits() & !quiet_bit_mask()) + 42) - } - - assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Equal, (-f16::INFINITY).total_cmp(&-f16::INFINITY)); - assert_eq!(Ordering::Equal, (-f16::MAX).total_cmp(&-f16::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f16).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f16).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f16).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f16).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f16::MIN_POSITIVE).total_cmp(&-f16::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Equal, (-0.0_f16).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f16.total_cmp(&0.0)); - assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Equal, f16::MIN_POSITIVE.total_cmp(&f16::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f16.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f16.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f16.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f16.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f16::MAX.total_cmp(&f16::MAX)); - assert_eq!(Ordering::Equal, f16::INFINITY.total_cmp(&f16::INFINITY)); - assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); - assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::INFINITY)); - assert_eq!(Ordering::Less, (-f16::INFINITY).total_cmp(&-f16::MAX)); - assert_eq!(Ordering::Less, (-f16::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f16).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f16).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f16).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f16).total_cmp(&-f16::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-f16::MIN_POSITIVE).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-0.0_f16).total_cmp(&0.0)); - assert_eq!(Ordering::Less, 0.0_f16.total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f16::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f16::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f16.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f16.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f16.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f16.total_cmp(&f16::MAX)); - assert_eq!(Ordering::Less, f16::MAX.total_cmp(&f16::INFINITY)); - assert_eq!(Ordering::Less, f16::INFINITY.total_cmp(&s_nan())); - assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Greater, (-f16::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f16::MAX).total_cmp(&-f16::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f16).total_cmp(&-f16::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f16).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f16).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f16).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f16::MIN_POSITIVE).total_cmp(&-0.5)); - assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f16::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Greater, (-0.0_f16).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f16.total_cmp(&-0.0)); - assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); - assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Greater, f16::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f16.total_cmp(&f16::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f16.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f16.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f16.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f16::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f16::INFINITY.total_cmp(&f16::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f16::INFINITY)); - assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f16::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f16::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f16::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f16::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f16::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f16::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); -} - -#[test] -fn test_algebraic() { - let a: f16 = 123.0; - let b: f16 = 456.0; - - // Check that individual operations match their primitive counterparts. - // - // This is a check of current implementations and does NOT imply any form of - // guarantee about future behavior. The compiler reserves the right to make - // these operations inexact matches in the future. - let eps_add = if cfg!(miri) { 1e1 } else { 0.0 }; - let eps_mul = if cfg!(miri) { 1e3 } else { 0.0 }; - let eps_div = if cfg!(miri) { 1e0 } else { 0.0 }; - - assert_approx_eq!(a.algebraic_add(b), a + b, eps_add); - assert_approx_eq!(a.algebraic_sub(b), a - b, eps_add); - assert_approx_eq!(a.algebraic_mul(b), a * b, eps_mul); - assert_approx_eq!(a.algebraic_div(b), a / b, eps_div); - assert_approx_eq!(a.algebraic_rem(b), a % b, eps_div); -} - -#[test] -fn test_from() { - assert_eq!(f16::from(false), 0.0); - assert_eq!(f16::from(true), 1.0); - assert_eq!(f16::from(u8::MIN), 0.0); - assert_eq!(f16::from(42_u8), 42.0); - assert_eq!(f16::from(u8::MAX), 255.0); - assert_eq!(f16::from(i8::MIN), -128.0); - assert_eq!(f16::from(42_i8), 42.0); - assert_eq!(f16::from(i8::MAX), 127.0); -} diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs index 9af23afc5bb..e54f227bb77 100644 --- a/library/std/tests/floats/f32.rs +++ b/library/std/tests/floats/f32.rs @@ -1,26 +1,4 @@ use std::f32::consts; -use std::num::FpCategory as Fp; - -/// Smallest number -const TINY_BITS: u32 = 0x1; - -/// Next smallest number -const TINY_UP_BITS: u32 = 0x2; - -/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -const MAX_DOWN_BITS: u32 = 0x7f7f_fffe; - -/// Zeroed exponent, full significant -const LARGEST_SUBNORMAL_BITS: u32 = 0x007f_ffff; - -/// Exponent = 0b1, zeroed significand -const SMALLEST_NORMAL_BITS: u32 = 0x0080_0000; - -/// First pattern over the mantissa -const NAN_MASK1: u32 = 0x002a_aaaa; - -/// Second pattern over the mantissa -const NAN_MASK2: u32 = 0x0055_5555; #[allow(unused_macros)] macro_rules! assert_f32_biteq { @@ -34,426 +12,6 @@ macro_rules! assert_f32_biteq { } #[test] -fn test_num_f32() { - crate::test_num(10f32, 2f32); -} - -#[test] -fn test_min_nan() { - assert_eq!(f32::NAN.min(2.0), 2.0); - assert_eq!(2.0f32.min(f32::NAN), 2.0); -} - -#[test] -fn test_max_nan() { - assert_eq!(f32::NAN.max(2.0), 2.0); - assert_eq!(2.0f32.max(f32::NAN), 2.0); -} - -#[test] -fn test_minimum() { - assert!(f32::NAN.minimum(2.0).is_nan()); - assert!(2.0f32.minimum(f32::NAN).is_nan()); -} - -#[test] -fn test_maximum() { - assert!(f32::NAN.maximum(2.0).is_nan()); - assert!(2.0f32.maximum(f32::NAN).is_nan()); -} - -#[test] -fn test_nan() { - let nan: f32 = f32::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - // Ensure the quiet bit is set. - assert!(nan.to_bits() & (1 << (f32::MANTISSA_DIGITS - 2)) != 0); -} - -#[test] -fn test_infinity() { - let inf: f32 = f32::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f32 = 0.0f32; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f32 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f32 = 1.0f32; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f32.is_nan()); - assert!(!5.3f32.is_nan()); - assert!(!(-10.732f32).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f32.is_infinite()); - assert!(!42.8f32.is_infinite()); - assert!(!(-109.2f32).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f32.is_finite()); - assert!(42.8f32.is_finite()); - assert!((-109.2f32).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f32.classify(), Fp::Normal); - assert_eq!(1e-37f32.classify(), Fp::Normal); - assert_eq!(1e-38f32.classify(), Fp::Subnormal); -} - -#[test] -fn test_floor() { - assert_approx_eq!(1.0f32.floor(), 1.0f32); - assert_approx_eq!(1.3f32.floor(), 1.0f32); - assert_approx_eq!(1.5f32.floor(), 1.0f32); - assert_approx_eq!(1.7f32.floor(), 1.0f32); - assert_approx_eq!(0.0f32.floor(), 0.0f32); - assert_approx_eq!((-0.0f32).floor(), -0.0f32); - assert_approx_eq!((-1.0f32).floor(), -1.0f32); - assert_approx_eq!((-1.3f32).floor(), -2.0f32); - assert_approx_eq!((-1.5f32).floor(), -2.0f32); - assert_approx_eq!((-1.7f32).floor(), -2.0f32); -} - -#[test] -fn test_ceil() { - assert_approx_eq!(1.0f32.ceil(), 1.0f32); - assert_approx_eq!(1.3f32.ceil(), 2.0f32); - assert_approx_eq!(1.5f32.ceil(), 2.0f32); - assert_approx_eq!(1.7f32.ceil(), 2.0f32); - assert_approx_eq!(0.0f32.ceil(), 0.0f32); - assert_approx_eq!((-0.0f32).ceil(), -0.0f32); - assert_approx_eq!((-1.0f32).ceil(), -1.0f32); - assert_approx_eq!((-1.3f32).ceil(), -1.0f32); - assert_approx_eq!((-1.5f32).ceil(), -1.0f32); - assert_approx_eq!((-1.7f32).ceil(), -1.0f32); -} - -#[test] -fn test_round() { - assert_approx_eq!(2.5f32.round(), 3.0f32); - assert_approx_eq!(1.0f32.round(), 1.0f32); - assert_approx_eq!(1.3f32.round(), 1.0f32); - assert_approx_eq!(1.5f32.round(), 2.0f32); - assert_approx_eq!(1.7f32.round(), 2.0f32); - assert_approx_eq!(0.0f32.round(), 0.0f32); - assert_approx_eq!((-0.0f32).round(), -0.0f32); - assert_approx_eq!((-1.0f32).round(), -1.0f32); - assert_approx_eq!((-1.3f32).round(), -1.0f32); - assert_approx_eq!((-1.5f32).round(), -2.0f32); - assert_approx_eq!((-1.7f32).round(), -2.0f32); -} - -#[test] -fn test_round_ties_even() { - assert_approx_eq!(2.5f32.round_ties_even(), 2.0f32); - assert_approx_eq!(1.0f32.round_ties_even(), 1.0f32); - assert_approx_eq!(1.3f32.round_ties_even(), 1.0f32); - assert_approx_eq!(1.5f32.round_ties_even(), 2.0f32); - assert_approx_eq!(1.7f32.round_ties_even(), 2.0f32); - assert_approx_eq!(0.0f32.round_ties_even(), 0.0f32); - assert_approx_eq!((-0.0f32).round_ties_even(), -0.0f32); - assert_approx_eq!((-1.0f32).round_ties_even(), -1.0f32); - assert_approx_eq!((-1.3f32).round_ties_even(), -1.0f32); - assert_approx_eq!((-1.5f32).round_ties_even(), -2.0f32); - assert_approx_eq!((-1.7f32).round_ties_even(), -2.0f32); -} - -#[test] -fn test_trunc() { - assert_approx_eq!(1.0f32.trunc(), 1.0f32); - assert_approx_eq!(1.3f32.trunc(), 1.0f32); - assert_approx_eq!(1.5f32.trunc(), 1.0f32); - assert_approx_eq!(1.7f32.trunc(), 1.0f32); - assert_approx_eq!(0.0f32.trunc(), 0.0f32); - assert_approx_eq!((-0.0f32).trunc(), -0.0f32); - assert_approx_eq!((-1.0f32).trunc(), -1.0f32); - assert_approx_eq!((-1.3f32).trunc(), -1.0f32); - assert_approx_eq!((-1.5f32).trunc(), -1.0f32); - assert_approx_eq!((-1.7f32).trunc(), -1.0f32); -} - -#[test] -fn test_fract() { - assert_approx_eq!(1.0f32.fract(), 0.0f32); - assert_approx_eq!(1.3f32.fract(), 0.3f32); - assert_approx_eq!(1.5f32.fract(), 0.5f32); - assert_approx_eq!(1.7f32.fract(), 0.7f32); - assert_approx_eq!(0.0f32.fract(), 0.0f32); - assert_approx_eq!((-0.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.3f32).fract(), -0.3f32); - assert_approx_eq!((-1.5f32).fract(), -0.5f32); - assert_approx_eq!((-1.7f32).fract(), -0.7f32); -} - -#[test] -fn test_abs() { - assert_eq!(f32::INFINITY.abs(), f32::INFINITY); - assert_eq!(1f32.abs(), 1f32); - assert_eq!(0f32.abs(), 0f32); - assert_eq!((-0f32).abs(), 0f32); - assert_eq!((-1f32).abs(), 1f32); - assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY); - assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32); - assert!(f32::NAN.abs().is_nan()); -} - -#[test] -fn test_signum() { - assert_eq!(f32::INFINITY.signum(), 1f32); - assert_eq!(1f32.signum(), 1f32); - assert_eq!(0f32.signum(), 1f32); - assert_eq!((-0f32).signum(), -1f32); - assert_eq!((-1f32).signum(), -1f32); - assert_eq!(f32::NEG_INFINITY.signum(), -1f32); - assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32); - assert!(f32::NAN.signum().is_nan()); -} - -#[test] -fn test_is_sign_positive() { - assert!(f32::INFINITY.is_sign_positive()); - assert!(1f32.is_sign_positive()); - assert!(0f32.is_sign_positive()); - assert!(!(-0f32).is_sign_positive()); - assert!(!(-1f32).is_sign_positive()); - assert!(!f32::NEG_INFINITY.is_sign_positive()); - assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive()); - assert!(f32::NAN.is_sign_positive()); - assert!(!(-f32::NAN).is_sign_positive()); -} - -#[test] -fn test_is_sign_negative() { - assert!(!f32::INFINITY.is_sign_negative()); - assert!(!1f32.is_sign_negative()); - assert!(!0f32.is_sign_negative()); - assert!((-0f32).is_sign_negative()); - assert!((-1f32).is_sign_negative()); - assert!(f32::NEG_INFINITY.is_sign_negative()); - assert!((1f32 / f32::NEG_INFINITY).is_sign_negative()); - assert!(!f32::NAN.is_sign_negative()); - assert!((-f32::NAN).is_sign_negative()); -} - -#[test] -fn test_next_up() { - let tiny = f32::from_bits(TINY_BITS); - let tiny_up = f32::from_bits(TINY_UP_BITS); - let max_down = f32::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f32::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f32::from_bits(SMALLEST_NORMAL_BITS); - assert_f32_biteq!(f32::NEG_INFINITY.next_up(), f32::MIN); - assert_f32_biteq!(f32::MIN.next_up(), -max_down); - assert_f32_biteq!((-1.0 - f32::EPSILON).next_up(), -1.0); - assert_f32_biteq!((-smallest_normal).next_up(), -largest_subnormal); - assert_f32_biteq!((-tiny_up).next_up(), -tiny); - assert_f32_biteq!((-tiny).next_up(), -0.0f32); - assert_f32_biteq!((-0.0f32).next_up(), tiny); - assert_f32_biteq!(0.0f32.next_up(), tiny); - assert_f32_biteq!(tiny.next_up(), tiny_up); - assert_f32_biteq!(largest_subnormal.next_up(), smallest_normal); - assert_f32_biteq!(1.0f32.next_up(), 1.0 + f32::EPSILON); - assert_f32_biteq!(f32::MAX.next_up(), f32::INFINITY); - assert_f32_biteq!(f32::INFINITY.next_up(), f32::INFINITY); - - // Check that NaNs roundtrip. - let nan0 = f32::NAN; - let nan1 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK2); - assert_f32_biteq!(nan0.next_up(), nan0); - assert_f32_biteq!(nan1.next_up(), nan1); - assert_f32_biteq!(nan2.next_up(), nan2); -} - -#[test] -fn test_next_down() { - let tiny = f32::from_bits(TINY_BITS); - let tiny_up = f32::from_bits(TINY_UP_BITS); - let max_down = f32::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f32::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f32::from_bits(SMALLEST_NORMAL_BITS); - assert_f32_biteq!(f32::NEG_INFINITY.next_down(), f32::NEG_INFINITY); - assert_f32_biteq!(f32::MIN.next_down(), f32::NEG_INFINITY); - assert_f32_biteq!((-max_down).next_down(), f32::MIN); - assert_f32_biteq!((-1.0f32).next_down(), -1.0 - f32::EPSILON); - assert_f32_biteq!((-largest_subnormal).next_down(), -smallest_normal); - assert_f32_biteq!((-tiny).next_down(), -tiny_up); - assert_f32_biteq!((-0.0f32).next_down(), -tiny); - assert_f32_biteq!((0.0f32).next_down(), -tiny); - assert_f32_biteq!(tiny.next_down(), 0.0f32); - assert_f32_biteq!(tiny_up.next_down(), tiny); - assert_f32_biteq!(smallest_normal.next_down(), largest_subnormal); - assert_f32_biteq!((1.0 + f32::EPSILON).next_down(), 1.0f32); - assert_f32_biteq!(f32::MAX.next_down(), max_down); - assert_f32_biteq!(f32::INFINITY.next_down(), f32::MAX); - - // Check that NaNs roundtrip. - let nan0 = f32::NAN; - let nan1 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f32::from_bits(f32::NAN.to_bits() ^ NAN_MASK2); - assert_f32_biteq!(nan0.next_down(), nan0); - assert_f32_biteq!(nan1.next_down(), nan1); - assert_f32_biteq!(nan2.next_down(), nan2); -} - -#[test] -fn test_mul_add() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05); - assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65); - assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2); - assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f32.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf); -} - -#[test] -fn test_recip() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.recip(), 1.0); - assert_eq!(2.0f32.recip(), 0.5); - assert_eq!((-0.4f32).recip(), -2.5); - assert_eq!(0.0f32.recip(), inf); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); -} - -#[test] -fn test_powi() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.powi(1), 1.0); - assert_approx_eq!((-3.1f32).powi(2), 9.61); - assert_approx_eq!(5.9f32.powi(-2), 0.028727); - assert_eq!(8.3f32.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); -} - -#[test] fn test_powf() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; @@ -470,17 +28,6 @@ fn test_powf() { } #[test] -fn test_sqrt_domain() { - assert!(f32::NAN.sqrt().is_nan()); - assert!(f32::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f32).sqrt().is_nan()); - assert_eq!((-0.0f32).sqrt(), -0.0); - assert_eq!(0.0f32.sqrt(), 0.0); - assert_eq!(1.0f32.sqrt(), 1.0); - assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); -} - -#[test] fn test_exp() { assert_eq!(1.0, 0.0f32.exp()); assert_approx_eq!(2.718282, 1.0f32.exp()); @@ -574,36 +121,6 @@ fn test_log10() { } #[test] -fn test_to_degrees() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(0.0f32.to_degrees(), 0.0); - assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); - assert_eq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); -} - -#[test] -fn test_to_radians() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(0.0f32.to_radians(), 0.0); - assert_approx_eq!(154.6f32.to_radians(), 2.698279); - assert_approx_eq!((-332.31f32).to_radians(), -5.799903); - assert_eq!(180.0f32.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); -} - -#[test] fn test_asinh() { assert_eq!(0.0f32.asinh(), 0.0f32); assert_eq!((-0.0f32).asinh(), -0.0f32); @@ -734,207 +251,3 @@ fn test_real_consts() { assert_approx_eq!(ln_2, 2f32.ln()); assert_approx_eq!(ln_10, 10f32.ln()); } - -#[test] -fn test_float_bits_conv() { - assert_eq!((1f32).to_bits(), 0x3f800000); - assert_eq!((12.5f32).to_bits(), 0x41480000); - assert_eq!((1337f32).to_bits(), 0x44a72000); - assert_eq!((-14.25f32).to_bits(), 0xc1640000); - assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); - assert_approx_eq!(f32::from_bits(0x41480000), 12.5); - assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); - assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f32::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f32::NAN.to_bits() ^ NAN_MASK2; - assert!(f32::from_bits(masked_nan1).is_nan()); - assert!(f32::from_bits(masked_nan2).is_nan()); - - assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2); -} - -#[test] -#[should_panic] -fn test_clamp_min_greater_than_max() { - let _ = 1.0f32.clamp(3.0, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_min_is_nan() { - let _ = 1.0f32.clamp(f32::NAN, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_max_is_nan() { - let _ = 1.0f32.clamp(3.0, f32::NAN); -} - -#[test] -fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u32 { - 1 << (f32::MANTISSA_DIGITS - 2) - } - - fn min_subnorm() -> f32 { - f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0) - } - - fn max_subnorm() -> f32 { - f32::MIN_POSITIVE - min_subnorm() - } - - fn q_nan() -> f32 { - f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f32 { - f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42) - } - - assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0)); - assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX)); - assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); - assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0)); - assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX)); - assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan())); - assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5)); - assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0)); - assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); - assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); -} - -#[test] -fn test_algebraic() { - let a: f32 = 123.0; - let b: f32 = 456.0; - - // Check that individual operations match their primitive counterparts. - // - // This is a check of current implementations and does NOT imply any form of - // guarantee about future behavior. The compiler reserves the right to make - // these operations inexact matches in the future. - let eps_add = if cfg!(miri) { 1e-3 } else { 0.0 }; - let eps_mul = if cfg!(miri) { 1e-1 } else { 0.0 }; - let eps_div = if cfg!(miri) { 1e-4 } else { 0.0 }; - - assert_approx_eq!(a.algebraic_add(b), a + b, eps_add); - assert_approx_eq!(a.algebraic_sub(b), a - b, eps_add); - assert_approx_eq!(a.algebraic_mul(b), a * b, eps_mul); - assert_approx_eq!(a.algebraic_div(b), a / b, eps_div); - assert_approx_eq!(a.algebraic_rem(b), a % b, eps_div); -} diff --git a/library/std/tests/floats/f64.rs b/library/std/tests/floats/f64.rs index de9c27eb33d..2d8dd1cf091 100644 --- a/library/std/tests/floats/f64.rs +++ b/library/std/tests/floats/f64.rs @@ -1,26 +1,4 @@ use std::f64::consts; -use std::num::FpCategory as Fp; - -/// Smallest number -const TINY_BITS: u64 = 0x1; - -/// Next smallest number -const TINY_UP_BITS: u64 = 0x2; - -/// Exponent = 0b11...10, Sifnificand 0b1111..10. Min val > 0 -const MAX_DOWN_BITS: u64 = 0x7fef_ffff_ffff_fffe; - -/// Zeroed exponent, full significant -const LARGEST_SUBNORMAL_BITS: u64 = 0x000f_ffff_ffff_ffff; - -/// Exponent = 0b1, zeroed significand -const SMALLEST_NORMAL_BITS: u64 = 0x0010_0000_0000_0000; - -/// First pattern over the mantissa -const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; - -/// Second pattern over the mantissa -const NAN_MASK2: u64 = 0x0005_5555_5555_5555; #[allow(unused_macros)] macro_rules! assert_f64_biteq { @@ -34,411 +12,6 @@ macro_rules! assert_f64_biteq { } #[test] -fn test_num_f64() { - crate::test_num(10f64, 2f64); -} - -#[test] -fn test_min_nan() { - assert_eq!(f64::NAN.min(2.0), 2.0); - assert_eq!(2.0f64.min(f64::NAN), 2.0); -} - -#[test] -fn test_max_nan() { - assert_eq!(f64::NAN.max(2.0), 2.0); - assert_eq!(2.0f64.max(f64::NAN), 2.0); -} - -#[test] -fn test_nan() { - let nan: f64 = f64::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - // Ensure the quiet bit is set. - assert!(nan.to_bits() & (1 << (f64::MANTISSA_DIGITS - 2)) != 0); -} - -#[test] -fn test_infinity() { - let inf: f64 = f64::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - -#[test] -fn test_neg_infinity() { - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - -#[test] -fn test_zero() { - let zero: f64 = 0.0f64; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - -#[test] -fn test_neg_zero() { - let neg_zero: f64 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - -#[test] -fn test_one() { - let one: f64 = 1.0f64; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - -#[test] -fn test_is_nan() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f64.is_nan()); - assert!(!5.3f64.is_nan()); - assert!(!(-10.732f64).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - -#[test] -fn test_is_infinite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f64.is_infinite()); - assert!(!42.8f64.is_infinite()); - assert!(!(-109.2f64).is_infinite()); -} - -#[test] -fn test_is_finite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f64.is_finite()); - assert!(42.8f64.is_finite()); - assert!((-109.2f64).is_finite()); -} - -#[test] -fn test_is_normal() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); -} - -#[test] -fn test_classify() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1e-307f64.classify(), Fp::Normal); - assert_eq!(1e-308f64.classify(), Fp::Subnormal); -} - -#[test] -fn test_floor() { - assert_approx_eq!(1.0f64.floor(), 1.0f64); - assert_approx_eq!(1.3f64.floor(), 1.0f64); - assert_approx_eq!(1.5f64.floor(), 1.0f64); - assert_approx_eq!(1.7f64.floor(), 1.0f64); - assert_approx_eq!(0.0f64.floor(), 0.0f64); - assert_approx_eq!((-0.0f64).floor(), -0.0f64); - assert_approx_eq!((-1.0f64).floor(), -1.0f64); - assert_approx_eq!((-1.3f64).floor(), -2.0f64); - assert_approx_eq!((-1.5f64).floor(), -2.0f64); - assert_approx_eq!((-1.7f64).floor(), -2.0f64); -} - -#[test] -fn test_ceil() { - assert_approx_eq!(1.0f64.ceil(), 1.0f64); - assert_approx_eq!(1.3f64.ceil(), 2.0f64); - assert_approx_eq!(1.5f64.ceil(), 2.0f64); - assert_approx_eq!(1.7f64.ceil(), 2.0f64); - assert_approx_eq!(0.0f64.ceil(), 0.0f64); - assert_approx_eq!((-0.0f64).ceil(), -0.0f64); - assert_approx_eq!((-1.0f64).ceil(), -1.0f64); - assert_approx_eq!((-1.3f64).ceil(), -1.0f64); - assert_approx_eq!((-1.5f64).ceil(), -1.0f64); - assert_approx_eq!((-1.7f64).ceil(), -1.0f64); -} - -#[test] -fn test_round() { - assert_approx_eq!(2.5f64.round(), 3.0f64); - assert_approx_eq!(1.0f64.round(), 1.0f64); - assert_approx_eq!(1.3f64.round(), 1.0f64); - assert_approx_eq!(1.5f64.round(), 2.0f64); - assert_approx_eq!(1.7f64.round(), 2.0f64); - assert_approx_eq!(0.0f64.round(), 0.0f64); - assert_approx_eq!((-0.0f64).round(), -0.0f64); - assert_approx_eq!((-1.0f64).round(), -1.0f64); - assert_approx_eq!((-1.3f64).round(), -1.0f64); - assert_approx_eq!((-1.5f64).round(), -2.0f64); - assert_approx_eq!((-1.7f64).round(), -2.0f64); -} - -#[test] -fn test_round_ties_even() { - assert_approx_eq!(2.5f64.round_ties_even(), 2.0f64); - assert_approx_eq!(1.0f64.round_ties_even(), 1.0f64); - assert_approx_eq!(1.3f64.round_ties_even(), 1.0f64); - assert_approx_eq!(1.5f64.round_ties_even(), 2.0f64); - assert_approx_eq!(1.7f64.round_ties_even(), 2.0f64); - assert_approx_eq!(0.0f64.round_ties_even(), 0.0f64); - assert_approx_eq!((-0.0f64).round_ties_even(), -0.0f64); - assert_approx_eq!((-1.0f64).round_ties_even(), -1.0f64); - assert_approx_eq!((-1.3f64).round_ties_even(), -1.0f64); - assert_approx_eq!((-1.5f64).round_ties_even(), -2.0f64); - assert_approx_eq!((-1.7f64).round_ties_even(), -2.0f64); -} - -#[test] -fn test_trunc() { - assert_approx_eq!(1.0f64.trunc(), 1.0f64); - assert_approx_eq!(1.3f64.trunc(), 1.0f64); - assert_approx_eq!(1.5f64.trunc(), 1.0f64); - assert_approx_eq!(1.7f64.trunc(), 1.0f64); - assert_approx_eq!(0.0f64.trunc(), 0.0f64); - assert_approx_eq!((-0.0f64).trunc(), -0.0f64); - assert_approx_eq!((-1.0f64).trunc(), -1.0f64); - assert_approx_eq!((-1.3f64).trunc(), -1.0f64); - assert_approx_eq!((-1.5f64).trunc(), -1.0f64); - assert_approx_eq!((-1.7f64).trunc(), -1.0f64); -} - -#[test] -fn test_fract() { - assert_approx_eq!(1.0f64.fract(), 0.0f64); - assert_approx_eq!(1.3f64.fract(), 0.3f64); - assert_approx_eq!(1.5f64.fract(), 0.5f64); - assert_approx_eq!(1.7f64.fract(), 0.7f64); - assert_approx_eq!(0.0f64.fract(), 0.0f64); - assert_approx_eq!((-0.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.3f64).fract(), -0.3f64); - assert_approx_eq!((-1.5f64).fract(), -0.5f64); - assert_approx_eq!((-1.7f64).fract(), -0.7f64); -} - -#[test] -fn test_abs() { - assert_eq!(f64::INFINITY.abs(), f64::INFINITY); - assert_eq!(1f64.abs(), 1f64); - assert_eq!(0f64.abs(), 0f64); - assert_eq!((-0f64).abs(), 0f64); - assert_eq!((-1f64).abs(), 1f64); - assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY); - assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64); - assert!(f64::NAN.abs().is_nan()); -} - -#[test] -fn test_signum() { - assert_eq!(f64::INFINITY.signum(), 1f64); - assert_eq!(1f64.signum(), 1f64); - assert_eq!(0f64.signum(), 1f64); - assert_eq!((-0f64).signum(), -1f64); - assert_eq!((-1f64).signum(), -1f64); - assert_eq!(f64::NEG_INFINITY.signum(), -1f64); - assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64); - assert!(f64::NAN.signum().is_nan()); -} - -#[test] -fn test_is_sign_positive() { - assert!(f64::INFINITY.is_sign_positive()); - assert!(1f64.is_sign_positive()); - assert!(0f64.is_sign_positive()); - assert!(!(-0f64).is_sign_positive()); - assert!(!(-1f64).is_sign_positive()); - assert!(!f64::NEG_INFINITY.is_sign_positive()); - assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive()); - assert!(f64::NAN.is_sign_positive()); - assert!(!(-f64::NAN).is_sign_positive()); -} - -#[test] -fn test_is_sign_negative() { - assert!(!f64::INFINITY.is_sign_negative()); - assert!(!1f64.is_sign_negative()); - assert!(!0f64.is_sign_negative()); - assert!((-0f64).is_sign_negative()); - assert!((-1f64).is_sign_negative()); - assert!(f64::NEG_INFINITY.is_sign_negative()); - assert!((1f64 / f64::NEG_INFINITY).is_sign_negative()); - assert!(!f64::NAN.is_sign_negative()); - assert!((-f64::NAN).is_sign_negative()); -} - -#[test] -fn test_next_up() { - let tiny = f64::from_bits(TINY_BITS); - let tiny_up = f64::from_bits(TINY_UP_BITS); - let max_down = f64::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f64::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f64::from_bits(SMALLEST_NORMAL_BITS); - assert_f64_biteq!(f64::NEG_INFINITY.next_up(), f64::MIN); - assert_f64_biteq!(f64::MIN.next_up(), -max_down); - assert_f64_biteq!((-1.0 - f64::EPSILON).next_up(), -1.0); - assert_f64_biteq!((-smallest_normal).next_up(), -largest_subnormal); - assert_f64_biteq!((-tiny_up).next_up(), -tiny); - assert_f64_biteq!((-tiny).next_up(), -0.0f64); - assert_f64_biteq!((-0.0f64).next_up(), tiny); - assert_f64_biteq!(0.0f64.next_up(), tiny); - assert_f64_biteq!(tiny.next_up(), tiny_up); - assert_f64_biteq!(largest_subnormal.next_up(), smallest_normal); - assert_f64_biteq!(1.0f64.next_up(), 1.0 + f64::EPSILON); - assert_f64_biteq!(f64::MAX.next_up(), f64::INFINITY); - assert_f64_biteq!(f64::INFINITY.next_up(), f64::INFINITY); - - let nan0 = f64::NAN; - let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2); - assert_f64_biteq!(nan0.next_up(), nan0); - assert_f64_biteq!(nan1.next_up(), nan1); - assert_f64_biteq!(nan2.next_up(), nan2); -} - -#[test] -fn test_next_down() { - let tiny = f64::from_bits(TINY_BITS); - let tiny_up = f64::from_bits(TINY_UP_BITS); - let max_down = f64::from_bits(MAX_DOWN_BITS); - let largest_subnormal = f64::from_bits(LARGEST_SUBNORMAL_BITS); - let smallest_normal = f64::from_bits(SMALLEST_NORMAL_BITS); - assert_f64_biteq!(f64::NEG_INFINITY.next_down(), f64::NEG_INFINITY); - assert_f64_biteq!(f64::MIN.next_down(), f64::NEG_INFINITY); - assert_f64_biteq!((-max_down).next_down(), f64::MIN); - assert_f64_biteq!((-1.0f64).next_down(), -1.0 - f64::EPSILON); - assert_f64_biteq!((-largest_subnormal).next_down(), -smallest_normal); - assert_f64_biteq!((-tiny).next_down(), -tiny_up); - assert_f64_biteq!((-0.0f64).next_down(), -tiny); - assert_f64_biteq!((0.0f64).next_down(), -tiny); - assert_f64_biteq!(tiny.next_down(), 0.0f64); - assert_f64_biteq!(tiny_up.next_down(), tiny); - assert_f64_biteq!(smallest_normal.next_down(), largest_subnormal); - assert_f64_biteq!((1.0 + f64::EPSILON).next_down(), 1.0f64); - assert_f64_biteq!(f64::MAX.next_down(), max_down); - assert_f64_biteq!(f64::INFINITY.next_down(), f64::MAX); - - let nan0 = f64::NAN; - let nan1 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK1); - let nan2 = f64::from_bits(f64::NAN.to_bits() ^ NAN_MASK2); - assert_f64_biteq!(nan0.next_down(), nan0); - assert_f64_biteq!(nan1.next_down(), nan1); - assert_f64_biteq!(nan2.next_down(), nan2); -} - -#[test] -fn test_mul_add() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); - assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); - assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); - assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f64.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); -} - -#[test] -fn test_recip() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(1.0f64.recip(), 1.0); - assert_eq!(2.0f64.recip(), 0.5); - assert_eq!((-0.4f64).recip(), -2.5); - assert_eq!(0.0f64.recip(), inf); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); -} - -#[test] -fn test_powi() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(1.0f64.powi(1), 1.0); - assert_approx_eq!((-3.1f64).powi(2), 9.61); - assert_approx_eq!(5.9f64.powi(-2), 0.028727); - assert_eq!(8.3f64.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); -} - -#[test] fn test_powf() { let nan: f64 = f64::NAN; let inf: f64 = f64::INFINITY; @@ -455,17 +28,6 @@ fn test_powf() { } #[test] -fn test_sqrt_domain() { - assert!(f64::NAN.sqrt().is_nan()); - assert!(f64::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f64).sqrt().is_nan()); - assert_eq!((-0.0f64).sqrt(), -0.0); - assert_eq!(0.0f64.sqrt(), 0.0); - assert_eq!(1.0f64.sqrt(), 1.0); - assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); -} - -#[test] fn test_exp() { assert_eq!(1.0, 0.0f64.exp()); assert_approx_eq!(2.718282, 1.0f64.exp()); @@ -559,35 +121,6 @@ fn test_log10() { } #[test] -fn test_to_degrees() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(0.0f64.to_degrees(), 0.0); - assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); - assert_eq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); -} - -#[test] -fn test_to_radians() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(0.0f64.to_radians(), 0.0); - assert_approx_eq!(154.6f64.to_radians(), 2.698279); - assert_approx_eq!((-332.31f64).to_radians(), -5.799903); - assert_eq!(180.0f64.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); -} - -#[test] fn test_asinh() { assert_eq!(0.0f64.asinh(), 0.0f64); assert_eq!((-0.0f64).asinh(), -0.0f64); @@ -714,204 +247,3 @@ fn test_real_consts() { assert_approx_eq!(ln_2, 2f64.ln()); assert_approx_eq!(ln_10, 10f64.ln()); } - -#[test] -fn test_float_bits_conv() { - assert_eq!((1f64).to_bits(), 0x3ff0000000000000); - assert_eq!((12.5f64).to_bits(), 0x4029000000000000); - assert_eq!((1337f64).to_bits(), 0x4094e40000000000); - assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); - assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); - assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); - assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); - assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - let masked_nan1 = f64::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f64::NAN.to_bits() ^ NAN_MASK2; - assert!(f64::from_bits(masked_nan1).is_nan()); - assert!(f64::from_bits(masked_nan2).is_nan()); - - assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2); -} - -#[test] -#[should_panic] -fn test_clamp_min_greater_than_max() { - let _ = 1.0f64.clamp(3.0, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_min_is_nan() { - let _ = 1.0f64.clamp(f64::NAN, 1.0); -} - -#[test] -#[should_panic] -fn test_clamp_max_is_nan() { - let _ = 1.0f64.clamp(3.0, f64::NAN); -} - -#[test] -fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u64 { - 1 << (f64::MANTISSA_DIGITS - 2) - } - - fn min_subnorm() -> f64 { - f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0) - } - - fn max_subnorm() -> f64 { - f64::MIN_POSITIVE - min_subnorm() - } - - fn q_nan() -> f64 { - f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f64 { - f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42) - } - - assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0)); - assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX)); - assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); - assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0)); - assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX)); - assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan())); - assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5)); - assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0)); - assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); - assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); -} - -#[test] -fn test_algebraic() { - let a: f64 = 123.0; - let b: f64 = 456.0; - - // Check that individual operations match their primitive counterparts. - // - // This is a check of current implementations and does NOT imply any form of - // guarantee about future behavior. The compiler reserves the right to make - // these operations inexact matches in the future. - let eps = if cfg!(miri) { 1e-6 } else { 0.0 }; - - assert_approx_eq!(a.algebraic_add(b), a + b, eps); - assert_approx_eq!(a.algebraic_sub(b), a - b, eps); - assert_approx_eq!(a.algebraic_mul(b), a * b, eps); - assert_approx_eq!(a.algebraic_div(b), a / b, eps); - assert_approx_eq!(a.algebraic_rem(b), a % b, eps); -} diff --git a/library/std/tests/floats/lib.rs b/library/std/tests/floats/lib.rs index 453a2d533ab..8bb8eb4bfc1 100644 --- a/library/std/tests/floats/lib.rs +++ b/library/std/tests/floats/lib.rs @@ -1,5 +1,4 @@ -#![feature(f16, f128, float_algebraic, float_gamma, float_minimum_maximum)] -#![feature(cfg_target_has_reliable_f16_f128)] +#![feature(f16, f128, float_gamma, float_minimum_maximum, cfg_target_has_reliable_f16_f128)] #![expect(internal_features)] // for reliable_f16_f128 use std::fmt; diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 9ed5b519b6e..9222710b843 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -47,7 +47,7 @@ fi # we only ensure that all assertions still pass. MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zmir-opt-level=4 -Cdebug-assertions=yes" \ MIRI_SKIP_UI_CHECKS=1 \ - python3 "$X_PY" test --stage 2 src/tools/miri -- tests/{pass,panic} + python3 "$X_PY" test --stage 2 src/tools/miri -- tests/pass tests/panic # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. case $HOST_TARGET in diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml index 167aece0ed6..01f127ad390 100644 --- a/src/doc/rustc/book.toml +++ b/src/doc/rustc/book.toml @@ -6,6 +6,8 @@ title = "The rustc book" [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc" edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/{path}" +additional-css = ["theme/pagetoc.css"] +additional-js = ["theme/pagetoc.js"] [output.html.search] use-boolean-and = true diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css new file mode 100644 index 00000000000..58ca1f8b26f --- /dev/null +++ b/src/doc/rustc/theme/pagetoc.css @@ -0,0 +1,84 @@ +/* Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) */ + +:root { + --toc-width: 270px; + --center-content-toc-shift: calc(-1 * var(--toc-width) / 2); +} + +.nav-chapters { + /* adjust width of buttons that bring to the previous or the next page */ + min-width: 50px; +} + +@media only screen { + @media (max-width: 1179px) { + .sidebar-hidden #sidetoc { + display: none; + } + } + + @media (max-width: 1439px) { + .sidebar-visible #sidetoc { + display: none; + } + } + + @media (1180px <= width <= 1439px) { + .sidebar-hidden main { + position: relative; + left: var(--center-content-toc-shift); + } + } + + @media (1440px <= width <= 1700px) { + .sidebar-visible main { + position: relative; + left: var(--center-content-toc-shift); + } + } + + #sidetoc { + margin-left: calc(100% + 20px); + } + #pagetoc { + position: fixed; + /* adjust TOC width */ + width: var(--toc-width); + height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); + overflow: auto; + } + #pagetoc a { + border-left: 1px solid var(--sidebar-bg); + color: var(--sidebar-fg) !important; + display: block; + padding-bottom: 5px; + padding-top: 5px; + padding-left: 10px; + text-align: left; + text-decoration: none; + } + #pagetoc a:hover, + #pagetoc a.active { + background: var(--sidebar-bg); + color: var(--sidebar-active) !important; + } + #pagetoc .active { + background: var(--sidebar-bg); + color: var(--sidebar-active); + } + #pagetoc .pagetoc-H2 { + padding-left: 20px; + } + #pagetoc .pagetoc-H3 { + padding-left: 40px; + } + #pagetoc .pagetoc-H4 { + padding-left: 60px; + } +} + +@media print { + #sidetoc { + display: none; + } +} diff --git a/src/doc/rustc/theme/pagetoc.js b/src/doc/rustc/theme/pagetoc.js new file mode 100644 index 00000000000..927a5b10749 --- /dev/null +++ b/src/doc/rustc/theme/pagetoc.js @@ -0,0 +1,104 @@ +// Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) + +let activeHref = location.href; +function updatePageToc(elem = undefined) { + let selectedPageTocElem = elem; + const pagetoc = document.getElementById("pagetoc"); + + function getRect(element) { + return element.getBoundingClientRect(); + } + + function overflowTop(container, element) { + return getRect(container).top - getRect(element).top; + } + + function overflowBottom(container, element) { + return getRect(container).bottom - getRect(element).bottom; + } + + // We've not selected a heading to highlight, and the URL needs updating + // so we need to find a heading based on the URL + if (selectedPageTocElem === undefined && location.href !== activeHref) { + activeHref = location.href; + for (const pageTocElement of pagetoc.children) { + if (pageTocElement.href === activeHref) { + selectedPageTocElem = pageTocElement; + } + } + } + + // We still don't have a selected heading, let's try and find the most + // suitable heading based on the scroll position + if (selectedPageTocElem === undefined) { + const margin = window.innerHeight / 3; + + const headers = document.getElementsByClassName("header"); + for (let i = 0; i < headers.length; i++) { + const header = headers[i]; + if (selectedPageTocElem === undefined && getRect(header).top >= 0) { + if (getRect(header).top < margin) { + selectedPageTocElem = header; + } else { + selectedPageTocElem = headers[Math.max(0, i - 1)]; + } + } + // a very long last section's heading is over the screen + if (selectedPageTocElem === undefined && i === headers.length - 1) { + selectedPageTocElem = header; + } + } + } + + // Remove the active flag from all pagetoc elements + for (const pageTocElement of pagetoc.children) { + pageTocElement.classList.remove("active"); + } + + // If we have a selected heading, set it to active and scroll to it + if (selectedPageTocElem !== undefined) { + for (const pageTocElement of pagetoc.children) { + if (selectedPageTocElem.href.localeCompare(pageTocElement.href) === 0) { + pageTocElement.classList.add("active"); + if (overflowTop(pagetoc, pageTocElement) > 0) { + pagetoc.scrollTop = pageTocElement.offsetTop; + } + if (overflowBottom(pagetoc, pageTocElement) < 0) { + pagetoc.scrollTop -= overflowBottom(pagetoc, pageTocElement); + } + } + } + } +} + +if (document.getElementById("sidetoc") === null && + document.getElementsByClassName("header").length > 0) { + // The sidetoc element doesn't exist yet, let's create it + + // Create the empty sidetoc and pagetoc elements + const sidetoc = document.createElement("div"); + const pagetoc = document.createElement("div"); + sidetoc.id = "sidetoc"; + pagetoc.id = "pagetoc"; + sidetoc.appendChild(pagetoc); + + // And append them to the current DOM + const main = document.querySelector('main'); + main.insertBefore(sidetoc, main.firstChild); + + // Populate sidebar on load + window.addEventListener("load", () => { + for (const header of document.getElementsByClassName("header")) { + const link = document.createElement("a"); + link.innerHTML = header.innerHTML; + link.href = header.hash; + link.classList.add("pagetoc-" + header.parentElement.tagName); + document.getElementById("pagetoc").appendChild(link); + link.onclick = () => updatePageToc(link); + } + updatePageToc(); + }); + + // Update page table of contents selected heading on scroll + window.addEventListener("scroll", () => updatePageToc()); +} diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 1541e7201ce..439777843fb 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -144,7 +144,7 @@ impl Cfg { /// Whether the configuration consists of just `Cfg` or `Not`. fn is_simple(&self) -> bool { - match *self { + match self { Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) => true, Cfg::All(..) | Cfg::Any(..) => false, } @@ -152,7 +152,7 @@ impl Cfg { /// Whether the configuration consists of just `Cfg`, `Not` or `All`. fn is_all(&self) -> bool { - match *self { + match self { Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) | Cfg::All(..) => true, Cfg::Any(..) => false, } @@ -204,7 +204,7 @@ impl Cfg { } fn should_append_only_to_description(&self) -> bool { - match *self { + match self { Cfg::False | Cfg::True => false, Cfg::Any(..) | Cfg::All(..) | Cfg::Cfg(..) => true, Cfg::Not(box Cfg::Cfg(..)) => true, @@ -261,17 +261,17 @@ impl ops::Not for Cfg { impl ops::BitAndAssign for Cfg { fn bitand_assign(&mut self, other: Cfg) { match (self, other) { - (&mut Cfg::False, _) | (_, Cfg::True) => {} + (Cfg::False, _) | (_, Cfg::True) => {} (s, Cfg::False) => *s = Cfg::False, - (s @ &mut Cfg::True, b) => *s = b, - (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => { + (s @ Cfg::True, b) => *s = b, + (Cfg::All(a), Cfg::All(ref mut b)) => { for c in b.drain(..) { if !a.contains(&c) { a.push(c); } } } - (&mut Cfg::All(ref mut a), ref mut b) => { + (Cfg::All(a), ref mut b) => { if !a.contains(b) { a.push(mem::replace(b, Cfg::True)); } @@ -305,15 +305,15 @@ impl ops::BitOrAssign for Cfg { fn bitor_assign(&mut self, other: Cfg) { match (self, other) { (Cfg::True, _) | (_, Cfg::False) | (_, Cfg::True) => {} - (s @ &mut Cfg::False, b) => *s = b, - (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => { + (s @ Cfg::False, b) => *s = b, + (Cfg::Any(a), Cfg::Any(ref mut b)) => { for c in b.drain(..) { if !a.contains(&c) { a.push(c); } } } - (&mut Cfg::Any(ref mut a), ref mut b) => { + (Cfg::Any(a), ref mut b) => { if !a.contains(b) { a.push(mem::replace(b, Cfg::True)); } @@ -440,40 +440,34 @@ impl Display<'_> { impl fmt::Display for Display<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self.0 { - Cfg::Not(ref child) => match **child { - Cfg::Any(ref sub_cfgs) => { - let separator = - if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " }; - fmt.write_str("neither ")?; - - sub_cfgs - .iter() - .map(|sub_cfg| { - fmt::from_fn(|fmt| { - write_with_opt_paren( - fmt, - !sub_cfg.is_all(), - Display(sub_cfg, self.1), - ) - }) + match self.0 { + Cfg::Not(box Cfg::Any(sub_cfgs)) => { + let separator = + if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " }; + fmt.write_str("neither ")?; + + sub_cfgs + .iter() + .map(|sub_cfg| { + fmt::from_fn(|fmt| { + write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1)) }) - .joined(separator, fmt) - } - ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Display(simple, self.1)), - ref c => write!(fmt, "not ({})", Display(c, self.1)), - }, + }) + .joined(separator, fmt) + } + Cfg::Not(box simple @ Cfg::Cfg(..)) => write!(fmt, "non-{}", Display(simple, self.1)), + Cfg::Not(box c) => write!(fmt, "not ({})", Display(c, self.1)), - Cfg::Any(ref sub_cfgs) => { + Cfg::Any(sub_cfgs) => { let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " }; self.display_sub_cfgs(fmt, sub_cfgs, separator) } - Cfg::All(ref sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "), + Cfg::All(sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "), Cfg::True => fmt.write_str("everywhere"), Cfg::False => fmt.write_str("nowhere"), - Cfg::Cfg(name, value) => { + &Cfg::Cfg(name, value) => { let human_readable = match (name, value) { (sym::unix, None) => "Unix", (sym::windows, None) => "Windows", diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 622a410837b..28dfa01534e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -224,9 +224,9 @@ fn clean_generic_bound<'tcx>( bound: &hir::GenericBound<'tcx>, cx: &mut DocContext<'tcx>, ) -> Option<GenericBound> { - Some(match *bound { + Some(match bound { hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)), - hir::GenericBound::Trait(ref t) => { + hir::GenericBound::Trait(t) => { // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. if let hir::BoundConstness::Maybe(_) = t.modifiers.constness && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap()) @@ -352,8 +352,8 @@ fn clean_where_predicate<'tcx>( if !predicate.kind.in_where_clause() { return None; } - Some(match *predicate.kind { - hir::WherePredicateKind::BoundPredicate(ref wbp) => { + Some(match predicate.kind { + hir::WherePredicateKind::BoundPredicate(wbp) => { let bound_params = wbp .bound_generic_params .iter() @@ -366,12 +366,12 @@ fn clean_where_predicate<'tcx>( } } - hir::WherePredicateKind::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate { + hir::WherePredicateKind::RegionPredicate(wrp) => WherePredicate::RegionPredicate { lifetime: clean_lifetime(wrp.lifetime, cx), bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }, - hir::WherePredicateKind::EqPredicate(ref wrp) => WherePredicate::EqPredicate { + hir::WherePredicateKind::EqPredicate(wrp) => WherePredicate::EqPredicate { lhs: clean_ty(wrp.lhs_ty, cx), rhs: clean_ty(wrp.rhs_ty, cx).into(), }, @@ -2112,7 +2112,7 @@ pub(crate) fn clean_middle_ty<'tcx>( ); Type::Path { path } } - ty::Dynamic(obj, ref reg, _) => { + ty::Dynamic(obj, reg, _) => { // HACK: pick the first `did` as the `did` of the trait object. Someone // might want to implement "native" support for marker-trait-only // trait objects. @@ -2129,7 +2129,7 @@ pub(crate) fn clean_middle_ty<'tcx>( inline::record_extern_fqn(cx, did, ItemType::Trait); - let lifetime = clean_trait_object_lifetime_bound(*reg, container, obj, cx.tcx); + let lifetime = clean_trait_object_lifetime_bound(reg, container, obj, cx.tcx); let mut bounds = dids .map(|did| { @@ -2846,7 +2846,7 @@ fn clean_maybe_renamed_item<'tcx>( )); return ret; } - ItemKind::Enum(_, ref def, generics) => EnumItem(Enum { + ItemKind::Enum(_, def, generics) => EnumItem(Enum { variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), generics: clean_generics(generics, cx), }), @@ -2854,11 +2854,11 @@ fn clean_maybe_renamed_item<'tcx>( generics: clean_generics(generics, cx), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }), - ItemKind::Union(_, ref variant_data, generics) => UnionItem(Union { + ItemKind::Union(_, variant_data, generics) => UnionItem(Union { generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), - ItemKind::Struct(_, ref variant_data, generics) => StructItem(Struct { + ItemKind::Struct(_, variant_data, generics) => StructItem(Struct { ctor_kind: variant_data.ctor_kind(), generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 15890fff0c3..75f1bc9549c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1337,9 +1337,9 @@ pub(crate) enum WherePredicate { impl WherePredicate { pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> { - match *self { - WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds), - WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds), + match self { + WherePredicate::BoundPredicate { bounds, .. } => Some(bounds), + WherePredicate::RegionPredicate { bounds, .. } => Some(bounds), _ => None, } } @@ -1709,13 +1709,13 @@ impl Type { /// /// [clean]: crate::clean pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> { - let t: PrimitiveType = match *self { - Type::Path { ref path } => return Some(path.def_id()), - DynTrait(ref bounds, _) => return bounds.first().map(|b| b.trait_.def_id()), - Primitive(p) => return cache.primitive_locations.get(&p).cloned(), + let t: PrimitiveType = match self { + Type::Path { path } => return Some(path.def_id()), + DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()), + Primitive(p) => return cache.primitive_locations.get(p).cloned(), BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference, - BorrowedRef { ref type_, .. } => return type_.def_id(cache), - Tuple(ref tys) => { + BorrowedRef { type_, .. } => return type_.def_id(cache), + Tuple(tys) => { if tys.is_empty() { PrimitiveType::Unit } else { @@ -1727,7 +1727,7 @@ impl Type { Array(..) => PrimitiveType::Array, Type::Pat(..) => PrimitiveType::Pat, RawPointer(..) => PrimitiveType::RawPointer, - QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache), + QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache), Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None, }; Primitive(t).def_id(cache) diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index de6537e992f..3aba7a370ad 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -70,12 +70,12 @@ impl Serialize for ItemType { impl<'a> From<&'a clean::Item> for ItemType { fn from(item: &'a clean::Item) -> ItemType { - let kind = match item.kind { - clean::StrippedItem(box ref item) => item, - ref kind => kind, + let kind = match &item.kind { + clean::StrippedItem(box item) => item, + kind => kind, }; - match *kind { + match kind { clean::ModuleItem(..) => ItemType::Module, clean::ExternCrateItem { .. } => ItemType::ExternCrate, clean::ImportItem(..) => ItemType::Import, @@ -103,7 +103,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::ForeignTypeItem => ItemType::ForeignType, clean::KeywordItem => ItemType::Keyword, clean::TraitAliasItem(..) => ItemType::TraitAlias, - clean::ProcMacroItem(ref mac) => match mac.kind { + clean::ProcMacroItem(mac) => match mac.kind { MacroKind::Bang => ItemType::Macro, MacroKind::Attr => ItemType::ProcAttribute, MacroKind::Derive => ItemType::ProcDerive, @@ -134,22 +134,15 @@ impl ItemType { DefKind::Trait => Self::Trait, DefKind::TyAlias => Self::TypeAlias, DefKind::TraitAlias => Self::TraitAlias, - DefKind::Macro(kind) => match kind { - MacroKind::Bang => ItemType::Macro, - MacroKind::Attr => ItemType::ProcAttribute, - MacroKind::Derive => ItemType::ProcDerive, - }, + DefKind::Macro(MacroKind::Bang) => ItemType::Macro, + DefKind::Macro(MacroKind::Attr) => ItemType::ProcAttribute, + DefKind::Macro(MacroKind::Derive) => ItemType::ProcDerive, DefKind::ForeignTy => Self::ForeignType, DefKind::Variant => Self::Variant, DefKind::Field => Self::StructField, DefKind::AssocTy => Self::AssocType, - DefKind::AssocFn => { - if let Some(DefKind::Trait) = parent_kind { - Self::TyMethod - } else { - Self::Method - } - } + DefKind::AssocFn if let Some(DefKind::Trait) = parent_kind => Self::TyMethod, + DefKind::AssocFn => Self::Method, DefKind::Ctor(CtorOf::Struct, _) => Self::Struct, DefKind::Ctor(CtorOf::Variant, _) => Self::Variant, DefKind::AssocConst => Self::AssocConst, @@ -170,7 +163,7 @@ impl ItemType { } pub(crate) fn as_str(&self) -> &'static str { - match *self { + match self { ItemType::Module => "mod", ItemType::ExternCrate => "externcrate", ItemType::Import => "import", @@ -199,10 +192,10 @@ impl ItemType { } } pub(crate) fn is_method(&self) -> bool { - matches!(*self, ItemType::Method | ItemType::TyMethod) + matches!(self, ItemType::Method | ItemType::TyMethod) } pub(crate) fn is_adt(&self) -> bool { - matches!(*self, ItemType::Struct | ItemType::Union | ItemType::Enum) + matches!(self, ItemType::Struct | ItemType::Union | ItemType::Enum) } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 299fd6b9adb..8c7ab640bed 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -856,15 +856,15 @@ fn fmt_type( ) -> fmt::Result { trace!("fmt_type(t = {t:?})"); - match *t { + match t { clean::Generic(name) => f.write_str(name.as_str()), clean::SelfTy => f.write_str("Self"), - clean::Type::Path { ref path } => { + clean::Type::Path { path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. let did = path.def_id(); resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx) } - clean::DynTrait(ref bounds, ref lt) => { + clean::DynTrait(bounds, lt) => { f.write_str("dyn ")?; tybounds(bounds, lt, cx).fmt(f) } @@ -872,8 +872,8 @@ fn fmt_type( clean::Primitive(clean::PrimitiveType::Never) => { primitive_link(f, PrimitiveType::Never, format_args!("!"), cx) } - clean::Primitive(prim) => primitive_link(f, prim, format_args!("{}", prim.as_sym()), cx), - clean::BareFunction(ref decl) => { + &clean::Primitive(prim) => primitive_link(f, prim, format_args!("{}", prim.as_sym()), cx), + clean::BareFunction(decl) => { print_higher_ranked_params_with_space(&decl.generic_params, cx, "for").fmt(f)?; decl.safety.print_with_space().fmt(f)?; print_abi_with_space(decl.abi).fmt(f)?; @@ -884,11 +884,11 @@ fn fmt_type( } decl.decl.print(cx).fmt(f) } - clean::UnsafeBinder(ref binder) => { + clean::UnsafeBinder(binder) => { print_higher_ranked_params_with_space(&binder.generic_params, cx, "unsafe").fmt(f)?; binder.ty.print(cx).fmt(f) } - clean::Tuple(ref typs) => match &typs[..] { + clean::Tuple(typs) => match &typs[..] { &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx), [one] => { if let clean::Generic(name) = one { @@ -925,45 +925,36 @@ fn fmt_type( } } }, - clean::Slice(ref t) => match **t { - clean::Generic(name) => { - primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx) - } - _ => { - write!(f, "[")?; - t.print(cx).fmt(f)?; - write!(f, "]") - } - }, - clean::Type::Pat(ref t, ref pat) => { + clean::Slice(box clean::Generic(name)) => { + primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx) + } + clean::Slice(t) => { + write!(f, "[")?; + t.print(cx).fmt(f)?; + write!(f, "]") + } + clean::Type::Pat(t, pat) => { fmt::Display::fmt(&t.print(cx), f)?; write!(f, " is {pat}") } - clean::Array(ref t, ref n) => match **t { - clean::Generic(name) if !f.alternate() => primitive_link( - f, - PrimitiveType::Array, - format_args!("[{name}; {n}]", n = Escape(n)), - cx, - ), - _ => { - write!(f, "[")?; - t.print(cx).fmt(f)?; - if f.alternate() { - write!(f, "; {n}")?; - } else { - write!(f, "; ")?; - primitive_link( - f, - PrimitiveType::Array, - format_args!("{n}", n = Escape(n)), - cx, - )?; - } - write!(f, "]") + clean::Array(box clean::Generic(name), n) if !f.alternate() => primitive_link( + f, + PrimitiveType::Array, + format_args!("[{name}; {n}]", n = Escape(n)), + cx, + ), + clean::Array(t, n) => { + write!(f, "[")?; + t.print(cx).fmt(f)?; + if f.alternate() { + write!(f, "; {n}")?; + } else { + write!(f, "; ")?; + primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)?; } - }, - clean::RawPointer(m, ref t) => { + write!(f, "]") + } + clean::RawPointer(m, t) => { let m = match m { hir::Mutability::Mut => "mut", hir::Mutability::Not => "const", @@ -991,7 +982,7 @@ fn fmt_type( t.print(cx).fmt(f) } } - clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => { + clean::BorrowedRef { lifetime: l, mutability, type_: ty } => { let lt = fmt::from_fn(|f| match l { Some(l) => write!(f, "{} ", l.print()), _ => Ok(()), @@ -1028,11 +1019,11 @@ fn fmt_type( } Ok(()) } - clean::ImplTrait(ref bounds) => { + clean::ImplTrait(bounds) => { f.write_str("impl ")?; print_generic_bounds(bounds, cx).fmt(f) } - clean::QPath(box clean::QPathData { + &clean::QPath(box clean::QPathData { ref assoc, ref self_type, ref trait_, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b4210e7b518..b4003044e20 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -11,7 +11,6 @@ #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(never_type)] #![feature(round_char_boundary)] #![feature(test)] diff --git a/src/llvm-project b/src/llvm-project -Subproject 8448283b4bd34ea00d76fd4f18ec730b549d6e1 +Subproject c1118fdbb3024157df7f4cfe765f2b0b4339e8a diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 7b7be97aa51..e4d7abdb0f7 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -6,7 +6,7 @@ name = "miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" default-run = "miri" -edition = "2021" +edition = "2024" [lib] test = true # we have unit tests diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml index ed142b0e211..23048914af1 100644 --- a/src/tools/miri/cargo-miri/Cargo.toml +++ b/src/tools/miri/cargo-miri/Cargo.toml @@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0" name = "cargo-miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" -edition = "2021" +edition = "2024" [[bin]] name = "cargo-miri" diff --git a/src/tools/miri/cargo-miri/src/main.rs b/src/tools/miri/cargo-miri/src/main.rs index 322ef0a6c2a..4c01a81fdfd 100644 --- a/src/tools/miri/cargo-miri/src/main.rs +++ b/src/tools/miri/cargo-miri/src/main.rs @@ -63,27 +63,37 @@ fn main() { return; } + let Some(first) = args.next() else { + show_error!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + ) + }; + // The way rustdoc invokes rustc is indistinguishable from the way cargo invokes rustdoc by the // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { // ...however, we then also see this variable when rustdoc invokes us as the testrunner! - // The runner is invoked as `$runtool ($runtool-arg)* output_file`; - // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to - // the test-builder unconditionally, we can just check the number of remaining arguments: - if args.len() == 1 { - phase_runner(args, RunnerPhase::Rustdoc); - } else { - phase_rustc(args, RustcPhase::Rustdoc); + // In that case the first argument is `runner` and there are no more arguments. + match first.as_str() { + "runner" => phase_runner(args, RunnerPhase::Rustdoc), + flag if flag.starts_with("--") || flag.starts_with("@") => { + // This is probably rustdoc invoking us to build the test. But we need to get `first` + // "back onto the iterator", it is some part of the rustc invocation. + phase_rustc(iter::once(first).chain(args), RustcPhase::Rustdoc); + } + _ => { + show_error!( + "`cargo-miri` failed to recognize which phase of the build process this is, please report a bug.\n\ + We are inside MIRI_CALLED_FROM_RUSTDOC.\n\ + The command-line arguments were: {:#?}", + Vec::from_iter(env::args()), + ); + } } return; } - let Some(first) = args.next() else { - show_error!( - "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - ) - }; match first.as_str() { "miri" => phase_cargo_miri(args), "runner" => phase_runner(args, RunnerPhase::Cargo), diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index cb62e12413c..171e157789d 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -176,6 +176,8 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { // Set `--target-dir` to `miri` inside the original target directory. let target_dir = get_target_dir(&metadata); cmd.arg("--target-dir").arg(target_dir); + // Enable cross-target doctests (for consistency between different cargo versions). + cmd.arg("-Zdoctest-xcompile"); // *After* we set all the flags that need setting, forward everything else. Make sure to skip // `--target-dir` (which would otherwise be set twice). @@ -666,11 +668,6 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) { if arg == "--extern" { // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. forward_patched_extern_arg(&mut args, &mut cmd); - } else if arg == "--test-runtool" { - // An existing --test-runtool flag indicates cargo is running in cross-target mode, which we don't support. - // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; - // otherwise, we won't be called as rustdoc at all. - show_error!("cross-interpreting doctests is not currently supported by Miri."); } else { cmd.arg(arg); } @@ -702,10 +699,10 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) { // make sure the 'miri' flag is set for rustdoc cmd.arg("--cfg").arg("miri"); - // Make rustdoc call us back. + // Make rustdoc call us back for the build. + // (cargo already sets `--test-runtool` to us since we are the cargo test runner.) let cargo_miri_path = env::current_exe().expect("current executable path invalid"); cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments - cmd.arg("--test-runtool").arg(&cargo_miri_path); // invoked with just a single path argument debug_cmd("[cargo-miri rustdoc]", verbose, &cmd); exec(cmd) diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs index 7afc8481009..b9b58c04f9e 100644 --- a/src/tools/miri/cargo-miri/src/setup.rs +++ b/src/tools/miri/cargo-miri/src/setup.rs @@ -24,11 +24,9 @@ pub fn setup( let ask_user = !only_setup; let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path let show_setup = only_setup && !print_sysroot; - if !only_setup { - if let Some(sysroot) = std::env::var_os("MIRI_SYSROOT") { - // Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`. - return sysroot.into(); - } + if !only_setup && let Some(sysroot) = std::env::var_os("MIRI_SYSROOT") { + // Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`. + return sysroot.into(); } // Determine where the rust sources are located. The env var trumps auto-detection. diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index a04898de6ab..462a9cc62bf 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -6,7 +6,7 @@ name = "miri-script" repository = "https://github.com/rust-lang/miri" version = "0.1.0" default-run = "miri-script" -edition = "2021" +edition = "2024" [workspace] # We make this a workspace root so that cargo does not go looking in ../Cargo.toml for the workspace root. diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 1c9750e2cbd..3b7b159aeab 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -675,11 +675,9 @@ impl Command { let mut early_flags = Vec::<OsString>::new(); // In `dep` mode, the target is already passed via `MIRI_TEST_TARGET` - if !dep { - if let Some(target) = &target { - early_flags.push("--target".into()); - early_flags.push(target.into()); - } + if !dep && let Some(target) = &target { + early_flags.push("--target".into()); + early_flags.push(target.into()); } early_flags.push("--edition".into()); early_flags.push(edition.as_deref().unwrap_or("2021").into()); @@ -707,10 +705,8 @@ impl Command { // Add Miri flags let mut cmd = cmd.args(&miri_flags).args(&early_flags).args(&flags); // For `--dep` we also need to set the target in the env var. - if dep { - if let Some(target) = &target { - cmd = cmd.env("MIRI_TEST_TARGET", target); - } + if dep && let Some(target) = &target { + cmd = cmd.env("MIRI_TEST_TARGET", target); } // Finally, run the thing. Ok(cmd.run()?) diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs index c039b4827ee..5c2a055990f 100644 --- a/src/tools/miri/miri-script/src/util.rs +++ b/src/tools/miri/miri-script/src/util.rs @@ -213,7 +213,7 @@ impl MiriEnv { let toolchain = &self.toolchain; let mut cmd = cmd!( self.sh, - "rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}" + "rustfmt +{toolchain} --edition=2024 --config-path {config_path} --unstable-features --skip-children {flags...}" ); if first { // Log an abbreviating command, and only once. diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 97bc826b57a..79abbfaeaf1 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -2ad5f8607d0e192b60b130e5cc416b477b351c18 +a69bc17fb8026bdc0d24bb1896ff95f0eba1da4e diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index f249b58aeb6..469fc264970 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -459,7 +459,7 @@ fn jemalloc_magic() { // linking, so we need to explicitly depend on the function. #[cfg(target_os = "macos")] { - extern "C" { + unsafe extern "C" { fn _rjem_je_zone_register(); } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index b2fd9b2bf05..f5a0013047a 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -179,7 +179,7 @@ impl NodeDebugInfo { /// Add a name to the tag. If a same tag is associated to several pointers, /// it can have several names which will be separated by commas. pub fn add_name(&mut self, name: &str) { - if let Some(ref mut prev_name) = &mut self.name { + if let Some(prev_name) = &mut self.name { prev_name.push_str(", "); prev_name.push_str(name); } else { diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 89768077d87..10570a37e5d 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -648,8 +648,7 @@ impl<'tcx> MiriMachine<'tcx> { AccessedAlloc(AllocId(id), access_kind) => format!("{access_kind} to allocation with id {id}"), FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), - RejectedIsolatedOp(ref op) => - format!("{op} was made to return an error due to isolation"), + RejectedIsolatedOp(op) => format!("{op} was made to return an error due to isolation"), ProgressReport { .. } => format!("progress report: current operation being executed is here"), Int2Ptr { .. } => format!("integer-to-pointer cast"), diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index a3aa8bbbfb3..d2a73516623 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -932,12 +932,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi) } - /// Check that the ABI is what we expect. - fn check_abi<'a>(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: Conv) -> InterpResult<'a, ()> { + /// Check that the calling convention is what we expect. + fn check_callconv<'a>(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: Conv) -> InterpResult<'a, ()> { if fn_abi.conv != exp_abi { throw_ub_format!( - "calling a function with ABI {:?} using caller ABI {:?}", - exp_abi, + "calling a function with calling convention {exp_abi} using caller calling convention {}", fn_abi.conv ); } @@ -973,7 +972,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { exp_abi: Conv, link_name: Symbol, ) -> InterpResult<'tcx, ()> { - self.check_abi(abi, exp_abi)?; + self.check_callconv(abi, exp_abi)?; if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? { // If compiler-builtins is providing the symbol, then don't treat it as a clash. // We'll use our built-in implementation in `emulate_foreign_item_inner` for increased diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 58b93ae82a1..0b7a067058b 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -9,7 +9,6 @@ #![feature(variant_count)] #![feature(yeet_expr)] #![feature(nonzero_ops)] -#![feature(let_chains)] #![feature(strict_overflow_ops)] #![feature(pointer_is_aligned_to)] #![feature(unqualified_local_imports)] diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 18af8214876..b5ed5ea837b 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -85,6 +85,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); + #[allow(clippy::cloned_ref_to_slice_refs)] // the code is clearer as-is this.call_function( f_instance, ExternAbi::Rust, diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index a9d09ac7a9d..40bfe7f845f 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -142,24 +142,19 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): - # rustdoc is not run on foreign targets - is_foreign = ARGS.target is not None - default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" - filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" - test("`cargo miri test`", cargo_miri("test"), - default_ref, "test.empty.ref", + "test.default.stdout.ref", "test.empty.ref", env={'MIRIFLAGS': "-Zmiri-seed=4242"}, ) test("`cargo miri test` (no isolation, no doctests)", cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml` - "test.cross-target.stdout.ref", "test.empty.ref", + "test.no-doc.stdout.ref", "test.empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "pl"], - filter_ref, "test.empty.ref", + "test.filter.stdout.ref", "test.empty.ref", ) test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], @@ -171,7 +166,7 @@ def test_cargo_miri_test(): ) test("`cargo miri t` (subcrate, no isolation)", cargo_miri("t") + ["-p", "subcrate"], - "test.subcrate.cross-target.stdout.ref" if is_foreign else "test.subcrate.stdout.ref", + "test.subcrate.stdout.ref", "test.empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) @@ -181,12 +176,12 @@ def test_cargo_miri_test(): ) test("`cargo miri test` (custom target dir)", cargo_miri("test") + ["--target-dir=custom-test"], - default_ref, "test.empty.ref", + "test.default.stdout.ref", "test.empty.ref", ) del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it test("`cargo miri test` (config-cli)", cargo_miri("test") + ["--config=build.target-dir=\"config-cli\""], - default_ref, "test.empty.ref", + "test.default.stdout.ref", "test.empty.ref", ) if ARGS.multi_target: test_cargo_miri_multi_target() diff --git a/src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref deleted file mode 100644 index 59b4deb1ff3..00000000000 --- a/src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref +++ /dev/null @@ -1,12 +0,0 @@ - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in $TIME - -imported main - -running 1 test -test simple ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out; finished in $TIME - diff --git a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref index 567c5db07d0..a376530a8cf 100644 --- a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref @@ -20,3 +20,13 @@ running 6 tests ...i.. test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + +running 5 tests +..... +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 5 tests +..... +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/tools/miri/test-cargo-miri/test.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref index 2ef124e4de8..2ef124e4de8 100644 --- a/src/tools/miri/test-cargo-miri/test.cross-target.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref diff --git a/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref deleted file mode 100644 index 436e6e4fbbb..00000000000 --- a/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref +++ /dev/null @@ -1,11 +0,0 @@ - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - -subcrate testing diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs index 2097126e16b..4a87411d755 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs @@ -1,5 +1,5 @@ //@error-in-other-file: aborted -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" #![feature(allocator_api)] diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr index 3642f3f28ca..fa84da841fd 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr @@ -2,7 +2,7 @@ memory allocation of 4 bytes failed error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs b/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs index ffa0443ce50..0e916364169 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs +++ b/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - let _ = malloc(0); //~ ERROR: calling a function with ABI C using caller ABI Rust + let _ = malloc(0); //~ ERROR: calling a function with calling convention "C" using caller calling convention "Rust" }; } diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr index bf1fbb7721f..78730182923 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with ABI C using caller ABI Rust +error: Undefined Behavior: calling a function with calling convention "C" using caller calling convention "Rust" --> tests/fail/function_calls/check_arg_abi.rs:LL:CC | LL | let _ = malloc(0); - | ^^^^^^^^^ calling a function with ABI C using caller ABI Rust + | ^^^^^^^^^ calling a function with calling convention "C" using caller calling convention "Rust" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs index 6a7a26710d1..177e38105e6 100644 --- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs +++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs @@ -9,7 +9,7 @@ fn main() { // Make sure we check the ABI when Miri itself invokes a function // as part of a shim implementation. std::intrinsics::catch_unwind( - //~^ ERROR: calling a function with calling convention C using calling convention Rust + //~^ ERROR: calling a function with calling convention "C" using calling convention "Rust" std::mem::transmute::<extern "C" fn(*mut u8), _>(try_fn), std::ptr::null_mut(), |_, _| unreachable!(), diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr index 6b0692e1c6e..20182ac9236 100644 --- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with calling convention C using calling convention Rust +error: Undefined Behavior: calling a function with calling convention "C" using calling convention "Rust" --> tests/fail/function_calls/check_callback_abi.rs:LL:CC | LL | / std::intrinsics::catch_unwind( @@ -7,7 +7,7 @@ LL | | std::mem::transmute::<extern "C" fn(*mut u8), _>(try_fn), LL | | std::ptr::null_mut(), LL | | |_, _| unreachable!(), LL | | ); - | |_________^ calling a function with calling convention C using calling convention Rust + | |_________^ calling a function with calling convention "C" using calling convention "Rust" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr index e4302ad1d3a..46a32d1487e 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with calling convention Rust using calling convention C +error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C" --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC | LL | foo(); - | ^^^^^ calling a function with calling convention Rust using calling convention C + | ^^^^^ calling a function with calling convention "Rust" using calling convention "C" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr index 9f40c48b338..38725289919 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with calling convention Rust using calling convention C +error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C" --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC | LL | std::mem::transmute::<unsafe fn(), unsafe extern "C" fn()>(foo)(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention "Rust" using calling convention "C" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr index e4302ad1d3a..46a32d1487e 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with calling convention Rust using calling convention C +error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C" --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC | LL | foo(); - | ^^^^^ calling a function with calling convention Rust using calling convention C + | ^^^^^ calling a function with calling convention "Rust" using calling convention "C" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index 50a0e8e6ede..1950e162c07 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -12,7 +12,7 @@ fn main() { #[cfg(fn_ptr)] unsafe { std::mem::transmute::<unsafe fn(), unsafe extern "C" fn()>(foo)(); - //~[fn_ptr]^ ERROR: calling a function with calling convention Rust using calling convention C + //~[fn_ptr]^ ERROR: calling a function with calling convention "Rust" using calling convention "C" } // `Instance` caching should not suppress ABI check. @@ -28,8 +28,8 @@ fn main() { } unsafe { foo(); - //~[no_cache]^ ERROR: calling a function with calling convention Rust using calling convention C - //~[cache]| ERROR: calling a function with calling convention Rust using calling convention C + //~[no_cache]^ ERROR: calling a function with calling convention "Rust" using calling convention "C" + //~[cache]| ERROR: calling a function with calling convention "Rust" using calling convention "C" } } } diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index b2a501db776..7cb2bf99678 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index b2a501db776..7cb2bf99678 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index 1382e9571f3..9d993786d57 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -1,5 +1,5 @@ //@revisions: extern_block definition both -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs index 6e0e0ca9f53..dd3246d8120 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs @@ -1,4 +1,4 @@ -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index 2c9bea1724d..ba96e595bee 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -7,7 +7,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs index 0e8d3d08c12..3d355bad626 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs @@ -1,4 +1,4 @@ -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr index 0634298a38f..7e1f4160cc0 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr @@ -7,7 +7,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.rs b/src/tools/miri/tests/fail/panic/abort_unwind.rs index e313d9c11de..bd819362da4 100644 --- a/src/tools/miri/tests/fail/panic/abort_unwind.rs +++ b/src/tools/miri/tests/fail/panic/abort_unwind.rs @@ -1,5 +1,5 @@ //@error-in-other-file: the program aborted execution -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.stderr b/src/tools/miri/tests/fail/panic/abort_unwind.stderr index 3a63cb38ad0..e6668b09f66 100644 --- a/src/tools/miri/tests/fail/panic/abort_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/abort_unwind.stderr @@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/panic/double_panic.rs b/src/tools/miri/tests/fail/panic/double_panic.rs index ddc75521eca..4d8f4cb6fb7 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.rs +++ b/src/tools/miri/tests/fail/panic/double_panic.rs @@ -1,4 +1,4 @@ -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 16e933be434..67f88955def 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -14,7 +14,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.rs b/src/tools/miri/tests/fail/panic/panic_abort1.rs index 7552c7b7e80..06cb673778a 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort1.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr index c950b2b4ea6..6d56874ebde 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr @@ -4,13 +4,15 @@ panicking from libstd note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/panic_abort/src/lib.rs:LL:CC + --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC + = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.rs b/src/tools/miri/tests/fail/panic/panic_abort2.rs index 624f9933545..c011b3ee7eb 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort2.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr index 9a9266ec493..dbb56f13f48 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr @@ -4,13 +4,15 @@ thread 'main' panicked at tests/fail/panic/panic_abort2.rs:LL:CC: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/panic_abort/src/lib.rs:LL:CC + --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC + = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.rs b/src/tools/miri/tests/fail/panic/panic_abort3.rs index d1435b55946..911dc4a44ab 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort3.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr index f04a2b0f3f1..7f0564879e4 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr @@ -4,13 +4,15 @@ panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/panic_abort/src/lib.rs:LL:CC + --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC + = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.rs b/src/tools/miri/tests/fail/panic/panic_abort4.rs index 54b9c9cbfdb..696fdff7422 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort4.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr index e71c4879ea3..ce6910b9933 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr @@ -4,13 +4,15 @@ thread 'main' panicked at tests/fail/panic/panic_abort4.rs:LL:CC: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/panic_abort/src/lib.rs:LL:CC + --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: - = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC + = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs index 6f627c416b0..6119e8604b4 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs @@ -1,6 +1,6 @@ //! This is a regression test for <https://github.com/rust-lang/miri/issues/4188>: The precondition //! check in `ptr::swap_nonoverlapping` was incorrectly disabled in Miri. -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr index 80dd2f39b42..f57487e3ffe 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr @@ -9,7 +9,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs index 5f00dbf2573..952f9697fc7 100644 --- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs @@ -1,4 +1,4 @@ -//@error-in-other-file: Undefined Behavior: calling a function with calling convention C using calling convention Rust +//@error-in-other-file: Undefined Behavior: calling a function with calling convention "C" using calling convention "Rust" #![feature(explicit_tail_calls)] #![allow(incomplete_features)] diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr index 5061c9e8dc3..61ddea64472 100644 --- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function with calling convention C using calling convention Rust +error: Undefined Behavior: calling a function with calling convention "C" using calling convention "Rust" --> RUSTLIB/core/src/ops/function.rs:LL:CC | LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention C using calling convention Rust + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention "C" using calling convention "Rust" | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs index 465625c7572..31ae829a2de 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.rs +++ b/src/tools/miri/tests/fail/terminate-terminator.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmir-opt-level=3 -Zinline-mir-hint-threshold=1000 -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index f2548bf5cdb..d16119a30e6 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -13,7 +13,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.rs b/src/tools/miri/tests/fail/unwind-action-terminate.rs index 465e07c8db4..f0fbcfd8867 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.rs +++ b/src/tools/miri/tests/fail/unwind-action-terminate.rs @@ -1,5 +1,5 @@ //@error-in-other-file: aborted execution -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index 7b9a4383fc4..222d4fb2866 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC | -LL | ABORT(); +LL | ABORT() | ^ the program aborted execution | = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr deleted file mode 100644 index a437ca34258..00000000000 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: Undefined Behavior: Race condition detected between (1) 4-byte atomic store on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - --> tests/fail/weak_memory/racing_mixed_size.rs:LL:CC - | -LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte atomic store on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - | -help: and (1) occurred earlier here - --> tests/fail/weak_memory/racing_mixed_size.rs:LL:CC - | -LL | x.store(1, Relaxed); - | ^^^^^^^^^^^^^^^^^^^ - = help: overlapping unsynchronized atomic accesses must use the same access size - = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at tests/fail/weak_memory/racing_mixed_size.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs index c2b6a7e68be..c76e7f2eebd 100644 --- a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs +++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs @@ -12,7 +12,6 @@ fn main() { mut_raw_mut(); partially_invalidate_mut(); drop_after_sharing(); - // direct_mut_to_const_raw(); two_raw(); shr_and_raw(); disjoint_mutable_subborrows(); diff --git a/src/tools/miri/tests/pass/coroutine.rs b/src/tools/miri/tests/pass/coroutine.rs index 9ec9b1fc5bc..96b60b515cb 100644 --- a/src/tools/miri/tests/pass/coroutine.rs +++ b/src/tools/miri/tests/pass/coroutine.rs @@ -183,18 +183,18 @@ fn basic() { fn smoke_resume_arg() { fn drain<G: Coroutine<R, Yield = Y> + Unpin, R, Y>( - gen: &mut G, + gen_: &mut G, inout: Vec<(R, CoroutineState<Y, G::Return>)>, ) where Y: Debug + PartialEq, G::Return: Debug + PartialEq, { - let mut gen = Pin::new(gen); + let mut gen_ = Pin::new(gen_); for (input, out) in inout { - assert_eq!(gen.as_mut().resume(input), out); + assert_eq!(gen_.as_mut().resume(input), out); // Test if the coroutine is valid (according to type invariants). - let _ = unsafe { ManuallyDrop::new(ptr::read(gen.as_mut().get_unchecked_mut())) }; + let _ = unsafe { ManuallyDrop::new(ptr::read(gen_.as_mut().get_unchecked_mut())) }; } } diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index c37cf15d40a..46472b51f9c 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -44,8 +44,7 @@ pub fn flagsplit(flags: &str) -> Vec<String> { fn build_native_lib() -> PathBuf { let cc = env::var("CC").unwrap_or_else(|_| "cc".into()); // Target directory that we can write to. - let so_target_dir = - Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-native-lib"); + let so_target_dir = Path::new(env!("CARGO_TARGET_TMPDIR")).join("miri-native-lib"); // Create the directory if it does not already exist. std::fs::create_dir_all(&so_target_dir) .expect("Failed to create directory for shared object file"); @@ -101,7 +100,7 @@ fn miri_config( let mut config = Config { target: Some(target.to_owned()), program, - out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri_ui"), + out_dir: PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("miri_ui"), threads: std::env::var("MIRI_TEST_THREADS") .ok() .map(|threads| NonZero::new(threads.parse().unwrap()).unwrap()), @@ -319,10 +318,10 @@ fn main() -> Result<()> { let mut args = std::env::args_os(); // Skip the program name and check whether this is a `./miri run-dep` invocation - if let Some(first) = args.nth(1) { - if first == "--miri-run-dep-mode" { - return run_dep_mode(target, args); - } + if let Some(first) = args.nth(1) + && first == "--miri-run-dep-mode" + { + return run_dep_mode(target, args); } ui(Mode::Pass, "tests/pass", &target, WithoutDependencies, tmpdir.path())?; diff --git a/tests/run-make/core-no-oom-handling/rmake.rs b/tests/run-make/core-no-oom-handling/rmake.rs index a9e2b33e210..5194d773114 100644 --- a/tests/run-make/core-no-oom-handling/rmake.rs +++ b/tests/run-make/core-no-oom-handling/rmake.rs @@ -6,7 +6,7 @@ use run_make_support::{rustc, source_root}; fn main() { rustc() - .edition("2021") + .edition("2024") .arg("-Dwarnings") .crate_type("rlib") .input(source_root().join("library/core/src/lib.rs")) diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs index 2727effe818..d28c8463016 100644 --- a/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs +++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs @@ -11,6 +11,13 @@ //@ needs-dynamic-linking //@ only-nightly (requires unstable rustc flag) +// This test trips a check in the MSVC linker for an outdated processor: +// "LNK1322: cannot avoid potential ARM hazard (Cortex-A53 MPCore processor bug #843419)" +// Until MSVC removes this check: +// https://developercommunity.microsoft.com/t/Remove-checking-for-and-fixing-Cortex-A/10905134 +// we'll need to disable this test on Arm64 Windows. +//@ ignore-aarch64-pc-windows-msvc + #![deny(warnings)] use run_make_support::{dynamic_lib_name, rfs, rust_lib_name, rustc}; diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.rs b/tests/ui/consts/miri_unleashed/abi-mismatch.rs index 0a2b3f3abd6..6a46079b39b 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.rs +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.rs @@ -10,7 +10,7 @@ const fn call_rust_fn(my_fn: extern "Rust" fn()) { static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); //~^ ERROR could not evaluate static initializer -//~| NOTE calling a function with calling convention C using calling convention Rust +//~| NOTE calling a function with calling convention "C" using calling convention "Rust" fn main() {} diff --git a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr index 88623b134b0..7d1fdcce526 100644 --- a/tests/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/tests/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/abi-mismatch.rs:11:18 | LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention C using calling convention Rust + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention "C" using calling convention "Rust" | note: inside `call_rust_fn` --> $DIR/abi-mismatch.rs:7:5 diff --git a/tests/ui/coroutine/delayed-obligations-emit.next.stderr b/tests/ui/coroutine/delayed-obligations-emit.next.stderr new file mode 100644 index 00000000000..3a3663398c9 --- /dev/null +++ b/tests/ui/coroutine/delayed-obligations-emit.next.stderr @@ -0,0 +1,15 @@ +error[E0275]: overflow evaluating the requirement `{async block@$DIR/delayed-obligations-emit.rs:17:11: 17:16}: Send` + --> $DIR/delayed-obligations-emit.rs:17:5 + | +LL | spawn(async { build_dependencies().await }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: required by a bound in `spawn` + --> $DIR/delayed-obligations-emit.rs:31:13 + | +LL | fn spawn<F: Send>(_: F) {} + | ^^^^ required by this bound in `spawn` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/coroutine/delayed-obligations-emit.rs b/tests/ui/coroutine/delayed-obligations-emit.rs new file mode 100644 index 00000000000..6334f29fcb2 --- /dev/null +++ b/tests/ui/coroutine/delayed-obligations-emit.rs @@ -0,0 +1,33 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ edition: 2024 +//@[current] check-pass + +// This previously caused an ICE with the new solver. +// The delayed coroutine obligations were checked with the +// opaque types inferred by borrowck. +// +// One of these delayed obligations failed with overflow in +// borrowck, causing us to taint `type_of` for the opaque. This +// then caused us to also not emit an error when checking the +// coroutine obligations. + +fn build_multiple<'a>() -> impl Sized { + spawn(async { build_dependencies().await }); + //[next]~^ ERROR overflow evaluating the requirement +} + +// Adding an explicit `Send` bound fixes it. +// Proving `build_dependencies(): Send` in `build_multiple` adds +// addiitional defining uses/placeholders. +fn build_dependencies() -> impl Future<Output = ()> /* + Send */ { + async { + Box::pin(build_dependencies()).await; + async { build_multiple() }.await; + } +} + +fn spawn<F: Send>(_: F) {} + +fn main() {} diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed index 0108f762400..ae63b0c4627 100644 --- a/tests/ui/imports/issue-99695-b.fixed +++ b/tests/ui/imports/issue-99695-b.fixed @@ -11,7 +11,7 @@ mod m { pub struct other_item; } - use ::nu; + use crate::nu; pub use self::p::{other_item as _}; //~^ ERROR unresolved import `self::p::nu` [E0432] //~| HELP a macro with this name exists at the root of the crate diff --git a/tests/ui/imports/issue-99695-b.stderr b/tests/ui/imports/issue-99695-b.stderr index d58d2798746..ad752d5c45a 100644 --- a/tests/ui/imports/issue-99695-b.stderr +++ b/tests/ui/imports/issue-99695-b.stderr @@ -7,7 +7,7 @@ LL | pub use self::p::{nu, other_item as _}; = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined help: a macro with this name exists at the root of the crate | -LL ~ use ::nu; +LL ~ use crate::nu; LL ~ pub use self::p::{other_item as _}; | diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.edition_2015.fixed index 51ccd3f8c48..798acfd5874 100644 --- a/tests/ui/imports/issue-99695.fixed +++ b/tests/ui/imports/issue-99695.edition_2015.fixed @@ -1,4 +1,8 @@ //@ run-rustfix +//@ revisions: edition_2015 edition_2018 +//@ [edition_2015] edition: 2015 +//@ [edition_2018] edition: 2018 + #![allow(unused, nonstandard_style)] mod m { #[macro_export] @@ -8,7 +12,7 @@ mod m { pub struct other_item; - use ::nu; + use crate::nu; pub use self::{other_item as _}; //~^ ERROR unresolved import `self::nu` [E0432] //~| HELP a macro with this name exists at the root of the crate diff --git a/tests/ui/imports/issue-99695.stderr b/tests/ui/imports/issue-99695.edition_2015.stderr index 536f51dcb3b..4ef8e6426fb 100644 --- a/tests/ui/imports/issue-99695.stderr +++ b/tests/ui/imports/issue-99695.edition_2015.stderr @@ -1,5 +1,5 @@ error[E0432]: unresolved import `self::nu` - --> $DIR/issue-99695.rs:11:20 + --> $DIR/issue-99695.rs:15:20 | LL | pub use self::{nu, other_item as _}; | ^^ no `nu` in `m` @@ -7,7 +7,7 @@ LL | pub use self::{nu, other_item as _}; = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined help: a macro with this name exists at the root of the crate | -LL ~ use ::nu; +LL ~ use crate::nu; LL ~ pub use self::{other_item as _}; | diff --git a/tests/ui/imports/issue-99695.edition_2018.fixed b/tests/ui/imports/issue-99695.edition_2018.fixed new file mode 100644 index 00000000000..798acfd5874 --- /dev/null +++ b/tests/ui/imports/issue-99695.edition_2018.fixed @@ -0,0 +1,21 @@ +//@ run-rustfix +//@ revisions: edition_2015 edition_2018 +//@ [edition_2015] edition: 2015 +//@ [edition_2018] edition: 2018 + +#![allow(unused, nonstandard_style)] +mod m { + #[macro_export] + macro_rules! nu { + {} => {}; + } + + pub struct other_item; + + use crate::nu; +pub use self::{other_item as _}; + //~^ ERROR unresolved import `self::nu` [E0432] + //~| HELP a macro with this name exists at the root of the crate +} + +fn main() {} diff --git a/tests/ui/imports/issue-99695.edition_2018.stderr b/tests/ui/imports/issue-99695.edition_2018.stderr new file mode 100644 index 00000000000..4ef8e6426fb --- /dev/null +++ b/tests/ui/imports/issue-99695.edition_2018.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `self::nu` + --> $DIR/issue-99695.rs:15:20 + | +LL | pub use self::{nu, other_item as _}; + | ^^ no `nu` in `m` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL ~ use crate::nu; +LL ~ pub use self::{other_item as _}; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs index a52370e0eb0..dc0a8f438e0 100644 --- a/tests/ui/imports/issue-99695.rs +++ b/tests/ui/imports/issue-99695.rs @@ -1,4 +1,8 @@ //@ run-rustfix +//@ revisions: edition_2015 edition_2018 +//@ [edition_2015] edition: 2015 +//@ [edition_2018] edition: 2018 + #![allow(unused, nonstandard_style)] mod m { #[macro_export] diff --git a/tests/ui/traits/object/ambiguity-vtable-segfault.rs b/tests/ui/traits/object/ambiguity-vtable-segfault.rs new file mode 100644 index 00000000000..dff7d26ae93 --- /dev/null +++ b/tests/ui/traits/object/ambiguity-vtable-segfault.rs @@ -0,0 +1,37 @@ +// In this example below, we have two overlapping candidates for `dyn Q: Q`. +// Specifically, the user written impl for `<dyn Q as Mirror>::Assoc` and the +// built-in impl for object types. Since they differ by their region responses, +// the goal is ambiguous. This affects codegen since impossible obligations +// for method dispatch will lead to a segfault, since we end up emitting dummy +// call vtable offsets due to <https://github.com/rust-lang/rust/pull/136311>. + +// Test for <https://github.com/rust-lang/rust/issues/141119>. + +//@ run-pass + +trait Mirror { + type Assoc: ?Sized; +} +impl<T: ?Sized> Mirror for T { + type Assoc = T; +} + +trait Q: 'static { + fn q(&self); +} + +impl Q for i32 { + fn q(&self) { println!("i32"); } +} + +impl Q for <dyn Q as Mirror>::Assoc where Self: 'static { + fn q(&self) { println!("dyn Q"); } +} + +fn foo<T: Q + ?Sized>(t: &T) { + t.q(); +} + +fn main() { + foo(&1 as &dyn Q); +} diff --git a/triagebot.toml b/triagebot.toml index f566a947e0e..3afa2d36410 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1424,3 +1424,6 @@ compiletest = [ # Enable `@rustbot note` functionality # Documentation at: https://forge.rust-lang.org/triagebot/note.html [note] + +[behind-upstream] +days-threshold = 14 |
