From c911f31a78ce3b10ede258818c3779f0f9522a00 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 17 Apr 2019 12:18:19 -0700 Subject: [PATCH 01/11] Allow floating-point operations to provide extra precision than specified, as an optimization This enables optimizations such as fused multiply-add operations by default. --- ...000-floating-point-additional-precision.md | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 text/0000-floating-point-additional-precision.md diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md new file mode 100644 index 00000000000..5d443a70adc --- /dev/null +++ b/text/0000-floating-point-additional-precision.md @@ -0,0 +1,141 @@ +- Feature Name: `allow_extra_fp_precision` +- Start Date: 2019-04-08 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +Update the Rust specification to allow floating-point operations to provide +*more* precision than specified, but not less precision; this allows many safe +optimizations. + +# Motivation +[motivation]: #motivation + +Some platforms provide instructions to run a series of floating-point +operations quickly, such as fused multiply-add instructions; using these +instructions can provide performance wins up to 2x or more. These instructions +may provide *more* precision than required by IEEE floating-point operations, +such as by doing multiple operations before rounding or losing precision. +Similarly, high-performance floating-point code could perform multiple +operations with higher-precision floating-point registers before converting +back to a lower-precision format. + +In general, providing more precision than required should not cause a +mathematical algorithm to fail or to lose numeric accuracy. + +This RFC proposes allowing floating-point types to perform intermediate +calculations using more precision than the type itself, as long as they provide +*at least* as much precision as the IEEE 754 standard requires. + +See the [prior art section](#prior-art) for precedent in several other +languages and compilers. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +After this RFC, we could explain floating-point operations as follows: + +Floating-point operations in Rust have a guaranteed minimum accuracy, which +specifies how far the result may differ from an infinitely accurate, +mathematically exact answer. The implementation of Rust for any target platform +must provide at least that much accuracy. In some cases, Rust can perform +operations with higher accuracy than required, and doing so provides greater +performance (such as by removing intermediate rounding steps). This will never +make any floating-point operation *less* accurate, but it can make +floating-point operations *more* accurate, making the result closer to the +mathematically exact answer. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +Currently, Rust's [specification for floating-point +types](https://doc.rust-lang.org/reference/types/numeric.html#floating-point-types) +states that: +> The IEEE 754-2008 "binary32" and "binary64" floating-point types are f32 and f64, respectively. + +This RFC proposes updating that definition as follows: + +The `f32` and `f64` types represent the IEEE 754-2008 "binary32" and "binary64" +floating-point types. Operations on those types must provide no less +precision than the IEEE standard requires; such operations may provide *more* +precision than the standard requires, such as by doing a series of operations +with higher precision before storing a value of the desired precision. + +rustc may provide a codegen (`-C`) option to disable this behavior, such as `-C +disable-extra-fp-precision`. Rust may also provide an attribute to disable this +behavior from within code, such as `#[disable_extra_fp_precision]`. + +# Drawbacks +[drawbacks]: #drawbacks + +If Rust already provided bit-for-bit identical floating-point computations +across platforms, this change could potentially allow floating-point +computations to differ by platform (though never below the standards-required +accuracy). However, standards-compliant implementations of math functions on +floating-point values may already vary slightly by platform, sufficiently so to +produce different binary results. This proposal can never make results *less* +accurate, it can only make results *more* accurate. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +We could provide a separate set of types and allow extra accuracy in their +operations; however, this would create ABI differences between floating-point +functions, and the longer, less-well-known types seem unlikely to see +widespread use. + +We could provide an option to enable extra accuracy for the default +floating-point types, but disable it by default. This would leave the majority +of floating-point code unable to use these optimizations, however; defaults +matter, and the majority of code seems likely to use the defaults. + +We could do nothing, and require code to use `a.mul_add(b, c)` for +optimization; however, this would not allow for similar future optimizations, +and would not allow code to easily enable this optimization without substantial +code changes. + +We could narrow the scope of optimization opportunities to *only* include +floating-point contraction but not any other precision-increasing operations. +See the [future possibilities](#future-possibilities) section for further +discussion on this point. + +# Prior art +[prior-art]: #prior-art + +This has precedent in several other languages and compilers: + +- [C11](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) allows + this with the `STDC FP_CONTRACT` pragma enabled, and the default state + of that pragma is implementation-defined. GCC enables this pragma by + default, [as does the Microsoft C + compiler](https://docs.microsoft.com/en-us/cpp/preprocessor/fp-contract?view=vs-2019). + +- [The C++ standard](http://eel.is/c++draft/expr.pre#6) states that "The + values of the floating operands and the results of floating + expressions may be represented in greater precision and range than + that required by the type; the types are not changed thereby." + +- The [Fortran standard](https://www.fortran.com/F77_std/rjcnf0001-sh-6.html#sh-6.6.4) + states that "the processor may evaluate any mathematically equivalent + expression", where "Two arithmetic expressions are mathematically + equivalent if, for all possible values of their primaries, their + mathematical values are equal. However, mathematically equivalent + arithmetic expressions may produce different computational results." + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +- Should we provide a rustc codegen option? +- Should we provide an attribute? + +# Future possibilities +[future-possibilities]: #future-possibilities + +The initial implementation of this RFC can simply enable floating-point +contraction within LLVM (and equivalent options in future codegen backends). +However, this RFC also allows other precision-increasing optimizations; in +particular, this RFC would allow the implementation of f32 or future f16 +formats using higher-precision registers, without having to apply rounding +after each operation. From 7ddfbcd122bbd91124351a1c656007ca419de855 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 18 Apr 2019 13:27:55 -0700 Subject: [PATCH 02/11] Clarify explanation of the effect of extra precision --- text/0000-floating-point-additional-precision.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index 5d443a70adc..2bd5634d4c1 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -22,8 +22,8 @@ Similarly, high-performance floating-point code could perform multiple operations with higher-precision floating-point registers before converting back to a lower-precision format. -In general, providing more precision than required should not cause a -mathematical algorithm to fail or to lose numeric accuracy. +In general, providing more precision than required will only bring a +calculation closer to the mathematically precise answer, never further away. This RFC proposes allowing floating-point types to perform intermediate calculations using more precision than the type itself, as long as they provide From f9fffdff6d1f3ff04e5026e915c6515585cd429e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 18 Apr 2019 13:29:17 -0700 Subject: [PATCH 03/11] Add clarification that this is *not* the equivalent of "fast math" from other languages "fast math" is widely perceived as an unsafe option to go faster by sacrificing accuracy. --- text/0000-floating-point-additional-precision.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index 2bd5634d4c1..2be18d2c775 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -42,8 +42,11 @@ specifies how far the result may differ from an infinitely accurate, mathematically exact answer. The implementation of Rust for any target platform must provide at least that much accuracy. In some cases, Rust can perform operations with higher accuracy than required, and doing so provides greater -performance (such as by removing intermediate rounding steps). This will never -make any floating-point operation *less* accurate, but it can make +performance (such as by removing intermediate rounding steps). + +A note for users of other languages: this is *not* the equivalent of the "fast +math" option provided by some compilers. Unlike such options, this behavior +will never make any floating-point operation *less* accurate, but it can make floating-point operations *more* accurate, making the result closer to the mathematically exact answer. From 047dea6f3f0a05e60c82070735471d135b6bdfb1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 18 Apr 2019 13:31:09 -0700 Subject: [PATCH 04/11] Minor wording improvements --- text/0000-floating-point-additional-precision.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index 2be18d2c775..43b72d7b6ff 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -35,8 +35,6 @@ languages and compilers. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -After this RFC, we could explain floating-point operations as follows: - Floating-point operations in Rust have a guaranteed minimum accuracy, which specifies how far the result may differ from an infinitely accurate, mathematically exact answer. The implementation of Rust for any target platform @@ -55,14 +53,14 @@ mathematically exact answer. Currently, Rust's [specification for floating-point types](https://doc.rust-lang.org/reference/types/numeric.html#floating-point-types) -states that: +states only that: > The IEEE 754-2008 "binary32" and "binary64" floating-point types are f32 and f64, respectively. This RFC proposes updating that definition as follows: The `f32` and `f64` types represent the IEEE 754-2008 "binary32" and "binary64" -floating-point types. Operations on those types must provide no less -precision than the IEEE standard requires; such operations may provide *more* +floating-point types. Operations on those types must provide at least as much +precision as the IEEE standard requires; such operations may provide *more* precision than the standard requires, such as by doing a series of operations with higher precision before storing a value of the desired precision. From ce7d87687abfef944ee9b675773fbc1c65b96eea Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 18 Apr 2019 13:22:58 -0700 Subject: [PATCH 05/11] Clarify evaluation of separate floating-point types This refers to type-level API incompatibility (of the sort that would result in semver major version bumps), not necessarily ABI differences. --- text/0000-floating-point-additional-precision.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index 43b72d7b6ff..5a9599d8278 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -83,9 +83,9 @@ accurate, it can only make results *more* accurate. [rationale-and-alternatives]: #rationale-and-alternatives We could provide a separate set of types and allow extra accuracy in their -operations; however, this would create ABI differences between floating-point -functions, and the longer, less-well-known types seem unlikely to see -widespread use. +operations; however, this would create API incompatibilities between +floating-point functions, and the longer, less-well-known types seem unlikely +to see widespread use. We could provide an option to enable extra accuracy for the default floating-point types, but disable it by default. This would leave the majority From 349c7119b82c1a0c5440a894ebfc184de5216fb5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 18 Apr 2019 13:24:21 -0700 Subject: [PATCH 06/11] Require codegen option and attribute; add attribute to enable --- text/0000-floating-point-additional-precision.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index 5a9599d8278..a7e653358e8 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -64,9 +64,11 @@ precision as the IEEE standard requires; such operations may provide *more* precision than the standard requires, such as by doing a series of operations with higher precision before storing a value of the desired precision. -rustc may provide a codegen (`-C`) option to disable this behavior, such as `-C -disable-extra-fp-precision`. Rust may also provide an attribute to disable this -behavior from within code, such as `#[disable_extra_fp_precision]`. +rustc should provide a codegen (`-C`) option to disable this behavior, such as +`-C extra-fp-precision=off`. Rust should also provide attributes to enable and +disable this behavior from within code, such as `#[extra_fp_precision]` or +`#[extra_fp_precision(off)]`, respectively. (An attribute would take precedence +over a codegen option.) # Drawbacks [drawbacks]: #drawbacks @@ -125,12 +127,6 @@ This has precedent in several other languages and compilers: mathematical values are equal. However, mathematically equivalent arithmetic expressions may produce different computational results." -# Unresolved questions -[unresolved-questions]: #unresolved-questions - -- Should we provide a rustc codegen option? -- Should we provide an attribute? - # Future possibilities [future-possibilities]: #future-possibilities From d78aa7503c145c3ae6248a40932aafc795ca409c Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 18 Apr 2019 13:24:54 -0700 Subject: [PATCH 07/11] Document existing Rust behavior for extra floating-point accuracy Rust already provides extra accuracy for operations on some target platforms and optimization levels. --- .../0000-floating-point-additional-precision.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index a7e653358e8..f219364effc 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -74,12 +74,17 @@ over a codegen option.) [drawbacks]: #drawbacks If Rust already provided bit-for-bit identical floating-point computations -across platforms, this change could potentially allow floating-point -computations to differ by platform (though never below the standards-required -accuracy). However, standards-compliant implementations of math functions on -floating-point values may already vary slightly by platform, sufficiently so to -produce different binary results. This proposal can never make results *less* -accurate, it can only make results *more* accurate. +across platforms, then this change could potentially allow floating-point +computations to differ (in the amount of additional accuracy beyond the +standards requirements) by platform, enabled target features (e.g. instruction +sets), or optimization level. + +However, standards-compliant implementations of operations on floating-point +values can and do *already* vary slightly by platform, sufficiently so to +produce different binary results; in particular, floating-point operations in +Rust can already produce more precise results depending on target platform and +optimization level. As with that existing behavior, this proposal can never +make results *less* accurate, it can only make results *more* accurate. # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives From 57e4331d0407c932f5e13e8d3febff48f0b5e112 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 18 Apr 2019 15:07:52 -0700 Subject: [PATCH 08/11] Add an additional rationale for the default --- text/0000-floating-point-additional-precision.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index f219364effc..e78a2bfcff8 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -97,7 +97,11 @@ to see widespread use. We could provide an option to enable extra accuracy for the default floating-point types, but disable it by default. This would leave the majority of floating-point code unable to use these optimizations, however; defaults -matter, and the majority of code seems likely to use the defaults. +matter, and the majority of code seems likely to use the defaults. In addition, +permitting extra floating-point precision by default would match the existing +behavior of Rust, and would allow the Rust compiler to assume that code +explicitly disabling extra precision has a specific requirement to do so and +depends on that behavior. We could do nothing, and require code to use `a.mul_add(b, c)` for optimization; however, this would not allow for similar future optimizations, From b699bc5c6b5e6e13a49b50f0558eca43f91c8d90 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 19 Apr 2019 18:48:10 -0700 Subject: [PATCH 09/11] Note that floating-point accuracy can also vary with libm and its version --- text/0000-floating-point-additional-precision.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index e78a2bfcff8..e1f946225ba 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -82,9 +82,10 @@ sets), or optimization level. However, standards-compliant implementations of operations on floating-point values can and do *already* vary slightly by platform, sufficiently so to produce different binary results; in particular, floating-point operations in -Rust can already produce more precise results depending on target platform and -optimization level. As with that existing behavior, this proposal can never -make results *less* accurate, it can only make results *more* accurate. +Rust can already produce more precise results depending on target platform, +optimization level, the target's libm library, and the version of the target +libm. As with that existing behavior, this proposal can never make results +*less* accurate, it can only make results *more* accurate. # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives From 84734aa06ac87eb4a3ff4823362fe9d12b34d4a5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 22 Apr 2019 17:51:23 -0700 Subject: [PATCH 10/11] Further clarification on separate types Credit to Robin Kruppe for the explanation and phrasing. --- text/0000-floating-point-additional-precision.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index e1f946225ba..2d60cbf6ae4 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -93,7 +93,8 @@ libm. As with that existing behavior, this proposal can never make results We could provide a separate set of types and allow extra accuracy in their operations; however, this would create API incompatibilities between floating-point functions, and the longer, less-well-known types seem unlikely -to see widespread use. +to see widespread use. Furthermore, allowing or disallowing extra accuracy +seems more closely a property of the calculation than a property of the type. We could provide an option to enable extra accuracy for the default floating-point types, but disable it by default. This would leave the majority From 9db70f29aac342a0e09e860ec9aceee1ffedcb0b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 24 Apr 2019 14:35:01 -0700 Subject: [PATCH 11/11] Substantial overhaul to better accommodate applications wanting to disable this - Add some explicit timeline guidance on stabilization, to ensure that this behavior does not make its way into stable too quickly. - Mention at the top of the document that this RFC specifies robust mechanisms to disable this behavior. - Add guide-level explanation of existing behavior, explicit discussion of applications still taking special care to achieve identical results across *some* platforms, and reference to the disabling mechanisms to help achieve that. - Add much more specific descriptions of the codegen option and attributes. - Remove the opt-in attribute, to ensure that the codegen option acts as a top-level opt-out, and avoid any need for a "force-off" mechanism. - Expand the alternatives section. - Discuss more C compilers; ICC and some other C compilers do this as well, and Clang does not by default. - Explicitly acknowledge, as a drawback, that though Rust has varations like this already, this does introduce variations in target platforms that didn't previously have them. This tones down the existing ameliorating language in the drawbacks section. --- ...000-floating-point-additional-precision.md | 75 +++++++++++++++---- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/text/0000-floating-point-additional-precision.md b/text/0000-floating-point-additional-precision.md index 2d60cbf6ae4..0c0141ab43d 100644 --- a/text/0000-floating-point-additional-precision.md +++ b/text/0000-floating-point-additional-precision.md @@ -8,7 +8,7 @@ Update the Rust specification to allow floating-point operations to provide *more* precision than specified, but not less precision; this allows many safe -optimizations. +optimizations. Specify robust mechanisms to disable this behavior. # Motivation [motivation]: #motivation @@ -48,6 +48,14 @@ will never make any floating-point operation *less* accurate, but it can make floating-point operations *more* accurate, making the result closer to the mathematically exact answer. +Due to differences in hardware, in platform libm implementations, and various +other factors, Rust cannot fully guarantee identical results on all target +platforms. (Doing so on *all* platforms would incur a massive performance +loss.) However, with some additional care, applications desiring cross-platform +identical results can potentially achieve that on multiple target platforms. In +particular, applications prioritizing identical, portable results across two or +more target platforms can disable extra floating-point precision entirely. + # Reference-level explanation [reference-level-explanation]: #reference-level-explanation @@ -65,10 +73,21 @@ precision than the standard requires, such as by doing a series of operations with higher precision before storing a value of the desired precision. rustc should provide a codegen (`-C`) option to disable this behavior, such as -`-C extra-fp-precision=off`. Rust should also provide attributes to enable and -disable this behavior from within code, such as `#[extra_fp_precision]` or -`#[extra_fp_precision(off)]`, respectively. (An attribute would take precedence -over a codegen option.) +`-C extra-fp-precision=off`; compiling with this option will disable extra +precision in all crates compiled into an application. (Cargo should provide a +means of specifying this option.) Rust should also provide attributes to +disable this behavior from within code, such as `#[extra_fp_precision(off)]`; +this attribute will disable extra precision within the module or function it is +applied to. On platforms that do not currently implement disabling extra +precision, the codegen option and attribute should produce an error (not a +warning), to avoid surprises. + +In addition, because this change makes extra floating-point precision visible +on more platforms, the Rust release notes, documentation, and similar channels +should explicitly discuss the issue of extra floating-point precision and how +to disable it. Furthermore, this change should not become part of a stable Rust +release until at least eight stable releases *after* it first becomes +implemented in the nightly compiler. # Drawbacks [drawbacks]: #drawbacks @@ -85,16 +104,22 @@ produce different binary results; in particular, floating-point operations in Rust can already produce more precise results depending on target platform, optimization level, the target's libm library, and the version of the target libm. As with that existing behavior, this proposal can never make results -*less* accurate, it can only make results *more* accurate. +*less* accurate, it can only make results *more* accurate. Nonetheless, this +change potentially introduces such variations on target platforms that did not +previously have them. # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives -We could provide a separate set of types and allow extra accuracy in their -operations; however, this would create API incompatibilities between -floating-point functions, and the longer, less-well-known types seem unlikely -to see widespread use. Furthermore, allowing or disallowing extra accuracy -seems more closely a property of the calculation than a property of the type. +For the attribute and codegen option, we could allow code to opt in via +attribute even if disabled via codegen, and then provide a `force-off` codegen +option to override that. This would have two serious downsides, however: it +would propagate the perception of extra floating-point precision as an unsafe +optimization that requires opting into, and it would make life more difficult +for people who wish to opt out of this behavior and attempt to achieve +identical results on multiple target platforms. This RFC recommends the simpler +approach of not providing an enablement option via attribute, such that the +codegen option always force-disables extra precision everywhere. We could provide an option to enable extra accuracy for the default floating-point types, but disable it by default. This would leave the majority @@ -103,7 +128,24 @@ matter, and the majority of code seems likely to use the defaults. In addition, permitting extra floating-point precision by default would match the existing behavior of Rust, and would allow the Rust compiler to assume that code explicitly disabling extra precision has a specific requirement to do so and -depends on that behavior. +depends on that behavior. Nonetheless, this alternative would still provide the +option to produce more optimized code, making it preferable over doing nothing. +This alternative would necessitate respecifying the codegen option and +attribute to support enabling it, as well as having a force-off codegen option +to override enablement via the attribute. + +We could provide a separate set of types and allow extra accuracy in their +operations; however, this would create API incompatibilities between +floating-point functions, and the longer, less-well-known types seem unlikely +to see widespread use. Furthermore, allowing or disallowing extra accuracy +seems more closely a property of the calculation than a property of the type. + +We could provide additional methods for floating-point operations that allow +passing additional flags, including floating-point contraction. The compiler +could then fuse and otherwise optimize such operations. However, this would +make optimized floating-point code *substantially* less ergonomic, due to the +inability to use operators. To enable operators, we could additionally +implement wrapper types, as above, with the same upsides and downsides. We could do nothing, and require code to use `a.mul_add(b, c)` for optimization; however, this would not allow for similar future optimizations, @@ -121,10 +163,11 @@ discussion on this point. This has precedent in several other languages and compilers: - [C11](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) allows - this with the `STDC FP_CONTRACT` pragma enabled, and the default state - of that pragma is implementation-defined. GCC enables this pragma by - default, [as does the Microsoft C - compiler](https://docs.microsoft.com/en-us/cpp/preprocessor/fp-contract?view=vs-2019). + extra floating-point precision with the `STDC FP_CONTRACT` pragma enabled, + and the default state of that pragma is implementation-defined. GCC, ICC, + MSVC, and some other C compilers enable this behavior by default; Clang + disables it by default, though some downstream users of Clang re-enable it + system-wide. - [The C++ standard](http://eel.is/c++draft/expr.pre#6) states that "The values of the floating operands and the results of floating