├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── benchmark.rs ├── rustfmt.toml └── src ├── checkers.rs ├── float_impl.rs ├── lib.rs └── types.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # rust 2 | target 3 | Cargo.lock 4 | 5 | # editor 6 | *.swp 7 | *.swo 8 | *~ 9 | .*~ 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "noisy_float" 3 | version = "0.2.0" 4 | edition = "2018" 5 | authors = ["Matthew Michelotti "] 6 | description = "Contains floating point types that panic if they are set to an illegal value, such as NaN" 7 | documentation = "https://docs.rs/noisy_float" 8 | repository = "https://github.com/SergiusIW/noisy_float-rs" 9 | readme = "README.md" 10 | keywords = ["float", "Ord", "NaN", "finite", "panic"] 11 | categories = ["mathematics"] 12 | license = "Apache-2.0" 13 | 14 | [dependencies] 15 | num-traits = "0.2" 16 | serde = { version = "1.0", optional = true } 17 | approx = { version = "0.5", optional = true } 18 | 19 | [dev-dependencies] 20 | serde_json = "1.0" 21 | serde_derive = "1.0" 22 | criterion = "0.3" 23 | 24 | [[bench]] 25 | name = "benchmark" 26 | harness = false 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # noisy_float-rs 2 | This is a Rust library containing floating point types that panic if they are set 3 | to an illegal value, such as NaN. 4 | 5 | ### Crate 6 | 7 | The Rust crate for this library can be found [here](https://crates.io/crates/noisy_float). 8 | 9 | ### Documentation 10 | 11 | The documentation for this library can be found [here](https://docs.rs/noisy_float). 12 | 13 | ### Description 14 | 15 | The name "Noisy Float" comes from 16 | the terms "quiet NaN" and "signaling NaN"; "signaling" was too long 17 | to put in a struct/crate name, so "noisy" is used instead, being the opposite 18 | of "quiet." 19 | 20 | The standard types defined in `noisy_float::types` follow the principle 21 | demonstrated by Rust's handling of integer overflow: 22 | a bad arithmetic operation is considered an error, 23 | but it is too costly to check everywhere in optimized builds. 24 | For each floating point number that is created, a `debug_assert!` invocation is used 25 | to check if it is valid or not. 26 | This way, there are guarantees when developing code that floating point 27 | numbers have valid values, 28 | but during a release run there is *no overhead* for using these floating 29 | point types compared to using `f32` or `f64` directly. 30 | 31 | This crate makes use of the num, bounded, signed and floating point traits in the 32 | popular `num_traits` crate. 33 | This crate can be compiled with no_std. 34 | 35 | ### Examples 36 | An example using the `R64` type, which corresponds to *finite* `f64` values. 37 | 38 | ```rust 39 | use noisy_float::prelude::*; 40 | 41 | fn geometric_mean(a: R64, b: R64) -> R64 { 42 | (a * b).sqrt() //used just like regular floating-point numbers 43 | } 44 | 45 | println!("geometric_mean(10.0, 20.0) = {}", geometric_mean(r64(10.0), r64(20.0))); 46 | //prints 14.142... 47 | ``` 48 | 49 | An example using the `N32` type, which corresponds to *non-NaN* `f32` values. 50 | The float types in this crate are able to implement `Eq` and `Ord` properly, 51 | since NaN is not allowed. 52 | 53 | ```rust 54 | use noisy_float::prelude::*; 55 | 56 | let values = vec![n32(3.0), n32(-1.5), n32(71.3), N32::infinity()]; 57 | assert!(values.iter().cloned().min() == Some(n32(-1.5))); 58 | assert!(values.iter().cloned().max() == Some(N32::infinity())); 59 | ``` 60 | 61 | ### License 62 | 63 | Noisy_float is licensed under the [Apache 2.0 64 | License](http://www.apache.org/licenses/LICENSE-2.0.html). 65 | -------------------------------------------------------------------------------- /benches/benchmark.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2021 Matthew D. Michelotti 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use criterion::{black_box as bb, criterion_group, criterion_main, Criterion}; 16 | use noisy_float::prelude::*; 17 | use std::iter::Sum; 18 | 19 | fn bench_ops(c: &mut Criterion) { 20 | let mut group = c.benchmark_group("Add [20. + 3.]"); 21 | group.bench_function("f32", |b| b.iter(|| bb(20_f32) + bb(3_f32))); 22 | group.bench_function("R32", |b| b.iter(|| r32(bb(20_f32)) + r32(bb(3_f32)))); 23 | group.bench_function("N32", |b| b.iter(|| n32(bb(20_f32)) + n32(bb(3_f32)))); 24 | group.bench_function("f64", |b| b.iter(|| bb(20_f64) + bb(3_f64))); 25 | group.bench_function("R64", |b| b.iter(|| r64(bb(20_f64)) + r64(bb(3_f64)))); 26 | group.bench_function("N64", |b| b.iter(|| n64(bb(20_f64)) + n64(bb(3_f64)))); 27 | group.finish(); 28 | 29 | let mut group = c.benchmark_group("Multiply [20. * 3.]"); 30 | group.bench_function("f64", |b| b.iter(|| bb(20_f64) * bb(3_f64))); 31 | group.bench_function("R64", |b| b.iter(|| r64(bb(20_f64)) * r64(bb(3_f64)))); 32 | group.finish(); 33 | 34 | let mut group = c.benchmark_group("Divide [20. / 3.]"); 35 | group.bench_function("f64", |b| b.iter(|| bb(20_f64) / bb(3_f64))); 36 | group.bench_function("R64", |b| b.iter(|| r64(bb(20_f64)) / r64(bb(3_f64)))); 37 | group.finish(); 38 | 39 | let mut group = c.benchmark_group("Divide-Assign [20. /= 3.]"); 40 | group.bench_function("f64", |b| { 41 | b.iter(|| { 42 | let mut x = bb(20_f64); 43 | x /= bb(3_f64); 44 | x 45 | }) 46 | }); 47 | group.bench_function("R64", |b| { 48 | b.iter(|| { 49 | let mut x = r64(bb(20_f64)); 50 | x /= r64(bb(3_f64)); 51 | x 52 | }) 53 | }); 54 | group.finish(); 55 | 56 | let mut group = c.benchmark_group("Equals [20. == 20.]"); 57 | group.bench_function("f64", |b| b.iter(|| bb(20_f64) == bb(20_f64))); 58 | group.bench_function("R64", |b| b.iter(|| r64(bb(20_f64)) == r64(bb(20_f64)))); 59 | group.finish(); 60 | 61 | let mut group = c.benchmark_group("Less than [20. < 3.]"); 62 | group.bench_function("f64", |b| b.iter(|| bb(20_f64) < bb(3_f64))); 63 | group.bench_function("R64", |b| b.iter(|| r64(bb(20_f64)) < r64(bb(3_f64)))); 64 | group.finish(); 65 | } 66 | 67 | fn matrix_vector_multiply(matrix: &[F], vector: &[F]) -> Vec { 68 | let dim = vector.len(); 69 | assert!(matrix.len() == dim * dim); 70 | matrix 71 | .chunks(dim) 72 | .map(|row| row.iter().zip(vector).map(|(&a, &b)| a * b).sum()) 73 | .collect() 74 | } 75 | 76 | fn bench_algorithm(c: &mut Criterion) { 77 | let matrix: Vec = (0..(20 * 20)).map(|i| ((i * 31) % 50) as f64).collect(); 78 | let vector: Vec = (0..20).map(|i| ((i * 37) % 70) as f64).collect(); 79 | let matrix_r64: Vec = matrix.iter().map(|&x| r64(x)).collect(); 80 | let vector_r64: Vec = vector.iter().map(|&x| r64(x)).collect(); 81 | 82 | let mut group = c.benchmark_group("Matrix-Vector multiply [20 x 20]"); 83 | group.bench_function("f64", move |b| { 84 | b.iter(|| matrix_vector_multiply(bb(&matrix), bb(&vector))) 85 | }); 86 | group.bench_function("R64", move |b| { 87 | b.iter(|| matrix_vector_multiply(bb(&matrix_r64), bb(&vector_r64))) 88 | }); 89 | group.finish(); 90 | } 91 | 92 | criterion_group!(benches, bench_ops, bench_algorithm); 93 | criterion_main!(benches); 94 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | format_code_in_doc_comments = true 2 | -------------------------------------------------------------------------------- /src/checkers.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2021 Matthew D. Michelotti 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Standard implementations of `FloatChecker`. 16 | 17 | use crate::{FloatChecker, NoisyFloat}; 18 | use num_traits::Float; 19 | 20 | /// A `FloatChecker` that considers all values valid except NaN. 21 | /// 22 | /// This checks that the value is a "number", i.e. it is not "not-a-number". 23 | /// 24 | /// The `assert` method is implemented using `debug_assert!`. 25 | pub struct NumChecker; 26 | 27 | impl FloatChecker for NumChecker { 28 | #[inline] 29 | fn assert(value: F) { 30 | debug_assert!(Self::check(value), "unexpected NaN"); 31 | } 32 | 33 | #[inline] 34 | fn check(value: F) -> bool { 35 | !value.is_nan() 36 | } 37 | } 38 | 39 | /// A `FloatChecker` that considers all values valid except NaN and +/- Infinity. 40 | /// 41 | /// The `assert` method is implemented using `debug_assert!`. 42 | pub struct FiniteChecker; 43 | 44 | impl FloatChecker for FiniteChecker { 45 | #[inline] 46 | fn assert(value: F) { 47 | debug_assert!(Self::check(value), "unexpected NaN or infinity"); 48 | } 49 | 50 | #[inline] 51 | fn check(value: F) -> bool { 52 | value.is_finite() 53 | } 54 | } 55 | 56 | impl From> for NoisyFloat { 57 | fn from(value: NoisyFloat) -> Self { 58 | Self::unchecked_new_generic(value.raw()) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/float_impl.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2021 Matthew D. Michelotti 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use crate::{FloatChecker, NoisyFloat}; 16 | use core::{ 17 | cmp::Ordering, 18 | convert::{From, TryFrom}, 19 | hash::{Hash, Hasher}, 20 | iter, 21 | num::FpCategory, 22 | ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign}, 23 | }; 24 | use num_traits::{ 25 | cast::{FromPrimitive, NumCast, ToPrimitive}, 26 | identities::{One, Zero}, 27 | Bounded, Float, FloatConst, Num, Signed, 28 | }; 29 | 30 | impl> Clone for NoisyFloat { 31 | #[inline] 32 | fn clone(&self) -> Self { 33 | Self::unchecked_new_generic(self.value) 34 | } 35 | } 36 | 37 | impl> Copy for NoisyFloat {} 38 | 39 | impl> AsRef for NoisyFloat { 40 | fn as_ref(&self) -> &F { 41 | &self.value 42 | } 43 | } 44 | 45 | impl> PartialEq for NoisyFloat { 46 | #[inline] 47 | fn eq(&self, other: &F) -> bool { 48 | self.value.eq(&other) 49 | } 50 | } 51 | 52 | impl> PartialEq for NoisyFloat { 53 | #[inline] 54 | fn eq(&self, other: &Self) -> bool { 55 | self.eq(&other.value) 56 | } 57 | } 58 | 59 | impl> Eq for NoisyFloat {} 60 | 61 | impl> PartialOrd for NoisyFloat { 62 | #[inline] 63 | fn partial_cmp(&self, other: &F) -> Option { 64 | self.value.partial_cmp(&other) 65 | } 66 | #[inline] 67 | fn lt(&self, other: &F) -> bool { 68 | self.value.lt(&other) 69 | } 70 | #[inline] 71 | fn le(&self, other: &F) -> bool { 72 | self.value.le(&other) 73 | } 74 | #[inline] 75 | fn gt(&self, other: &F) -> bool { 76 | self.value.gt(&other) 77 | } 78 | #[inline] 79 | fn ge(&self, other: &F) -> bool { 80 | self.value.ge(&other) 81 | } 82 | } 83 | 84 | impl> PartialOrd for NoisyFloat { 85 | #[inline] 86 | fn partial_cmp(&self, other: &Self) -> Option { 87 | self.value.partial_cmp(&other.value) 88 | } 89 | #[inline] 90 | fn lt(&self, other: &Self) -> bool { 91 | self.lt(&other.value) 92 | } 93 | #[inline] 94 | fn le(&self, other: &Self) -> bool { 95 | self.le(&other.value) 96 | } 97 | #[inline] 98 | fn gt(&self, other: &Self) -> bool { 99 | self.gt(&other.value) 100 | } 101 | #[inline] 102 | fn ge(&self, other: &Self) -> bool { 103 | self.ge(&other.value) 104 | } 105 | } 106 | 107 | impl> Ord for NoisyFloat { 108 | #[inline] 109 | fn cmp(&self, other: &Self) -> Ordering { 110 | if self.value < other.value { 111 | Ordering::Less 112 | } else if self.value == other.value { 113 | Ordering::Equal 114 | } else { 115 | Ordering::Greater 116 | } 117 | } 118 | } 119 | 120 | impl> Hash for NoisyFloat { 121 | #[inline] 122 | fn hash(&self, state: &mut H) { 123 | let bits = if self.value == 0.0 { 124 | 0 // this accounts for +0.0 and -0.0 125 | } else { 126 | self.value.to_bits() 127 | }; 128 | bits.hash(state); 129 | } 130 | } 131 | 132 | impl> Hash for NoisyFloat { 133 | #[inline] 134 | fn hash(&self, state: &mut H) { 135 | let bits = if self.value == 0.0 { 136 | 0 // this accounts for +0.0 and -0.0 137 | } else { 138 | self.value.to_bits() 139 | }; 140 | bits.hash(state); 141 | } 142 | } 143 | 144 | // TODO why is `impl> Hash for NoisyFloat` considered conflicting? 145 | 146 | impl> Add for NoisyFloat { 147 | type Output = Self; 148 | #[inline] 149 | fn add(self, rhs: F) -> Self { 150 | Self::new(self.value.add(rhs)) 151 | } 152 | } 153 | 154 | impl<'a, F: Float, C: FloatChecker> Add<&'a F> for NoisyFloat { 155 | type Output = Self; 156 | #[inline] 157 | fn add(self, rhs: &'a F) -> Self { 158 | Self::new(self.value.add(*rhs)) 159 | } 160 | } 161 | 162 | impl> Add for NoisyFloat { 163 | type Output = Self; 164 | #[inline] 165 | fn add(self, rhs: Self) -> Self { 166 | self.add(rhs.value) 167 | } 168 | } 169 | 170 | impl<'a, F: Float, C: FloatChecker> Add<&'a Self> for NoisyFloat { 171 | type Output = Self; 172 | #[inline] 173 | fn add(self, rhs: &'a Self) -> Self { 174 | self.add(rhs.value) 175 | } 176 | } 177 | 178 | impl> Sub for NoisyFloat { 179 | type Output = Self; 180 | #[inline] 181 | fn sub(self, rhs: F) -> Self { 182 | Self::new(self.value.sub(rhs)) 183 | } 184 | } 185 | 186 | impl<'a, F: Float, C: FloatChecker> Sub<&'a F> for NoisyFloat { 187 | type Output = Self; 188 | #[inline] 189 | fn sub(self, rhs: &'a F) -> Self { 190 | Self::new(self.value.sub(*rhs)) 191 | } 192 | } 193 | 194 | impl> Sub for NoisyFloat { 195 | type Output = Self; 196 | #[inline] 197 | fn sub(self, rhs: Self) -> Self { 198 | self.sub(rhs.value) 199 | } 200 | } 201 | 202 | impl<'a, F: Float, C: FloatChecker> Sub<&'a Self> for NoisyFloat { 203 | type Output = Self; 204 | #[inline] 205 | fn sub(self, rhs: &'a Self) -> Self { 206 | self.sub(rhs.value) 207 | } 208 | } 209 | 210 | impl> Mul for NoisyFloat { 211 | type Output = Self; 212 | #[inline] 213 | fn mul(self, rhs: F) -> Self { 214 | Self::new(self.value.mul(rhs)) 215 | } 216 | } 217 | 218 | impl<'a, F: Float, C: FloatChecker> Mul<&'a F> for NoisyFloat { 219 | type Output = Self; 220 | #[inline] 221 | fn mul(self, rhs: &'a F) -> Self { 222 | Self::new(self.value.mul(*rhs)) 223 | } 224 | } 225 | 226 | impl> Mul for NoisyFloat { 227 | type Output = Self; 228 | #[inline] 229 | fn mul(self, rhs: Self) -> Self { 230 | self.mul(rhs.value) 231 | } 232 | } 233 | 234 | impl<'a, F: Float, C: FloatChecker> Mul<&'a Self> for NoisyFloat { 235 | type Output = Self; 236 | #[inline] 237 | fn mul(self, rhs: &'a Self) -> Self { 238 | self.mul(rhs.value) 239 | } 240 | } 241 | 242 | impl> Div for NoisyFloat { 243 | type Output = Self; 244 | #[inline] 245 | fn div(self, rhs: F) -> Self { 246 | Self::new(self.value.div(rhs)) 247 | } 248 | } 249 | 250 | impl<'a, F: Float, C: FloatChecker> Div<&'a F> for NoisyFloat { 251 | type Output = Self; 252 | #[inline] 253 | fn div(self, rhs: &'a F) -> Self { 254 | Self::new(self.value.div(*rhs)) 255 | } 256 | } 257 | 258 | impl> Div for NoisyFloat { 259 | type Output = Self; 260 | #[inline] 261 | fn div(self, rhs: Self) -> Self { 262 | self.div(rhs.value) 263 | } 264 | } 265 | 266 | impl<'a, F: Float, C: FloatChecker> Div<&'a Self> for NoisyFloat { 267 | type Output = Self; 268 | #[inline] 269 | fn div(self, rhs: &'a Self) -> Self { 270 | self.div(rhs.value) 271 | } 272 | } 273 | 274 | impl> Rem for NoisyFloat { 275 | type Output = Self; 276 | #[inline] 277 | fn rem(self, rhs: F) -> Self { 278 | Self::new(self.value.rem(rhs)) 279 | } 280 | } 281 | 282 | impl<'a, F: Float, C: FloatChecker> Rem<&'a F> for NoisyFloat { 283 | type Output = Self; 284 | #[inline] 285 | fn rem(self, rhs: &'a F) -> Self { 286 | Self::new(self.value.rem(*rhs)) 287 | } 288 | } 289 | 290 | impl> Rem for NoisyFloat { 291 | type Output = Self; 292 | #[inline] 293 | fn rem(self, rhs: Self) -> Self { 294 | self.rem(rhs.value) 295 | } 296 | } 297 | 298 | impl<'a, F: Float, C: FloatChecker> Rem<&'a Self> for NoisyFloat { 299 | type Output = Self; 300 | #[inline] 301 | fn rem(self, rhs: &'a Self) -> Self { 302 | self.rem(rhs.value) 303 | } 304 | } 305 | 306 | impl> AddAssign for NoisyFloat { 307 | #[inline] 308 | fn add_assign(&mut self, rhs: F) { 309 | self.value.add_assign(rhs); 310 | C::assert(self.value); 311 | } 312 | } 313 | 314 | impl<'a, F: Float + AddAssign, C: FloatChecker> AddAssign<&'a F> for NoisyFloat { 315 | #[inline] 316 | fn add_assign(&mut self, rhs: &'a F) { 317 | self.value.add_assign(*rhs); 318 | C::assert(self.value); 319 | } 320 | } 321 | 322 | impl> AddAssign for NoisyFloat { 323 | #[inline] 324 | fn add_assign(&mut self, rhs: Self) { 325 | self.add_assign(rhs.value); 326 | } 327 | } 328 | 329 | impl<'a, F: Float + AddAssign, C: FloatChecker> AddAssign<&'a Self> for NoisyFloat { 330 | #[inline] 331 | fn add_assign(&mut self, rhs: &'a Self) { 332 | self.add_assign(rhs.value); 333 | } 334 | } 335 | 336 | impl> SubAssign for NoisyFloat { 337 | #[inline] 338 | fn sub_assign(&mut self, rhs: F) { 339 | self.value.sub_assign(rhs); 340 | C::assert(self.value); 341 | } 342 | } 343 | 344 | impl<'a, F: Float + SubAssign, C: FloatChecker> SubAssign<&'a F> for NoisyFloat { 345 | #[inline] 346 | fn sub_assign(&mut self, rhs: &'a F) { 347 | self.value.sub_assign(*rhs); 348 | C::assert(self.value); 349 | } 350 | } 351 | 352 | impl> SubAssign for NoisyFloat { 353 | #[inline] 354 | fn sub_assign(&mut self, rhs: Self) { 355 | self.sub_assign(rhs.value); 356 | } 357 | } 358 | 359 | impl<'a, F: Float + SubAssign, C: FloatChecker> SubAssign<&'a Self> for NoisyFloat { 360 | #[inline] 361 | fn sub_assign(&mut self, rhs: &'a Self) { 362 | self.sub_assign(rhs.value); 363 | } 364 | } 365 | 366 | impl> MulAssign for NoisyFloat { 367 | #[inline] 368 | fn mul_assign(&mut self, rhs: F) { 369 | self.value.mul_assign(rhs); 370 | C::assert(self.value); 371 | } 372 | } 373 | 374 | impl<'a, F: Float + MulAssign, C: FloatChecker> MulAssign<&'a F> for NoisyFloat { 375 | #[inline] 376 | fn mul_assign(&mut self, rhs: &'a F) { 377 | self.value.mul_assign(*rhs); 378 | C::assert(self.value); 379 | } 380 | } 381 | 382 | impl> MulAssign for NoisyFloat { 383 | #[inline] 384 | fn mul_assign(&mut self, rhs: Self) { 385 | self.mul_assign(rhs.value); 386 | } 387 | } 388 | 389 | impl<'a, F: Float + MulAssign, C: FloatChecker> MulAssign<&'a Self> for NoisyFloat { 390 | #[inline] 391 | fn mul_assign(&mut self, rhs: &'a Self) { 392 | self.mul_assign(rhs.value); 393 | } 394 | } 395 | 396 | impl> DivAssign for NoisyFloat { 397 | #[inline] 398 | fn div_assign(&mut self, rhs: F) { 399 | self.value.div_assign(rhs); 400 | C::assert(self.value); 401 | } 402 | } 403 | 404 | impl<'a, F: Float + DivAssign, C: FloatChecker> DivAssign<&'a F> for NoisyFloat { 405 | #[inline] 406 | fn div_assign(&mut self, rhs: &'a F) { 407 | self.value.div_assign(*rhs); 408 | C::assert(self.value); 409 | } 410 | } 411 | 412 | impl> DivAssign for NoisyFloat { 413 | #[inline] 414 | fn div_assign(&mut self, rhs: Self) { 415 | self.div_assign(rhs.value); 416 | } 417 | } 418 | 419 | impl<'a, F: Float + DivAssign, C: FloatChecker> DivAssign<&'a Self> for NoisyFloat { 420 | #[inline] 421 | fn div_assign(&mut self, rhs: &'a Self) { 422 | self.div_assign(rhs.value); 423 | } 424 | } 425 | 426 | impl> RemAssign for NoisyFloat { 427 | #[inline] 428 | fn rem_assign(&mut self, rhs: F) { 429 | self.value.rem_assign(rhs); 430 | C::assert(self.value); 431 | } 432 | } 433 | 434 | impl<'a, F: Float + RemAssign, C: FloatChecker> RemAssign<&'a F> for NoisyFloat { 435 | #[inline] 436 | fn rem_assign(&mut self, rhs: &'a F) { 437 | self.value.rem_assign(*rhs); 438 | C::assert(self.value); 439 | } 440 | } 441 | 442 | impl> RemAssign for NoisyFloat { 443 | #[inline] 444 | fn rem_assign(&mut self, rhs: Self) { 445 | self.rem_assign(rhs.value); 446 | } 447 | } 448 | 449 | impl<'a, F: Float + RemAssign, C: FloatChecker> RemAssign<&'a Self> for NoisyFloat { 450 | #[inline] 451 | fn rem_assign(&mut self, rhs: &'a Self) { 452 | self.rem_assign(rhs.value); 453 | } 454 | } 455 | 456 | impl> Neg for NoisyFloat { 457 | type Output = Self; 458 | #[inline] 459 | fn neg(self) -> Self { 460 | Self::new(self.value.neg()) 461 | } 462 | } 463 | 464 | impl<'a, F: Float, C: FloatChecker> Neg for &'a NoisyFloat { 465 | type Output = NoisyFloat; 466 | #[inline] 467 | fn neg(self) -> Self::Output { 468 | Self::Output::neg(*self) 469 | } 470 | } 471 | 472 | impl> Zero for NoisyFloat { 473 | #[inline] 474 | fn zero() -> Self { 475 | Self::new(F::zero()) 476 | } 477 | #[inline] 478 | fn is_zero(&self) -> bool { 479 | self.value.is_zero() 480 | } 481 | } 482 | 483 | impl> One for NoisyFloat { 484 | #[inline] 485 | fn one() -> Self { 486 | Self::new(F::one()) 487 | } 488 | } 489 | 490 | impl> Num for NoisyFloat { 491 | type FromStrRadixErr = F::FromStrRadixErr; 492 | #[inline] 493 | fn from_str_radix(str: &str, radix: u32) -> Result { 494 | F::from_str_radix(str, radix).map(|v| Self::new(v)) 495 | } 496 | } 497 | 498 | impl> ToPrimitive for NoisyFloat { 499 | #[inline] 500 | fn to_i64(&self) -> Option { 501 | self.value.to_i64() 502 | } 503 | #[inline] 504 | fn to_u64(&self) -> Option { 505 | self.value.to_u64() 506 | } 507 | #[inline] 508 | fn to_isize(&self) -> Option { 509 | self.value.to_isize() 510 | } 511 | #[inline] 512 | fn to_i8(&self) -> Option { 513 | self.value.to_i8() 514 | } 515 | #[inline] 516 | fn to_i16(&self) -> Option { 517 | self.value.to_i16() 518 | } 519 | #[inline] 520 | fn to_i32(&self) -> Option { 521 | self.value.to_i32() 522 | } 523 | #[inline] 524 | fn to_usize(&self) -> Option { 525 | self.value.to_usize() 526 | } 527 | #[inline] 528 | fn to_u8(&self) -> Option { 529 | self.value.to_u8() 530 | } 531 | #[inline] 532 | fn to_u16(&self) -> Option { 533 | self.value.to_u16() 534 | } 535 | #[inline] 536 | fn to_u32(&self) -> Option { 537 | self.value.to_u32() 538 | } 539 | #[inline] 540 | fn to_f32(&self) -> Option { 541 | self.value.to_f32() 542 | } 543 | #[inline] 544 | fn to_f64(&self) -> Option { 545 | self.value.to_f64() 546 | } 547 | } 548 | 549 | impl> FromPrimitive for NoisyFloat { 550 | #[inline] 551 | fn from_isize(n: isize) -> Option { 552 | Self::try_new(F::from_isize(n)?) 553 | } 554 | #[inline] 555 | fn from_i8(n: i8) -> Option { 556 | Self::try_new(F::from_i8(n)?) 557 | } 558 | #[inline] 559 | fn from_i16(n: i16) -> Option { 560 | Self::try_new(F::from_i16(n)?) 561 | } 562 | #[inline] 563 | fn from_i32(n: i32) -> Option { 564 | Self::try_new(F::from_i32(n)?) 565 | } 566 | #[inline] 567 | fn from_i64(n: i64) -> Option { 568 | Self::try_new(F::from_i64(n)?) 569 | } 570 | #[inline] 571 | fn from_i128(n: i128) -> Option { 572 | Self::try_new(F::from_i128(n)?) 573 | } 574 | #[inline] 575 | fn from_usize(n: usize) -> Option { 576 | Self::try_new(F::from_usize(n)?) 577 | } 578 | #[inline] 579 | fn from_u8(n: u8) -> Option { 580 | Self::try_new(F::from_u8(n)?) 581 | } 582 | #[inline] 583 | fn from_u16(n: u16) -> Option { 584 | Self::try_new(F::from_u16(n)?) 585 | } 586 | #[inline] 587 | fn from_u32(n: u32) -> Option { 588 | Self::try_new(F::from_u32(n)?) 589 | } 590 | #[inline] 591 | fn from_u64(n: u64) -> Option { 592 | Self::try_new(F::from_u64(n)?) 593 | } 594 | #[inline] 595 | fn from_u128(n: u128) -> Option { 596 | Self::try_new(F::from_u128(n)?) 597 | } 598 | #[inline] 599 | fn from_f32(n: f32) -> Option { 600 | Self::try_new(F::from_f32(n)?) 601 | } 602 | #[inline] 603 | fn from_f64(n: f64) -> Option { 604 | Self::try_new(F::from_f64(n)?) 605 | } 606 | } 607 | 608 | impl> NumCast for NoisyFloat { 609 | #[inline] 610 | fn from(n: T) -> Option { 611 | F::from(n).and_then(|v| Self::try_new(v)) 612 | } 613 | } 614 | 615 | impl> From> for f32 { 616 | #[inline] 617 | fn from(n: NoisyFloat) -> Self { 618 | n.value 619 | } 620 | } 621 | 622 | impl> From> for f64 { 623 | #[inline] 624 | fn from(n: NoisyFloat) -> Self { 625 | n.value 626 | } 627 | } 628 | 629 | impl> From> for f64 { 630 | #[inline] 631 | fn from(n: NoisyFloat) -> Self { 632 | n.value as f64 633 | } 634 | } 635 | 636 | impl> TryFrom for NoisyFloat { 637 | type Error = &'static str; 638 | #[inline] 639 | fn try_from(f: f64) -> Result { 640 | Self::try_new(f).ok_or("illegal value") 641 | } 642 | } 643 | 644 | impl> TryFrom for NoisyFloat { 645 | type Error = &'static str; 646 | #[inline] 647 | fn try_from(f: f32) -> Result { 648 | Self::try_new(f).ok_or("illegal value") 649 | } 650 | } 651 | 652 | impl> Float for NoisyFloat { 653 | #[inline] 654 | fn nan() -> Self { 655 | panic!("unexpected NaN") 656 | } 657 | #[inline] 658 | fn infinity() -> Self { 659 | Self::new(F::infinity()) 660 | } 661 | #[inline] 662 | fn neg_infinity() -> Self { 663 | Self::new(F::neg_infinity()) 664 | } 665 | #[inline] 666 | fn neg_zero() -> Self { 667 | Self::new(F::neg_zero()) 668 | } 669 | #[inline] 670 | fn min_value() -> Self { 671 | Self::new(F::min_value()) 672 | } 673 | #[inline] 674 | fn min_positive_value() -> Self { 675 | Self::new(F::min_positive_value()) 676 | } 677 | #[inline] 678 | fn max_value() -> Self { 679 | Self::new(F::max_value()) 680 | } 681 | #[inline] 682 | fn is_nan(self) -> bool { 683 | self.value.is_nan() 684 | } 685 | #[inline] 686 | fn is_infinite(self) -> bool { 687 | self.value.is_infinite() 688 | } 689 | #[inline] 690 | fn is_finite(self) -> bool { 691 | self.value.is_finite() 692 | } 693 | #[inline] 694 | fn is_normal(self) -> bool { 695 | self.value.is_normal() 696 | } 697 | #[inline] 698 | fn classify(self) -> FpCategory { 699 | self.value.classify() 700 | } 701 | #[inline] 702 | fn floor(self) -> Self { 703 | Self::new(self.value.floor()) 704 | } 705 | #[inline] 706 | fn ceil(self) -> Self { 707 | Self::new(self.value.ceil()) 708 | } 709 | #[inline] 710 | fn round(self) -> Self { 711 | Self::new(self.value.round()) 712 | } 713 | #[inline] 714 | fn trunc(self) -> Self { 715 | Self::new(self.value.trunc()) 716 | } 717 | #[inline] 718 | fn fract(self) -> Self { 719 | Self::new(self.value.fract()) 720 | } 721 | #[inline] 722 | fn abs(self) -> Self { 723 | Self::new(self.value.abs()) 724 | } 725 | #[inline] 726 | fn signum(self) -> Self { 727 | Self::new(self.value.signum()) 728 | } 729 | #[inline] 730 | fn is_sign_positive(self) -> bool { 731 | self.value.is_sign_positive() 732 | } 733 | #[inline] 734 | fn is_sign_negative(self) -> bool { 735 | self.value.is_sign_negative() 736 | } 737 | #[inline] 738 | fn mul_add(self, a: Self, b: Self) -> Self { 739 | Self::new(self.value.mul_add(a.value, b.value)) 740 | } 741 | #[inline] 742 | fn recip(self) -> Self { 743 | Self::new(self.value.recip()) 744 | } 745 | #[inline] 746 | fn powi(self, n: i32) -> Self { 747 | Self::new(self.value.powi(n)) 748 | } 749 | #[inline] 750 | fn powf(self, n: Self) -> Self { 751 | Self::new(self.value.powf(n.value)) 752 | } 753 | #[inline] 754 | fn sqrt(self) -> Self { 755 | Self::new(self.value.sqrt()) 756 | } 757 | #[inline] 758 | fn exp(self) -> Self { 759 | Self::new(self.value.exp()) 760 | } 761 | #[inline] 762 | fn exp2(self) -> Self { 763 | Self::new(self.value.exp2()) 764 | } 765 | #[inline] 766 | fn ln(self) -> Self { 767 | Self::new(self.value.ln()) 768 | } 769 | #[inline] 770 | fn log(self, base: Self) -> Self { 771 | Self::new(self.value.log(base.value)) 772 | } 773 | #[inline] 774 | fn log2(self) -> Self { 775 | Self::new(self.value.log2()) 776 | } 777 | #[inline] 778 | fn log10(self) -> Self { 779 | Self::new(self.value.log10()) 780 | } 781 | #[inline] 782 | fn max(self, other: Self) -> Self { 783 | Self::new(self.value.max(other.value)) 784 | } 785 | #[inline] 786 | fn min(self, other: Self) -> Self { 787 | Self::new(self.value.min(other.value)) 788 | } 789 | #[inline] 790 | fn abs_sub(self, other: Self) -> Self { 791 | Self::new(self.value.abs_sub(other.value)) 792 | } 793 | #[inline] 794 | fn cbrt(self) -> Self { 795 | Self::new(self.value.cbrt()) 796 | } 797 | #[inline] 798 | fn hypot(self, other: Self) -> Self { 799 | Self::new(self.value.hypot(other.value)) 800 | } 801 | #[inline] 802 | fn sin(self) -> Self { 803 | Self::new(self.value.sin()) 804 | } 805 | #[inline] 806 | fn cos(self) -> Self { 807 | Self::new(self.value.cos()) 808 | } 809 | #[inline] 810 | fn tan(self) -> Self { 811 | Self::new(self.value.tan()) 812 | } 813 | #[inline] 814 | fn asin(self) -> Self { 815 | Self::new(self.value.asin()) 816 | } 817 | #[inline] 818 | fn acos(self) -> Self { 819 | Self::new(self.value.acos()) 820 | } 821 | #[inline] 822 | fn atan(self) -> Self { 823 | Self::new(self.value.atan()) 824 | } 825 | #[inline] 826 | fn atan2(self, other: Self) -> Self { 827 | Self::new(self.value.atan2(other.value)) 828 | } 829 | #[inline] 830 | fn sin_cos(self) -> (Self, Self) { 831 | let (a, b) = self.value.sin_cos(); 832 | (Self::new(a), Self::new(b)) 833 | } 834 | #[inline] 835 | fn exp_m1(self) -> Self { 836 | Self::new(self.value.exp_m1()) 837 | } 838 | #[inline] 839 | fn ln_1p(self) -> Self { 840 | Self::new(self.value.ln_1p()) 841 | } 842 | #[inline] 843 | fn sinh(self) -> Self { 844 | Self::new(self.value.sinh()) 845 | } 846 | #[inline] 847 | fn cosh(self) -> Self { 848 | Self::new(self.value.cosh()) 849 | } 850 | #[inline] 851 | fn tanh(self) -> Self { 852 | Self::new(self.value.tanh()) 853 | } 854 | #[inline] 855 | fn asinh(self) -> Self { 856 | Self::new(self.value.asinh()) 857 | } 858 | #[inline] 859 | fn acosh(self) -> Self { 860 | Self::new(self.value.acosh()) 861 | } 862 | #[inline] 863 | fn atanh(self) -> Self { 864 | Self::new(self.value.atanh()) 865 | } 866 | #[inline] 867 | fn integer_decode(self) -> (u64, i16, i8) { 868 | self.value.integer_decode() 869 | } 870 | #[inline] 871 | fn epsilon() -> Self { 872 | Self::new(F::epsilon()) 873 | } 874 | #[inline] 875 | fn to_degrees(self) -> Self { 876 | Self::new(self.value.to_degrees()) 877 | } 878 | #[inline] 879 | fn to_radians(self) -> Self { 880 | Self::new(self.value.to_radians()) 881 | } 882 | } 883 | 884 | impl> FloatConst for NoisyFloat { 885 | #[inline] 886 | fn E() -> Self { 887 | Self::new(F::E()) 888 | } 889 | #[inline] 890 | fn FRAC_1_PI() -> Self { 891 | Self::new(F::FRAC_1_PI()) 892 | } 893 | #[inline] 894 | fn FRAC_1_SQRT_2() -> Self { 895 | Self::new(F::FRAC_1_SQRT_2()) 896 | } 897 | #[inline] 898 | fn FRAC_2_PI() -> Self { 899 | Self::new(F::FRAC_2_PI()) 900 | } 901 | #[inline] 902 | fn FRAC_2_SQRT_PI() -> Self { 903 | Self::new(F::FRAC_2_SQRT_PI()) 904 | } 905 | #[inline] 906 | fn FRAC_PI_2() -> Self { 907 | Self::new(F::FRAC_PI_2()) 908 | } 909 | #[inline] 910 | fn FRAC_PI_3() -> Self { 911 | Self::new(F::FRAC_PI_3()) 912 | } 913 | #[inline] 914 | fn FRAC_PI_4() -> Self { 915 | Self::new(F::FRAC_PI_4()) 916 | } 917 | #[inline] 918 | fn FRAC_PI_6() -> Self { 919 | Self::new(F::FRAC_PI_6()) 920 | } 921 | #[inline] 922 | fn FRAC_PI_8() -> Self { 923 | Self::new(F::FRAC_PI_8()) 924 | } 925 | #[inline] 926 | fn LN_10() -> Self { 927 | Self::new(F::LN_10()) 928 | } 929 | #[inline] 930 | fn LN_2() -> Self { 931 | Self::new(F::LN_2()) 932 | } 933 | #[inline] 934 | fn LOG10_E() -> Self { 935 | Self::new(F::LOG10_E()) 936 | } 937 | #[inline] 938 | fn LOG2_E() -> Self { 939 | Self::new(F::LOG2_E()) 940 | } 941 | #[inline] 942 | fn PI() -> Self { 943 | Self::new(F::PI()) 944 | } 945 | #[inline] 946 | fn SQRT_2() -> Self { 947 | Self::new(F::SQRT_2()) 948 | } 949 | } 950 | 951 | impl> Signed for NoisyFloat { 952 | #[inline] 953 | fn abs(&self) -> Self { 954 | Self::new(self.value.abs()) 955 | } 956 | #[inline] 957 | fn abs_sub(&self, other: &Self) -> Self { 958 | Self::new(self.value.abs_sub(other.value)) 959 | } 960 | #[inline] 961 | fn signum(&self) -> Self { 962 | Self::new(self.value.signum()) 963 | } 964 | #[inline] 965 | fn is_positive(&self) -> bool { 966 | self.value.is_positive() 967 | } 968 | #[inline] 969 | fn is_negative(&self) -> bool { 970 | self.value.is_negative() 971 | } 972 | } 973 | 974 | impl> Bounded for NoisyFloat { 975 | #[inline] 976 | fn min_value() -> Self { 977 | Self::new(Float::min_value()) 978 | } 979 | #[inline] 980 | fn max_value() -> Self { 981 | Self::new(Float::max_value()) 982 | } 983 | } 984 | 985 | impl> iter::Sum for NoisyFloat { 986 | fn sum(iter: I) -> Self 987 | where 988 | I: Iterator, 989 | { 990 | Self::new(iter.map(|i| i.raw()).fold(F::zero(), |acc, i| acc + i)) 991 | } 992 | } 993 | 994 | impl<'a, F: Float, C: FloatChecker> iter::Sum<&'a Self> for NoisyFloat { 995 | fn sum(iter: I) -> Self 996 | where 997 | I: Iterator, 998 | { 999 | Self::new(iter.map(|i| i.raw()).fold(F::zero(), |acc, i| acc + i)) 1000 | } 1001 | } 1002 | 1003 | impl> iter::Product for NoisyFloat { 1004 | fn product(iter: I) -> Self 1005 | where 1006 | I: Iterator, 1007 | { 1008 | Self::new(iter.map(|i| i.raw()).fold(F::one(), |acc, i| acc * i)) 1009 | } 1010 | } 1011 | 1012 | impl<'a, F: Float, C: FloatChecker> iter::Product<&'a Self> for NoisyFloat { 1013 | fn product(iter: I) -> Self 1014 | where 1015 | I: Iterator, 1016 | { 1017 | Self::new(iter.map(|i| i.raw()).fold(F::one(), |acc, i| acc * i)) 1018 | } 1019 | } 1020 | 1021 | #[cfg(feature = "approx")] 1022 | mod approx_impl { 1023 | use super::*; 1024 | use approx::{AbsDiffEq, RelativeEq, UlpsEq}; 1025 | 1026 | impl AbsDiffEq for NoisyFloat 1027 | where 1028 | F: Float + AbsDiffEq, 1029 | C: FloatChecker, 1030 | { 1031 | type Epsilon = NoisyFloat; 1032 | 1033 | fn default_epsilon() -> Self::Epsilon { 1034 | Self::Epsilon::new(F::default_epsilon()) 1035 | } 1036 | 1037 | fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { 1038 | self.raw().abs_diff_eq(&other.raw(), epsilon.raw()) 1039 | } 1040 | } 1041 | 1042 | impl RelativeEq for NoisyFloat 1043 | where 1044 | F: Float + RelativeEq, 1045 | C: FloatChecker, 1046 | { 1047 | fn default_max_relative() -> Self::Epsilon { 1048 | Self::new(F::default_max_relative()) 1049 | } 1050 | 1051 | fn relative_eq( 1052 | &self, 1053 | other: &Self, 1054 | epsilon: Self::Epsilon, 1055 | max_relative: Self::Epsilon, 1056 | ) -> bool { 1057 | self.raw() 1058 | .relative_eq(&other.raw(), epsilon.raw(), max_relative.raw()) 1059 | } 1060 | } 1061 | 1062 | impl UlpsEq for NoisyFloat 1063 | where 1064 | F: Float + UlpsEq, 1065 | C: FloatChecker, 1066 | { 1067 | fn default_max_ulps() -> u32 { 1068 | F::default_max_ulps() 1069 | } 1070 | 1071 | fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { 1072 | self.raw().ulps_eq(&other.raw(), epsilon.raw(), max_ulps) 1073 | } 1074 | } 1075 | } 1076 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2021 Matthew D. Michelotti 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! This crate contains floating point types that panic if they are set 16 | //! to an illegal value, such as NaN. 17 | //! 18 | //! The name "Noisy Float" comes from 19 | //! the terms "quiet NaN" and "signaling NaN"; "signaling" was too long 20 | //! to put in a struct/crate name, so "noisy" is used instead, being the opposite 21 | //! of "quiet." 22 | //! 23 | //! The standard types defined in `noisy_float::types` follow the principle 24 | //! demonstrated by Rust's handling of integer overflow: 25 | //! a bad arithmetic operation is considered an error, 26 | //! but it is too costly to check everywhere in optimized builds. 27 | //! For each floating point number that is created, a `debug_assert!` invocation is used 28 | //! to check if it is valid or not. 29 | //! This way, there are guarantees when developing code that floating point 30 | //! numbers have valid values, 31 | //! but during a release run there is *no overhead* for using these floating 32 | //! point types compared to using `f32` or `f64` directly. 33 | //! 34 | //! This crate makes use of the num, bounded, signed and floating point traits 35 | //! in the popular `num_traits` crate. 36 | //! This crate can be compiled with no_std. 37 | //! 38 | //! # Examples 39 | //! An example using the `R64` type, which corresponds to *finite* `f64` values. 40 | //! 41 | //! ``` 42 | //! use noisy_float::prelude::*; 43 | //! 44 | //! fn geometric_mean(a: R64, b: R64) -> R64 { 45 | //! (a * b).sqrt() //used just like regular floating point numbers 46 | //! } 47 | //! 48 | //! fn mean(a: R64, b: R64) -> R64 { 49 | //! (a + b) * 0.5 //the RHS of ops can be the underlying float type 50 | //! } 51 | //! 52 | //! println!( 53 | //! "geometric_mean(10.0, 20.0) = {}", 54 | //! geometric_mean(r64(10.0), r64(20.0)) 55 | //! ); 56 | //! //prints 14.142... 57 | //! assert!(mean(r64(10.0), r64(20.0)) == 15.0); 58 | //! ``` 59 | //! 60 | //! An example using the `N32` type, which corresponds to *non-NaN* `f32` values. 61 | //! The float types in this crate are able to implement `Eq` and `Ord` properly, 62 | //! since NaN is not allowed. 63 | //! 64 | //! ``` 65 | //! use noisy_float::prelude::*; 66 | //! 67 | //! let values = vec![n32(3.0), n32(-1.5), n32(71.3), N32::infinity()]; 68 | //! assert!(values.iter().cloned().min() == Some(n32(-1.5))); 69 | //! assert!(values.iter().cloned().max() == Some(N32::infinity())); 70 | //! ``` 71 | //! 72 | //! An example converting from R64 to primitive types. 73 | //! 74 | //! ``` 75 | //! use noisy_float::prelude::*; 76 | //! use num_traits::cast::ToPrimitive; 77 | //! 78 | //! let value_r64: R64 = r64(1.0); 79 | //! let value_f64_a: f64 = value_r64.into(); 80 | //! let value_f64_b: f64 = value_r64.raw(); 81 | //! let value_u64: u64 = value_r64.to_u64().unwrap(); 82 | //! 83 | //! assert!(value_f64_a == value_f64_b); 84 | //! assert!(value_f64_a as u64 == value_u64); 85 | //! ``` 86 | //! 87 | //! # Features 88 | //! 89 | //! This crate has the following cargo features: 90 | //! 91 | //! - `serde`: Enable serialization for all `NoisyFloats` using serde 1.0 and 92 | //! will transparently serialize then as floats 93 | //! - `approx`: Adds implementations to use `NoisyFloat` with the `approx` 94 | //! crate 95 | 96 | #![no_std] 97 | 98 | #[cfg(feature = "serde")] 99 | use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; 100 | 101 | pub mod checkers; 102 | mod float_impl; 103 | pub mod types; 104 | 105 | /// Prelude for the `noisy_float` crate. 106 | /// 107 | /// This includes all of the types defined in the `noisy_float::types` module, 108 | /// as well as a re-export of the `Float` trait from the `num_traits` crate. 109 | /// It is important to have this re-export here, because it allows the user 110 | /// to access common floating point methods like `abs()`, `sqrt()`, etc. 111 | pub mod prelude { 112 | pub use crate::types::*; 113 | 114 | #[doc(no_inline)] 115 | pub use num_traits::Float; 116 | } 117 | 118 | use core::{fmt, marker::PhantomData}; 119 | use num_traits::Float; 120 | 121 | /// Trait for checking whether a floating point number is *valid*. 122 | /// 123 | /// The implementation defines its own criteria for what constitutes a *valid* value. 124 | pub trait FloatChecker { 125 | /// Returns `true` if (and only if) the given floating point number is *valid* 126 | /// according to this checker's criteria. 127 | /// 128 | /// The only hard requirement is that NaN *must* be considered *invalid* 129 | /// for all implementations of `FloatChecker`. 130 | fn check(value: F) -> bool; 131 | 132 | /// A function that may panic if the floating point number is *invalid*. 133 | /// 134 | /// Should either call `assert!(check(value), ...)` or `debug_assert!(check(value), ...)`. 135 | fn assert(value: F); 136 | } 137 | 138 | /// A floating point number with a restricted set of legal values. 139 | /// 140 | /// Typical users will not need to access this struct directly, but 141 | /// can instead use the type aliases found in the module `noisy_float::types`. 142 | /// However, this struct together with a `FloatChecker` implementation can be used 143 | /// to define custom behavior. 144 | /// 145 | /// The underlying float type is `F`, usually `f32` or `f64`. 146 | /// Valid values for the float are determined by the float checker `C`. 147 | /// If an invalid value would ever be returned from a method on this type, 148 | /// the method will panic instead, using either `assert!` or `debug_assert!` 149 | /// as defined by the float checker. 150 | /// The exception to this rule is for methods that return an `Option` containing 151 | /// a `NoisyFloat`, in which case the result would be `None` if the value is invalid. 152 | #[repr(transparent)] 153 | pub struct NoisyFloat> { 154 | value: F, 155 | checker: PhantomData, 156 | } 157 | 158 | impl> NoisyFloat { 159 | /// Constructs a `NoisyFloat` with the given value. 160 | /// 161 | /// Uses the `FloatChecker` to assert that the value is valid. 162 | #[inline] 163 | pub fn new(value: F) -> Self { 164 | C::assert(value); 165 | Self::unchecked_new_generic(value) 166 | } 167 | 168 | #[inline] 169 | fn unchecked_new_generic(value: F) -> Self { 170 | NoisyFloat { 171 | value, 172 | checker: PhantomData, 173 | } 174 | } 175 | 176 | /// Tries to construct a `NoisyFloat` with the given value. 177 | /// 178 | /// Returns `None` if the value is invalid. 179 | #[inline] 180 | pub fn try_new(value: F) -> Option { 181 | if C::check(value) { 182 | Some(NoisyFloat { 183 | value, 184 | checker: PhantomData, 185 | }) 186 | } else { 187 | None 188 | } 189 | } 190 | 191 | /// Converts the value in-place to a reference to a `NoisyFloat`. 192 | /// 193 | /// Uses the `FloatChecker` to assert that the value is valid. 194 | #[inline] 195 | pub fn borrowed(value: &F) -> &Self { 196 | C::assert(*value); 197 | Self::unchecked_borrowed(value) 198 | } 199 | 200 | #[inline] 201 | fn unchecked_borrowed(value: &F) -> &Self { 202 | // This is safe because `NoisyFloat` is a thin wrapper around the 203 | // floating-point type. 204 | unsafe { &*(value as *const F as *const Self) } 205 | } 206 | 207 | /// Tries to convert the value in-place to a reference to a `NoisyFloat`. 208 | /// 209 | /// Returns `None` if the value is invalid. 210 | #[inline] 211 | pub fn try_borrowed(value: &F) -> Option<&Self> { 212 | if C::check(*value) { 213 | Some(Self::unchecked_borrowed(value)) 214 | } else { 215 | None 216 | } 217 | } 218 | 219 | /// Converts the value in-place to a mutable reference to a `NoisyFloat`. 220 | /// 221 | /// Uses the `FloatChecker` to assert that the value is valid. 222 | #[inline] 223 | pub fn borrowed_mut(value: &mut F) -> &mut Self { 224 | C::assert(*value); 225 | Self::unchecked_borrowed_mut(value) 226 | } 227 | 228 | #[inline] 229 | fn unchecked_borrowed_mut(value: &mut F) -> &mut Self { 230 | // This is safe because `NoisyFloat` is a thin wrapper around the 231 | // floating-point type. 232 | unsafe { &mut *(value as *mut F as *mut Self) } 233 | } 234 | 235 | /// Tries to convert the value in-place to a mutable reference to a `NoisyFloat`. 236 | /// 237 | /// Returns `None` if the value is invalid. 238 | #[inline] 239 | pub fn try_borrowed_mut(value: &mut F) -> Option<&mut Self> { 240 | if C::check(*value) { 241 | Some(Self::unchecked_borrowed_mut(value)) 242 | } else { 243 | None 244 | } 245 | } 246 | 247 | /// Constructs a `NoisyFloat` with the given `f32` value. 248 | /// 249 | /// May panic not only by the `FloatChecker` but also 250 | /// by unwrapping the result of a `NumCast` invocation for type `F`, 251 | /// although the later should not occur in normal situations. 252 | #[inline] 253 | pub fn from_f32(value: f32) -> Self { 254 | Self::new(F::from(value).unwrap()) 255 | } 256 | 257 | /// Constructs a `NoisyFloat` with the given `f64` value. 258 | /// 259 | /// May panic not only by the `FloatChecker` but also 260 | /// by unwrapping the result of a `NumCast` invocation for type `F`, 261 | /// although the later should not occur in normal situations. 262 | #[inline] 263 | pub fn from_f64(value: f64) -> Self { 264 | Self::new(F::from(value).unwrap()) 265 | } 266 | 267 | /// Returns the underlying float value. 268 | #[inline] 269 | pub fn raw(self) -> F { 270 | self.value 271 | } 272 | 273 | /// Compares and returns the minimum of two values. 274 | /// 275 | /// This method exists to disambiguate between `num_traits::Float.min` and `std::cmp::Ord.min`. 276 | #[inline] 277 | pub fn min(self, other: Self) -> Self { 278 | Ord::min(self, other) 279 | } 280 | 281 | /// Compares and returns the maximum of two values. 282 | /// 283 | /// This method exists to disambiguate between `num_traits::Float.max` and `std::cmp::Ord.max`. 284 | #[inline] 285 | pub fn max(self, other: Self) -> Self { 286 | Ord::max(self, other) 287 | } 288 | } 289 | 290 | impl> Default for NoisyFloat { 291 | #[inline] 292 | fn default() -> Self { 293 | Self::new(F::default()) 294 | } 295 | } 296 | 297 | impl> fmt::Debug for NoisyFloat { 298 | #[inline] 299 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 300 | fmt::Debug::fmt(&self.value, f) 301 | } 302 | } 303 | 304 | impl> fmt::Display for NoisyFloat { 305 | #[inline] 306 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 307 | fmt::Display::fmt(&self.value, f) 308 | } 309 | } 310 | 311 | impl> fmt::LowerExp for NoisyFloat { 312 | #[inline] 313 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 314 | fmt::LowerExp::fmt(&self.value, f) 315 | } 316 | } 317 | 318 | impl> fmt::UpperExp for NoisyFloat { 319 | #[inline] 320 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 321 | fmt::UpperExp::fmt(&self.value, f) 322 | } 323 | } 324 | 325 | #[cfg(feature = "serde")] 326 | impl> Serialize for NoisyFloat { 327 | fn serialize(&self, ser: S) -> Result { 328 | self.value.serialize(ser) 329 | } 330 | } 331 | 332 | #[cfg(feature = "serde")] 333 | impl<'de, F: Float + Deserialize<'de>, C: FloatChecker> Deserialize<'de> for NoisyFloat { 334 | fn deserialize>(de: D) -> Result { 335 | let value = F::deserialize(de)?; 336 | Self::try_new(value).ok_or_else(|| D::Error::custom("invalid NoisyFloat")) 337 | } 338 | } 339 | 340 | #[cfg(test)] 341 | mod tests { 342 | extern crate std; 343 | use std::prelude::v1::*; 344 | 345 | use crate::prelude::*; 346 | #[cfg(feature = "serde")] 347 | use serde_derive::{Deserialize, Serialize}; 348 | #[cfg(feature = "serde")] 349 | use serde_json; 350 | use std::{ 351 | f32, 352 | f64::{self, consts}, 353 | hash::{Hash, Hasher}, 354 | mem::{align_of, size_of}, 355 | }; 356 | 357 | #[test] 358 | fn smoke_test() { 359 | assert_eq!(n64(1.0) + 2.0, 3.0); 360 | assert_ne!(n64(3.0), n64(2.9)); 361 | assert!(r64(1.0) < 2.0); 362 | let mut value = n64(18.0); 363 | value %= n64(5.0); 364 | assert_eq!(-value, n64(-3.0)); 365 | assert_eq!(r64(1.0).exp(), consts::E); 366 | assert_eq!((N64::try_new(1.0).unwrap() / N64::infinity()), 0.0); 367 | assert_eq!(N64::from_f32(f32::INFINITY), N64::from_f64(f64::INFINITY)); 368 | assert_eq!(R64::try_new(f64::NEG_INFINITY), None); 369 | assert_eq!(N64::try_new(f64::NAN), None); 370 | assert_eq!(R64::try_new(f64::NAN), None); 371 | assert_eq!(N64::try_borrowed(&f64::NAN), None); 372 | let mut nan = f64::NAN; 373 | assert_eq!(N64::try_borrowed_mut(&mut nan), None); 374 | } 375 | 376 | #[test] 377 | fn ensure_layout() { 378 | assert_eq!(size_of::(), size_of::()); 379 | assert_eq!(align_of::(), align_of::()); 380 | 381 | assert_eq!(size_of::(), size_of::()); 382 | assert_eq!(align_of::(), align_of::()); 383 | } 384 | 385 | #[test] 386 | fn borrowed_casts() { 387 | assert_eq!(R64::borrowed(&3.12), &3.12); 388 | assert_eq!(N64::borrowed(&[f64::INFINITY; 2][0]), &f64::INFINITY); 389 | assert_eq!(N64::borrowed_mut(&mut 2.72), &mut 2.72); 390 | } 391 | 392 | #[test] 393 | fn test_convert() { 394 | assert_eq!(f32::from(r32(3.0)), 3.0f32); 395 | assert_eq!(f64::from(r32(5.0)), 5.0f64); 396 | assert_eq!(f64::from(r64(7.0)), 7.0f64); 397 | } 398 | 399 | #[test] 400 | #[cfg(debug_assertions)] 401 | #[should_panic] 402 | fn n64_nan() { 403 | let _ = n64(0.0) / n64(0.0); 404 | } 405 | 406 | #[test] 407 | #[cfg(debug_assertions)] 408 | #[should_panic] 409 | fn r64_nan() { 410 | let _ = r64(0.0) / r64(0.0); 411 | } 412 | 413 | #[test] 414 | #[cfg(debug_assertions)] 415 | #[should_panic] 416 | fn r64_infinity() { 417 | let _ = r64(1.0) / r64(0.0); 418 | } 419 | 420 | #[test] 421 | fn resolves_min_max() { 422 | assert_eq!(r64(1.0).min(r64(3.0)), r64(1.0)); 423 | assert_eq!(r64(1.0).max(r64(3.0)), r64(3.0)); 424 | } 425 | 426 | #[test] 427 | fn epsilon() { 428 | assert_eq!(R32::epsilon(), f32::EPSILON); 429 | assert_eq!(R64::epsilon(), f64::EPSILON); 430 | } 431 | 432 | #[test] 433 | fn test_try_into() { 434 | use std::convert::{TryFrom, TryInto}; 435 | let _: R64 = 1.0.try_into().unwrap(); 436 | let _ = R64::try_from(f64::INFINITY).unwrap_err(); 437 | } 438 | 439 | struct TestHasher { 440 | bytes: Vec, 441 | } 442 | 443 | impl Hasher for TestHasher { 444 | fn finish(&self) -> u64 { 445 | panic!("unexpected Hasher.finish invocation") 446 | } 447 | fn write(&mut self, bytes: &[u8]) { 448 | self.bytes.extend_from_slice(bytes) 449 | } 450 | } 451 | 452 | fn hash_bytes(value: T) -> Vec { 453 | let mut hasher = TestHasher { bytes: Vec::new() }; 454 | value.hash(&mut hasher); 455 | hasher.bytes 456 | } 457 | 458 | #[test] 459 | fn test_hash() { 460 | assert_eq!(hash_bytes(r64(10.3)), hash_bytes(10.3f64.to_bits())); 461 | assert_ne!(hash_bytes(r64(10.3)), hash_bytes(10.4f64.to_bits())); 462 | assert_eq!(hash_bytes(r32(10.3)), hash_bytes(10.3f32.to_bits())); 463 | assert_ne!(hash_bytes(r32(10.3)), hash_bytes(10.4f32.to_bits())); 464 | 465 | assert_eq!( 466 | hash_bytes(N64::infinity()), 467 | hash_bytes(f64::INFINITY.to_bits()) 468 | ); 469 | assert_eq!( 470 | hash_bytes(N64::neg_infinity()), 471 | hash_bytes(f64::NEG_INFINITY.to_bits()) 472 | ); 473 | 474 | // positive and negative zero should have the same hashes 475 | assert_eq!(hash_bytes(r64(0.0)), hash_bytes(0.0f64.to_bits())); 476 | assert_eq!(hash_bytes(r64(-0.0)), hash_bytes(0.0f64.to_bits())); 477 | assert_eq!(hash_bytes(r32(0.0)), hash_bytes(0.0f32.to_bits())); 478 | assert_eq!(hash_bytes(r32(-0.0)), hash_bytes(0.0f32.to_bits())); 479 | } 480 | 481 | #[cfg(feature = "serde")] 482 | #[test] 483 | fn serialize_transparently_as_float() { 484 | let num = R32::new(3.14); 485 | let should_be = "3.14"; 486 | 487 | let got = serde_json::to_string(&num).unwrap(); 488 | assert_eq!(got, should_be); 489 | } 490 | 491 | #[cfg(feature = "serde")] 492 | #[test] 493 | fn deserialize_transparently_as_float() { 494 | let src = "3.14"; 495 | let should_be = R32::new(3.14); 496 | 497 | let got: R32 = serde_json::from_str(src).unwrap(); 498 | assert_eq!(got, should_be); 499 | } 500 | 501 | #[cfg(feature = "serde")] 502 | #[test] 503 | fn deserialize_invalid_float() { 504 | use crate::{FloatChecker, NoisyFloat}; 505 | struct PositiveChecker; 506 | impl FloatChecker for PositiveChecker { 507 | fn check(value: f64) -> bool { 508 | value > 0. 509 | } 510 | fn assert(value: f64) { 511 | debug_assert!(Self::check(value)) 512 | } 513 | } 514 | 515 | let src = "-1.0"; 516 | let got: Result, _> = serde_json::from_str(src); 517 | assert!(got.is_err()); 518 | } 519 | 520 | // Make sure you can use serde_derive with noisy floats. 521 | #[cfg(feature = "serde")] 522 | #[derive(Debug, PartialEq, Serialize, Deserialize)] 523 | struct Dummy { 524 | value: N64, 525 | } 526 | 527 | #[cfg(feature = "serde")] 528 | #[test] 529 | fn deserialize_struct_containing_n64() { 530 | let src = r#"{ "value": 3.14 }"#; 531 | let should_be = Dummy { value: n64(3.14) }; 532 | 533 | let got: Dummy = serde_json::from_str(src).unwrap(); 534 | assert_eq!(got, should_be); 535 | } 536 | 537 | #[cfg(feature = "serde")] 538 | #[test] 539 | fn serialize_struct_containing_n64() { 540 | let src = Dummy { value: n64(3.14) }; 541 | let should_be = r#"{"value":3.14}"#; 542 | 543 | let got = serde_json::to_string(&src).unwrap(); 544 | assert_eq!(got, should_be); 545 | } 546 | 547 | #[cfg(feature = "approx")] 548 | #[test] 549 | fn approx_assert_eq() { 550 | use approx::{assert_abs_diff_eq, assert_relative_eq, assert_ulps_eq}; 551 | 552 | let lhs = r64(0.1000000000000001); 553 | let rhs = r64(0.1); 554 | 555 | assert_abs_diff_eq!(lhs, rhs); 556 | assert_relative_eq!(lhs, rhs); 557 | assert_ulps_eq!(lhs, rhs); 558 | } 559 | 560 | #[test] 561 | fn const_functions() { 562 | const A: N32 = N32::unchecked_new(1.0); 563 | const B: N64 = N64::unchecked_new(2.0); 564 | const C: R32 = R32::unchecked_new(3.0); 565 | const D: R64 = R64::unchecked_new(4.0); 566 | 567 | const A_RAW: f32 = A.const_raw(); 568 | const B_RAW: f64 = B.const_raw(); 569 | const C_RAW: f32 = C.const_raw(); 570 | const D_RAW: f64 = D.const_raw(); 571 | 572 | assert_eq!(A_RAW, 1.0); 573 | assert_eq!(B_RAW, 2.0); 574 | assert_eq!(C_RAW, 3.0); 575 | assert_eq!(D_RAW, 4.0); 576 | } 577 | } 578 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2021 Matthew D. Michelotti 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //! Standard definitions of `NoisyFloat`. 16 | //! 17 | //! Definitions in this module all use `debug_assert!` 18 | //! to check for valid values, so there is no overhead 19 | //! when running in an optimized build. 20 | 21 | use crate::{ 22 | checkers::{FiniteChecker, NumChecker}, 23 | NoisyFloat, 24 | }; 25 | use core::marker::PhantomData; 26 | 27 | /// A floating point number behaving like `f32` that does not allow NaN. 28 | /// 29 | /// The "N" in the name stands for "Number", since all values of this type 30 | /// are "numbers", i.e. they are not "not-a-number". 31 | pub type N32 = NoisyFloat; 32 | 33 | /// A floating point number behaving like `f64` that does not allow NaN. 34 | /// 35 | /// The "N" in the name stands for "Number", since all values of this type 36 | /// are "numbers", i.e. they are not "not-a-number". 37 | pub type N64 = NoisyFloat; 38 | 39 | /// A floating point number behaving like `f32` that does not allow NaN or +/- Infinity. 40 | /// 41 | /// The "R" in the name stands for "Real", since in Mathematics, the Real 42 | /// numbers do not include NaN or +/- Infinity. 43 | pub type R32 = NoisyFloat; 44 | 45 | /// A floating point number behaving like `f64` that does not allow NaN or +/- Infinity. 46 | /// 47 | /// The "R" in the name stands for "Real", since in Mathematics, the Real 48 | /// numbers do not include NaN or +/- Infinity. 49 | pub type R64 = NoisyFloat; 50 | 51 | /// Shorthand for `N32::new(value)`. 52 | #[inline] 53 | pub const fn n32(value: f32) -> N32 { 54 | debug_assert!(!value.is_nan()); 55 | N32::unchecked_new(value) 56 | } 57 | 58 | /// Shorthand for `N64::new(value)`. 59 | #[inline] 60 | pub const fn n64(value: f64) -> N64 { 61 | debug_assert!(!value.is_nan()); 62 | N64::unchecked_new(value) 63 | } 64 | 65 | /// Shorthand for `R32::new(value)`. 66 | #[inline] 67 | pub const fn r32(value: f32) -> R32 { 68 | debug_assert!(value.is_finite()); 69 | R32::unchecked_new(value) 70 | } 71 | 72 | /// Shorthand for `R64::new(value)`. 73 | #[inline] 74 | pub const fn r64(value: f64) -> R64 { 75 | debug_assert!(value.is_finite()); 76 | R64::unchecked_new(value) 77 | } 78 | 79 | macro_rules! const_fns { 80 | ($type:ty, $raw:ty) => { 81 | impl $type { 82 | /// A const constructor that does not check whether `value` is valid. 83 | /// 84 | /// WARNING: This constructor does not panic even in debug mode. 85 | /// As always, it is the user's responsibility to ensure `value` is valid. 86 | /// Until Rust supports panics in const functions, this constructor 87 | /// is necessary to create a NoisyFloat in a const setting. 88 | pub const fn unchecked_new(value: $raw) -> Self { 89 | Self { 90 | value, 91 | checker: PhantomData, 92 | } 93 | } 94 | 95 | /// A const function that returns the underlying float value. 96 | pub const fn const_raw(self) -> $raw { 97 | self.value 98 | } 99 | } 100 | }; 101 | } 102 | 103 | const_fns!(N32, f32); 104 | const_fns!(N64, f64); 105 | const_fns!(R32, f32); 106 | const_fns!(R64, f64); 107 | --------------------------------------------------------------------------------