├── .github ├── dependabot.yml └── workflows │ ├── 1-rustfmt.yml │ └── 2-tests.yml ├── .gitignore ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── README.md ├── rustfmt.toml └── src ├── defs.rs ├── ext.rs ├── inc ├── inc.rs ├── mod.rs └── ops │ ├── add.rs │ ├── cbrt.rs │ ├── log.rs │ ├── mod.rs │ ├── mul.rs │ ├── other.rs │ ├── pow.rs │ ├── sqrt.rs │ ├── tables │ ├── asin_const.rs │ ├── asinh_const.rs │ ├── atan_const.rs │ ├── cbrt_const.rs │ ├── exp_const.rs │ ├── fact_const.rs │ ├── ln_const.rs │ ├── mod.rs │ ├── sin_const.rs │ ├── sqrt_const.rs │ ├── tan_const.rs │ └── tanh_const.rs │ ├── trig.rs │ ├── trigh.rs │ └── util.rs ├── lib.rs ├── num_traits.rs ├── ops ├── add.rs ├── cbrt.rs ├── log.rs ├── mod.rs ├── mul.rs ├── other.rs ├── pow.rs ├── sqrt.rs ├── trig.rs ├── trigh.rs └── util.rs ├── parser.rs ├── serde.rs └── util.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "cargo" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/1-rustfmt.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ main, develop ] 6 | pull_request: 7 | branches: [ main, develop ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | check-formatting: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Check formatting 20 | run: rustfmt --check ./src/*.rs -------------------------------------------------------------------------------- /.github/workflows/2-tests.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ main, develop ] 6 | pull_request: 7 | branches: [ main, develop ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build-and-test: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | run: cargo build --release --verbose --target x86_64-unknown-linux-gnu 21 | - name: Run tests 22 | run: cargo test --release --verbose --target x86_64-unknown-linux-gnu 23 | - name: Run tests with no features and with no_std 24 | run: cargo test --release --verbose --no-default-features --target x86_64-unknown-linux-gnu 25 | - name: Run tests with features serde, num_traits and with no_std 26 | run: cargo test --release --no-default-features --features num-traits,serde --target x86_64-unknown-linux-gnu -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | The following is information than may be useful for contributors. The information is advisory in nature. 2 | 3 | All communication is held in [issues](https://github.com/stencillogic/num-bigfloat/issues) and [PRs](https://github.com/stencillogic/num-bigfloat/pulls). 4 | 5 | There are several ways to contribute to the project. The list includes, but is not limited by: 6 | 7 | - opening issues, participating in discussions 8 | - implementing features, or fixing bugs which are defined by current open issues, opening pull requests 9 | - writing documentation, or articles about the library 10 | - developing and improving algorithms used in the library 11 | 12 | Rust is the primary programming language of the library. The following are reccomendations to follow with regard to the coding standards: 13 | 14 | - use of unsafe code must be kept at a minimum; any use of unsafe must be justified. 15 | - use of `unwrap()`, `expect()`, any unhandled errors are only acceptable when it was proved that they will never appear (i.e. there are checks that guarantee the code will never panic or return error). 16 | - new code must be covered by regression tests. 17 | - code must be formatted with [rustfmt](https://rust-lang.github.io/rustfmt/). 18 | - all public items (functions, structs, etc.) must be documented. 19 | - any pull request must pass all tests before it can be merged. 20 | - public api should follow [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/). 21 | - library's documentation should be kept up to date. 22 | - common sense and proper reasoning supersede any written rule. 23 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "num-bigfloat" 3 | version = "1.7.2" 4 | edition = "2021" 5 | authors = ["stencillogic "] 6 | license = "MIT" 7 | description = "Increased precision floating point numbers implemented purely in Rust." 8 | categories = ["algorithms", "data-structures", "science"] 9 | keywords = ["big-float", "numeric", "decimal", "mathematics", "bignum"] 10 | readme = "README.md" 11 | repository = "https://github.com/stencillogic/num-bigfloat" 12 | 13 | [dev-dependencies] 14 | rand = "0.8.5" 15 | serde_json = "1.0" 16 | 17 | [dependencies] 18 | serde = { version = "~1.0.188", optional = true, default-features = false, features = ['derive'] } 19 | rand = { version = "~0.8.5", optional = true, default-features = false } 20 | num-traits = { version = "~0.2.16", optional = true, default-features = false } 21 | 22 | [features] 23 | default = ["std", "rand", "serde", "num-traits"] 24 | std = ["serde/std", "num-traits/std", "rand/std", "rand/std_rng"] 25 | serde = ["dep:serde"] 26 | rand = ["dep:rand", "std"] 27 | num-traits = ["dep:num-traits"] 28 | 29 | [profile.release] 30 | opt-level = 3 31 | lto = true 32 | 33 | [package.metadata.docs.rs] 34 | all-features = true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 stencillogic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Tests](https://github.com/stencillogic/num-bigfloat/workflows/Rust/badge.svg) 2 | ![Minimum rustc version](https://img.shields.io/badge/rustc-1.62.1+-blue.svg) 3 | 4 | 5 | Increased precision floating point numbers implemented purely in Rust. 6 | 7 | ## Arbitrary precision numbers 8 | 9 | **A fork of the library is available that implements floating-point numbers of arbitrary precision: [astro-float](https://github.com/stencillogic/astro-float). 10 | The new library uses more elaborate algorithms, has higher accuracy and better test coverage.** 11 | 12 | ## Rationale 13 | 14 | There are several notable implementations of numbers with increased precision for Rust. Among the libraries, one can recall [num-bigint](https://crates.io/crates/num-bigint), [rust_decimal](https://crates.io/crates/rust_decimal). 15 | 16 | While these libraries are great in many ways, they don't allow you to perform operations on numbers while still providing fairly high precision. 17 | 18 | There are also wrapper libraries, like [rug](https://crates.io/crates/rug), that depend on MPFR for implementing arbitrary precision floating point numbers. 19 | 20 | This library is written in pure Rust, provides more precision than f32, f64, and some other data types with increased precision. 21 | 22 | ## Number characteristics 23 | 24 | Number has fixed-size mantissa and exponent. 25 | 26 | | Name | Value | 27 | |:------------------------------|-------:| 28 | | Base | 10 | 29 | | Decimal positions in mantissa | 40 | 30 | | Exponent minimum value | -128 | 31 | | Exponent maximum value | 127 | 32 | 33 | 34 | ## no_std 35 | 36 | Library can be used without the standard Rust library. This can be achieved by turning off `std` feature. 37 | 38 | 39 | ## Performance 40 | 41 | Benchmark for `num-bigfloat`, `rug`(`MPFR`), and `astro-float` can be found here: [bigfloat-bench](https://github.com/stencillogic/bigfloat-bench). 42 | 43 | ## Other features 44 | 45 | The library depends on [rand](https://crates.io/crates/rand) which is used by `BigFloat::random_normal`. This dependecy can be excluded by turning off the `rand` feature. `rand` feature requires `std` feature. 46 | 47 | The library depends on [serde](https://crates.io/crates/serde) which is also optional and can be eliminated by turning off the `serde` feature. 48 | 49 | In addition, the library implements [num-traits](https://crates.io/crates/num_traits). Dependency on `num-traits` can be excluded by turning off `num-traits` feature. -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | array_width = 80 2 | single_line_if_else_max_width = 80 -------------------------------------------------------------------------------- /src/defs.rs: -------------------------------------------------------------------------------- 1 | //! Definitions. 2 | 3 | #[cfg(feature = "serde")] 4 | use serde::{Deserialize, Serialize}; 5 | 6 | /// Number of "digits" in BigFloat number. 7 | pub const DECIMAL_PARTS: usize = 10; 8 | 9 | /// i64::MAX. 10 | pub const I64_MAX: BigFloatNum = BigFloatNum { 11 | m: [0, 0, 0, 0, 0, 8070, 4775, 3685, 3720, 9223], 12 | n: DECIMAL_POSITIONS as i16, 13 | sign: DECIMAL_SIGN_POS, 14 | e: -(DECIMAL_POSITIONS as i8 - 19), 15 | }; 16 | 17 | /// i64::MIN. 18 | pub const I64_MIN: BigFloatNum = BigFloatNum { 19 | m: [0, 0, 0, 0, 0, 8080, 4775, 3685, 3720, 9223], 20 | n: DECIMAL_POSITIONS as i16, 21 | sign: DECIMAL_SIGN_NEG, 22 | e: -(DECIMAL_POSITIONS as i8 - 19), 23 | }; 24 | 25 | /// u64::MAX. 26 | pub const U64_MAX: BigFloatNum = BigFloatNum { 27 | m: [0, 0, 0, 0, 0, 1615, 955, 737, 6744, 1844], 28 | n: DECIMAL_POSITIONS as i16, 29 | sign: DECIMAL_SIGN_POS, 30 | e: -(DECIMAL_POSITIONS as i8 - 20), 31 | }; 32 | 33 | // i128::MAX 34 | pub const I128_MAX: BigFloatNum = BigFloatNum { 35 | m: [7270, 4105, 1588, 3037, 1687, 3173, 4692, 3460, 4118, 1701], 36 | n: DECIMAL_POSITIONS as i16, 37 | sign: DECIMAL_SIGN_POS, 38 | e: -1, 39 | }; 40 | 41 | /// i128::MIN. 42 | pub const I128_MIN: BigFloatNum = BigFloatNum { 43 | m: [7280, 4105, 1588, 3037, 1687, 3173, 4692, 3460, 4118, 1701], 44 | n: DECIMAL_POSITIONS as i16, 45 | sign: DECIMAL_SIGN_NEG, 46 | e: -1, 47 | }; 48 | 49 | /// u128::MAX. 50 | pub const U128_MAX: BigFloatNum = BigFloatNum { 51 | m: [4550, 8211, 3176, 6074, 3374, 6346, 9384, 6920, 8236, 3402], 52 | n: DECIMAL_POSITIONS as i16, 53 | sign: DECIMAL_SIGN_POS, 54 | e: -1, 55 | }; 56 | 57 | /// Number representation. 58 | #[derive(Copy, Clone, Debug)] 59 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 60 | pub struct BigFloatNum { 61 | pub(crate) sign: i8, // sign 62 | pub(crate) e: i8, // exponent 63 | pub(crate) n: i16, // the number of decimal positions in the mantissa excluding leading zeroes 64 | pub(crate) m: [i16; DECIMAL_PARTS], // mantissa 65 | } 66 | 67 | /// Possible errors. 68 | #[derive(Eq, PartialEq, Debug, Copy, Clone)] 69 | pub enum Error { 70 | /// Exponent value becomes greater than the upper bound. 71 | /// Error stores sign of resulting number. 72 | ExponentOverflow(i8), 73 | 74 | /// Divizor is zero. 75 | DivisionByZero, 76 | 77 | /// Argument must not be a negative number. 78 | ArgumentIsNegative, 79 | 80 | /// Invalid argument. 81 | InvalidArgument, 82 | } 83 | 84 | /// Rounding modes. 85 | #[derive(Eq, PartialEq, Debug, Copy, Clone)] 86 | pub enum RoundingMode { 87 | /// Round half toward positive infinity. 88 | Up, 89 | 90 | /// Round half toward negative infinity. 91 | Down, 92 | 93 | /// Round half toward zero. 94 | ToZero, 95 | 96 | /// Round half away from zero. 97 | FromZero, 98 | 99 | /// Round half to even. 100 | ToEven, 101 | 102 | /// Round half to odd. 103 | ToOdd, 104 | } 105 | 106 | pub const DECIMAL_BASE_LOG10: usize = 4; // number decimal positions in a digit = log10(DECIMAL_BASE) 107 | pub const DECIMAL_POSITIONS: usize = DECIMAL_PARTS * DECIMAL_BASE_LOG10; 108 | pub const DECIMAL_BASE: usize = 10000; // 9999 is the maximum of a digit 109 | pub const DECIMAL_SIGN_POS: i8 = 1; // + sign 110 | pub const DECIMAL_SIGN_NEG: i8 = -1; // - sign 111 | pub const DECIMAL_MIN_EXPONENT: i8 = -128; // min exponent value 112 | pub const DECIMAL_MAX_EXPONENT: i8 = 127; // max exponent value 113 | pub const ZEROED_MANTISSA: [i16; DECIMAL_PARTS] = [0; DECIMAL_PARTS]; 114 | 115 | /// Zero. 116 | pub const ZERO: BigFloatNum = BigFloatNum { 117 | m: ZEROED_MANTISSA, 118 | n: 0, 119 | sign: DECIMAL_SIGN_POS, 120 | e: 0, 121 | }; 122 | 123 | /// One. 124 | pub const ONE: BigFloatNum = BigFloatNum { 125 | m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1000], 126 | n: DECIMAL_POSITIONS as i16, 127 | sign: DECIMAL_SIGN_POS, 128 | e: 1 - (DECIMAL_POSITIONS as i8), 129 | }; 130 | 131 | /// Two. 132 | pub const TWO: BigFloatNum = BigFloatNum { 133 | m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 2000], 134 | n: DECIMAL_POSITIONS as i16, 135 | sign: DECIMAL_SIGN_POS, 136 | e: 1 - (DECIMAL_POSITIONS as i8), 137 | }; 138 | 139 | /// Eulers number. 140 | pub const E: BigFloatNum = BigFloatNum { 141 | m: [7757, 6249, 3526, 7471, 6028, 2353, 9045, 2845, 2818, 2718], 142 | n: DECIMAL_POSITIONS as i16, 143 | sign: DECIMAL_SIGN_POS, 144 | e: 1 - (DECIMAL_POSITIONS as i8), 145 | }; 146 | 147 | /// Pi number. 148 | pub const PI: BigFloatNum = BigFloatNum { 149 | m: [4197, 288, 2795, 3383, 6264, 2384, 9793, 5358, 5926, 3141], 150 | n: DECIMAL_POSITIONS as i16, 151 | sign: DECIMAL_SIGN_POS, 152 | e: 1 - (DECIMAL_POSITIONS as i8), 153 | }; 154 | 155 | /// Largest value possible. 156 | pub const MAX: BigFloatNum = BigFloatNum { 157 | m: [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999], 158 | n: DECIMAL_POSITIONS as i16, 159 | sign: DECIMAL_SIGN_POS, 160 | e: DECIMAL_MAX_EXPONENT, 161 | }; 162 | 163 | /// Smalles value possible. 164 | pub const MIN: BigFloatNum = BigFloatNum { 165 | m: [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999], 166 | n: DECIMAL_POSITIONS as i16, 167 | sign: DECIMAL_SIGN_NEG, 168 | e: DECIMAL_MAX_EXPONENT, 169 | }; 170 | 171 | /// Smalles positive number. 172 | pub const MIN_POSITIVE: BigFloatNum = BigFloatNum { 173 | m: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], 174 | n: 1, 175 | sign: DECIMAL_SIGN_POS, 176 | e: DECIMAL_MIN_EXPONENT, 177 | }; 178 | 179 | /// Smalles positive normal number. 180 | pub const MIN_POSITIVE_NORMAL: BigFloatNum = BigFloatNum { 181 | m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1000], 182 | n: 1, 183 | sign: DECIMAL_SIGN_POS, 184 | e: DECIMAL_MIN_EXPONENT, 185 | }; 186 | 187 | /// Creation and number manipulation functions. 188 | impl BigFloatNum { 189 | /// Return new BigFloat with value zero. 190 | pub fn new() -> Self { 191 | BigFloatNum { 192 | sign: DECIMAL_SIGN_POS, 193 | e: 0, 194 | n: 0, 195 | m: ZEROED_MANTISSA, 196 | } 197 | } 198 | 199 | /// Return BigFloat with the value of 1. 200 | pub fn one() -> Self { 201 | let mut val = Self::new(); 202 | val.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10; 203 | val.n = DECIMAL_POSITIONS as i16; 204 | val.e = 1 - DECIMAL_POSITIONS as i8; 205 | val 206 | } 207 | 208 | /// Create a BigFloat value from a sequence of `bytes`. Each byte must represent a decimal digit. 209 | /// First byte is the most significant. The length of `bytes` can be any. If the length of 210 | /// `bytes` is greater than required, then the remaining part is ignored. 211 | /// If `sign` is negative, then the resulting BigFloat will be 212 | /// negative. 213 | pub fn from_bytes(bytes: &[u8], sign: i8, exponent: i8) -> BigFloatNum { 214 | let mut mantissa = ZEROED_MANTISSA; 215 | let mut n: usize = 0; 216 | let mut p: i16 = 1; 217 | let d = if bytes.len() > DECIMAL_POSITIONS { DECIMAL_POSITIONS } else { bytes.len() }; 218 | for i in 1..d + 1 { 219 | mantissa[n] += (bytes[d - i] % 10) as i16 * p; 220 | p *= 10; 221 | if p == DECIMAL_BASE as i16 { 222 | n += 1; 223 | p = 1; 224 | } 225 | } 226 | 227 | BigFloatNum { 228 | sign: if sign >= 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }, 229 | e: exponent, 230 | n: Self::num_digits(&mantissa), 231 | m: mantissa, 232 | } 233 | } 234 | 235 | /// Get BigFloat's mantissa as bytes. Each byte represents a decimal digit. 236 | /// First byte is the most significant. The length of `bytes` can be any. If the length of 237 | /// `bytes` is smaller than required, then remaining part of mantissa will be omitted. 238 | /// 239 | /// The length of mantissa can be determined using `get_mantissa_len`. 240 | pub fn get_mantissa_bytes(&self, bytes: &mut [u8]) { 241 | let mut n: usize = 0; 242 | let mut p: i16 = 1; 243 | let d = if bytes.len() < self.n as usize { bytes.len() } else { self.n as usize }; 244 | for i in 1..d + 1 { 245 | bytes[d - i] = ((self.m[n] / p) % 10) as u8; 246 | p *= 10; 247 | if p == DECIMAL_BASE as i16 { 248 | n += 1; 249 | p = 1; 250 | } 251 | } 252 | } 253 | 254 | /// Return the number of decimal positions filled in the mantissa. 255 | pub fn get_mantissa_len(&self) -> usize { 256 | self.n as usize 257 | } 258 | 259 | /// Return true if the number is zero. 260 | pub fn is_zero(&self) -> bool { 261 | self.n == 0 262 | } 263 | 264 | /// Return true if integer part of number is zero. 265 | pub fn is_int_even(&self) -> bool { 266 | let int = self.int(); 267 | if int.e < 0 { 268 | let p = int.n + int.e as i16; 269 | let mut d = int.m[p as usize / DECIMAL_BASE_LOG10]; 270 | let mut i = p % DECIMAL_BASE_LOG10 as i16; 271 | while i > 0 { 272 | d /= 10; 273 | i -= 1; 274 | } 275 | d & 1 == 0 276 | } else if int.e == 0 { 277 | int.m[0] & 1 == 0 278 | } else { 279 | true 280 | } 281 | } 282 | 283 | /// Returns true if `self` is subnormal. 284 | pub fn is_subnormal(&self) -> bool { 285 | self.n < DECIMAL_POSITIONS as i16 && self.e == DECIMAL_MIN_EXPONENT 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /src/inc/inc.rs: -------------------------------------------------------------------------------- 1 | //! BigFloat number with increased mantissa length for providing more accurate compuations. 2 | use crate::defs::DECIMAL_BASE; 3 | use crate::defs::DECIMAL_BASE_LOG10; 4 | use crate::defs::DECIMAL_PARTS as DECIMAL_PARTS_BASE; 5 | use crate::defs::DECIMAL_SIGN_POS; 6 | 7 | pub const DECIMAL_PARTS: usize = DECIMAL_PARTS_BASE + 1; 8 | pub const DECIMAL_POSITIONS: usize = DECIMAL_PARTS * DECIMAL_BASE_LOG10; 9 | pub const ZEROED_MANTISSA: [i16; DECIMAL_PARTS] = [0; DECIMAL_PARTS]; 10 | 11 | /// Eulers number. 12 | pub(crate) const E: BigFloatInc = BigFloatInc { 13 | m: [2471, 7757, 6249, 3526, 7471, 6028, 2353, 9045, 2845, 2818, 2718], 14 | n: DECIMAL_POSITIONS as i16, 15 | sign: DECIMAL_SIGN_POS, 16 | e: 1 - (DECIMAL_POSITIONS as i8), 17 | }; 18 | 19 | /// BigFloat number with increased mantissa length for providing more accurate compuations. 20 | #[derive(Copy, Clone, Debug)] 21 | pub(crate) struct BigFloatInc { 22 | pub(crate) sign: i8, // sign 23 | pub(crate) e: i8, // exponent 24 | pub(crate) n: i16, // the number of decimal positions in the mantissa excluding leading zeroes 25 | pub(crate) m: [i16; DECIMAL_PARTS], // mantissa 26 | } 27 | 28 | impl BigFloatInc { 29 | /// Return new BigFloatInc with value zero. 30 | pub fn new() -> Self { 31 | BigFloatInc { 32 | sign: DECIMAL_SIGN_POS, 33 | e: 0, 34 | n: 0, 35 | m: ZEROED_MANTISSA, 36 | } 37 | } 38 | 39 | /// Return new BigFloatInc with value one. 40 | pub fn one() -> Self { 41 | let mut val = Self::new(); 42 | val.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10; 43 | val.n = DECIMAL_POSITIONS as i16; 44 | val.e = 1 - DECIMAL_POSITIONS as i8; 45 | val 46 | } 47 | 48 | /// Return new BigFloat with value two. 49 | pub fn two() -> Self { 50 | let mut val = Self::new(); 51 | val.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 5; 52 | val.n = DECIMAL_POSITIONS as i16; 53 | val.e = 1 - DECIMAL_POSITIONS as i8; 54 | val 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/inc/mod.rs: -------------------------------------------------------------------------------- 1 | //! BigFloat number with increased mantissa length for providing more accurate compuations. 2 | pub mod inc; 3 | pub mod ops; 4 | -------------------------------------------------------------------------------- /src/inc/ops/add.rs: -------------------------------------------------------------------------------- 1 | //! Addition and subtraction. 2 | 3 | use crate::defs::Error; 4 | use crate::defs::DECIMAL_BASE; 5 | use crate::defs::DECIMAL_MAX_EXPONENT; 6 | use crate::defs::DECIMAL_SIGN_POS; 7 | use crate::inc::inc::BigFloatInc; 8 | use crate::inc::inc::DECIMAL_PARTS; 9 | use crate::inc::inc::DECIMAL_POSITIONS; 10 | use crate::inc::inc::ZEROED_MANTISSA; 11 | use crate::RoundingMode; 12 | 13 | impl BigFloatInc { 14 | /// Add d2 and return result of addition. 15 | /// 16 | /// # Errors 17 | /// 18 | /// ExponentOverflow - when result is too big. 19 | pub fn add(&self, d2: &Self) -> Result { 20 | self.add_sub(d2, 1) 21 | } 22 | 23 | /// Subtract d2 and return result of subtraction. 24 | /// 25 | /// # Errors 26 | /// 27 | /// ExponentOverflow - when result is too big. 28 | pub fn sub(&self, d2: &Self) -> Result { 29 | self.add_sub(d2, -1) 30 | } 31 | 32 | // add if op >= 0 subtract if op < 0 33 | fn add_sub(&self, d2: &Self, op: i8) -> Result { 34 | let mut d3 = Self::new(); 35 | let shift: i32; 36 | let free: i32; 37 | let mut e: i32; 38 | let cmp: i16; 39 | let mut n1: Self; 40 | let mut n2: Self; 41 | 42 | // one of the numbers is zero 43 | if 0 == self.n { 44 | d3 = *d2; 45 | if op < 0 46 | // 0 - d2 47 | { 48 | d3.sign = -d3.sign; 49 | } 50 | return Ok(d3); 51 | } 52 | if 0 == d2.n { 53 | d3 = *self; 54 | return Ok(d3); 55 | } 56 | 57 | // assign d1 and d2 to n1 and n2 such that n1 has more significant digits than n2 58 | // (we want to save more digits while not sacrificing any significant digits) 59 | if self.e as i32 + (self.n as i32) < d2.e as i32 + d2.n as i32 { 60 | n1 = if op < 0 { d2.inv_sign() } else { *d2 }; 61 | n2 = *self; 62 | } else { 63 | n1 = *self; 64 | n2 = if op < 0 { d2.inv_sign() } else { *d2 }; 65 | } 66 | shift = n1.e as i32 - n2.e as i32; 67 | e = n1.e as i32; 68 | 69 | // bring n1 and n2 to having common exponent 70 | if shift > 0 { 71 | free = DECIMAL_POSITIONS as i32 - n1.n as i32; 72 | 73 | if shift > free { 74 | if shift - free > n2.n as i32 { 75 | // n2 is too small 76 | d3 = n1; 77 | return Ok(d3); 78 | } else { 79 | if free > 0 { 80 | Self::shift_left(&mut n1.m, free as usize); 81 | } 82 | let actual_shift = if Self::round_mantissa( 83 | &mut n2.m, 84 | (shift - free) as i16, 85 | RoundingMode::ToEven, 86 | true, 87 | ) { 88 | (shift - free) as usize - 1 89 | } else { 90 | (shift - free) as usize 91 | }; 92 | if actual_shift > 0 { 93 | Self::shift_right(&mut n2.m, actual_shift); 94 | } 95 | e -= free; 96 | } 97 | } else { 98 | Self::shift_left(&mut n1.m, shift as usize); 99 | e -= shift; 100 | } 101 | } else if shift < 0 { 102 | Self::shift_left(&mut n2.m, (-shift) as usize); 103 | } 104 | 105 | if n1.sign != n2.sign { 106 | // subtract 107 | cmp = Self::abs_cmp(&n1.m, &n2.m); 108 | if cmp > 0 { 109 | d3.sign = n1.sign; 110 | d3.e = e as i8; 111 | Self::abs_sub(&n1.m, &n2.m, &mut d3.m); 112 | d3.n = Self::num_digits(&d3.m); 113 | } else if cmp < 0 { 114 | d3.sign = n2.sign; 115 | d3.e = e as i8; 116 | Self::abs_sub(&n2.m, &n1.m, &mut d3.m); 117 | d3.n = Self::num_digits(&d3.m); 118 | } else { 119 | d3.sign = DECIMAL_SIGN_POS; 120 | d3.e = 0; 121 | d3.n = 0; 122 | d3.m = ZEROED_MANTISSA; 123 | } 124 | } else { 125 | // add 126 | d3.sign = n1.sign; 127 | d3.e = e as i8; 128 | if Self::abs_add(&n1.m, &n2.m, &mut d3.m) > 0 { 129 | if d3.e == DECIMAL_MAX_EXPONENT { 130 | return Err(Error::ExponentOverflow(d3.sign)); 131 | } 132 | d3.e += 1; 133 | if Self::round_mantissa(&mut d3.m, 1, RoundingMode::ToEven, true) { 134 | // e.g. m = 998, round 1 => m = 100, m is supposed to be shifted to the right by 135 | // one digit, so no additional shift required. 136 | if d3.e == DECIMAL_MAX_EXPONENT { 137 | return Err(Error::ExponentOverflow(d3.sign)); 138 | } 139 | d3.e += 1; 140 | } else { 141 | // rounding did not cause additional significant digit, but addition itself did. 142 | Self::shift_right(&mut d3.m, 1); 143 | } 144 | d3.m[DECIMAL_PARTS - 1] += DECIMAL_BASE as i16 / 10; 145 | d3.n = DECIMAL_POSITIONS as i16; 146 | } else { 147 | d3.n = Self::num_digits(&d3.m); 148 | } 149 | } 150 | Ok(d3) 151 | } 152 | 153 | fn abs_add(d1: &[i16], d2: &[i16], d3: &mut [i16]) -> u32 { 154 | let mut s: u32; 155 | let mut c: u32 = 0; 156 | 157 | for ((v1, v2), v3) in d1.iter().zip(d2.iter()).zip(d3.iter_mut()) { 158 | s = *v1 as u32 + *v2 as u32 + c; 159 | if s >= DECIMAL_BASE as u32 { 160 | s -= DECIMAL_BASE as u32; 161 | c = 1; 162 | } else { 163 | c = 0; 164 | } 165 | *v3 = s as i16; 166 | } 167 | c 168 | } 169 | 170 | // subtract absolute value of d2 from d1 171 | // d1 is supposed to be > d2 172 | fn abs_sub(d1: &[i16], d2: &[i16], d3: &mut [i16]) { 173 | let mut c: i16 = 0; 174 | for ((v1, v2), v3) in d1.iter().zip(d2.iter()).zip(d3.iter_mut()) { 175 | if *v1 < *v2 + c { 176 | *v3 = *v1 + DECIMAL_BASE as i16 - *v2 - c; 177 | c = 1; 178 | } else { 179 | *v3 = *v1 - *v2 - c; 180 | c = 0; 181 | } 182 | } 183 | assert!(0 == c); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/inc/ops/cbrt.rs: -------------------------------------------------------------------------------- 1 | //! Cube root. 2 | 3 | use crate::defs::Error; 4 | use crate::defs::DECIMAL_SIGN_POS; 5 | use crate::inc::inc::BigFloatInc; 6 | use crate::inc::inc::DECIMAL_PARTS; 7 | use crate::inc::inc::ZEROED_MANTISSA; 8 | use crate::inc::ops::tables::cbrt_const::CBRT_VALUES; 9 | 10 | const ONE_THIRD: BigFloatInc = BigFloatInc { 11 | m: [3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333], 12 | n: 44, 13 | sign: DECIMAL_SIGN_POS, 14 | e: -44, 15 | }; 16 | 17 | const TWO_THIRD: BigFloatInc = BigFloatInc { 18 | m: [6667, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 6666], 19 | n: 44, 20 | sign: DECIMAL_SIGN_POS, 21 | e: -44, 22 | }; 23 | 24 | const CBRT_OF_10: BigFloatInc = BigFloatInc { 25 | m: [3449, 5259, 5049, 5193, 3566, 5929, 7217, 1883, 9003, 4346, 2154], 26 | n: 44, 27 | sign: DECIMAL_SIGN_POS, 28 | e: -43, 29 | }; 30 | 31 | const CBRT_OF_100: BigFloatInc = BigFloatInc { 32 | m: [3491, 6551, 4657, 9194, 6350, 1007, 8924, 2778, 3361, 5888, 4641], 33 | n: 44, 34 | sign: DECIMAL_SIGN_POS, 35 | e: -43, 36 | }; 37 | 38 | impl BigFloatInc { 39 | /// Return cube root of a number. 40 | pub fn cbrt(&self) -> Result { 41 | // cbrt(self) = cbrt(mantissa)*cbrt(10^exponent) 42 | // = cbrt(mantissa)*cbrt(10^(exponent%3))*10^(exponent/3) 43 | if self.n == 0 || self.m == ZEROED_MANTISSA { 44 | return Ok(*self); 45 | } 46 | 47 | // cbrt(mantissa) 48 | let mut int_num = *self; 49 | int_num.e = 0; 50 | int_num.sign = DECIMAL_SIGN_POS; 51 | let part1 = Self::cbrt_int(&int_num)?; 52 | 53 | let e = (self.e as i32).abs() % 3; 54 | let mut ret = if e > 0 { 55 | // cbrt(10^(exponent%3)) 56 | let part2 = if e < 2 { CBRT_OF_10 } else { CBRT_OF_100 }; 57 | 58 | // result 59 | if self.e < 0 { part1.div(&part2) } else { part1.mul(&part2) }? 60 | } else { 61 | part1 62 | }; 63 | ret.e += self.e / 3; 64 | ret.sign = self.sign; 65 | Ok(ret) 66 | } 67 | 68 | // cube root of integer 69 | fn cbrt_int(d1: &Self) -> Result { 70 | // choose initial value 71 | let mut i = DECIMAL_PARTS - 1; 72 | while d1.m[i] == 0 && i > 0 { 73 | i -= 1; 74 | } 75 | let j = d1.m[i] / 100; 76 | let mut n = if i > 0 || j > 0 { CBRT_VALUES[i * 99 + j as usize] } else { *d1 }; 77 | 78 | // Newton's method: n2 = d1/3/n/n + 2/3*n 79 | let s = d1.mul(&ONE_THIRD)?; 80 | let mut err = *d1; 81 | loop { 82 | if n.n == 0 { 83 | break; 84 | } 85 | let p1 = s.div(&n)?.div(&n)?; 86 | let p2 = TWO_THIRD.mul(&n)?; 87 | let n2 = p1.add(&p2)?; 88 | let err2 = n.sub(&n2)?; 89 | if err2.cmp(&err) >= 0 { 90 | break; 91 | } 92 | err = err2; 93 | n = n2; 94 | } 95 | Ok(n) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/inc/ops/log.rs: -------------------------------------------------------------------------------- 1 | //! Logarithms. 2 | 3 | use crate::defs::Error; 4 | use crate::defs::DECIMAL_BASE; 5 | use crate::defs::DECIMAL_MAX_EXPONENT; 6 | use crate::defs::DECIMAL_MIN_EXPONENT; 7 | use crate::defs::DECIMAL_SIGN_NEG; 8 | use crate::defs::DECIMAL_SIGN_POS; 9 | use crate::inc::inc::BigFloatInc; 10 | use crate::inc::inc::DECIMAL_POSITIONS; 11 | use crate::inc::inc::E; 12 | use crate::inc::ops::tables::atan_const::ATAN_VALUES1; 13 | use crate::inc::ops::tables::ln_const::LN_VALUES; 14 | 15 | const LN_OF_10: BigFloatInc = BigFloatInc { 16 | m: [1015, 7601, 6420, 6843, 1454, 1799, 6840, 4045, 9299, 5850, 2302], 17 | n: 44, 18 | sign: DECIMAL_SIGN_POS, 19 | e: -43, 20 | }; 21 | 22 | impl BigFloatInc { 23 | /// Returns natural logarithm of a number. 24 | /// 25 | /// # Errors 26 | /// 27 | /// ExponentOverflow - when result is too big. 28 | /// 29 | /// InvalidArgument - when `self` is negative or zero. 30 | pub fn ln(&self) -> Result { 31 | if self.sign == DECIMAL_SIGN_NEG || self.n == 0 { 32 | return Err(Error::InvalidArgument); 33 | } 34 | 35 | // factoring: ln(d) = ln(d.m ^ (1 - d.n)) + (d.e - 1 + d.n) * ln(10) 36 | let mut add = Self::new(); 37 | let mut s = self.e as i16 - 1 + self.n; 38 | if s != 0 { 39 | // check if s fits in single "digit" 40 | assert!( 41 | DECIMAL_MAX_EXPONENT as i16 + 1 + (DECIMAL_POSITIONS as i16) < DECIMAL_BASE as i16 42 | && DECIMAL_POSITIONS as i16 + 1 - (DECIMAL_MIN_EXPONENT as i16) 43 | < DECIMAL_BASE as i16 44 | ); 45 | if s > 0 { 46 | add.m[0] = s; 47 | } else { 48 | add.m[0] = -s; 49 | add.sign = DECIMAL_SIGN_NEG; 50 | } 51 | while s != 0 { 52 | add.n += 1; 53 | s /= 10; 54 | } 55 | add = add.mul(&LN_OF_10)?; 56 | } 57 | 58 | let one = BigFloatInc::one(); 59 | let two = BigFloatInc::two(); 60 | let mut ml = *self; 61 | ml.e = 1 - ml.n as i8; 62 | 63 | // arctanh series 64 | ml = ml.sub(&one)?.div(&ml.add(&one)?)?; // (x-1)/(x+1) 65 | 66 | // further reduction: arctanh(x) = arctanh(s) + arctanh((x - s) / (1 - x*s)) 67 | let (idx, mut dx) = Self::get_trig_params(&mut ml, 0); 68 | let atanh_s = LN_VALUES[idx]; 69 | let s = ml.sub(&dx)?; 70 | dx = dx.div(&one.sub(&ml.mul(&s)?)?)?; 71 | 72 | let mut ret = dx; 73 | let dxx = dx.mul(&dx)?; 74 | for i in 0..ATAN_VALUES1.len() { 75 | dx = dx.mul(&dxx)?; 76 | let mut poly_coeff = ATAN_VALUES1[i]; 77 | poly_coeff.sign = DECIMAL_SIGN_POS; // same as for atan, but always positive 78 | let p = poly_coeff.mul(&dx)?; 79 | let val = ret.add(&p)?; 80 | if val.cmp(&ret) == 0 { 81 | break; 82 | } 83 | ret = val; 84 | assert!(i != ATAN_VALUES1.len() - 2); 85 | } 86 | ret = ret.add(&atanh_s)?.mul(&two)?.add(&add)?; 87 | 88 | Ok(ret) 89 | } 90 | 91 | /// E to the power of `self`. 92 | /// 93 | /// # Errors 94 | /// 95 | /// ExponentOverflow - when result is too big. 96 | /// 97 | /// ArgumentIsNegative - when `d1` has fractional part and `self` is negative. 98 | pub fn exp(&self) -> Result { 99 | E.pow(self) 100 | } 101 | 102 | /// Returns logarithm of base `b` of a number. 103 | /// 104 | /// # Errors 105 | /// 106 | /// ExponentOverflow - when result is too big. 107 | /// 108 | /// InvalidArgument - when `self` or `b` is negative or zero. 109 | /// 110 | /// DivisionByZero - when `b` is equal to 1. 111 | pub fn log(&self, b: &Self) -> Result { 112 | self.ln()?.div(&b.ln()?) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/inc/ops/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod add; 2 | pub mod cbrt; 3 | pub mod log; 4 | pub mod mul; 5 | pub mod other; 6 | pub mod pow; 7 | pub mod sqrt; 8 | pub mod tables; 9 | pub mod trig; 10 | pub mod trigh; 11 | mod util; 12 | -------------------------------------------------------------------------------- /src/inc/ops/mul.rs: -------------------------------------------------------------------------------- 1 | //! Multiplication and division. 2 | 3 | use crate::defs::Error; 4 | use crate::defs::DECIMAL_BASE; 5 | use crate::defs::DECIMAL_BASE_LOG10; 6 | use crate::defs::DECIMAL_MAX_EXPONENT; 7 | use crate::defs::DECIMAL_MIN_EXPONENT; 8 | use crate::defs::DECIMAL_SIGN_NEG; 9 | use crate::defs::DECIMAL_SIGN_POS; 10 | use crate::inc::inc::BigFloatInc; 11 | use crate::inc::inc::DECIMAL_PARTS; 12 | use crate::inc::inc::DECIMAL_POSITIONS; 13 | use crate::RoundingMode; 14 | 15 | impl BigFloatInc { 16 | /// Multiply by d2 and return result of multiplication. 17 | /// 18 | /// # Errors 19 | /// 20 | /// ExponentOverflow - when result is too big. 21 | pub fn mul(&self, d2: &Self) -> Result { 22 | let mut d3 = Self::new(); 23 | let mut m: i32; 24 | let mut k: i32; 25 | let mut n: i32; 26 | let mut nd: i32; 27 | let mut e: i32 = self.e as i32 + d2.e as i32; 28 | let mut d1mi: i32; 29 | let mut m3 = [0i16; DECIMAL_PARTS * 2 + 1]; 30 | 31 | if self.n == 0 || d2.n == 0 { 32 | return Ok(Self::new()); 33 | } 34 | 35 | for (i, v1) in self.m.iter().enumerate() { 36 | d1mi = *v1 as i32; 37 | if d1mi == 0 { 38 | continue; 39 | } 40 | 41 | k = 0; 42 | for (m2j, m3ij) in d2.m.iter().zip(m3[i..].iter_mut()) { 43 | m = d1mi * (*m2j as i32) + *m3ij as i32 + k; 44 | 45 | *m3ij = (m % DECIMAL_BASE as i32) as i16; 46 | k = m / DECIMAL_BASE as i32; 47 | } 48 | 49 | m3[i + d2.m.len()] += k as i16; 50 | } 51 | 52 | n = Self::num_digits(&m3[DECIMAL_PARTS..]) as i32; 53 | if n > 0 { 54 | n += DECIMAL_POSITIONS as i32; 55 | } else { 56 | n = Self::num_digits(&m3) as i32; 57 | } 58 | 59 | // take care if result is not fitting in d3.m without truncating 60 | if n > DECIMAL_POSITIONS as i32 { 61 | // save as much digits as we can 62 | e += n - DECIMAL_POSITIONS as i32; 63 | nd = n % DECIMAL_BASE_LOG10 as i32; 64 | n = n / DECIMAL_BASE_LOG10 as i32 - DECIMAL_PARTS as i32 + 1; 65 | 66 | Self::shift_left(&mut m3[n as usize..], DECIMAL_BASE_LOG10 - nd as usize); 67 | 68 | k = 1; 69 | while nd > 0 { 70 | k *= 10; 71 | nd -= 1; 72 | } 73 | m3[n as usize] += m3[n as usize - 1] / k as i16; 74 | 75 | d3.n = DECIMAL_POSITIONS as i16; 76 | } else { 77 | d3.n = n as i16; 78 | n = 0; 79 | } 80 | 81 | // round n digits in the beginning before copying [n..n + DECIMAL_PARTS] to d3 82 | if Self::round_mantissa( 83 | &mut m3[0..n as usize + DECIMAL_PARTS], 84 | n as i16 * DECIMAL_BASE_LOG10 as i16, 85 | RoundingMode::ToEven, 86 | true, 87 | ) { 88 | e += 1; 89 | } 90 | 91 | for i in 0..d3.m.len() { 92 | d3.m[i] = m3[n as usize + i]; 93 | } 94 | d3.sign = if self.sign == d2.sign || self.n == 0 { 95 | DECIMAL_SIGN_POS 96 | } else { 97 | DECIMAL_SIGN_NEG 98 | }; 99 | 100 | if e < DECIMAL_MIN_EXPONENT as i32 { 101 | return Ok(d3.process_subnormal(e)); 102 | } 103 | 104 | if e > DECIMAL_MAX_EXPONENT as i32 { 105 | return Err(Error::ExponentOverflow(d3.sign)); 106 | } 107 | 108 | d3.e = e as i8; 109 | 110 | Ok(d3) 111 | } 112 | 113 | /// Divide by d2 and return result of division. 114 | /// 115 | /// # Errors 116 | /// 117 | /// ExponentOverflow - when result is too big. 118 | /// DivisionByZero - in case of d2 equal to zero. 119 | /// InvalidArgument - in case both d1 and self are zeroes. 120 | pub fn div(&self, d2: &Self) -> Result { 121 | // Knuth's division 122 | let mut d3 = Self::new(); 123 | let mut m3 = [0; DECIMAL_PARTS + 1]; 124 | let mut d: i32; 125 | let mut c: i16; 126 | let mut i: i32; 127 | let mut j: i32; 128 | let n: i32; 129 | let m: i32; 130 | let e: i32; 131 | let mut qh: i32; 132 | let mut k: i32; 133 | let mut rh: i32; 134 | let mut p: i32; 135 | let mut buf = [0i16; DECIMAL_PARTS * 3 + 4]; 136 | let v1: i32; 137 | let v2: i32; 138 | let n1: usize = 2 + DECIMAL_PARTS; 139 | let n2: usize = DECIMAL_PARTS * 2 + 3; 140 | let mut n1j: usize; 141 | 142 | if d2.n == 0 { 143 | if self.n == 0 { 144 | return Err(Error::InvalidArgument); 145 | } else { 146 | return Err(Error::DivisionByZero); 147 | } 148 | } 149 | n = (d2.n as i32 - 1) / DECIMAL_BASE_LOG10 as i32; 150 | 151 | if self.n == 0 { 152 | return Ok(d3); // d1 / d2 = 0 153 | } 154 | m = (self.n as i32 - 1) / DECIMAL_BASE_LOG10 as i32; 155 | 156 | i = DECIMAL_PARTS as i32; 157 | p = 1; 158 | 159 | if n == 0 { 160 | // division by single digit 161 | d = d2.m[0] as i32; 162 | rh = 0; 163 | j = m; 164 | if (self.m[j as usize] as i32) < d { 165 | rh = self.m[j as usize] as i32; 166 | j -= 1; 167 | p -= 1; 168 | } 169 | 170 | let mut m3i = m3.iter_mut().rev(); 171 | let mut m1i = self.m[..(j + 1) as usize].iter().rev(); 172 | for m3v in m3i.by_ref() { 173 | qh = 174 | rh * DECIMAL_BASE as i32 + if j >= 0 { *m1i.next().unwrap() as i32 } else { 0 }; 175 | rh = qh % d; 176 | *m3v = (qh / d) as i16; 177 | 178 | if rh == 0 && j <= 0 { 179 | break; 180 | } 181 | 182 | j -= 1; 183 | } 184 | 185 | for m3v in m3i { 186 | *m3v = 0; 187 | } 188 | } else { 189 | // normalize: n1 = d1 * d, n2 = d2 * d 190 | d = DECIMAL_BASE as i32 / (d2.m[n as usize] as i32 + 1); // factor d: d * d2[most significant] is close to DECIMAL_BASE 191 | 192 | if d == 1 { 193 | buf[n1..(self.m.len() + n1)].copy_from_slice(&self.m[..]); 194 | buf[n2..(d2.m.len() + n2)].copy_from_slice(&d2.m[..]); 195 | } else { 196 | Self::mul_by_digit(&self.m, d, &mut buf[n1..]); 197 | Self::mul_by_digit(&d2.m, d, &mut buf[n2..]); 198 | } 199 | 200 | v1 = buf[n2 + n as usize] as i32; 201 | v2 = buf[n2 + n as usize - 1] as i32; 202 | 203 | j = m - n; 204 | let mut m3i = m3.iter_mut().rev(); 205 | loop { 206 | n1j = (n1 as i32 + j) as usize; 207 | 208 | let b2 = buf[n1j + n as usize + 1]; 209 | let b1 = buf[n1j + n as usize]; 210 | let b0 = buf[n1j + n as usize - 1]; 211 | 212 | qh = b2 as i32 * DECIMAL_BASE as i32 + b1 as i32; 213 | rh = qh % v1; 214 | qh /= v1; 215 | 216 | if qh >= DECIMAL_BASE as i32 || (qh * v2 > DECIMAL_BASE as i32 * rh + b0 as i32) { 217 | qh -= 1; 218 | rh += v1; 219 | if rh < DECIMAL_BASE as i32 220 | && (qh >= DECIMAL_BASE as i32 221 | || (qh * v2 > DECIMAL_BASE as i32 * rh + b0 as i32)) 222 | { 223 | qh -= 1; 224 | } 225 | } 226 | 227 | // n1_j = n1_j - n2 * qh 228 | c = 0; 229 | k = 0; 230 | let (buf1, buf2) = buf.split_at_mut(n2); 231 | for (a, b) in buf2[..(n + 2) as usize] 232 | .iter() 233 | .zip(buf1[n1j..n1j + (n + 2) as usize].iter_mut()) 234 | { 235 | k = *a as i32 * qh + k / DECIMAL_BASE as i32; 236 | let val = k % DECIMAL_BASE as i32 + c as i32; 237 | if (*b as i32) < val { 238 | *b += (DECIMAL_BASE as i32 - val) as i16; 239 | c = 1; 240 | } else { 241 | *b -= val as i16; 242 | c = 0; 243 | } 244 | } 245 | 246 | if c > 0 { 247 | // compensate 248 | qh -= 1; 249 | c = 0; 250 | for (a, b) in buf2[..(n + 2) as usize] 251 | .iter() 252 | .zip(buf1[n1j..n1j + (n + 2) as usize].iter_mut()) 253 | { 254 | *b += *a + c; 255 | if *b >= DECIMAL_BASE as i16 { 256 | *b -= DECIMAL_BASE as i16; 257 | c = 1; 258 | } else { 259 | c = 0; 260 | } 261 | } 262 | assert!(c > 0); 263 | } 264 | 265 | if i < DECIMAL_PARTS as i32 || qh > 0 { 266 | *m3i.next().unwrap() = qh as i16; 267 | i -= 1; 268 | } else { 269 | p -= 1; 270 | } 271 | 272 | j -= 1; 273 | if i < 0 || n1 as i32 + j < 0 { 274 | break; 275 | } 276 | } 277 | } 278 | 279 | let mut rnd_e = 0; 280 | if Self::round_mantissa( 281 | &mut m3[0..DECIMAL_PARTS + 1], 282 | DECIMAL_BASE_LOG10 as i16, 283 | RoundingMode::ToEven, 284 | true, 285 | ) { 286 | rnd_e = 1; 287 | } 288 | d3.m.copy_from_slice(&m3[1..DECIMAL_PARTS + 1]); 289 | 290 | // exponent 291 | j = 0; 292 | d = d3.m[DECIMAL_PARTS - 1] as i32; 293 | while d > 0 { 294 | d /= 10; 295 | j += 1; 296 | } 297 | 298 | e = self.e as i32 299 | - d2.e as i32 300 | - (DECIMAL_PARTS as i32 - m + n - p) * DECIMAL_BASE_LOG10 as i32 301 | + rnd_e; 302 | 303 | d3.n = DECIMAL_POSITIONS as i16 - DECIMAL_BASE_LOG10 as i16 + j as i16; 304 | d3.sign = if self.sign == d2.sign { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }; 305 | 306 | if e < DECIMAL_MIN_EXPONENT as i32 { 307 | return Ok(d3.process_subnormal(e)); 308 | } 309 | 310 | if e > DECIMAL_MAX_EXPONENT as i32 { 311 | return Err(Error::ExponentOverflow(d3.sign)); 312 | } 313 | 314 | d3.e = e as i8; 315 | 316 | Ok(d3) 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /src/inc/ops/other.rs: -------------------------------------------------------------------------------- 1 | //! Other operations. 2 | 3 | use crate::defs::DECIMAL_BASE; 4 | use crate::defs::DECIMAL_BASE_LOG10; 5 | use crate::defs::DECIMAL_SIGN_NEG; 6 | use crate::defs::DECIMAL_SIGN_POS; 7 | use crate::inc::inc::BigFloatInc; 8 | 9 | impl BigFloatInc { 10 | /// Return absolute value. 11 | pub fn abs(&self) -> Self { 12 | let mut ret = *self; 13 | if ret.sign == DECIMAL_SIGN_NEG { 14 | ret.sign = DECIMAL_SIGN_POS; 15 | } 16 | ret 17 | } 18 | 19 | /// Return absolute value. 20 | pub fn inv_sign(&self) -> Self { 21 | let mut ret = *self; 22 | if ret.sign == DECIMAL_SIGN_NEG { 23 | ret.sign = DECIMAL_SIGN_POS; 24 | } else { 25 | ret.sign = DECIMAL_SIGN_NEG; 26 | } 27 | ret 28 | } 29 | 30 | /// Compare to d2. 31 | /// Returns positive if self > d2, negative if self < d2, 0 otherwise. 32 | pub fn cmp(&self, d2: &Self) -> i16 { 33 | if self.n == 0 || d2.n == 0 { 34 | if d2.n != 0 { 35 | return -d2.sign as i16; 36 | } else if self.n != 0 { 37 | return self.sign as i16; 38 | } else { 39 | return 0; 40 | } 41 | } 42 | 43 | if self.sign != d2.sign { 44 | return self.sign as i16; 45 | } 46 | 47 | let diff: i32 = self.e as i32 + self.n as i32 - d2.e as i32 - d2.n as i32; 48 | if diff > 0 { 49 | return self.sign as i16; 50 | } 51 | if diff < 0 { 52 | return -self.sign as i16; 53 | } 54 | 55 | if self.n != d2.n { 56 | return Self::abs_cmp_with_shift(&self.m, self.n, &d2.m, d2.n) * self.sign as i16; 57 | } 58 | 59 | Self::abs_cmp(&self.m, &d2.m) * self.sign as i16 60 | } 61 | 62 | // compare absolute values of two floats with shifts n1, n2 63 | // return positive if d1 > d2, negative if d1 < d2, 0 otherwise 64 | fn abs_cmp_with_shift(d1: &[i16], mut n1: i16, d2: &[i16], mut n2: i16) -> i16 { 65 | let mut t1: i16 = DECIMAL_BASE as i16 / 10; 66 | let mut t2: i16 = DECIMAL_BASE as i16 / 10; 67 | let mut s: i16; 68 | let mut v1: i16; 69 | let mut v2: i16; 70 | 71 | s = DECIMAL_BASE_LOG10 as i16 - n1 % DECIMAL_BASE_LOG10 as i16; 72 | while s > 0 { 73 | s -= 1; 74 | t1 /= 10; 75 | if t1 == 0 { 76 | t1 = DECIMAL_BASE as i16 / 10; 77 | }; 78 | } 79 | s = DECIMAL_BASE_LOG10 as i16 - n2 % DECIMAL_BASE_LOG10 as i16; 80 | while s > 0 { 81 | s -= 1; 82 | t2 /= 10; 83 | if t2 == 0 { 84 | t2 = DECIMAL_BASE as i16 / 10; 85 | }; 86 | } 87 | 88 | n1 -= 1; 89 | n2 -= 1; 90 | while n1 >= 0 && n2 >= 0 { 91 | v1 = (d1[n1 as usize / DECIMAL_BASE_LOG10] / t1) % 10; 92 | v2 = (d2[n2 as usize / DECIMAL_BASE_LOG10] / t2) % 10; 93 | if v1 != v2 { 94 | return v1 - v2; 95 | } 96 | t1 /= 10; 97 | if t1 == 0 { 98 | t1 = DECIMAL_BASE as i16 / 10; 99 | } 100 | t2 /= 10; 101 | if t2 == 0 { 102 | t2 = DECIMAL_BASE as i16 / 10; 103 | } 104 | n1 -= 1; 105 | n2 -= 1; 106 | } 107 | while n1 >= 0 { 108 | v1 = (d1[n1 as usize / DECIMAL_BASE_LOG10] / t1) % 10; 109 | if v1 != 0 { 110 | return 1; 111 | } 112 | n1 -= 1; 113 | } 114 | while n2 >= 0 { 115 | v2 = (d2[n2 as usize / DECIMAL_BASE_LOG10] / t2) % 10; 116 | if v2 != 0 { 117 | return -1; 118 | } 119 | n2 -= 1; 120 | } 121 | 0 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/inc/ops/pow.rs: -------------------------------------------------------------------------------- 1 | //! Power. 2 | 3 | use crate::defs::Error; 4 | use crate::defs::DECIMAL_BASE; 5 | use crate::defs::DECIMAL_BASE_LOG10; 6 | use crate::defs::DECIMAL_SIGN_NEG; 7 | use crate::defs::DECIMAL_SIGN_POS; 8 | use crate::inc::inc::BigFloatInc; 9 | use crate::inc::inc::DECIMAL_PARTS; 10 | use crate::inc::ops::tables::exp_const::EXP_VALUES; 11 | use crate::inc::ops::tables::exp_const::EXP_VALUES2; 12 | use crate::inc::ops::tables::fact_const::INVFACT_VALUES; 13 | 14 | impl BigFloatInc { 15 | /// Return BigFloatInc to the power of `d1`. 16 | /// 17 | /// # Errors 18 | /// 19 | /// ExponentOverflow - when result is too big. 20 | /// 21 | /// InvalidArgument - when `d1` and `self` both equal to zero. 22 | pub fn pow(&self, d1: &Self) -> Result { 23 | if self.n == 0 { 24 | if d1.sign == DECIMAL_SIGN_NEG { 25 | return Err(Error::ExponentOverflow(DECIMAL_SIGN_POS)); 26 | } else if d1.n == 0 { 27 | return Err(Error::InvalidArgument); 28 | } else { 29 | return Ok(*self); 30 | } 31 | } 32 | if Self::extract_fract_part(d1).n == 0 { 33 | let mut int = Self::extract_int_part(d1); 34 | int.sign = d1.sign; 35 | Self::result_inversion(self.powi(&int), d1.sign == DECIMAL_SIGN_NEG, self.sign) 36 | } else { 37 | self.powexp(d1) 38 | } 39 | } 40 | 41 | // compute power by replacing base to e. 42 | fn powexp(&self, d1: &Self) -> Result { 43 | // self^d1 = e^(d1*ln(self)) 44 | // e^(d1*ln(self)) = e^int * e^fract 45 | // e^int = e.powi(int) 46 | // e^fract = fract.exp() 47 | let b = self.abs(); 48 | let x = d1.mul(&b.ln()?)?; 49 | let one = BigFloatInc::one(); 50 | let int = Self::extract_int_part(&x); 51 | let frac = Self::extract_fract_part(&x); 52 | let p1 = if int.n != 0 { 53 | Self::result_inversion(Self::expi(&int), x.sign == DECIMAL_SIGN_NEG, self.sign)? 54 | } else { 55 | one 56 | }; 57 | let p2 = if frac.n != 0 { BigFloatInc::expf(&frac)? } else { one }; 58 | let ml = Self::result_inversion(p1.mul(&p2), x.sign == DECIMAL_SIGN_NEG, self.sign)?; 59 | let mut ret = if x.sign == DECIMAL_SIGN_NEG { one.div(&ml)? } else { ml }; 60 | ret.sign = self.sign; 61 | Ok(ret) 62 | } 63 | 64 | // Convert exponent overflow to zero if conv is true. 65 | fn result_inversion(r: Result, conv: bool, base_sign: i8) -> Result { 66 | match r { 67 | Ok(v) => Ok(v), 68 | Err(Error::ExponentOverflow(_)) => { 69 | if conv { 70 | Ok(Self::new()) 71 | } else { 72 | Err(Error::ExponentOverflow(base_sign)) 73 | } 74 | } 75 | Err(Error::DivisionByZero) => Err(Error::ExponentOverflow(base_sign)), 76 | Err(e) => Err(e), 77 | } 78 | } 79 | 80 | // e^d1, for integer d1 81 | fn expi(d1: &Self) -> Result { 82 | let mut int = *d1; 83 | let mut ret = Self::one(); 84 | let mut pow_idx = 0; 85 | while int.n > 0 { 86 | if pow_idx > 2 { 87 | return Err(Error::ExponentOverflow(DECIMAL_SIGN_POS)); 88 | } 89 | let mut cnt = int.m[0] % 10; 90 | while cnt > 0 { 91 | ret = ret.mul(&EXP_VALUES2[pow_idx])?; 92 | cnt -= 1; 93 | } 94 | pow_idx += 1; 95 | Self::shift_right(&mut int.m, 1); 96 | int.n -= 1; 97 | } 98 | Ok(ret) 99 | } 100 | 101 | // self^d1, for integer d1 102 | fn powi(&self, d1: &Self) -> Result { 103 | let mut int = *d1; 104 | let mut ret = Self::one(); 105 | let mut ml = *self; 106 | while int.n > 0 { 107 | if int.m[0] & 1 != 0 { 108 | ret = ret.mul(&ml)?; 109 | if ret.n == 0 { 110 | break; 111 | } 112 | } 113 | Self::divide_by_two_int(&mut int); 114 | if int.n > 0 { 115 | ml = ml.mul(&ml)?; 116 | } 117 | } 118 | if d1.sign == DECIMAL_SIGN_NEG { 119 | ret = Self::one().div(&ret)? 120 | } 121 | Ok(ret) 122 | } 123 | 124 | // e^d1, where d1 is fractional < 1 125 | fn expf(d1: &Self) -> Result { 126 | // if d1 >= 0.001, factoring: d1 = p1 + p2, p2 < 0.001 127 | // e^p1 - precomputed 128 | // e^p2 = 1 + p2 + p2^2/2! + p2^3/3! + ... 129 | let one = Self::one(); 130 | if d1.n == 0 { 131 | return Ok(one); 132 | } 133 | let mut p2 = *d1; 134 | p2.maximize_mantissa(); 135 | let mut idx = p2.m[DECIMAL_PARTS - 1]; 136 | let mut e = -(p2.e as i32); 137 | let e_p1; 138 | if e < 48 { 139 | let mut t = 1; 140 | while e >= 44 { 141 | t *= 10; 142 | e -= 1; 143 | } 144 | idx /= t; 145 | p2.m[DECIMAL_PARTS - 1] %= t; 146 | p2.n = Self::num_digits(&p2.m); 147 | e_p1 = EXP_VALUES[idx as usize]; 148 | } else { 149 | e_p1 = one; 150 | } 151 | let mut ret = one.add(&p2)?; 152 | let mut ml = p2; 153 | for i in 1..INVFACT_VALUES.len() { 154 | ml = ml.mul(&p2)?; 155 | let val = ret.add(&ml.mul(&INVFACT_VALUES[i])?)?; 156 | if val.cmp(&ret) == 0 { 157 | break; 158 | } 159 | ret = val; 160 | } 161 | ret.mul(&e_p1) 162 | } 163 | 164 | // divide BigFloat by two as integer 165 | fn divide_by_two_int(d1: &mut Self) { 166 | if d1.m[0] & 1 == 1 && d1.e > 0 { 167 | d1.maximize_mantissa(); 168 | } 169 | d1.m[0] >>= 1; 170 | for i in 1..(d1.n as usize + DECIMAL_BASE_LOG10 - 1) / DECIMAL_BASE_LOG10 { 171 | if d1.m[i] & 1 != 0 { 172 | d1.m[i - 1] += DECIMAL_BASE as i16 / 2; 173 | } 174 | d1.m[i] >>= 1; 175 | } 176 | d1.n = Self::num_digits(&d1.m); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/inc/ops/sqrt.rs: -------------------------------------------------------------------------------- 1 | //! Square root. 2 | 3 | use crate::defs::Error; 4 | use crate::defs::DECIMAL_SIGN_NEG; 5 | use crate::defs::DECIMAL_SIGN_POS; 6 | use crate::inc::inc::BigFloatInc; 7 | use crate::inc::inc::DECIMAL_PARTS; 8 | use crate::inc::inc::ZEROED_MANTISSA; 9 | use crate::inc::ops::tables::sqrt_const::SQRT_VALUES; 10 | 11 | const SQRT_OF_10: BigFloatInc = BigFloatInc { 12 | m: [5551, 3719, 1853, 4327, 3544, 9889, 3319, 8379, 6016, 2776, 3162], 13 | n: 44, 14 | sign: DECIMAL_SIGN_POS, 15 | e: -43, 16 | }; 17 | 18 | impl BigFloatInc { 19 | /// Return square root of a number. 20 | /// 21 | /// # Errors 22 | /// 23 | /// Returns ArgumentIsNegative if `self` is less than 0. 24 | pub fn sqrt(&self) -> Result { 25 | if self.sign == DECIMAL_SIGN_NEG { 26 | return Err(Error::ArgumentIsNegative); 27 | } 28 | 29 | if self.n == 0 || self.m == ZEROED_MANTISSA { 30 | return Ok(*self); 31 | } 32 | 33 | // calc sqrt of integer number with the same mantissa 34 | let mut int_num = *self; 35 | int_num.e = 0; 36 | let mut sq = Self::sqrt_int(&int_num)?; 37 | 38 | // make exponent even by dividing or multiplying number by sqrt(10), 39 | // then sqrt of even exponent is simply e/2 40 | if self.e & 1 != 0 { 41 | if self.e < 0 { 42 | sq = sq.div(&SQRT_OF_10)?; 43 | } else { 44 | sq = sq.mul(&SQRT_OF_10)?; 45 | } 46 | } 47 | sq.e += self.e / 2; 48 | Ok(sq) 49 | } 50 | 51 | // sqrt of integer 52 | fn sqrt_int(d1: &Self) -> Result { 53 | // choose initial value 54 | let mut i = DECIMAL_PARTS - 1; 55 | while d1.m[i] == 0 && i > 0 { 56 | i -= 1; 57 | } 58 | let j = d1.m[i] / 100; 59 | let mut n = if i > 0 || j > 0 { SQRT_VALUES[i * 99 + j as usize] } else { *d1 }; 60 | 61 | // Newton's method 62 | let two = Self::two(); 63 | let mut err = *d1; 64 | loop { 65 | let nsq = n.mul(&n)?; 66 | let nd = n.mul(&two)?; 67 | let n2 = d1.add(&nsq)?.div(&nd)?; 68 | let err2 = n.sub(&n2)?; 69 | if err2.cmp(&err) >= 0 { 70 | break; 71 | } 72 | err = err2; 73 | n = n2; 74 | } 75 | Ok(n) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/inc/ops/tables/asin_const.rs: -------------------------------------------------------------------------------- 1 | use crate::inc::inc::BigFloatInc; 2 | 3 | // arcsine polynomial coefficients 4 | pub(crate) const ASIN_VALUES: [BigFloatInc; 20] = [ 5 | BigFloatInc { 6 | sign: -1, 7 | e: -44, 8 | n: 44, 9 | m: [3932, 2141, 8173, 5080, 603, 3474, 2073, 7579, 197, 5113, 1178], 10 | }, 11 | BigFloatInc { 12 | sign: -1, 13 | e: -45, 14 | n: 44, 15 | m: [1348, 7318, 8389, 8931, 6357, 316, 2165, 9553, 2944, 6504, 2651], 16 | }, 17 | BigFloatInc { 18 | sign: -1, 19 | e: -46, 20 | n: 44, 21 | m: [5439, 7732, 3302, 7773, 5112, 8799, 4776, 4146, 5431, 8167, 7891], 22 | }, 23 | BigFloatInc { 24 | sign: -1, 25 | e: -46, 26 | n: 44, 27 | m: [7684, 1936, 7582, 4311, 2781, 7994, 6208, 7452, 6778, 4098, 2685], 28 | }, 29 | BigFloatInc { 30 | sign: -1, 31 | e: -47, 32 | n: 44, 33 | m: [5565, 4403, 4734, 4511, 7513, 2160, 8314, 3802, 7685, 1908, 9887], 34 | }, 35 | BigFloatInc { 36 | sign: -1, 37 | e: -47, 38 | n: 44, 39 | m: [6357, 361, 6163, 4858, 8298, 4491, 6365, 5737, 3621, 4554, 3834], 40 | }, 41 | BigFloatInc { 42 | sign: -1, 43 | e: -47, 44 | n: 44, 45 | m: [9915, 9835, 8717, 97, 9982, 5735, 7156, 6808, 3028, 9118, 1542], 46 | }, 47 | BigFloatInc { 48 | sign: -1, 49 | e: -48, 50 | n: 44, 51 | m: [9501, 1306, 7418, 6507, 2572, 6224, 1658, 5955, 982, 5287, 6381], 52 | }, 53 | BigFloatInc { 54 | sign: -1, 55 | e: -48, 56 | n: 44, 57 | m: [9424, 3446, 1131, 5615, 3718, 6109, 861, 4826, 7710, 2891, 2696], 58 | }, 59 | BigFloatInc { 60 | sign: -1, 61 | e: -48, 62 | n: 44, 63 | m: [1264, 1136, 3998, 8, 8610, 8589, 8298, 1478, 7254, 7623, 1158], 64 | }, 65 | BigFloatInc { 66 | sign: -1, 67 | e: -49, 68 | n: 44, 69 | m: [5786, 9061, 8647, 3514, 1729, 2926, 4306, 2017, 9299, 5474, 5049], 70 | }, 71 | BigFloatInc { 72 | sign: -1, 73 | e: -49, 74 | n: 44, 75 | m: [9792, 2852, 1362, 6891, 9545, 239, 6840, 647, 5316, 88, 2226], 76 | }, 77 | BigFloatInc { 78 | sign: -1, 79 | e: -50, 80 | n: 44, 81 | m: [1968, 1361, 2973, 8696, 2934, 726, 3312, 5390, 4462, 2274, 9909], 82 | }, 83 | BigFloatInc { 84 | sign: -1, 85 | e: -50, 86 | n: 44, 87 | m: [1924, 6750, 4930, 9950, 1846, 6582, 193, 4230, 1621, 1692, 4448], 88 | }, 89 | BigFloatInc { 90 | sign: -1, 91 | e: -50, 92 | n: 44, 93 | m: [3074, 6869, 347, 9155, 9017, 8529, 248, 90, 260, 2421, 2011], 94 | }, 95 | BigFloatInc { 96 | sign: -1, 97 | e: -51, 98 | n: 44, 99 | m: [9376, 6322, 2178, 1477, 1838, 1464, 9939, 5295, 8389, 5324, 9151], 100 | }, 101 | BigFloatInc { 102 | sign: -1, 103 | e: -51, 104 | n: 44, 105 | m: [8484, 3657, 5757, 6314, 1748, 716, 2762, 9486, 8863, 4028, 4187], 106 | }, 107 | BigFloatInc { 108 | sign: -1, 109 | e: -51, 110 | n: 44, 111 | m: [8319, 8757, 3585, 4600, 4182, 8925, 4565, 4448, 1568, 5137, 1925], 112 | }, 113 | BigFloatInc { 114 | sign: -1, 115 | e: -52, 116 | n: 44, 117 | m: [7972, 2629, 2365, 3272, 8447, 9098, 2073, 5229, 1515, 4827, 8893], 118 | }, 119 | BigFloatInc { 120 | sign: -1, 121 | e: -52, 122 | n: 44, 123 | m: [6102, 4039, 8633, 8733, 9459, 1758, 5928, 7531, 6638, 814, 4124], 124 | }, 125 | ]; 126 | -------------------------------------------------------------------------------- /src/inc/ops/tables/asinh_const.rs: -------------------------------------------------------------------------------- 1 | use crate::inc::inc::BigFloatInc; 2 | 3 | // hyperbolic arcsine polynomial coefficients 4 | pub(crate) const ASINH_VALUES: [BigFloatInc; 50] = [ 5 | BigFloatInc { 6 | sign: -1, 7 | e: -44, 8 | n: 44, 9 | m: [6667, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 1666], 10 | }, 11 | BigFloatInc { 12 | sign: 1, 13 | e: -45, 14 | n: 44, 15 | m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7500], 16 | }, 17 | BigFloatInc { 18 | sign: -1, 19 | e: -45, 20 | n: 44, 21 | m: [2857, 5714, 1428, 2857, 5714, 1428, 2857, 5714, 1428, 2857, 4464], 22 | }, 23 | BigFloatInc { 24 | sign: 1, 25 | e: -45, 26 | n: 44, 27 | m: [4444, 4444, 4444, 4444, 4444, 4444, 4444, 4444, 4444, 1944, 3038], 28 | }, 29 | BigFloatInc { 30 | sign: -1, 31 | e: -45, 32 | n: 44, 33 | m: [909, 909, 909, 909, 909, 909, 909, 909, 909, 2159, 2237], 34 | }, 35 | BigFloatInc { 36 | sign: 1, 37 | e: -45, 38 | n: 44, 39 | m: [3077, 7692, 9230, 3076, 7692, 9230, 3076, 7692, 4230, 2764, 1735], 40 | }, 41 | BigFloatInc { 42 | sign: -1, 43 | e: -45, 44 | n: 44, 45 | m: [0, 0, 0, 0, 0, 0, 0, 0, 7500, 4843, 1396], 46 | }, 47 | BigFloatInc { 48 | sign: 1, 49 | e: -45, 50 | n: 44, 51 | m: [4118, 3529, 5882, 6470, 4117, 3529, 5882, 3970, 8961, 1800, 1155], 52 | }, 53 | BigFloatInc { 54 | sign: -1, 55 | e: -46, 56 | n: 44, 57 | m: [4210, 7368, 7894, 6315, 1052, 6842, 9473, 4078, 2919, 6095, 9761], 58 | }, 59 | BigFloatInc { 60 | sign: 1, 61 | e: -46, 62 | n: 44, 63 | m: [4762, 6190, 9047, 4761, 6190, 9047, 4761, 6815, 961, 3358, 8390], 64 | }, 65 | BigFloatInc { 66 | sign: -1, 67 | e: -46, 68 | n: 44, 69 | m: [8696, 8260, 4347, 9130, 2173, 9565, 1086, 8845, 7359, 5258, 7312], 70 | }, 71 | BigFloatInc { 72 | sign: 1, 73 | e: -46, 74 | n: 44, 75 | m: [0, 0, 0, 0, 0, 0, 4375, 9648, 1188, 2103, 6447], 76 | }, 77 | BigFloatInc { 78 | sign: -1, 79 | e: -46, 80 | n: 44, 81 | m: [1852, 5185, 8518, 1851, 5185, 3518, 4664, 1923, 7084, 376, 5740], 82 | }, 83 | BigFloatInc { 84 | sign: 1, 85 | e: -46, 86 | n: 44, 87 | m: [9655, 2068, 7586, 4482, 3103, 5129, 1958, 9904, 8231, 3096, 5153], 88 | }, 89 | BigFloatInc { 90 | sign: -1, 91 | e: -46, 92 | n: 44, 93 | m: [8710, 5483, 4193, 9677, 3870, 423, 1599, 5096, 8691, 1434, 4660], 94 | }, 95 | BigFloatInc { 96 | sign: 1, 97 | e: -46, 98 | n: 44, 99 | m: [8182, 8181, 8181, 3181, 1619, 3709, 773, 9363, 9367, 9070, 4240], 100 | }, 101 | BigFloatInc { 102 | sign: -1, 103 | e: -46, 104 | n: 44, 105 | m: [7143, 4285, 8571, 9642, 5691, 1940, 2363, 7669, 5883, 9645, 3880], 106 | }, 107 | BigFloatInc { 108 | sign: 1, 109 | e: -46, 110 | n: 44, 111 | m: [270, 7027, 2702, 3395, 7847, 1386, 5454, 5934, 9382, 2053, 3569], 112 | }, 113 | BigFloatInc { 114 | sign: -1, 115 | e: -46, 116 | n: 44, 117 | m: [8462, 6153, 384, 6274, 2579, 9243, 7453, 3484, 347, 595, 3297], 118 | }, 119 | BigFloatInc { 120 | sign: 1, 121 | e: -46, 122 | n: 44, 123 | m: [4390, 3902, 7149, 3251, 947, 5481, 6693, 8030, 4925, 8216, 3057], 124 | }, 125 | BigFloatInc { 126 | sign: -1, 127 | e: -46, 128 | n: 44, 129 | m: [9767, 2906, 4600, 4117, 4785, 7676, 1678, 8942, 110, 1784, 2846], 130 | }, 131 | BigFloatInc { 132 | sign: 1, 133 | e: -46, 134 | n: 44, 135 | m: [3333, 9583, 8098, 9021, 3478, 3744, 9335, 7289, 3820, 8706, 2657], 136 | }, 137 | BigFloatInc { 138 | sign: -1, 139 | e: -46, 140 | n: 44, 141 | m: [6383, 6635, 1438, 2067, 9965, 4075, 4946, 6883, 7824, 4486, 2489], 142 | }, 143 | BigFloatInc { 144 | sign: 1, 145 | e: -46, 146 | n: 44, 147 | m: [2436, 101, 4017, 8663, 3827, 3088, 1869, 1975, 9211, 918, 2338], 148 | }, 149 | BigFloatInc { 150 | sign: -1, 151 | e: -46, 152 | n: 44, 153 | m: [7592, 9573, 3048, 8851, 419, 2002, 2054, 138, 7371, 4739, 2201], 154 | }, 155 | BigFloatInc { 156 | sign: 1, 157 | e: -46, 158 | n: 44, 159 | m: [9070, 2808, 1219, 193, 3553, 7847, 4427, 8167, 3251, 6610, 2077], 160 | }, 161 | BigFloatInc { 162 | sign: -1, 163 | e: -46, 164 | n: 44, 165 | m: [1346, 606, 7574, 5559, 3774, 3930, 6184, 7283, 1627, 336, 1965], 166 | }, 167 | BigFloatInc { 168 | sign: 1, 169 | e: -46, 170 | n: 44, 171 | m: [8587, 2848, 6222, 6465, 2104, 7910, 4892, 3127, 640, 2264, 1862], 172 | }, 173 | BigFloatInc { 174 | sign: -1, 175 | e: -46, 176 | n: 44, 177 | m: [7955, 4510, 1030, 8757, 2500, 5219, 2386, 5418, 2051, 811, 1768], 178 | }, 179 | BigFloatInc { 180 | sign: 1, 181 | e: -46, 182 | n: 44, 183 | m: [2183, 4208, 8731, 9858, 8659, 444, 8002, 3106, 9358, 6093, 1681], 184 | }, 185 | BigFloatInc { 186 | sign: -1, 187 | e: -46, 188 | n: 44, 189 | m: [8137, 3217, 9060, 4688, 9596, 2983, 357, 1444, 7535, 9632, 1601], 190 | }, 191 | BigFloatInc { 192 | sign: 1, 193 | e: -46, 194 | n: 44, 195 | m: [7650, 1002, 2375, 733, 1288, 9705, 6388, 2567, 9612, 4115, 1528], 196 | }, 197 | BigFloatInc { 198 | sign: -1, 199 | e: -46, 200 | n: 44, 201 | m: [6287, 8341, 4505, 9488, 5687, 6857, 3944, 9115, 9407, 3208, 1460], 202 | }, 203 | BigFloatInc { 204 | sign: 1, 205 | e: -46, 206 | n: 44, 207 | m: [1755, 1819, 6783, 4966, 8666, 8930, 4112, 253, 1763, 1399, 1397], 208 | }, 209 | BigFloatInc { 210 | sign: -1, 211 | e: -46, 212 | n: 44, 213 | m: [8742, 6275, 7113, 906, 1642, 4032, 3684, 5178, 5127, 3869, 1338], 214 | }, 215 | BigFloatInc { 216 | sign: 1, 217 | e: -46, 218 | n: 44, 219 | m: [3565, 8593, 7130, 5789, 7206, 6142, 5683, 9028, 8762, 6393, 1283], 220 | }, 221 | BigFloatInc { 222 | sign: -1, 223 | e: -46, 224 | n: 44, 225 | m: [1796, 1260, 7263, 917, 1997, 4379, 8001, 16, 9850, 5250, 1232], 226 | }, 227 | BigFloatInc { 228 | sign: 1, 229 | e: -46, 230 | n: 44, 231 | m: [1904, 3923, 3319, 3809, 31, 7615, 2516, 2439, 5616, 7152, 1184], 232 | }, 233 | BigFloatInc { 234 | sign: -1, 235 | e: -46, 236 | n: 44, 237 | m: [8695, 9699, 4350, 6104, 1508, 4052, 6811, 2223, 3070, 9183, 1139], 238 | }, 239 | BigFloatInc { 240 | sign: 1, 241 | e: -46, 242 | n: 44, 243 | m: [1737, 1487, 8178, 8576, 6841, 9598, 2212, 1447, 4659, 8750, 1097], 244 | }, 245 | BigFloatInc { 246 | sign: -1, 247 | e: -46, 248 | n: 44, 249 | m: [9472, 5150, 2488, 3068, 5890, 93, 9061, 2242, 2587, 3541, 1058], 250 | }, 251 | BigFloatInc { 252 | sign: 1, 253 | e: -46, 254 | n: 44, 255 | m: [6912, 2521, 5947, 3478, 8956, 7581, 6442, 627, 7971, 1486, 1021], 256 | }, 257 | BigFloatInc { 258 | sign: -1, 259 | e: -47, 260 | n: 44, 261 | m: [7681, 2281, 5291, 6555, 9654, 848, 9242, 3312, 6983, 7313, 9860], 262 | }, 263 | BigFloatInc { 264 | sign: 1, 265 | e: -47, 266 | n: 44, 267 | m: [4196, 9563, 8763, 8048, 2537, 5501, 351, 9564, 9742, 6061, 9529], 268 | }, 269 | BigFloatInc { 270 | sign: -1, 271 | e: -47, 272 | n: 44, 273 | m: [5222, 8703, 6043, 3580, 8658, 4686, 1541, 6334, 2183, 6069, 9216], 274 | }, 275 | BigFloatInc { 276 | sign: 1, 277 | e: -47, 278 | n: 44, 279 | m: [5497, 4869, 5779, 6090, 5717, 7599, 1400, 7097, 3091, 3742, 8920], 280 | }, 281 | BigFloatInc { 282 | sign: -1, 283 | e: -47, 284 | n: 44, 285 | m: [9917, 7516, 7299, 9373, 3511, 2892, 6063, 8675, 2465, 6771, 8639], 286 | }, 287 | BigFloatInc { 288 | sign: 1, 289 | e: -47, 290 | n: 44, 291 | m: [4882, 9642, 9940, 4813, 2746, 5551, 6343, 7120, 1602, 3984, 8373], 292 | }, 293 | BigFloatInc { 294 | sign: -1, 295 | e: -47, 296 | n: 44, 297 | m: [8494, 6215, 4401, 300, 7076, 5889, 5098, 6701, 2908, 5221, 8120], 298 | }, 299 | BigFloatInc { 300 | sign: 1, 301 | e: -47, 302 | n: 44, 303 | m: [3802, 1577, 2687, 5119, 5370, 7396, 5938, 2055, 1358, 1225, 7880], 304 | }, 305 | ]; 306 | -------------------------------------------------------------------------------- /src/inc/ops/tables/fact_const.rs: -------------------------------------------------------------------------------- 1 | use crate::inc::inc::BigFloatInc; 2 | 3 | // inverse factorial values: 1/1!, 1/2!, 1/3!, 1/4!, ... 4 | pub(crate) const INVFACT_VALUES: [BigFloatInc; 50] = [ 5 | BigFloatInc { 6 | sign: 1, 7 | e: -43, 8 | n: 44, 9 | m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000], 10 | }, 11 | BigFloatInc { 12 | sign: 1, 13 | e: -44, 14 | n: 44, 15 | m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5000], 16 | }, 17 | BigFloatInc { 18 | sign: 1, 19 | e: -44, 20 | n: 44, 21 | m: [6667, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 1666], 22 | }, 23 | BigFloatInc { 24 | sign: 1, 25 | e: -45, 26 | n: 44, 27 | m: [6667, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 6666, 4166], 28 | }, 29 | BigFloatInc { 30 | sign: 1, 31 | e: -46, 32 | n: 44, 33 | m: [3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 8333], 34 | }, 35 | BigFloatInc { 36 | sign: 1, 37 | e: -46, 38 | n: 44, 39 | m: [8889, 8888, 8888, 8888, 8888, 8888, 8888, 8888, 8888, 8888, 1388], 40 | }, 41 | BigFloatInc { 42 | sign: 1, 43 | e: -47, 44 | n: 44, 45 | m: [1270, 6984, 8412, 1269, 6984, 8412, 1269, 6984, 8412, 1269, 1984], 46 | }, 47 | BigFloatInc { 48 | sign: 1, 49 | e: -48, 50 | n: 44, 51 | m: [1587, 8730, 3015, 1587, 8730, 3015, 1587, 8730, 3015, 1587, 2480], 52 | }, 53 | BigFloatInc { 54 | sign: 1, 55 | e: -49, 56 | n: 44, 57 | m: [7319, 5255, 8906, 3985, 1922, 5573, 652, 8589, 2239, 7319, 2755], 58 | }, 59 | BigFloatInc { 60 | sign: 1, 61 | e: -50, 62 | n: 44, 63 | m: [7319, 5255, 8906, 3985, 1922, 5573, 652, 8589, 2239, 7319, 2755], 64 | }, 65 | BigFloatInc { 66 | sign: 1, 67 | e: -51, 68 | n: 44, 69 | m: [2108, 7505, 7187, 5441, 838, 521, 8775, 4171, 3854, 2108, 2505], 70 | }, 71 | BigFloatInc { 72 | sign: 1, 73 | e: -52, 74 | n: 44, 75 | m: [3424, 1254, 4323, 1201, 9032, 2100, 8979, 6809, 9878, 6756, 2087], 76 | }, 77 | BigFloatInc { 78 | sign: 1, 79 | e: -53, 80 | n: 44, 81 | m: [5710, 3272, 9479, 154, 7717, 3923, 4599, 2161, 8368, 9043, 1605], 82 | }, 83 | BigFloatInc { 84 | sign: 1, 85 | e: -54, 86 | n: 44, 87 | m: [2650, 6623, 1056, 8682, 9797, 8516, 4713, 2972, 5977, 745, 1147], 88 | }, 89 | BigFloatInc { 90 | sign: 1, 91 | e: -56, 92 | n: 44, 93 | m: [1002, 4155, 7044, 7880, 1985, 113, 4759, 9816, 3181, 1637, 7647], 94 | }, 95 | BigFloatInc { 96 | sign: 1, 97 | e: -57, 98 | n: 44, 99 | m: [9376, 7596, 4402, 1175, 7491, 3820, 2974, 7385, 3238, 4773, 4779], 100 | }, 101 | BigFloatInc { 102 | sign: 1, 103 | e: -58, 104 | n: 44, 105 | m: [4927, 6233, 2001, 103, 5583, 9894, 7631, 5520, 5434, 4572, 2811], 106 | }, 107 | BigFloatInc { 108 | sign: 1, 109 | e: -59, 110 | n: 44, 111 | m: [9404, 2351, 3334, 57, 6435, 2163, 6462, 8622, 9685, 9206, 1561], 112 | }, 113 | BigFloatInc { 114 | sign: 1, 115 | e: -61, 116 | n: 44, 117 | m: [7390, 9220, 8074, 8722, 1236, 5598, 7169, 4329, 4662, 6352, 8220], 118 | }, 119 | BigFloatInc { 120 | sign: 1, 121 | e: -62, 122 | n: 44, 123 | m: [3695, 4610, 4037, 4361, 618, 7799, 8584, 2164, 2331, 3176, 4110], 124 | }, 125 | BigFloatInc { 126 | sign: 1, 127 | e: -63, 128 | n: 44, 129 | m: [7474, 5528, 4303, 3505, 7437, 8475, 1230, 9126, 633, 2941, 1957], 130 | }, 131 | BigFloatInc { 132 | sign: 1, 133 | e: -65, 134 | n: 44, 135 | m: [4881, 3312, 6834, 5024, 7442, 4889, 2867, 573, 9245, 7913, 8896], 136 | }, 137 | BigFloatInc { 138 | sign: 1, 139 | e: -66, 140 | n: 44, 141 | m: [3426, 3179, 1232, 5228, 1931, 1691, 377, 684, 7063, 1701, 3868], 142 | }, 143 | BigFloatInc { 144 | sign: 1, 145 | e: -67, 146 | n: 44, 147 | m: [7261, 1324, 7180, 8011, 3304, 4871, 3490, 6118, 7109, 7375, 1611], 148 | }, 149 | BigFloatInc { 150 | sign: 1, 151 | e: -69, 152 | n: 44, 153 | m: [9044, 5298, 8720, 2046, 3219, 9485, 3961, 4473, 8438, 9502, 6446], 154 | }, 155 | BigFloatInc { 156 | sign: 1, 157 | e: -70, 158 | n: 44, 159 | m: [6555, 7422, 5661, 8479, 3545, 7494, 4600, 4797, 6322, 5962, 2479], 160 | }, 161 | BigFloatInc { 162 | sign: 1, 163 | e: -72, 164 | n: 44, 165 | m: [6872, 7861, 1339, 4739, 6836, 2571, 1484, 5546, 6379, 6898, 9183], 166 | }, 167 | BigFloatInc { 168 | sign: 1, 169 | e: -73, 170 | n: 44, 171 | m: [7454, 7807, 1192, 3121, 1727, 5204, 9101, 9837, 3706, 8892, 3279], 172 | }, 173 | BigFloatInc { 174 | sign: 1, 175 | e: -74, 176 | n: 44, 177 | m: [501, 9244, 3169, 6938, 6457, 5587, 6931, 4771, 8864, 9962, 1130], 178 | }, 179 | BigFloatInc { 180 | sign: 1, 181 | e: -76, 182 | n: 44, 183 | m: [8338, 4146, 566, 6461, 1525, 5292, 6438, 5905, 2881, 9876, 3769], 184 | }, 185 | BigFloatInc { 186 | sign: 1, 187 | e: -77, 188 | n: 44, 189 | m: [7851, 9724, 9214, 6922, 4685, 2997, 9496, 3517, 4155, 1250, 1216], 190 | }, 191 | BigFloatInc { 192 | sign: 1, 193 | e: -79, 194 | n: 44, 195 | m: [9534, 7889, 1296, 7884, 892, 9367, 5925, 4743, 5485, 3907, 3800], 196 | }, 197 | BigFloatInc { 198 | sign: 1, 199 | e: -80, 200 | n: 44, 201 | m: [8041, 1481, 2211, 3298, 8149, 5868, 280, 7195, 6207, 6335, 1151], 202 | }, 203 | BigFloatInc { 204 | sign: 1, 205 | e: -82, 206 | n: 44, 207 | m: [6002, 240, 621, 3230, 5733, 3143, 8472, 1161, 3552, 1575, 3387], 208 | }, 209 | BigFloatInc { 210 | sign: 1, 211 | e: -84, 212 | n: 44, 213 | m: [7149, 6401, 7488, 9228, 6380, 8981, 9920, 1890, 5863, 5929, 9677], 214 | }, 215 | BigFloatInc { 216 | sign: 1, 217 | e: -85, 218 | n: 44, 219 | m: [6986, 6222, 6524, 3674, 5661, 9161, 3866, 6636, 6628, 2202, 2688], 220 | }, 221 | BigFloatInc { 222 | sign: 1, 223 | e: -87, 224 | n: 44, 225 | m: [1313, 3845, 7904, 7228, 5030, 8274, 3153, 3071, 7915, 4601, 7265], 226 | }, 227 | BigFloatInc { 228 | sign: 1, 229 | e: -88, 230 | n: 44, 231 | m: [8767, 1011, 2080, 5060, 2376, 72, 9251, 281, 504, 9632, 1911], 232 | }, 233 | BigFloatInc { 234 | sign: 1, 235 | e: -90, 236 | n: 44, 237 | m: [2478, 4902, 2769, 7590, 9939, 9415, 3976, 3543, 5651, 4697, 4902], 238 | }, 239 | BigFloatInc { 240 | sign: 1, 241 | e: -91, 242 | n: 44, 243 | m: [5620, 3725, 5692, 9397, 9984, 2353, 8494, 8385, 3912, 6174, 1225], 244 | }, 245 | BigFloatInc { 246 | sign: 1, 247 | e: -93, 248 | n: 44, 249 | m: [7365, 9086, 1200, 4872, 1914, 8912, 5107, 2404, 2714, 3108, 2989], 250 | }, 251 | BigFloatInc { 252 | sign: 1, 253 | e: -95, 254 | n: 44, 255 | m: [4678, 2587, 5240, 9695, 1224, 267, 3114, 1439, 3129, 4067, 7117], 256 | }, 257 | BigFloatInc { 258 | sign: 1, 259 | e: -96, 260 | n: 44, 261 | m: [5739, 5950, 4939, 7138, 5633, 9829, 1886, 2195, 6774, 2108, 1655], 262 | }, 263 | BigFloatInc { 264 | sign: 1, 265 | e: -98, 266 | n: 44, 267 | m: [3953, 7160, 4862, 2587, 6440, 9612, 7924, 2261, 8123, 8428, 3761], 268 | }, 269 | BigFloatInc { 270 | sign: 1, 271 | e: -100, 272 | n: 44, 273 | m: [5450, 1467, 1917, 7972, 5422, 2472, 9833, 2803, 4718, 6508, 8359], 274 | }, 275 | BigFloatInc { 276 | sign: 1, 277 | e: -101, 278 | n: 44, 279 | m: [1620, 2058, 9547, 9993, 2917, 972, 1268, 1479, 156, 3154, 1817], 280 | }, 281 | BigFloatInc { 282 | sign: 1, 283 | e: -103, 284 | n: 44, 285 | m: [4297, 5868, 5419, 8710, 7697, 2919, 8868, 593, 1396, 6285, 3866], 286 | }, 287 | BigFloatInc { 288 | sign: 1, 289 | e: -105, 290 | n: 44, 291 | m: [8952, 4725, 2957, 8980, 5203, 2749, 2642, 1237, 7075, 4760, 8055], 292 | }, 293 | BigFloatInc { 294 | sign: 1, 295 | e: -106, 296 | n: 44, 297 | m: [602, 9944, 9174, 7342, 5347, 1581, 335, 6579, 831, 9747, 1643], 298 | }, 299 | BigFloatInc { 300 | sign: 1, 301 | e: -108, 302 | n: 44, 303 | m: [1205, 9888, 8349, 4685, 695, 3163, 670, 3158, 1663, 9494, 3287], 304 | }, 305 | ]; 306 | -------------------------------------------------------------------------------- /src/inc/ops/tables/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod asin_const; 2 | pub mod asinh_const; 3 | pub mod atan_const; 4 | pub mod cbrt_const; 5 | pub mod exp_const; 6 | pub mod fact_const; 7 | pub mod ln_const; 8 | pub mod sin_const; 9 | pub mod sqrt_const; 10 | pub mod tan_const; 11 | pub mod tanh_const; 12 | -------------------------------------------------------------------------------- /src/inc/ops/tables/tan_const.rs: -------------------------------------------------------------------------------- 1 | use crate::inc::inc::BigFloatInc; 2 | 3 | // tangent polynomial coefficients 4 | pub(crate) const TAN_VALUES: [BigFloatInc; 50] = [ 5 | BigFloatInc { 6 | sign: 1, 7 | e: -44, 8 | n: 44, 9 | m: [3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333], 10 | }, 11 | BigFloatInc { 12 | sign: 1, 13 | e: -44, 14 | n: 44, 15 | m: [3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 1333], 16 | }, 17 | BigFloatInc { 18 | sign: 1, 19 | e: -45, 20 | n: 44, 21 | m: [8254, 5396, 9682, 8253, 5396, 9682, 8253, 5396, 9682, 8253, 5396], 22 | }, 23 | BigFloatInc { 24 | sign: 1, 25 | e: -45, 26 | n: 44, 27 | m: [9488, 2186, 2028, 6155, 8853, 8694, 2821, 5520, 5361, 9488, 2186], 28 | }, 29 | BigFloatInc { 30 | sign: 1, 31 | e: -46, 32 | n: 44, 33 | m: [2355, 8863, 9656, 9021, 5529, 6323, 5688, 2196, 2990, 2355, 8863], 34 | }, 35 | BigFloatInc { 36 | sign: 1, 37 | e: -46, 38 | n: 44, 39 | m: [7947, 258, 1435, 9058, 1369, 2546, 169, 2481, 3657, 1280, 3592], 40 | }, 41 | BigFloatInc { 42 | sign: 1, 43 | e: -46, 44 | n: 44, 45 | m: [1360, 9043, 1191, 7021, 5180, 4948, 2682, 1318, 8705, 8343, 1455], 46 | }, 47 | BigFloatInc { 48 | sign: 1, 49 | e: -47, 50 | n: 44, 51 | m: [5984, 7543, 1088, 2, 9937, 8075, 8137, 5859, 945, 2744, 5900], 52 | }, 53 | BigFloatInc { 54 | sign: 1, 55 | e: -47, 56 | n: 44, 57 | m: [6910, 3205, 2809, 8511, 4588, 5731, 8148, 5524, 4243, 2911, 2391], 58 | }, 59 | BigFloatInc { 60 | sign: 1, 61 | e: -48, 62 | n: 44, 63 | m: [7555, 7858, 937, 3888, 5000, 9587, 3255, 9450, 5692, 5379, 9691], 64 | }, 65 | BigFloatInc { 66 | sign: 1, 67 | e: -48, 68 | n: 44, 69 | m: [6564, 9520, 3350, 3123, 809, 3708, 4053, 1683, 8833, 8323, 3927], 70 | }, 71 | BigFloatInc { 72 | sign: 1, 73 | e: -48, 74 | n: 44, 75 | m: [4793, 5531, 430, 6570, 7981, 7442, 4740, 2896, 693, 8905, 1591], 76 | }, 77 | BigFloatInc { 78 | sign: 1, 79 | e: -49, 80 | n: 44, 81 | m: [8242, 4631, 5804, 3025, 2315, 9084, 7631, 5430, 1565, 6892, 6451], 82 | }, 83 | BigFloatInc { 84 | sign: 1, 85 | e: -49, 86 | n: 44, 87 | m: [4299, 7370, 4109, 4097, 4256, 6359, 5542, 754, 5129, 7711, 2614], 88 | }, 89 | BigFloatInc { 90 | sign: 1, 91 | e: -49, 92 | n: 44, 93 | m: [4452, 9004, 7761, 1247, 5394, 9135, 4350, 465, 3201, 7268, 1059], 94 | }, 95 | BigFloatInc { 96 | sign: 1, 97 | e: -50, 98 | n: 44, 99 | m: [3116, 2615, 7224, 3972, 1280, 2035, 8548, 3805, 7827, 9110, 4294], 100 | }, 101 | BigFloatInc { 102 | sign: 1, 103 | e: -50, 104 | n: 44, 105 | m: [4028, 1937, 7292, 3302, 9231, 8622, 7779, 7164, 9635, 6618, 1740], 106 | }, 107 | BigFloatInc { 108 | sign: 1, 109 | e: -51, 110 | n: 44, 111 | m: [9114, 9836, 5656, 4805, 8544, 1451, 3252, 968, 4640, 6369, 7054], 112 | }, 113 | BigFloatInc { 114 | sign: 1, 115 | e: -51, 116 | n: 44, 117 | m: [9289, 3574, 4694, 1416, 4534, 3109, 9083, 5253, 6230, 1366, 2859], 118 | }, 119 | BigFloatInc { 120 | sign: 1, 121 | e: -51, 122 | n: 44, 123 | m: [6926, 9630, 7903, 9091, 3202, 1979, 2200, 9885, 4327, 7644, 1158], 124 | }, 125 | BigFloatInc { 126 | sign: 1, 127 | e: -52, 128 | n: 44, 129 | m: [1976, 2366, 7238, 4676, 3472, 1904, 6288, 901, 9823, 2953, 4696], 130 | }, 131 | BigFloatInc { 132 | sign: 1, 133 | e: -52, 134 | n: 44, 135 | m: [9652, 4736, 8403, 4623, 6595, 1970, 9213, 1275, 3393, 3368, 1903], 136 | }, 137 | BigFloatInc { 138 | sign: 1, 139 | e: -53, 140 | n: 44, 141 | m: [1929, 8990, 2854, 1627, 3072, 7893, 2904, 9062, 3535, 9336, 7713], 142 | }, 143 | BigFloatInc { 144 | sign: 1, 145 | e: -53, 146 | n: 44, 147 | m: [439, 5440, 9995, 4408, 13, 7812, 457, 2087, 4589, 3395, 3126], 148 | }, 149 | BigFloatInc { 150 | sign: 1, 151 | e: -53, 152 | n: 44, 153 | m: [8503, 2488, 4386, 1223, 8808, 962, 1060, 540, 9303, 576, 1267], 154 | }, 155 | BigFloatInc { 156 | sign: 1, 157 | e: -54, 158 | n: 44, 159 | m: [9013, 6988, 9517, 542, 9513, 7604, 7400, 9367, 803, 1914, 5135], 160 | }, 161 | BigFloatInc { 162 | sign: 1, 163 | e: -54, 164 | n: 44, 165 | m: [3748, 6049, 7108, 609, 7195, 9722, 4198, 47, 8677, 2146, 2081], 166 | }, 167 | BigFloatInc { 168 | sign: 1, 169 | e: -55, 170 | n: 44, 171 | m: [9879, 3423, 645, 5587, 8188, 4914, 2938, 4338, 1909, 8454, 8434], 172 | }, 173 | BigFloatInc { 174 | sign: 1, 175 | e: -55, 176 | n: 44, 177 | m: [3760, 2778, 8322, 4856, 292, 3868, 8140, 1155, 8681, 5140, 3418], 178 | }, 179 | BigFloatInc { 180 | sign: 1, 181 | e: -55, 182 | n: 44, 183 | m: [6997, 4910, 8823, 3523, 4465, 9005, 8993, 4846, 7429, 4715, 1385], 184 | }, 185 | BigFloatInc { 186 | sign: 1, 187 | e: -56, 188 | n: 44, 189 | m: [2630, 9933, 4799, 7764, 1187, 5910, 832, 4680, 9241, 1047, 5615], 190 | }, 191 | BigFloatInc { 192 | sign: 1, 193 | e: -56, 194 | n: 44, 195 | m: [7462, 7131, 4152, 3768, 4565, 4337, 8455, 2874, 5537, 7162, 2275], 196 | }, 197 | BigFloatInc { 198 | sign: 1, 199 | e: -57, 200 | n: 44, 201 | m: [546, 8146, 7769, 779, 6031, 4879, 7350, 9531, 8513, 1305, 9223], 202 | }, 203 | BigFloatInc { 204 | sign: 1, 205 | e: -57, 206 | n: 44, 207 | m: [4348, 1549, 4090, 579, 9474, 2238, 8850, 6738, 3109, 9940, 3737], 208 | }, 209 | BigFloatInc { 210 | sign: 1, 211 | e: -57, 212 | n: 44, 213 | m: [5669, 1088, 6643, 1079, 8831, 1108, 5075, 4860, 1871, 9519, 1514], 214 | }, 215 | BigFloatInc { 216 | sign: 1, 217 | e: -58, 218 | n: 44, 219 | m: [7976, 7290, 8528, 9698, 5336, 1746, 8245, 6813, 6261, 8688, 6139], 220 | }, 221 | BigFloatInc { 222 | sign: 1, 223 | e: -58, 224 | n: 44, 225 | m: [3827, 44, 5416, 7291, 424, 4726, 9382, 6278, 2227, 3951, 2488], 226 | }, 227 | BigFloatInc { 228 | sign: 1, 229 | e: -58, 230 | n: 44, 231 | m: [2901, 3771, 2611, 9613, 5292, 384, 6487, 5409, 5663, 5085, 1008], 232 | }, 233 | BigFloatInc { 234 | sign: 1, 235 | e: -59, 236 | n: 44, 237 | m: [3237, 9994, 7998, 5554, 2076, 242, 7619, 9013, 2686, 3312, 4087], 238 | }, 239 | BigFloatInc { 240 | sign: 1, 241 | e: -59, 242 | n: 44, 243 | m: [2085, 5906, 7856, 3744, 4940, 7701, 3672, 8628, 5137, 5329, 1656], 244 | }, 245 | BigFloatInc { 246 | sign: 1, 247 | e: -60, 248 | n: 44, 249 | m: [4270, 5715, 646, 5470, 4887, 7064, 6560, 8711, 7504, 6751, 6713], 250 | }, 251 | BigFloatInc { 252 | sign: 1, 253 | e: -60, 254 | n: 44, 255 | m: [5109, 1546, 9076, 1055, 4664, 3141, 7910, 4458, 6130, 9500, 2720], 256 | }, 257 | BigFloatInc { 258 | sign: 1, 259 | e: -60, 260 | n: 44, 261 | m: [718, 5179, 9383, 219, 3955, 8178, 1458, 2237, 2337, 7595, 1102], 262 | }, 263 | BigFloatInc { 264 | sign: 1, 265 | e: -61, 266 | n: 44, 267 | m: [2606, 4410, 1464, 495, 7813, 4893, 4663, 7412, 723, 3160, 4469], 268 | }, 269 | BigFloatInc { 270 | sign: 1, 271 | e: -61, 272 | n: 44, 273 | m: [5700, 8748, 3894, 6439, 6206, 6703, 7076, 9766, 5169, 3455, 1811], 274 | }, 275 | BigFloatInc { 276 | sign: 1, 277 | e: -62, 278 | n: 44, 279 | m: [8732, 7654, 7641, 3867, 1118, 3807, 5455, 147, 1134, 1070, 7341], 280 | }, 281 | BigFloatInc { 282 | sign: 1, 283 | e: -62, 284 | n: 44, 285 | m: [5715, 7216, 3791, 958, 9896, 1492, 9292, 6193, 653, 2386, 2975], 286 | }, 287 | BigFloatInc { 288 | sign: 1, 289 | e: -62, 290 | n: 44, 291 | m: [2591, 2071, 6419, 9611, 8452, 4690, 3490, 507, 8893, 8187, 1205], 292 | }, 293 | BigFloatInc { 294 | sign: 1, 295 | e: -63, 296 | n: 44, 297 | m: [4275, 3017, 532, 6525, 7927, 9625, 5216, 4370, 7810, 9994, 4886], 298 | }, 299 | BigFloatInc { 300 | sign: 1, 301 | e: -63, 302 | n: 44, 303 | m: [1618, 2098, 9526, 8581, 1564, 6622, 901, 4087, 8632, 6262, 1980], 304 | }, 305 | ]; 306 | -------------------------------------------------------------------------------- /src/inc/ops/tables/tanh_const.rs: -------------------------------------------------------------------------------- 1 | use crate::inc::inc::BigFloatInc; 2 | 3 | // hyperbolic tangent polynomial coefficients 4 | pub(crate) const TANH_VALUES: [BigFloatInc; 10] = [ 5 | BigFloatInc { 6 | sign: -1, 7 | e: -44, 8 | n: 44, 9 | m: [3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333], 10 | }, 11 | BigFloatInc { 12 | sign: 1, 13 | e: -44, 14 | n: 44, 15 | m: [3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 3333, 1333], 16 | }, 17 | BigFloatInc { 18 | sign: -1, 19 | e: -45, 20 | n: 44, 21 | m: [8254, 5396, 9682, 8253, 5396, 9682, 8253, 5396, 9682, 8253, 5396], 22 | }, 23 | BigFloatInc { 24 | sign: 1, 25 | e: -45, 26 | n: 44, 27 | m: [9488, 2186, 2028, 6155, 8853, 8694, 2821, 5520, 5361, 9488, 2186], 28 | }, 29 | BigFloatInc { 30 | sign: -1, 31 | e: -46, 32 | n: 44, 33 | m: [2355, 8863, 9656, 9021, 5529, 6323, 5688, 2196, 2990, 2355, 8863], 34 | }, 35 | BigFloatInc { 36 | sign: 1, 37 | e: -46, 38 | n: 44, 39 | m: [7947, 258, 1435, 9058, 1369, 2546, 169, 2481, 3657, 1280, 3592], 40 | }, 41 | BigFloatInc { 42 | sign: -1, 43 | e: -46, 44 | n: 44, 45 | m: [1360, 9043, 1191, 7021, 5180, 4948, 2682, 1318, 8705, 8343, 1455], 46 | }, 47 | BigFloatInc { 48 | sign: 1, 49 | e: -47, 50 | n: 44, 51 | m: [5984, 7543, 1088, 2, 9937, 8075, 8137, 5859, 945, 2744, 5900], 52 | }, 53 | BigFloatInc { 54 | sign: -1, 55 | e: -47, 56 | n: 44, 57 | m: [6910, 3205, 2809, 8511, 4588, 5731, 8148, 5524, 4243, 2911, 2391], 58 | }, 59 | BigFloatInc { 60 | sign: 1, 61 | e: -48, 62 | n: 44, 63 | m: [7555, 7858, 937, 3888, 5000, 9587, 3255, 9450, 5692, 5379, 9691], 64 | }, 65 | ]; 66 | -------------------------------------------------------------------------------- /src/inc/ops/trig.rs: -------------------------------------------------------------------------------- 1 | //! Trigonometric functions and inverse trigonometric functions. 2 | 3 | use crate::defs::Error; 4 | use crate::defs::DECIMAL_SIGN_NEG; 5 | use crate::defs::DECIMAL_SIGN_POS; 6 | use crate::inc::inc::BigFloatInc; 7 | use crate::inc::ops::tables::asin_const::ASIN_VALUES; 8 | use crate::inc::ops::tables::atan_const::ATAN_VALUES1; 9 | use crate::inc::ops::tables::atan_const::ATAN_VALUES2; 10 | use crate::inc::ops::tables::fact_const::INVFACT_VALUES; 11 | use crate::inc::ops::tables::sin_const::SIN_VALUES1; 12 | use crate::inc::ops::tables::sin_const::SIN_VALUES2; 13 | use crate::inc::ops::tables::tan_const::TAN_VALUES; 14 | 15 | const HALF_PI: BigFloatInc = BigFloatInc { 16 | m: [5846, 2098, 5144, 6397, 1691, 3132, 6192, 4896, 2679, 7963, 1570], 17 | n: 44, 18 | sign: DECIMAL_SIGN_POS, 19 | e: -43, 20 | }; 21 | const PI: BigFloatInc = BigFloatInc { 22 | m: [1694, 4197, 288, 2795, 3383, 6264, 2384, 9793, 5358, 5926, 3141], 23 | n: 44, 24 | sign: DECIMAL_SIGN_POS, 25 | e: -43, 26 | }; 27 | const PI2: BigFloatInc = BigFloatInc { 28 | m: [3388, 8394, 576, 5590, 6766, 2528, 4769, 9586, 717, 1853, 6283], 29 | n: 44, 30 | sign: DECIMAL_SIGN_POS, 31 | e: -43, 32 | }; 33 | const SQRT_2: BigFloatInc = BigFloatInc { 34 | sign: 1, 35 | e: -43, 36 | n: 44, 37 | m: [6719, 8569, 9807, 2096, 8724, 168, 488, 3095, 6237, 2135, 1414], 38 | }; 39 | 40 | impl BigFloatInc { 41 | /// Returns sine of a number. Argument is an angle in radians. 42 | /// 43 | /// # Errors 44 | /// 45 | /// ExponentOverflow - when result is too big. 46 | pub fn sin(&self) -> Result { 47 | self.sin_cos(0) 48 | } 49 | 50 | /// Returns cosine of a number. Argument is an angle in radians. 51 | /// 52 | /// # Errors 53 | /// 54 | /// ExponentOverflow - when result is too big. 55 | pub fn cos(&self) -> Result { 56 | self.sin_cos(1) 57 | } 58 | 59 | /// Returns tangent of a number. Argument is an angle in radians. 60 | /// 61 | /// # Errors 62 | /// 63 | /// ExponentOverflow - when result is too big. 64 | pub fn tan(&self) -> Result { 65 | // tan(x) = tan(s + dx) = tan(s) + tan(dx) / (1 - tan(s)*tan(dx)); 66 | // tan(s) = sin(s)/cos(s) 67 | // tan(dx) = x + 1/3*x^3 + 2/15*x^5 + ... (Taylor series) 68 | // do calculation only for angles [0, pi/2) 69 | let mut x = *self; 70 | 71 | // determine quadrant 72 | let mut quadrant = 0; 73 | x = x.div(&PI)?; 74 | let fractional = x.get_fractional_part(); 75 | x = PI.mul(&fractional)?; 76 | while x.cmp(&HALF_PI) > 0 { 77 | x = PI.sub(&x)?; 78 | quadrant = 1; 79 | } 80 | let (idx, mut dx) = Self::get_trig_params(&mut x, 1); 81 | 82 | // sin(s) / cos(s) = sin(s) / sin(s + pi/2) 83 | let tan_s = SIN_VALUES1[idx].div(&SIN_VALUES2[idx])?; 84 | 85 | // Taylor series 86 | let mut tan_dx = dx; 87 | let dxq = dx.mul(&dx)?; 88 | let mut i = 0; 89 | while i < TAN_VALUES.len() { 90 | dx = dx.mul(&dxq)?; 91 | let p = dx.mul(&TAN_VALUES[i])?; 92 | let val = tan_dx.add(&p)?; 93 | if val.cmp(&tan_dx) == 0 { 94 | break; 95 | } 96 | tan_dx = val; 97 | i += 1; 98 | assert!(i != TAN_VALUES.len() - 2); 99 | } 100 | 101 | // tan(x) 102 | let d = BigFloatInc::one().sub(&tan_s.mul(&tan_dx)?)?; 103 | let mut ret = tan_s.add(&tan_dx)?.div(&d)?; 104 | if (quadrant == 1 && self.sign == DECIMAL_SIGN_POS) 105 | || (quadrant == 0 && self.sign == DECIMAL_SIGN_NEG) 106 | { 107 | ret.sign = DECIMAL_SIGN_NEG; 108 | } 109 | Ok(ret) 110 | } 111 | 112 | /// Returns arcsine of a number. Result is an angle in radians ranging from `-pi/2` to `pi/2`. 113 | /// 114 | /// # Errors 115 | /// 116 | /// ExponentOverflow - when result is too big. 117 | /// InvalidArgument - when |`self`| > 1. 118 | pub fn asin(&self) -> Result { 119 | let one = Self::one(); 120 | let mut dx = one.sub(&self.abs())?; 121 | if dx.e as i16 + dx.n <= -5 { 122 | // Taylor series for arsine(1-x) when x is close to 1 123 | let mut ret = HALF_PI.sub(&dx.sqrt()?.mul(&SQRT_2)?)?; 124 | let dxx = dx.mul(&dx)?; 125 | let mut i = 0; 126 | while i < ASIN_VALUES.len() { 127 | dx = dx.mul(&dxx)?; 128 | let p = dx.sqrt()?.mul(&ASIN_VALUES[i])?; 129 | let val = ret.add(&p)?; 130 | if val.cmp(&ret) == 0 { 131 | break; 132 | } 133 | ret = val; 134 | i += 1; 135 | } 136 | ret.sign = self.sign; 137 | Ok(ret) 138 | } else { 139 | // arcsin(x) = arctan(x / sqrt(1 - x^2)) 140 | let x = *self; 141 | let d = one.sub(&x.mul(&x)?)?.sqrt()?; 142 | if d.n == 0 { 143 | Ok(if x.sign == DECIMAL_SIGN_NEG { HALF_PI.inv_sign() } else { HALF_PI }) 144 | } else { 145 | let arg = x.div(&d)?; 146 | arg.atan() 147 | } 148 | } 149 | } 150 | 151 | /// Returns arccosine of a number. Result is an angle in radians ranging from `0` to `pi`. 152 | /// 153 | /// # Errors 154 | /// 155 | /// ExponentOverflow - when result is too big. 156 | /// InvalidArgument - when |`self`| > 1. 157 | pub fn acos(&self) -> Result { 158 | HALF_PI.sub(&self.asin()?) 159 | } 160 | 161 | /// Returns arctangent of a number. Result is an angle in radians ranging from `-pi/2` to `pi/2`. 162 | /// 163 | /// # Errors 164 | /// 165 | /// ExponentOverflow - when result is too big. 166 | pub fn atan(&self) -> Result { 167 | if self.n == 0 { 168 | return Ok(Self::new()); 169 | } 170 | 171 | let one = BigFloatInc::one(); 172 | let mut x = *self; 173 | x.sign = DECIMAL_SIGN_POS; 174 | 175 | // if x > 1 then arctan(x) = pi/2 - arctan(1/x) 176 | let mut inverse_arg = false; 177 | let x_one_cmp = x.abs().cmp(&one); 178 | if x_one_cmp > 0 { 179 | x = one.div(&x)?; 180 | if x.n == 0 { 181 | return Ok(if self.sign == DECIMAL_SIGN_NEG { 182 | HALF_PI.inv_sign() 183 | } else { 184 | HALF_PI 185 | }); 186 | } 187 | inverse_arg = true; 188 | } else if x_one_cmp == 0 { 189 | let mut ret = ATAN_VALUES2[10000]; 190 | ret.sign = self.sign; 191 | return Ok(ret); 192 | } 193 | 194 | // further reduction: arctan(x) = arctan(s) + arctan((x - s) / (1 + x*s)) 195 | let (idx, mut dx) = Self::get_trig_params(&mut x, 0); 196 | let atan_s = ATAN_VALUES2[idx]; 197 | let s = x.sub(&dx)?; 198 | if s.n != 0 { 199 | dx = dx.div(&one.add(&x.mul(&s)?)?)?; 200 | } 201 | 202 | // Taylor series 203 | let mut ret = dx; 204 | let dxx = dx.mul(&dx)?; 205 | for i in 0..ATAN_VALUES1.len() { 206 | dx = dx.mul(&dxx)?; 207 | let p = ATAN_VALUES1[i].mul(&dx)?; 208 | let val = ret.add(&p)?; 209 | if val.cmp(&ret) == 0 { 210 | break; 211 | } 212 | ret = val; 213 | assert!(i != ATAN_VALUES1.len() - 2); 214 | } 215 | 216 | ret = ret.add(&atan_s)?; 217 | 218 | if inverse_arg { 219 | ret = HALF_PI.sub(&ret)?; 220 | } 221 | ret.sign = self.sign; 222 | 223 | Ok(ret) 224 | } 225 | 226 | // sin: q=0, cos: q=1; 227 | fn sin_cos(&self, q: usize) -> Result { 228 | // calculation: 229 | // x = s + dx, x is in [0, pi/2) 230 | // use series: sin(x) = sin(s) + sum( der(sin(s), n) * (dx)^n / n! ) 231 | // where: der(sin(s), n) = sin(s + n*pi/2) - n'th derivative of sin 232 | // use precalculated values: sin(s), sin(s + pi/2), sin(s + pi) = -sin(s), sin(s + 3*pi/2) 233 | // = -sin(s + pi/2) 234 | // do calculation only for angles [0, pi/2) 235 | let mut x = *self; 236 | 237 | // determine quadrant 238 | let mut quadrant = q; 239 | x = x.div(&PI2)?; 240 | let fractional = x.get_fractional_part(); 241 | x = PI2.mul(&fractional)?; 242 | while x.cmp(&HALF_PI) > 0 { 243 | x = x.sub(&HALF_PI)?; 244 | quadrant += 1; 245 | } 246 | if quadrant >= 4 { 247 | quadrant -= 4; 248 | } 249 | let (idx, dx) = Self::get_trig_params(&mut x, 1); 250 | 251 | // determine closest precomputed values of derivatives 252 | let mut s = [Self::new(), Self::new(), Self::new(), Self::new()]; 253 | s[0] = SIN_VALUES1[idx]; 254 | s[1] = SIN_VALUES2[idx]; 255 | s[2] = s[0]; 256 | s[2].sign = DECIMAL_SIGN_NEG; 257 | s[3] = s[1]; 258 | s[3].sign = DECIMAL_SIGN_NEG; 259 | 260 | let mut ret = s[quadrant]; 261 | let mut dxn = dx; 262 | let one = Self::one(); 263 | let mut der_n = (quadrant + 1) % 4; 264 | for i in 0..INVFACT_VALUES.len() { 265 | let p = dxn.mul(&INVFACT_VALUES[i])?; 266 | let der = s[der_n]; 267 | if der.n != 0 { 268 | let add = der.mul(&p)?; 269 | let val = ret.add(&add)?; 270 | if val.cmp(&ret) == 0 { 271 | break; 272 | } 273 | ret = val; 274 | } 275 | dxn = dxn.mul(&dx)?; 276 | der_n += 1; 277 | if der_n > 3 { 278 | der_n = 0; 279 | } 280 | } 281 | ret.sign = if quadrant > 1 { DECIMAL_SIGN_NEG } else { DECIMAL_SIGN_POS }; 282 | if q == 0 { 283 | ret.sign *= self.sign; 284 | } 285 | if ret.abs().cmp(&one) > 0 { 286 | ret = if ret.sign == DECIMAL_SIGN_NEG { one.inv_sign() } else { one }; 287 | } 288 | Ok(ret) 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/inc/ops/trigh.rs: -------------------------------------------------------------------------------- 1 | //! Hyperbolic trigonometric functions and inverse hyperbolic trigonometric functions. 2 | 3 | use crate::defs::Error; 4 | use crate::defs::DECIMAL_SIGN_NEG; 5 | use crate::defs::DECIMAL_SIGN_POS; 6 | use crate::inc::inc::BigFloatInc; 7 | use crate::inc::inc::DECIMAL_POSITIONS; 8 | use crate::inc::ops::tables::asinh_const::ASINH_VALUES; 9 | use crate::inc::ops::tables::fact_const::INVFACT_VALUES; 10 | use crate::inc::ops::tables::tanh_const::TANH_VALUES; 11 | 12 | const ONE_HALF: BigFloatInc = BigFloatInc { 13 | m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5000], 14 | n: DECIMAL_POSITIONS as i16, 15 | sign: DECIMAL_SIGN_POS, 16 | e: -(DECIMAL_POSITIONS as i8), 17 | }; 18 | 19 | const LN_OF_2: BigFloatInc = BigFloatInc { 20 | m: [13, 755, 6568, 5817, 1214, 7232, 941, 9453, 559, 4718, 6931], 21 | n: DECIMAL_POSITIONS as i16, 22 | sign: DECIMAL_SIGN_POS, 23 | e: -(DECIMAL_POSITIONS as i8), 24 | }; 25 | 26 | impl BigFloatInc { 27 | /// Returns hyperbolic sine of a number. 28 | /// 29 | /// # Errors 30 | /// 31 | /// ExponentOverflow - when result is too big. 32 | pub fn sinh(&self) -> Result { 33 | if self.e as i16 + self.n <= -1 { 34 | // sinh(x) = x + x^3/3! + x^5/5! + ... 35 | let mut ret = *self; 36 | let dxx = self.mul(self)?; 37 | let mut dx = ret; 38 | for i in 1..INVFACT_VALUES.len() / 2 { 39 | dx = dx.mul(&dxx)?; 40 | let p = dx.mul(&INVFACT_VALUES[i * 2])?; 41 | let val = ret.add(&p)?; 42 | if val.cmp(&ret) == 0 { 43 | break; 44 | } 45 | ret = val; 46 | } 47 | Ok(ret) 48 | } else { 49 | // 0.5*(e^x - e^-x) 50 | let e_x1 = 51 | if self.sign == DECIMAL_SIGN_NEG { self.inv_sign().exp() } else { self.exp() } 52 | .map_err(|e| { 53 | if let Error::ExponentOverflow(_) = e { 54 | Error::ExponentOverflow(self.sign) 55 | } else { 56 | e 57 | } 58 | })?; 59 | let e_x2 = Self::one().div(&e_x1)?; 60 | let mut ret = e_x1.sub(&e_x2)?.mul(&ONE_HALF)?; 61 | ret.sign = self.sign; 62 | Ok(ret) 63 | } 64 | } 65 | 66 | /// Returns hyperbolic cosine of a number. 67 | /// 68 | /// # Errors 69 | /// 70 | /// ExponentOverflow - when result is too big. 71 | pub fn cosh(&self) -> Result { 72 | if self.e as i16 + self.n <= -1 { 73 | // cosh(x) = 1 + x^2/2! + x^4/4! + ... 74 | let one = Self::one(); 75 | let mut ret = one; 76 | let dxx = self.mul(self)?; 77 | let mut dx = dxx; 78 | for i in 0..INVFACT_VALUES.len() / 2 - 1 { 79 | let p = dx.mul(&INVFACT_VALUES[i * 2 + 1])?; 80 | let val = ret.add(&p)?; 81 | if val.cmp(&ret) == 0 { 82 | break; 83 | } 84 | ret = val; 85 | dx = dx.mul(&dxx)?; 86 | } 87 | Ok(ret) 88 | } else { 89 | // 0.5*(e^x + e^-x) 90 | let e_x1 = 91 | if self.sign == DECIMAL_SIGN_NEG { self.inv_sign().exp() } else { self.exp() }?; 92 | let e_x2 = Self::one().div(&e_x1)?; 93 | e_x1.add(&e_x2)?.mul(&ONE_HALF) 94 | } 95 | } 96 | 97 | /// Returns hyperbolic tangent of a number. 98 | /// 99 | /// # Errors 100 | /// 101 | /// ExponentOverflow - when result is too big. 102 | pub fn tanh(&self) -> Result { 103 | if self.e as i16 + self.n < -1 { 104 | // tanh series 105 | let mut ret = *self; 106 | let dxx = self.mul(self)?; 107 | let mut dx = *self; 108 | for pcoef in TANH_VALUES { 109 | dx = dx.mul(&dxx)?; 110 | let p = pcoef.mul(&dx)?; 111 | let val = ret.add(&p)?; 112 | if val.cmp(&ret) == 0 { 113 | break; 114 | } 115 | ret = val; 116 | } 117 | Ok(ret) 118 | } else if self.n + self.e as i16 > 2 { 119 | // int part of x has at least 3 digits 120 | // this is not the best estimate for optimisation, but it is simple 121 | Ok(if self.sign == DECIMAL_SIGN_NEG { Self::one().inv_sign() } else { Self::one() }) 122 | } else { 123 | // (e^x - e^-x) / (e^x + e^-x) 124 | let e_x1 = 125 | if self.sign == DECIMAL_SIGN_NEG { self.inv_sign().exp() } else { self.exp() }?; 126 | let e_x2 = Self::one().div(&e_x1)?; 127 | let mut ret = e_x1.sub(&e_x2)?.div(&e_x1.add(&e_x2)?)?; 128 | ret.sign = self.sign; 129 | Ok(ret) 130 | } 131 | } 132 | 133 | /// Returns inverse hyperbolic sine of a number. 134 | /// 135 | /// # Errors 136 | /// 137 | /// ExponentOverflow - when result is too big. 138 | pub fn asinh(&self) -> Result { 139 | if self.e as i16 + self.n < 0 { 140 | // asinh series 141 | let mut ret = *self; 142 | let dxx = self.mul(self)?; 143 | let mut dx = *self; 144 | for pcoef in ASINH_VALUES { 145 | dx = dx.mul(&dxx)?; 146 | let p = pcoef.mul(&dx)?; 147 | let val = ret.add(&p)?; 148 | if val.cmp(&ret) == 0 { 149 | break; 150 | } 151 | ret = val; 152 | } 153 | Ok(ret) 154 | } else if (self.e as i16 + self.n - 1) * 2 >= DECIMAL_POSITIONS as i16 { 155 | // sign(x)*(ln(|x|) + ln(2)) 156 | let x = self.abs(); 157 | let mut ret = x.ln()?.add(&LN_OF_2)?; 158 | ret.sign = self.sign; 159 | Ok(ret) 160 | } else { 161 | // sign(x)*ln(|x| + sqrt(x^2 + 1)) 162 | let x = self.abs(); 163 | let xx = x.mul(&x)?; 164 | let xx1 = xx.add(&Self::one())?; 165 | let sq = xx1.sqrt()?; 166 | let arg = x.add(&sq)?; 167 | if arg.n == 0 { 168 | Err(Error::ExponentOverflow(DECIMAL_SIGN_NEG)) 169 | } else { 170 | let mut ret = arg.ln()?; 171 | ret.sign = self.sign; 172 | Ok(ret) 173 | } 174 | } 175 | } 176 | 177 | /// Returns inverse hyperbolic cosine of a number. 178 | /// 179 | /// # Errors 180 | /// 181 | /// ExponentOverflow - when result is too big. 182 | /// InvalidArgument - when `self` is less than 1. 183 | pub fn acosh(&self) -> Result { 184 | let x = *self; 185 | let one = Self::one(); 186 | if x.cmp(&one) < 0 { 187 | return Err(Error::InvalidArgument); 188 | } 189 | if (x.e as i16 + x.n - 1) * 2 >= DECIMAL_POSITIONS as i16 { 190 | // ln(x) + ln(2) 191 | x.ln()?.add(&LN_OF_2) 192 | } else { 193 | // ln(x + sqrt(x^2 - 1)) 194 | let xx = x.mul(&x)?; 195 | let arg = x.add(&xx.sub(&one)?.sqrt()?)?; 196 | arg.ln() 197 | } 198 | } 199 | 200 | /// Returns inverse hyperbolic tangent of a number. 201 | /// 202 | /// # Errors 203 | /// 204 | /// InvalidArgument - when |`self`| > 1. 205 | pub fn atanh(&self) -> Result { 206 | if self.e as i16 + self.n < -1 { 207 | // atanh(x) = x + x^3/3 + x^5/5 + ... 208 | let two = Self::two(); 209 | let mut ret = *self; 210 | let dxx = self.mul(self)?; 211 | let mut dx = *self; 212 | let mut factor = Self::one(); 213 | loop { 214 | dx = dx.mul(&dxx)?; 215 | factor = factor.add(&two)?; 216 | let p = dx.div(&factor)?; 217 | let val = ret.add(&p)?; 218 | if val.cmp(&ret) == 0 { 219 | break; 220 | } 221 | ret = val; 222 | } 223 | Ok(ret) 224 | } else { 225 | // 0.5 * ln( (1+x) / (1-x) ) 226 | let x = *self; 227 | let one = Self::one(); 228 | let cmp_result = x.abs().cmp(&one); 229 | if cmp_result > 0 { 230 | Err(Error::InvalidArgument) 231 | } else if cmp_result == 0 { 232 | Err(Error::ExponentOverflow(x.sign)) 233 | } else { 234 | let arg = one.add(&x)?.div(&one.sub(&x)?)?; 235 | ONE_HALF.mul(&arg.ln()?) 236 | } 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/inc/ops/util.rs: -------------------------------------------------------------------------------- 1 | //! Utility functions. 2 | 3 | use crate::defs::DECIMAL_BASE; 4 | use crate::defs::DECIMAL_BASE_LOG10; 5 | use crate::defs::DECIMAL_MIN_EXPONENT; 6 | use crate::defs::DECIMAL_SIGN_POS; 7 | use crate::inc::inc::BigFloatInc; 8 | use crate::inc::inc::DECIMAL_PARTS; 9 | use crate::inc::inc::DECIMAL_POSITIONS; 10 | use crate::RoundingMode; 11 | 12 | impl BigFloatInc { 13 | // compare absolute values of two big floats 14 | // return positive if d1 > d2, negative if d1 < d2, 0 otherwise 15 | pub(super) fn abs_cmp(d1: &[i16], d2: &[i16]) -> i16 { 16 | let mut i: i32 = DECIMAL_PARTS as i32 - 1; 17 | while i >= 0 { 18 | if d1[i as usize] != d2[i as usize] { 19 | return d1[i as usize] - d2[i as usize]; 20 | } 21 | i -= 1; 22 | } 23 | 0 24 | } 25 | 26 | // shift m to the right by n digits 27 | pub(super) fn shift_right(m: &mut [i16], mut n: usize) { 28 | assert!(n > 0 && n <= DECIMAL_POSITIONS); 29 | 30 | let mut s: i16; 31 | let mut t: i16; 32 | let mut x: i32 = (n % DECIMAL_BASE_LOG10) as i32; 33 | n /= DECIMAL_BASE_LOG10; 34 | if x == 0 { 35 | if n > 0 { 36 | for i in 0..DECIMAL_PARTS - n { 37 | m[i] = m[i + n]; 38 | } 39 | } 40 | } else { 41 | s = 10; 42 | t = DECIMAL_BASE as i16 / 10; 43 | x -= 1; 44 | while x > 0 { 45 | s *= 10; 46 | t /= 10; 47 | x -= 1; 48 | } 49 | 50 | let mut i = 0; 51 | while i < DECIMAL_PARTS - n - 1 { 52 | m[i] = (m[i + n + 1] % s) * t + m[i + n] / s; 53 | i += 1; 54 | } 55 | m[i] = m[i + n] / s; 56 | } 57 | for i in 0..n { 58 | m[i + DECIMAL_PARTS - n] = 0; 59 | } 60 | } 61 | 62 | // shift m to the left by n digits 63 | pub(crate) fn shift_left(m: &mut [i16], mut n: usize) { 64 | assert!(n > 0 && n <= DECIMAL_POSITIONS); 65 | 66 | let mut i: usize; 67 | let mut s: i16; 68 | let mut t: i16; 69 | let mut x: i32 = (n % DECIMAL_BASE_LOG10) as i32; 70 | n /= DECIMAL_BASE_LOG10; 71 | if x == 0 { 72 | if n > 0 { 73 | i = DECIMAL_PARTS - 1; 74 | while i >= n { 75 | m[i] = m[i - n]; 76 | i -= 1; 77 | } 78 | } 79 | } else { 80 | s = 10; 81 | t = DECIMAL_BASE as i16 / 10; 82 | x -= 1; 83 | while x > 0 { 84 | s *= 10; 85 | t /= 10; 86 | x -= 1; 87 | } 88 | 89 | i = DECIMAL_PARTS - 1; 90 | while i > n { 91 | m[i] = (m[i - n] % t) * s + m[i - n - 1] / t; 92 | i -= 1; 93 | } 94 | m[i] = (m[i - n] % t) * s; 95 | } 96 | for k in 0..n { 97 | m[k] = 0; 98 | } 99 | } 100 | 101 | // return number of digits taken in mantissa 102 | pub(crate) fn num_digits(m: &[i16]) -> i16 { 103 | let mut n: i16 = DECIMAL_POSITIONS as i16; 104 | let mut t: i16; 105 | let mut p: i16 = DECIMAL_PARTS as i16 - 1; 106 | 107 | while p >= 0 && 0 == m[p as usize] { 108 | p -= 1; 109 | n -= DECIMAL_BASE_LOG10 as i16; 110 | } 111 | 112 | if n > 0 { 113 | t = m[p as usize]; 114 | n -= DECIMAL_BASE_LOG10 as i16; 115 | loop { 116 | n += 1; 117 | t /= 10; 118 | if t == 0 { 119 | break; 120 | } 121 | } 122 | } 123 | n 124 | } 125 | 126 | // multiply d1 by digit d and put result to d3 with overflow 127 | pub(super) fn mul_by_digit(d1: &[i16], d: i32, d3: &mut [i16]) { 128 | let mut m: i32 = 0; 129 | for i in 0..DECIMAL_PARTS { 130 | m = d1[i] as i32 * d + m / DECIMAL_BASE as i32; 131 | d3[i] = (m % DECIMAL_BASE as i32) as i16; 132 | } 133 | d3[DECIMAL_PARTS] = (m / DECIMAL_BASE as i32) as i16; 134 | } 135 | 136 | // fractional part of d1 137 | pub(super) fn extract_fract_part(d1: &Self) -> Self { 138 | let mut fractional = Self::new(); 139 | let e = -(d1.e as i16); 140 | if e >= d1.n { 141 | fractional = *d1; 142 | fractional.sign = DECIMAL_SIGN_POS; 143 | } else if e > 0 { 144 | let mut i = 0; 145 | while i + (DECIMAL_BASE_LOG10 as i16) <= e { 146 | fractional.m[i as usize / DECIMAL_BASE_LOG10] = 147 | d1.m[i as usize / DECIMAL_BASE_LOG10]; 148 | i += DECIMAL_BASE_LOG10 as i16; 149 | } 150 | if i < e { 151 | let mut t = 1; 152 | while i < e { 153 | t *= 10; 154 | i += 1; 155 | } 156 | fractional.m[i as usize / DECIMAL_BASE_LOG10] += 157 | d1.m[i as usize / DECIMAL_BASE_LOG10 as usize] % t; 158 | } 159 | fractional.n = Self::num_digits(&fractional.m); 160 | if fractional.n > 0 { 161 | fractional.e = d1.e; 162 | } 163 | } 164 | fractional 165 | } 166 | 167 | // integer part of d1 168 | pub(super) fn extract_int_part(d1: &Self) -> Self { 169 | if d1.e >= 0 { 170 | return *d1; 171 | } 172 | if d1.e as i16 + d1.n < 0 { 173 | return Self::new(); 174 | } 175 | let mut int = Self::new(); 176 | let mut i = -(d1.e as i16); 177 | let mut t = Self::get_div_factor(i); 178 | if i < 0 { 179 | i = 0; 180 | } 181 | let mut t2 = 1; 182 | while i < d1.n { 183 | int.m[int.n as usize / DECIMAL_BASE_LOG10] += 184 | (d1.m[i as usize / DECIMAL_BASE_LOG10 as usize] / t % 10) * t2; 185 | int.n += 1; 186 | i += 1; 187 | t *= 10; 188 | if t == DECIMAL_BASE as i16 { 189 | t = 1; 190 | } 191 | t2 *= 10; 192 | if t2 == DECIMAL_BASE as i16 { 193 | t2 = 1; 194 | } 195 | } 196 | if int.n > 0 { 197 | int.e = d1.e + (i - int.n) as i8; 198 | } 199 | int 200 | } 201 | 202 | // factor to divide by to get a digit at position n 203 | pub(super) fn get_div_factor(n: i16) -> i16 { 204 | let mut x = n % DECIMAL_BASE_LOG10 as i16; 205 | let mut t = 1; 206 | while x > 0 { 207 | t *= 10; 208 | x -= 1; 209 | } 210 | t 211 | } 212 | 213 | // determine parameters for computation of trig function 214 | pub(super) fn get_trig_params(x: &mut BigFloatInc, add_one: i32) -> (usize, BigFloatInc) { 215 | x.maximize_mantissa(); 216 | let mut i = add_one - (x.n as i32 + x.e as i32); 217 | let mut idx = 0; 218 | let mut dx = *x; 219 | 220 | // x = s + dx 221 | if i < DECIMAL_BASE_LOG10 as i32 { 222 | idx = x.m[DECIMAL_PARTS - 1] as usize; 223 | let mut m = 1; 224 | while i > 0 { 225 | idx /= 10; 226 | i -= 1; 227 | m *= 10; 228 | } 229 | dx.m[DECIMAL_PARTS - 1] = x.m[DECIMAL_PARTS - 1] % m; 230 | dx.n = Self::num_digits(&dx.m); 231 | } 232 | (idx, dx) 233 | } 234 | 235 | /// If exponent is too small try to present number in subnormal form. 236 | /// If not successful, then return 0.0 237 | pub(crate) fn process_subnormal(&mut self, e: i32) -> Self { 238 | if (DECIMAL_POSITIONS as i32) + e > DECIMAL_MIN_EXPONENT as i32 { 239 | // subnormal 240 | let shift = (DECIMAL_MIN_EXPONENT as i32 - e) as usize; 241 | Self::shift_right(&mut self.m, shift); 242 | self.n -= shift as i16; 243 | self.e = DECIMAL_MIN_EXPONENT; 244 | *self 245 | } else { 246 | // zero 247 | Self::new() 248 | } 249 | } 250 | 251 | // Round n positons to even, return true if exponent is to be incremented. 252 | pub(crate) fn round_mantissa( 253 | m: &mut [i16], 254 | n: i16, 255 | rm: RoundingMode, 256 | is_positive: bool, 257 | ) -> bool { 258 | if n > 0 && n <= DECIMAL_POSITIONS as i16 { 259 | let n = n - 1; 260 | let mut rem_zero = true; 261 | // anything before n'th digit becomes 0 262 | for i in 0..n as usize / DECIMAL_BASE_LOG10 { 263 | if m[i] != 0 { 264 | rem_zero = false; 265 | } 266 | m[i] = 0; 267 | } 268 | 269 | // analyze digits at n and at n+1 270 | // to decide if we need to add 1 or not. 271 | let mut c = false; 272 | let np1 = n + 1; 273 | let mut i = n as usize / DECIMAL_BASE_LOG10; 274 | let i1 = np1 as usize / DECIMAL_BASE_LOG10; 275 | let t = Self::get_div_factor(n); 276 | let t2 = Self::get_div_factor(np1); 277 | let num = m[i] / t % 10; 278 | if m[i] % t != 0 { 279 | rem_zero = false; 280 | } 281 | 282 | let num2 = if i1 < m.len() { m[i1] / t2 % 10 } else { 0 }; 283 | 284 | let eq5 = num == 5 && rem_zero; 285 | let gt5 = num > 5 || (num == 5 && !rem_zero); 286 | let gte5 = gt5 || eq5; 287 | 288 | match rm { 289 | RoundingMode::Up => { 290 | if gte5 && is_positive || gt5 && !is_positive { 291 | // add 1 292 | c = true; 293 | } 294 | } 295 | RoundingMode::Down => { 296 | if gt5 && is_positive || gte5 && !is_positive { 297 | // add 1 298 | c = true; 299 | } 300 | } 301 | RoundingMode::FromZero => { 302 | if gte5 { 303 | // add 1 304 | c = true; 305 | } 306 | } 307 | RoundingMode::ToZero => { 308 | if gt5 { 309 | // add 1 310 | c = true; 311 | } 312 | } 313 | RoundingMode::ToEven => { 314 | if gt5 || (eq5 && num2 & 1 != 0) { 315 | // add 1 316 | c = true; 317 | } 318 | } 319 | RoundingMode::ToOdd => { 320 | if gt5 || (eq5 && num2 & 1 == 0) { 321 | // add 1 322 | c = true; 323 | } 324 | } 325 | }; 326 | 327 | if c { 328 | // add 1 at (n+1)'th position 329 | if i1 > i { 330 | m[i] = 0; 331 | } 332 | i = i1; 333 | if i < m.len() { 334 | if m[i] / t2 + 1 < DECIMAL_BASE as i16 / t2 { 335 | m[i] = (m[i] / t2 + 1) * t2; 336 | return false; 337 | } else { 338 | m[i] = 0; 339 | } 340 | } 341 | 342 | // process overflows 343 | i += 1; 344 | while i < m.len() { 345 | if m[i] < DECIMAL_BASE as i16 - 1 { 346 | m[i] += 1; 347 | return false; 348 | } else { 349 | m[i] = 0; 350 | } 351 | i += 1; 352 | } 353 | m[m.len() - 1] = DECIMAL_BASE as i16 / 10; 354 | return true; 355 | } else { 356 | // just remove trailing digits 357 | let t = t * 10; 358 | m[i] = (m[i] / t) * t; 359 | } 360 | } 361 | false 362 | } 363 | 364 | /// Shift to the left as much as possibe. 365 | pub fn maximize_mantissa(&mut self) { 366 | if self.n < DECIMAL_POSITIONS as i16 { 367 | let mut shift = DECIMAL_POSITIONS - self.n as usize; 368 | if shift > (self.e as i32 - DECIMAL_MIN_EXPONENT as i32) as usize { 369 | shift = (self.e - DECIMAL_MIN_EXPONENT) as usize; 370 | } 371 | if shift > 0 { 372 | Self::shift_left(&mut self.m, shift); 373 | self.e -= shift as i8; 374 | self.n += shift as i16; 375 | } 376 | } 377 | } 378 | 379 | /// Return fractional part of number with positive sign. 380 | pub fn get_fractional_part(&self) -> Self { 381 | let mut fractional = Self::new(); 382 | let e = -(self.e as i16); 383 | if e >= self.n { 384 | fractional = *self; 385 | fractional.sign = DECIMAL_SIGN_POS; 386 | } else if e > 0 { 387 | let mut i = 0; 388 | while i + (DECIMAL_BASE_LOG10 as i16) <= e { 389 | fractional.m[i as usize / DECIMAL_BASE_LOG10] = 390 | self.m[i as usize / DECIMAL_BASE_LOG10]; 391 | i += DECIMAL_BASE_LOG10 as i16; 392 | } 393 | if i < e { 394 | let mut t = 1; 395 | while i < e { 396 | t *= 10; 397 | i += 1; 398 | } 399 | fractional.m[i as usize / DECIMAL_BASE_LOG10] += 400 | self.m[i as usize / DECIMAL_BASE_LOG10 as usize] % t; 401 | } 402 | fractional.n = Self::num_digits(&fractional.m); 403 | if fractional.n > 0 { 404 | fractional.e = self.e; 405 | } 406 | } 407 | fractional 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /src/ops/add.rs: -------------------------------------------------------------------------------- 1 | //! Addition and subtraction. 2 | 3 | use crate::defs::BigFloatNum; 4 | use crate::defs::Error; 5 | 6 | impl BigFloatNum { 7 | /// Add d2 and return result of addition. 8 | /// 9 | /// # Errors 10 | /// 11 | /// ExponentOverflow - when result is too big. 12 | pub fn add(&self, d2: &Self) -> Result { 13 | let n = Self::to_big_float_inc(self); 14 | let m = Self::to_big_float_inc(d2); 15 | let ret = n.add(&m)?; 16 | Self::from_big_float_inc(ret) 17 | } 18 | 19 | /// Subtract d2 and return result of subtraction. 20 | /// 21 | /// # Errors 22 | /// 23 | /// ExponentOverflow - when result is too big. 24 | pub fn sub(&self, d2: &Self) -> Result { 25 | let n = Self::to_big_float_inc(self); 26 | let m = Self::to_big_float_inc(d2); 27 | let ret = n.sub(&m)?; 28 | Self::from_big_float_inc(ret) 29 | } 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | 35 | use crate::*; 36 | use defs::*; 37 | 38 | #[test] 39 | fn test_add() { 40 | let mut d1 = BigFloatNum::new(); 41 | let mut d2 = BigFloatNum::new(); 42 | let mut d3: BigFloatNum; 43 | let mut ref_num = BigFloatNum::new(); 44 | 45 | // 46 | // addition 47 | // 48 | 49 | d2.sign = DECIMAL_SIGN_POS; 50 | d1.sign = DECIMAL_SIGN_POS; 51 | for i in 0..DECIMAL_PARTS { 52 | d1.m[i] = 9999; 53 | d2.m[i] = 0; 54 | } 55 | d1.m[0] = 9990; 56 | d2.m[0] = 10; 57 | d1.n = DECIMAL_POSITIONS as i16; 58 | d2.n = 2; 59 | d2.e = DECIMAL_MAX_EXPONENT; 60 | d1.e = DECIMAL_MAX_EXPONENT; 61 | 62 | assert!(d1.add(&d2).unwrap_err() == Error::ExponentOverflow(DECIMAL_SIGN_POS)); 63 | 64 | d2.sign = DECIMAL_SIGN_NEG; 65 | d1.sign = DECIMAL_SIGN_NEG; 66 | assert!(d1.add(&d2).unwrap_err() == Error::ExponentOverflow(DECIMAL_SIGN_NEG)); 67 | 68 | d2.e = 0; 69 | d1.e = 0; 70 | ref_num.m.iter_mut().for_each(|x| *x = 0); 71 | ref_num.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10; 72 | ref_num.sign = DECIMAL_SIGN_NEG; 73 | ref_num.n = DECIMAL_POSITIONS as i16; 74 | ref_num.e = 1; 75 | d3 = d1.add(&d2).unwrap(); 76 | assert!(d3.cmp(&ref_num) == 0); 77 | 78 | d2.sign = DECIMAL_SIGN_POS; 79 | ref_num.sign = DECIMAL_SIGN_NEG; 80 | for i in 0..DECIMAL_PARTS { 81 | ref_num.m[i] = 9999; 82 | } 83 | ref_num.m[0] = 9980; 84 | ref_num.n = DECIMAL_POSITIONS as i16; 85 | ref_num.e = 0; 86 | d3 = d1.add(&d2).unwrap(); 87 | assert!(d3.cmp(&ref_num) == 0); 88 | 89 | ref_num.sign = DECIMAL_SIGN_POS; 90 | d1.sign = DECIMAL_SIGN_POS; 91 | d2.sign = DECIMAL_SIGN_NEG; 92 | d3 = d1.add(&d2).unwrap(); 93 | assert!(d3.cmp(&ref_num) == 0); 94 | 95 | d1 = BigFloatNum::new(); 96 | d2 = BigFloatNum::new(); 97 | ref_num = BigFloatNum::new(); 98 | d1.m[1] = 9999; 99 | d2.m[1] = 9999; 100 | ref_num.m[1] = 9998; 101 | ref_num.m[2] = 1; 102 | d1.n = 8; 103 | d2.n = 8; 104 | ref_num.n = 9; 105 | d3 = d1.add(&d2).unwrap(); 106 | assert!(d3.cmp(&ref_num) == 0); 107 | 108 | // 0 + d2 109 | d1.m[1] = 0; 110 | d1.n = 0; 111 | d2.e = 3; 112 | ref_num = d2; 113 | d3 = d1.add(&d2).unwrap(); 114 | assert!(d3.cmp(&ref_num) == 0); 115 | 116 | // d1 + 0 117 | d2.m[1] = 0; 118 | d2.n = 0; 119 | d2.e = 0; 120 | d1.m[1] = 11; 121 | d1.n = 6; 122 | d1.e = 123; 123 | ref_num = d1; 124 | d3 = d1.add(&d2).unwrap(); 125 | assert!(d3.cmp(&ref_num) == 0); 126 | 127 | // different exponents and precisions 128 | d1 = BigFloatNum::new(); 129 | d2 = BigFloatNum::new(); 130 | 131 | for i in 0..DECIMAL_PARTS { 132 | d1.m[i] = 9999; 133 | } 134 | d1.n = DECIMAL_POSITIONS as i16; 135 | d1.e = 5; 136 | d2.m[0] = 11; 137 | d2.n = 2; 138 | d2.e = 3; 139 | ref_num = d1; 140 | d3 = d1.add(&d2).unwrap(); 141 | assert!(d3.cmp(&ref_num) == 0); 142 | 143 | d1.e = 4; 144 | d2.m[0] = 11; 145 | d2.n = 2; 146 | d2.e = 3; 147 | ref_num.m.iter_mut().for_each(|x| *x = 0); 148 | ref_num.e = 5; 149 | ref_num.n = DECIMAL_POSITIONS as i16; 150 | ref_num.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10; 151 | d3 = d1.add(&d2).unwrap(); 152 | assert!(d3.cmp(&ref_num) == 0); 153 | 154 | d1.e = 5; // 0000 0022 2..2 2211 0000e+5 + 1122 3346e+3 155 | for i in 0..DECIMAL_PARTS { 156 | ref_num.m[i] = 2222; 157 | d1.m[i] = 2222; 158 | } 159 | d1.m[0] = 0; 160 | d1.m[1] = 2211; 161 | d1.m[DECIMAL_PARTS - 1] = 0; 162 | d1.m[DECIMAL_PARTS - 2] = 22; 163 | d1.n = DECIMAL_POSITIONS as i16 - 6; 164 | d2.m[0] = 3346; 165 | d2.m[1] = 1122; 166 | d2.n = 8; 167 | d2.e = 3; 168 | ref_num.e = 3; 169 | ref_num.m[0] = 3346; 170 | ref_num.m[DECIMAL_PARTS - 1] = 0; 171 | ref_num.n = DECIMAL_POSITIONS as i16 - 4; 172 | d3 = d1.add(&d2).unwrap(); 173 | assert!(d3.cmp(&ref_num) == 0); 174 | 175 | d1.m[DECIMAL_PARTS - 1] = 222; // 0222 2..2 2211 0000e+5 + 1122 3346e+3 176 | d1.m[DECIMAL_PARTS - 2] = 2222; 177 | d1.n = DECIMAL_POSITIONS as i16 - 1; 178 | ref_num.e = 4; 179 | ref_num.m[0] = 2335; 180 | ref_num.m[DECIMAL_PARTS - 1] = 2222; 181 | ref_num.n = DECIMAL_POSITIONS as i16; 182 | d3 = d1.add(&d2).unwrap(); 183 | assert!(d3.cmp(&ref_num) == 0); 184 | 185 | // 186 | // subtracton 187 | // 188 | 189 | d2.sign = DECIMAL_SIGN_POS; 190 | d1.sign = DECIMAL_SIGN_NEG; 191 | for i in 0..DECIMAL_PARTS { 192 | d1.m[i] = 9999; 193 | d2.m[i] = 0; 194 | } 195 | d1.m[0] = 9990; 196 | d2.m[0] = 10; 197 | d1.n = DECIMAL_POSITIONS as i16; 198 | d2.n = 2; 199 | d1.e = DECIMAL_MAX_EXPONENT; 200 | d2.e = DECIMAL_MAX_EXPONENT; 201 | assert!(d1.sub(&d2).unwrap_err() == Error::ExponentOverflow(DECIMAL_SIGN_NEG)); 202 | 203 | d2.sign = DECIMAL_SIGN_NEG; 204 | d1.sign = DECIMAL_SIGN_POS; 205 | assert!(d1.sub(&d2).unwrap_err() == Error::ExponentOverflow(DECIMAL_SIGN_POS)); 206 | 207 | d1.e -= 1; 208 | ref_num.m.iter_mut().for_each(|x| *x = 0); 209 | ref_num.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10; 210 | ref_num.m[0] = 9; 211 | ref_num.sign = DECIMAL_SIGN_POS; 212 | ref_num.n = DECIMAL_POSITIONS as i16; 213 | ref_num.e = DECIMAL_MAX_EXPONENT; 214 | d3 = d1.sub(&d2).unwrap(); 215 | assert!(d3.cmp(&ref_num) == 0); 216 | 217 | d1.sign = DECIMAL_SIGN_POS; 218 | d2.sign = DECIMAL_SIGN_POS; 219 | d1.e += 1; 220 | ref_num.sign = DECIMAL_SIGN_POS; 221 | for i in 0..DECIMAL_PARTS { 222 | ref_num.m[i] = 9999; 223 | } 224 | ref_num.m[0] = 9980; 225 | ref_num.n = DECIMAL_POSITIONS as i16; 226 | d3 = d1.sub(&d2).unwrap(); 227 | assert!(d3.cmp(&ref_num) == 0); 228 | 229 | ref_num.sign = DECIMAL_SIGN_NEG; 230 | d1.sign = DECIMAL_SIGN_NEG; 231 | d2.sign = DECIMAL_SIGN_NEG; 232 | d3 = d1.sub(&d2).unwrap(); 233 | assert!(d3.cmp(&ref_num) == 0); 234 | 235 | d1 = BigFloatNum::new(); 236 | d2 = BigFloatNum::new(); 237 | ref_num = BigFloatNum::new(); 238 | d1.m[1] = 9998; 239 | d1.m[2] = 1; 240 | d1.n = 9; 241 | d2.m[1] = 9999; 242 | d2.n = 8; 243 | ref_num.m[1] = 9999; 244 | ref_num.n = 8; 245 | d3 = d1.sub(&d2).unwrap(); 246 | assert!(d3.cmp(&ref_num) == 0); 247 | 248 | // d1 - 0 249 | d2.m[1] = 0; 250 | d2.n = 0; 251 | d2.e = -5; 252 | d1.e = 5; 253 | ref_num = d1; 254 | d3 = d1.sub(&d2).unwrap(); 255 | assert!(d3.cmp(&ref_num) == 0); 256 | 257 | // 0 - d2 258 | d1.m[1] = 0; 259 | d1.m[2] = 0; 260 | d1.n = 0; 261 | d2.m[3] = 345; 262 | d2.n = 15; 263 | ref_num = d2; 264 | ref_num.sign = -ref_num.sign; 265 | d3 = d1.sub(&d2).unwrap(); 266 | assert!(d3.cmp(&ref_num) == 0); 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/ops/cbrt.rs: -------------------------------------------------------------------------------- 1 | //! Cube root. 2 | 3 | use crate::defs::BigFloatNum; 4 | use crate::defs::Error; 5 | 6 | impl BigFloatNum { 7 | /// Return cube root of a number. 8 | pub fn cbrt(&self) -> Result { 9 | let arg = Self::to_big_float_inc(self); 10 | let ret = arg.cbrt()?; 11 | Self::from_big_float_inc(ret) 12 | } 13 | } 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | 18 | use super::*; 19 | use crate::defs::{ 20 | DECIMAL_MIN_EXPONENT, DECIMAL_POSITIONS, DECIMAL_SIGN_NEG, DECIMAL_SIGN_POS, 21 | }; 22 | 23 | #[test] 24 | fn test_cbrt() { 25 | let mut d1; 26 | 27 | let one = BigFloatNum::one(); 28 | let mut epsilon = BigFloatNum::one(); 29 | epsilon.e = -epsilon.n as i8 + 2 - (DECIMAL_POSITIONS as i8); 30 | 31 | /* 32 | for i in 0..11 { 33 | for j in 1..100 { 34 | let mut d = crate::inc::inc::BigFloatInc::new(); 35 | d.m[i] = j*100; 36 | d.n = crate::inc::inc::BigFloatInc::num_digits(&d.m); 37 | let ret = d.cbrt().unwrap(); 38 | } 39 | } 40 | */ 41 | // 0 42 | d1 = BigFloatNum::new(); 43 | assert!(d1.cbrt().unwrap().n == 0); 44 | 45 | // |d1| = 1 46 | d1 = BigFloatNum::one(); 47 | let d2 = d1; 48 | let ret = d1.cbrt().unwrap(); 49 | assert!(ret.sub(&d2).unwrap().abs().cmp(&epsilon) <= 0); 50 | 51 | d1.sign = DECIMAL_SIGN_NEG; 52 | let d2 = d1; 53 | let ret = d1.cbrt().unwrap(); 54 | assert!(ret.sub(&d2).unwrap().abs().cmp(&epsilon) <= 0); 55 | 56 | // |d1| < 1 57 | d1 = BigFloatNum::one(); 58 | d1.m[0] = 456; 59 | d1.m[8] = 123; 60 | d1.e -= 1; 61 | let d2 = d1; 62 | let ret = d1.cbrt().unwrap(); 63 | let ret = ret.mul(&ret).unwrap().mul(&ret).unwrap(); 64 | assert!(ret.div(&d2).unwrap().sub(&one).unwrap().abs().cmp(&epsilon) <= 0); 65 | 66 | d1.sign = DECIMAL_SIGN_NEG; 67 | let d2 = d1; 68 | let ret = d1.cbrt().unwrap(); 69 | let ret = ret.mul(&ret).unwrap().mul(&ret).unwrap(); 70 | assert!(ret.div(&d2).unwrap().sub(&one).unwrap().abs().cmp(&epsilon) <= 0); 71 | 72 | // |d1| > 1 73 | d1.e += 2; 74 | d1.sign = DECIMAL_SIGN_POS; 75 | let d2 = d1; 76 | let ret = d1.cbrt().unwrap(); 77 | let ret = ret.mul(&ret).unwrap().mul(&ret).unwrap(); 78 | assert!(ret.div(&d2).unwrap().sub(&one).unwrap().abs().cmp(&epsilon) <= 0); 79 | 80 | d1.sign = DECIMAL_SIGN_NEG; 81 | let d2 = d1; 82 | let ret = d1.cbrt().unwrap(); 83 | let ret = ret.mul(&ret).unwrap().mul(&ret).unwrap(); 84 | assert!(ret.div(&d2).unwrap().sub(&one).unwrap().abs().cmp(&epsilon) <= 0); 85 | 86 | // subnormal 87 | d1 = BigFloatNum::new(); 88 | d1.m[0] = 456; 89 | d1.m[1] = 123; 90 | d1.n = 7; 91 | d1.e = DECIMAL_MIN_EXPONENT; 92 | let d2 = d1; 93 | let ret = d1.cbrt().unwrap(); 94 | let ret = ret.mul(&ret).unwrap().mul(&ret).unwrap(); 95 | assert!(ret.sub(&d2).unwrap().abs().get_mantissa_len() < 2); 96 | 97 | // range of numbers 98 | let mut ret; 99 | let mut d1 = BigFloatNum::new(); 100 | d1.m[0] = 4560; 101 | d1.m[1] = 123; 102 | d1.m[2] = 6789; 103 | d1.m[3] = 2345; 104 | d1.m[4] = 651; 105 | d1.m[5] = 41; 106 | d1.m[6] = 671; 107 | d1.m[7] = 100; 108 | d1.m[8] = 0; 109 | d1.m[9] = 0; 110 | d1.n = 32; 111 | d1.e = -38; 112 | epsilon.e = -epsilon.n as i8 + 3 - (DECIMAL_POSITIONS as i8); 113 | for i in 1..8000 { 114 | d1.m[8] = 10 + i; 115 | d1.m[9] = i; 116 | d1.n = if i < 10 { 117 | 1 118 | } else if i < 100 { 119 | 2 120 | } else if i < 1000 { 121 | 3 122 | } else { 123 | 4 124 | } + 36; 125 | ret = d1.cbrt().unwrap(); 126 | ret = ret.mul(&ret).unwrap().mul(&ret).unwrap(); 127 | assert!(ret.div(&d1).unwrap().sub(&one).unwrap().abs().cmp(&epsilon) <= 0); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/ops/log.rs: -------------------------------------------------------------------------------- 1 | //! Logarithms. 2 | 3 | use crate::defs::BigFloatNum; 4 | use crate::defs::Error; 5 | use crate::defs::DECIMAL_BASE; 6 | use crate::defs::DECIMAL_PARTS; 7 | use crate::defs::DECIMAL_POSITIONS; 8 | 9 | impl BigFloatNum { 10 | /// Returns natural logarithm of a number. 11 | /// 12 | /// # Errors 13 | /// 14 | /// ExponentOverflow - when result is too big. 15 | /// 16 | /// InvalidArgument - when `self` is negative or zero. 17 | pub fn ln(&self) -> Result { 18 | let arg = Self::to_big_float_inc(self); 19 | let ret = arg.ln()?; 20 | Self::from_big_float_inc(ret) 21 | } 22 | 23 | /// E to the power of `self`. 24 | /// 25 | /// # Errors 26 | /// 27 | /// ExponentOverflow - when result is too big. 28 | pub fn exp(&self) -> Result { 29 | let arg = Self::to_big_float_inc(self); 30 | let ret = arg.exp()?; 31 | Self::from_big_float_inc(ret) 32 | } 33 | 34 | /// Returns logarithm of base `b` of a number. 35 | /// 36 | /// # Errors 37 | /// 38 | /// ExponentOverflow - when result is too big. 39 | /// 40 | /// InvalidArgument - when `self` or `b` is negative or zero. 41 | /// 42 | /// DivisionByZero - when `b` is equal to 1. 43 | pub fn log(&self, b: &Self) -> Result { 44 | let arg = Self::to_big_float_inc(self); 45 | let base = Self::to_big_float_inc(b); 46 | let ret = arg.log(&base)?; 47 | Self::from_big_float_inc(ret) 48 | } 49 | 50 | /// Returns logarithm of base 2 of a number. 51 | /// 52 | /// # Errors 53 | /// 54 | /// ExponentOverflow - when result is too big. 55 | /// 56 | /// InvalidArgument - when `self` or `b` is negative or zero. 57 | pub fn log2(&self) -> Result { 58 | let mut two = Self::new(); 59 | two.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 5; 60 | two.n = DECIMAL_POSITIONS as i16; 61 | two.e = 1 - DECIMAL_POSITIONS as i8; 62 | self.log(&two) 63 | } 64 | 65 | /// Returns logarithm of base 10 of a number. 66 | /// 67 | /// # Errors 68 | /// 69 | /// ExponentOverflow - when result is too big. 70 | /// 71 | /// InvalidArgument - when `self` or `b` is negative or zero. 72 | pub fn log10(&self) -> Result { 73 | let mut ten = Self::new(); 74 | ten.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10; 75 | ten.n = DECIMAL_POSITIONS as i16; 76 | ten.e = 2 - DECIMAL_POSITIONS as i8; 77 | self.log(&ten) 78 | } 79 | } 80 | 81 | #[cfg(test)] 82 | mod tests { 83 | 84 | use super::*; 85 | use crate::defs::DECIMAL_POSITIONS; 86 | use crate::defs::DECIMAL_SIGN_NEG; 87 | use crate::defs::E; 88 | 89 | #[test] 90 | fn test_log() { 91 | let mut d1; 92 | let mut d2; 93 | let one = BigFloatNum::one(); 94 | let two = one.add(&one).unwrap(); 95 | let mut epsilon = BigFloatNum::one(); 96 | epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8); 97 | 98 | // arg = 0 99 | d1 = BigFloatNum::new(); 100 | assert!(d1.ln().unwrap_err() == Error::InvalidArgument); 101 | assert!(d1.log(&two).unwrap_err() == Error::InvalidArgument); 102 | 103 | // base = 0 104 | assert!(two.log(&d1).unwrap_err() == Error::InvalidArgument); 105 | 106 | // arg < 0 107 | d1 = BigFloatNum::one(); 108 | d1.sign = DECIMAL_SIGN_NEG; 109 | assert!(d1.ln().unwrap_err() == Error::InvalidArgument); 110 | assert!(d1.log(&two).unwrap_err() == Error::InvalidArgument); 111 | 112 | // base < 0 113 | assert!(two.log(&d1).unwrap_err() == Error::InvalidArgument); 114 | 115 | // ln of E = 1 116 | epsilon.e = -77; // 1*10^(-39) 117 | assert!(E.ln().unwrap().sub(&one).unwrap().abs().cmp(&epsilon) <= 0); 118 | 119 | // log2 of 4 = 2 120 | let four = two.add(&two).unwrap(); 121 | assert!( 122 | four.log(&two) 123 | .unwrap() 124 | .sub(&two) 125 | .unwrap() 126 | .abs() 127 | .cmp(&epsilon) 128 | <= 0 129 | ); 130 | 131 | // log0.5 of 4 = -2 132 | let half = one.div(&two).unwrap(); 133 | assert!( 134 | four.log(&half) 135 | .unwrap() 136 | .add(&two) 137 | .unwrap() 138 | .abs() 139 | .cmp(&epsilon) 140 | <= 0 141 | ); 142 | 143 | // base = 1 144 | assert!(four.log(&one).unwrap_err() == Error::DivisionByZero); 145 | 146 | d2 = BigFloatNum::new(); 147 | d2.m[0] = 4567; 148 | d2.m[1] = 123; 149 | d2.m[2] = 6789; 150 | d2.m[3] = 2345; 151 | d2.m[4] = 651; 152 | d2.m[5] = 41; 153 | d2.m[6] = 671; 154 | d2.m[7] = 9999; 155 | d2.m[8] = 0; 156 | d2.m[9] = 0; 157 | d2.e = -10; 158 | for i in 1..1000 { 159 | d2.m[2] = i; 160 | d2.m[9] = i; 161 | d2.n = if i < 10 { 162 | 1 163 | } else if i < 100 { 164 | 2 165 | } else if i < 1000 { 166 | 3 167 | } else { 168 | 4 169 | } + 36; 170 | d2.e = -50 + (i % 100) as i8; 171 | epsilon.e = -epsilon.n as i8 + 4 - (DECIMAL_POSITIONS as i8) + d2.e + d2.n as i8; 172 | let ret = d2.ln().unwrap(); 173 | d1 = ret.exp().unwrap(); 174 | assert!(d2.sub(&d1).unwrap().abs().cmp(&epsilon) < 0); 175 | 176 | // base > 1 177 | let ret = d2.log(&two).unwrap(); 178 | d1 = two.pow(&ret).unwrap(); 179 | assert!(d2.sub(&d1).unwrap().abs().cmp(&epsilon) < 0); 180 | 181 | // base < 1 182 | let ret = d2.log(&half).unwrap(); 183 | d1 = half.pow(&ret).unwrap(); 184 | assert!(d2.sub(&d1).unwrap().abs().cmp(&epsilon) < 0); 185 | } 186 | 187 | // log2 188 | epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8); 189 | assert!(four.log2().unwrap().sub(&two).unwrap().abs().cmp(&epsilon) <= 0); 190 | 191 | // log10 192 | d1 = BigFloatNum::new(); 193 | d1.m[0] = 100; 194 | d1.n = 3; 195 | assert!(d1.log10().unwrap().sub(&two).unwrap().abs().cmp(&epsilon) <= 0); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/ops/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod add; 2 | pub mod cbrt; 3 | pub mod log; 4 | pub mod mul; 5 | pub mod other; 6 | pub mod pow; 7 | pub mod sqrt; 8 | pub mod trig; 9 | pub mod trigh; 10 | mod util; 11 | -------------------------------------------------------------------------------- /src/ops/mul.rs: -------------------------------------------------------------------------------- 1 | //! Multiplication and division. 2 | 3 | use crate::defs::BigFloatNum; 4 | use crate::defs::Error; 5 | 6 | impl BigFloatNum { 7 | /// Multiply by d2 and return result of multiplication. 8 | /// 9 | /// # Errors 10 | /// 11 | /// ExponentOverflow - when result is too big. 12 | pub fn mul(&self, d2: &Self) -> Result { 13 | let n = Self::to_big_float_inc(self); 14 | let m = Self::to_big_float_inc(d2); 15 | let ret = n.mul(&m)?; 16 | Self::from_big_float_inc(ret) 17 | } 18 | 19 | /// Divide by d2 and return result of division. 20 | /// 21 | /// # Errors 22 | /// 23 | /// ExponentOverflow - when result is too big. 24 | /// DivisionByZero - in case of d2 equal to zero. 25 | /// InvalidArgument - in case both d1 and self are zeroes. 26 | pub fn div(&self, d2: &Self) -> Result { 27 | let n = Self::to_big_float_inc(self); 28 | let m = Self::to_big_float_inc(d2); 29 | let ret = n.div(&m)?; 30 | Self::from_big_float_inc(ret) 31 | } 32 | } 33 | 34 | #[cfg(test)] 35 | mod tests { 36 | 37 | use crate::defs::DECIMAL_BASE; 38 | use crate::defs::DECIMAL_MAX_EXPONENT; 39 | use crate::defs::DECIMAL_MIN_EXPONENT; 40 | use crate::defs::DECIMAL_PARTS; 41 | use crate::defs::DECIMAL_POSITIONS; 42 | use crate::defs::DECIMAL_SIGN_NEG; 43 | use crate::defs::DECIMAL_SIGN_POS; 44 | use crate::defs::ONE; 45 | 46 | use super::*; 47 | 48 | #[test] 49 | fn test_mul() { 50 | let mut d1; 51 | let mut d2; 52 | let mut d3: BigFloatNum; 53 | let mut ref_num; 54 | 55 | // 0 * 0 56 | d1 = BigFloatNum::new(); 57 | d2 = BigFloatNum::new(); 58 | ref_num = BigFloatNum::new(); 59 | d3 = d1.mul(&d2).unwrap(); 60 | assert!(d3.cmp(&ref_num) == 0); 61 | 62 | // 99 0000 * 0 63 | d1.m[1] = 99; 64 | d1.n = 6; 65 | d3 = d1.mul(&d2).unwrap(); 66 | assert!(d3.cmp(&ref_num) == 0); 67 | 68 | // 0 * 1234 9999 69 | d2.m[0] = 9999; 70 | d2.m[1] = 1234; 71 | d2.n = 8; 72 | d1.m[0] = 0; 73 | d1.m[1] = 0; 74 | d1.n = 0; 75 | d3 = d1.mul(&d2).unwrap(); 76 | assert!(d3.cmp(&ref_num) == 0); 77 | 78 | // 1 * 1 79 | d1.m[1] = 0; 80 | d2.m[1] = 0; 81 | d2.m[0] = 1; 82 | d1.m[0] = 1; 83 | ref_num.m[0] = 1; 84 | d1.n = 1; 85 | d2.n = 1; 86 | ref_num.n = 1; 87 | d3 = d1.mul(&d2).unwrap(); 88 | assert!(d3.cmp(&ref_num) == 0); 89 | 90 | // 1 * -1 91 | d2.sign = DECIMAL_SIGN_NEG; 92 | ref_num.sign = DECIMAL_SIGN_NEG; 93 | d3 = d1.mul(&d2).unwrap(); 94 | assert!(d3.cmp(&ref_num) == 0); 95 | 96 | // -1 * 1 97 | d2.sign = DECIMAL_SIGN_POS; 98 | d1.sign = DECIMAL_SIGN_NEG; 99 | d3 = d1.mul(&d2).unwrap(); 100 | assert!(d3.cmp(&ref_num) == 0); 101 | 102 | // -1 * -1 103 | d1.sign = DECIMAL_SIGN_NEG; 104 | d2.sign = DECIMAL_SIGN_NEG; 105 | ref_num.sign = DECIMAL_SIGN_POS; 106 | d3 = d1.mul(&d2).unwrap(); 107 | assert!(d3.cmp(&ref_num) == 0); 108 | 109 | // 9999 * 9999 110 | d2.m[0] = 9999; 111 | d1.m[0] = 9999; 112 | d1.n = 4; 113 | d2.n = 4; 114 | ref_num.m[0] = 1; 115 | ref_num.m[1] = 9998; 116 | ref_num.n = 8; 117 | d3 = d1.mul(&d2).unwrap(); 118 | assert!(d3.cmp(&ref_num) == 0); 119 | 120 | // 2 0000 9999 * 9999 121 | d1.m[2] = 2; 122 | d1.n = 9; 123 | ref_num.m[0] = 1; 124 | ref_num.m[1] = 9998; 125 | ref_num.m[2] = 9998; 126 | ref_num.m[3] = 1; 127 | ref_num.n = 13; 128 | d3 = d1.mul(&d2).unwrap(); 129 | assert!(d3.cmp(&ref_num) == 0); 130 | 131 | // 2 0000 9999 * 5000 0000 9999 132 | d2.m[2] = 5000; 133 | d2.n = 12; 134 | ref_num.m[0] = 1; 135 | ref_num.m[1] = 9998; 136 | ref_num.m[2] = 4998; 137 | ref_num.m[3] = 5001; 138 | ref_num.m[4] = 0; 139 | ref_num.m[5] = 1; 140 | ref_num.n = 21; 141 | d3 = d1.mul(&d2).unwrap(); 142 | assert!(d3.cmp(&ref_num) == 0); 143 | 144 | // exponent modificaton and overflows 145 | d1 = BigFloatNum::new(); 146 | d2 = BigFloatNum::new(); 147 | ref_num = BigFloatNum::new(); 148 | 149 | // 5000..0 * 2 150 | d1.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 2; 151 | d1.n = DECIMAL_POSITIONS as i16; 152 | d2.m[0] = 2; 153 | d2.n = 1; 154 | ref_num.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10; 155 | ref_num.n = DECIMAL_POSITIONS as i16; 156 | ref_num.e = 1; 157 | d3 = d1.mul(&d2).unwrap(); 158 | assert!(d3.cmp(&ref_num) == 0); 159 | 160 | // overflow 161 | d2.e = 123; 162 | d1.e = DECIMAL_MAX_EXPONENT - d2.e; 163 | assert!(d1.mul(&d2).unwrap_err() == Error::ExponentOverflow(DECIMAL_SIGN_POS)); 164 | 165 | // no overflow 166 | d1.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 2 - 1; 167 | assert!(d1.mul(&d2).is_ok()); 168 | 169 | // no overflow with negative e 170 | d1.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 2; 171 | d2.e = -123; 172 | d1.e = DECIMAL_MIN_EXPONENT + 122; // d1.e + d2.e = min_exp - 1 173 | assert!(d1.mul(&d2).is_ok()); 174 | 175 | // overflow 176 | d2.e = 123; 177 | d1.e = DECIMAL_MAX_EXPONENT - d2.e; 178 | d2.m[0] = 0; 179 | d1.m[DECIMAL_PARTS - 1] = 0; 180 | d1.m[5] = 1; 181 | d2.m[5] = 1; 182 | d1.n = 21; 183 | d2.n = 21; 184 | assert!(d1.mul(&d2).unwrap_err() == Error::ExponentOverflow(DECIMAL_SIGN_POS)); 185 | 186 | // no overflow 187 | d1.m[5] = 0; 188 | d1.m[0] = 9999; 189 | d1.m[1] = 9999; 190 | d1.m[2] = 9999; 191 | d1.m[3] = 9999; 192 | d1.m[4] = 9999; 193 | d1.n = 20; 194 | assert!(d1.mul(&d2).is_ok()); 195 | 196 | // overflow 197 | for i in 0..DECIMAL_PARTS { 198 | d1.m[i] = 9999; 199 | d2.m[i] = 9999; 200 | } 201 | d1.n = DECIMAL_POSITIONS as i16; 202 | d2.n = DECIMAL_POSITIONS as i16; 203 | assert!(d1.mul(&d2).unwrap_err() == Error::ExponentOverflow(DECIMAL_SIGN_POS)); 204 | 205 | // overflow with negative e: 0.0 206 | d1 = ONE; 207 | d1.e = DECIMAL_MIN_EXPONENT; 208 | d2 = ONE; 209 | d2.e = DECIMAL_MIN_EXPONENT + 49; 210 | assert!(d1.mul(&d2).unwrap().n == 0); 211 | 212 | // minimum positive value (subnormal) 213 | d2.e = DECIMAL_MIN_EXPONENT + 50; 214 | assert!(d1.mul(&d2).unwrap().n == 1); 215 | // 216 | // division 217 | // 218 | 219 | d1 = BigFloatNum::new(); 220 | d2 = BigFloatNum::new(); 221 | ref_num = BigFloatNum::new(); 222 | 223 | // 0 / 0 224 | assert!(d1.div(&d2).unwrap_err() == Error::InvalidArgument); 225 | 226 | // d2 / 0 227 | d2.m[0] = 1; 228 | d2.n = 1; 229 | assert!(d2.div(&d1).unwrap_err() == Error::DivisionByZero); 230 | 231 | // 0 / d2 232 | d3 = d1.div(&d2).unwrap(); 233 | assert!(d3.cmp(&ref_num) == 0); 234 | 235 | d2.sign = DECIMAL_SIGN_NEG; 236 | d3 = d1.div(&d2).unwrap(); 237 | assert!(d3.cmp(&ref_num) == 0); 238 | 239 | // division by single digit 240 | // 9998 / 3 241 | ref_num.sign = DECIMAL_SIGN_POS; 242 | d1.sign = DECIMAL_SIGN_POS; 243 | d2.sign = DECIMAL_SIGN_POS; 244 | d2.m[0] = 3; 245 | d2.n = 1; 246 | d1.m[0] = 9998; 247 | d1.n = 4; 248 | ref_num.m[0] = 6667; 249 | for i in 1..DECIMAL_PARTS - 1 { 250 | ref_num.m[i] = 6666; 251 | } 252 | ref_num.m[DECIMAL_PARTS - 1] = 3332; 253 | ref_num.n = DECIMAL_POSITIONS as i16; 254 | ref_num.e = -36; 255 | d3 = d1.div(&d2).unwrap(); 256 | assert!(d3.cmp(&ref_num) == 0); 257 | 258 | // 1998 / 3 259 | ref_num.sign = DECIMAL_SIGN_POS; 260 | d1.sign = DECIMAL_SIGN_POS; 261 | d2.sign = DECIMAL_SIGN_POS; 262 | d2.m[0] = 3; 263 | d2.n = 1; 264 | d1.m[0] = 1998; 265 | d1.n = 1; 266 | for i in 0..DECIMAL_PARTS - 1 { 267 | ref_num.m[i] = 0; 268 | } 269 | ref_num.m[DECIMAL_PARTS - 1] = 666; 270 | ref_num.n = DECIMAL_POSITIONS as i16 - 1; 271 | ref_num.e = -36; 272 | d3 = d1.div(&d2).unwrap(); 273 | assert!(d3.cmp(&ref_num) == 0); 274 | 275 | // 91998 / 33 276 | d1.m[1] = 9; 277 | d1.n = 5; 278 | d2.m[0] = 33; 279 | d2.n = 1; 280 | ref_num.m[0] = 8182; 281 | for i in 1..DECIMAL_PARTS - 1 { 282 | ref_num.m[i] = 8181; 283 | } 284 | ref_num.m[DECIMAL_PARTS - 1] = 2787; 285 | ref_num.n = DECIMAL_POSITIONS as i16; 286 | ref_num.e = -36; 287 | d3 = d1.div(&d2).unwrap(); 288 | assert!(d3.cmp(&ref_num) == 0); 289 | 290 | // 9999 9..9 9999 / 3 291 | for i in 0..DECIMAL_PARTS { 292 | d1.m[i] = 9999; 293 | ref_num.m[i] = 3333; 294 | } 295 | ref_num.e = 0; 296 | d1.n = DECIMAL_POSITIONS as i16; 297 | ref_num.n = DECIMAL_POSITIONS as i16; 298 | d2.m[0] = 3; 299 | d2.n = 1; 300 | d3 = d1.div(&d2).unwrap(); 301 | assert!(d3.cmp(&ref_num) == 0); 302 | 303 | // 3333 3..3 3333 / 9999 304 | for i in 0..DECIMAL_PARTS { 305 | d1.m[i] = 3333; 306 | ref_num.m[i] = if i % 3 == 1 { 307 | 0 308 | } else if i % 3 == 2 { 309 | 6667 310 | } else { 311 | 3333 312 | }; 313 | } 314 | d2.m[0] = 9999; 315 | d2.n = 4; 316 | ref_num.e = -4; 317 | d3 = d1.div(&d2).unwrap(); 318 | assert!(d3.cmp(&ref_num) == 0); 319 | 320 | // signs again but with non zero quotinent 321 | ref_num.sign = DECIMAL_SIGN_NEG; 322 | d2.sign = DECIMAL_SIGN_NEG; 323 | d3 = d1.div(&d2).unwrap(); 324 | assert!(d3.cmp(&ref_num) == 0); 325 | 326 | ref_num.sign = DECIMAL_SIGN_NEG; 327 | d1.sign = DECIMAL_SIGN_NEG; 328 | d2.sign = DECIMAL_SIGN_POS; 329 | d3 = d1.div(&d2).unwrap(); 330 | assert!(d3.cmp(&ref_num) == 0); 331 | 332 | d2.sign = DECIMAL_SIGN_NEG; 333 | d1.sign = DECIMAL_SIGN_NEG; 334 | ref_num.sign = DECIMAL_SIGN_POS; 335 | d3 = d1.div(&d2).unwrap(); 336 | assert!(d3.cmp(&ref_num) == 0); 337 | 338 | // division by divisor with two or more digits 339 | d1 = BigFloatNum::new(); 340 | d2 = BigFloatNum::new(); 341 | ref_num = BigFloatNum::new(); 342 | 343 | // 1111 9999 9999 9999 / 3333 3333 344 | d1.m[3] = 1111; 345 | d1.m[2] = 9999; 346 | d1.m[1] = 9999; 347 | d1.m[0] = 9999; 348 | d1.n = 16; 349 | d2.m[1] = 3333; 350 | d2.m[0] = 3333; 351 | d2.n = 8; 352 | for i in 0..DECIMAL_PARTS - 2 { 353 | ref_num.m[i] = if i % 2 > 0 { 3335 } else { 9997 }; 354 | } 355 | ref_num.m[DECIMAL_PARTS - 2] = 0; 356 | ref_num.m[DECIMAL_PARTS - 1] = 3336; 357 | ref_num.n = DECIMAL_POSITIONS as i16; 358 | ref_num.e = -32; 359 | d3 = d1.div(&d2).unwrap(); 360 | assert!(d3.cmp(&ref_num) == 0); 361 | 362 | // 9999 9999. 9999 9999 / 3333 3333 363 | ref_num.sign = DECIMAL_SIGN_POS; 364 | d1.sign = DECIMAL_SIGN_POS; 365 | d2.sign = DECIMAL_SIGN_POS; 366 | d1.e = -8; 367 | d2.e = 0; 368 | d1.m[3] = 9999; 369 | d1.m[2] = 9999; 370 | d1.m[1] = 9999; 371 | d1.m[0] = 9999; 372 | d1.n = 16; 373 | d2.m[1] = 3333; 374 | d2.m[0] = 3333; 375 | d2.n = 8; 376 | ref_num.m.iter_mut().for_each(|x| *x = 0); 377 | ref_num.m[DECIMAL_PARTS - 1] = 3; 378 | ref_num.m[DECIMAL_PARTS - 3] = 3; 379 | ref_num.m[DECIMAL_PARTS - 2] = 0; 380 | ref_num.n = 37; 381 | ref_num.e = -36; 382 | d3 = d1.div(&d2).unwrap(); 383 | assert!(d3.cmp(&ref_num) == 0); 384 | 385 | // 9999 9999. 9999 9999 / 6666 6666 386 | ref_num.sign = DECIMAL_SIGN_NEG; 387 | d1.sign = DECIMAL_SIGN_NEG; 388 | d2.sign = DECIMAL_SIGN_POS; 389 | d2.m[1] = 6666; 390 | d2.m[0] = 6666; 391 | ref_num.m[DECIMAL_PARTS - 1] = 1; 392 | ref_num.m[DECIMAL_PARTS - 3] = 1; 393 | ref_num.m[DECIMAL_PARTS - 2] = 5000; 394 | ref_num.m[DECIMAL_PARTS - 4] = 5000; 395 | d3 = d1.div(&d2).unwrap(); 396 | assert!(d3.cmp(&ref_num) == 0); 397 | 398 | // 6666 6665 / 6666 6666 399 | ref_num.sign = DECIMAL_SIGN_NEG; 400 | d2.sign = DECIMAL_SIGN_NEG; 401 | d1.sign = DECIMAL_SIGN_POS; 402 | d1.m[3] = 0; 403 | d1.m[2] = 0; 404 | d1.m[0] = 6665; 405 | d1.m[1] = 6666; 406 | d2.m[1] = 6666; 407 | d2.m[0] = 6666; 408 | d1.e = DECIMAL_MAX_EXPONENT; 409 | d2.e = DECIMAL_MAX_EXPONENT; 410 | d1.n = 8; 411 | d2.n = 8; 412 | for i in 0..DECIMAL_PARTS - 1 { 413 | ref_num.m[i] = if i % 2 == 0 { 9998 } else { 4999 }; 414 | } 415 | ref_num.m[0] = 9998; 416 | ref_num.m[DECIMAL_PARTS - 1] = 9999; 417 | ref_num.n = 40; 418 | ref_num.e = -40; 419 | d3 = d1.div(&d2).unwrap(); 420 | assert!(d3.cmp(&ref_num) == 0); 421 | 422 | // special cases for 100% coverage of Knuth's div 423 | d1.sign = DECIMAL_SIGN_NEG; 424 | d2.sign = DECIMAL_SIGN_NEG; 425 | ref_num.sign = DECIMAL_SIGN_POS; 426 | d1.e = DECIMAL_MIN_EXPONENT; 427 | d2.e = DECIMAL_MIN_EXPONENT; 428 | d1.m[4] = 6666; 429 | d1.m[3] = 6666; 430 | d1.m[2] = 0; 431 | d1.m[1] = 0; 432 | d1.m[0] = 0; 433 | d1.n = 20; 434 | d2.m[2] = 6666; 435 | d2.m[1] = 6666; 436 | d2.m[0] = 9999; 437 | d2.n = 12; 438 | ref_num.m[9] = 9999; 439 | ref_num.m[8] = 9998; 440 | ref_num.m[7] = 5001; 441 | ref_num.m[6] = 5000; 442 | ref_num.m[5] = 7497; 443 | ref_num.m[4] = 1; 444 | ref_num.m[3] = 8752; 445 | ref_num.m[2] = 6244; 446 | ref_num.m[1] = 5626; 447 | ref_num.m[0] = 5007; 448 | ref_num.n = 40; 449 | ref_num.e = -32; 450 | d3 = d1.div(&d2).unwrap(); 451 | assert!(d3.cmp(&ref_num) == 0); 452 | 453 | d1.m[4] = 0; 454 | d1.m[3] = 0; 455 | d1.m[2] = 4999; 456 | d1.m[1] = 9997; 457 | d1.m[0] = 0; 458 | d1.n = 12; 459 | d1.e = -4; 460 | d2.m[2] = 0; 461 | d2.m[1] = 5003; 462 | d2.m[0] = 9999; 463 | d2.n = 8; 464 | d2.e = 3; 465 | ref_num.m[9] = 9992; 466 | ref_num.m[8] = 59; 467 | ref_num.m[7] = 9504; 468 | ref_num.m[6] = 4084; 469 | ref_num.m[5] = 6331; 470 | ref_num.m[4] = 7515; 471 | ref_num.m[3] = 2541; 472 | ref_num.m[2] = 4698; 473 | ref_num.m[1] = 7492; 474 | ref_num.m[0] = 9454; 475 | ref_num.n = 40; 476 | ref_num.e = -43; 477 | d3 = d1.div(&d2).unwrap(); 478 | assert!(d3.cmp(&ref_num) == 0); 479 | 480 | // subnormal 481 | d2.e = -35; 482 | d1.e = DECIMAL_MIN_EXPONENT; 483 | assert!(d1.div(&d2).unwrap().n == 39); 484 | 485 | // zero 486 | d2.e = -35 + 39; 487 | d1.e = DECIMAL_MIN_EXPONENT; 488 | assert!(d1.div(&d2).unwrap().n == 0); 489 | 490 | // overflow 491 | d2.e = -37; 492 | d1.e = DECIMAL_MAX_EXPONENT; 493 | assert!(d1.div(&d2).unwrap_err() == Error::ExponentOverflow(DECIMAL_SIGN_POS)); 494 | } 495 | } 496 | -------------------------------------------------------------------------------- /src/ops/pow.rs: -------------------------------------------------------------------------------- 1 | //! Power. 2 | 3 | use crate::defs::BigFloatNum; 4 | use crate::defs::Error; 5 | 6 | impl BigFloatNum { 7 | /// Return BigFloat to the power of `d1`. 8 | /// 9 | /// # Errors 10 | /// 11 | /// ExponentOverflow - when result is too big. 12 | /// 13 | /// ArgumentIsNegative - when `d1` has fractional part and `self` is negative. 14 | pub fn pow(&self, d1: &Self) -> Result { 15 | let a = Self::to_big_float_inc(self); 16 | let n = Self::to_big_float_inc(d1); 17 | let ret = a.pow(&n)?; 18 | Self::from_big_float_inc(ret) 19 | } 20 | } 21 | 22 | #[cfg(test)] 23 | mod tests { 24 | 25 | use super::*; 26 | use crate::defs::DECIMAL_POSITIONS; 27 | use crate::defs::DECIMAL_SIGN_NEG; 28 | use crate::defs::DECIMAL_SIGN_POS; 29 | 30 | #[test] 31 | fn test_pow() { 32 | let mut d1; 33 | let mut d2; 34 | let mut ref_num; 35 | let one = BigFloatNum::one(); 36 | let mut epsilon = BigFloatNum::one(); 37 | epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8); 38 | 39 | d1 = BigFloatNum::new(); 40 | d2 = BigFloatNum::new(); 41 | d2.m[0] = 2; 42 | d2.n = 1; 43 | d1.m[0] = 2345; 44 | d1.m[1] = 8901; 45 | d1.m[2] = 4567; 46 | d1.m[3] = 123; 47 | d1.n = 15; 48 | d1.e = -12; 49 | d2.pow(&d1).unwrap(); 50 | 51 | // zero number 52 | d1 = BigFloatNum::new(); 53 | d2 = BigFloatNum::new(); 54 | ref_num = BigFloatNum::new(); 55 | d1.m[0] = 123; 56 | d1.n = 3; 57 | d1.e = -1; 58 | assert!(d2.pow(&d1).unwrap().cmp(&ref_num) == 0); 59 | 60 | // zero argument 61 | d1 = BigFloatNum::new(); 62 | d2 = BigFloatNum::new(); 63 | ref_num = BigFloatNum::new(); 64 | ref_num.m[0] = 1; 65 | ref_num.n = 1; 66 | d2.m[0] = 400; 67 | d2.n = 3; 68 | d2.e = -1; 69 | assert!(d2.pow(&d1).unwrap().cmp(&ref_num) == 0); 70 | 71 | // argument is too large 72 | d1 = BigFloatNum::new(); 73 | d2 = BigFloatNum::new(); 74 | d2.m[0] = 2; 75 | d2.n = 1; 76 | d1.m[0] = 400; 77 | d1.n = 3; 78 | d1.e = 1; 79 | assert!(d2.pow(&d1).unwrap_err() == Error::ExponentOverflow(DECIMAL_SIGN_POS)); 80 | 81 | // argument is too small 82 | d1 = BigFloatNum::new(); 83 | d2 = BigFloatNum::new(); 84 | ref_num = BigFloatNum::new(); 85 | ref_num.m[0] = 1; 86 | ref_num.n = 1; 87 | d1.m[0] = 123; 88 | d1.m[1] = 123; 89 | d1.n = 7; 90 | d1.e = -47; 91 | d2.m[0] = 2; 92 | d2.n = 1; 93 | assert!(d2.pow(&d1).unwrap().cmp(&ref_num) == 0); 94 | 95 | // 2^123.4567890 96 | d1 = BigFloatNum::new(); 97 | d2 = BigFloatNum::new(); 98 | ref_num = BigFloatNum::new(); 99 | ref_num.m[0] = 5308; 100 | ref_num.m[1] = 7857; 101 | ref_num.m[2] = 6147; 102 | ref_num.m[3] = 8828; 103 | ref_num.m[4] = 46; 104 | ref_num.m[5] = 873; 105 | ref_num.m[6] = 5984; 106 | ref_num.m[7] = 9057; 107 | ref_num.m[8] = 4749; 108 | ref_num.m[9] = 1459; 109 | ref_num.n = 40; 110 | ref_num.e = -2; 111 | d1.m[0] = 7890; 112 | d1.m[1] = 3456; 113 | d1.m[2] = 12; 114 | d1.n = 10; 115 | d1.e = -7; 116 | d2.m[0] = 2; 117 | d2.n = 1; 118 | assert!(d2.pow(&d1).unwrap().cmp(&ref_num) == 0); 119 | 120 | // negative argument 121 | ref_num = one.div(&ref_num).unwrap(); 122 | d1.sign = DECIMAL_SIGN_NEG; 123 | let ret = d2.pow(&d1).unwrap(); 124 | assert!(ret.sub(&ref_num).unwrap().abs().cmp(&epsilon) <= 0); 125 | 126 | // negative base 127 | d2.sign = DECIMAL_SIGN_NEG; 128 | ref_num.sign = DECIMAL_SIGN_NEG; 129 | let ret = d2.pow(&d1).unwrap(); 130 | assert!(ret.sub(&ref_num).unwrap().abs().cmp(&epsilon) <= 0); 131 | 132 | // negative base, even int arg 133 | d1 = BigFloatNum::new(); 134 | d1.m[0] = 2; 135 | d1.n = 1; 136 | d2.sign = DECIMAL_SIGN_NEG; 137 | let ret = d2.pow(&d1).unwrap(); 138 | ref_num = d2.mul(&d2).unwrap(); 139 | assert!(ret.sub(&ref_num).unwrap().abs().cmp(&epsilon) <= 0); 140 | 141 | // negative base, odd int arg 142 | d1 = d1.add(&BigFloatNum::one()).unwrap(); 143 | d2.sign = DECIMAL_SIGN_NEG; 144 | let ret = d2.pow(&d1).unwrap(); 145 | ref_num = d2.mul(&d2).unwrap().mul(&d2).unwrap(); 146 | assert!(ret.sub(&ref_num).unwrap().abs().cmp(&epsilon) <= 0); 147 | 148 | let mut ret; 149 | let mut inv; 150 | d2 = BigFloatNum::new(); 151 | d2.m[0] = 4560; 152 | d2.m[1] = 123; 153 | d2.m[2] = 6789; 154 | d2.m[3] = 2345; 155 | d2.m[4] = 651; 156 | d2.m[5] = 41; 157 | d2.m[6] = 671; 158 | d2.m[7] = 100; 159 | d2.m[8] = 10; 160 | d2.m[9] = 0; 161 | d2.n = 34; 162 | d2.e = -33; 163 | d1 = BigFloatNum::new(); 164 | d1.m[0] = 2; 165 | d1.m[1] = 0; 166 | d1.m[2] = 0; 167 | d1.n = 10; 168 | epsilon.e = -79; // 1 digit discrepancy 169 | d1.e = -8; 170 | for i in 1..100 { 171 | for j in 0..10 { 172 | d2.m[2] = i; 173 | d2.m[5] = i; 174 | d1.m[1] = j * 1000; 175 | d1.m[2] = 10 + j; 176 | inv = one.div(&d1).unwrap(); 177 | ret = d2.pow(&d1).unwrap(); 178 | ret = ret.pow(&inv).unwrap(); 179 | assert!(d2.sub(&ret).unwrap().abs().cmp(&epsilon) <= 0); 180 | } 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/ops/sqrt.rs: -------------------------------------------------------------------------------- 1 | //! Square root. 2 | 3 | use crate::defs::BigFloatNum; 4 | use crate::defs::Error; 5 | 6 | impl BigFloatNum { 7 | /// Return square root of a number. 8 | /// 9 | /// # Errors 10 | /// 11 | /// Returns ArgumentIsNegative if `self` is less than 0. 12 | pub fn sqrt(&self) -> Result { 13 | let arg = Self::to_big_float_inc(self); 14 | let ret = arg.sqrt()?; 15 | Self::from_big_float_inc(ret) 16 | } 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | 22 | use super::*; 23 | use crate::defs::DECIMAL_POSITIONS; 24 | use crate::defs::DECIMAL_SIGN_NEG; 25 | 26 | #[test] 27 | fn test_sqrt() { 28 | let mut d1; 29 | 30 | let mut epsilon = BigFloatNum::one(); 31 | epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8); 32 | 33 | d1 = BigFloatNum::new(); 34 | d1.m[0] = 10; 35 | d1.n = 2; 36 | let ret = d1.sqrt().unwrap(); 37 | let ret = ret.mul(&ret).unwrap(); 38 | assert!(d1.sub(&ret).unwrap().abs().cmp(&epsilon) <= 0); 39 | 40 | // sqrt(1234567890.1234567 = 1.2345...+10^9) 41 | d1 = BigFloatNum::new(); 42 | d1.m[0] = 4567; 43 | d1.m[1] = 123; 44 | d1.m[2] = 6789; 45 | d1.m[3] = 2345; 46 | d1.m[4] = 1; 47 | d1.n = 17; 48 | d1.e = -7; 49 | let ret = d1.sqrt().unwrap(); 50 | let ret = ret.mul(&ret).unwrap(); 51 | epsilon.e = -69; // 1*10^(-30) 52 | assert!(d1.sub(&ret).unwrap().abs().cmp(&epsilon) <= 0); 53 | 54 | // positive exponent 55 | d1 = BigFloatNum::new(); 56 | d1.m[0] = 4567; 57 | d1.m[1] = 123; 58 | d1.m[2] = 6789; 59 | d1.m[3] = 2345; 60 | d1.m[4] = 1; 61 | d1.n = 17; 62 | d1.e = 7; 63 | let ret = d1.sqrt().unwrap(); 64 | let ret = ret.mul(&ret).unwrap(); 65 | epsilon.e = -55; // 1*10^(-16) 66 | assert!(d1.sub(&ret).unwrap().abs().cmp(&epsilon) <= 0); 67 | 68 | // value less than 1 69 | d1 = BigFloatNum::new(); 70 | d1.m[0] = 4567; 71 | d1.m[1] = 123; 72 | d1.m[2] = 6789; 73 | d1.m[3] = 2345; 74 | d1.m[4] = 1; 75 | d1.n = 17; 76 | d1.e = -20; 77 | let ret = d1.sqrt().unwrap(); 78 | let ret = ret.mul(&ret).unwrap(); 79 | epsilon.e = -82; // 1*10^(-43) 80 | assert!(d1.sub(&ret).unwrap().abs().cmp(&epsilon) <= 0); 81 | 82 | // value is negative 83 | d1 = BigFloatNum::new(); 84 | d1.sign = DECIMAL_SIGN_NEG; 85 | assert!(d1.sqrt().unwrap_err() == Error::ArgumentIsNegative); 86 | 87 | let mut ret; 88 | let mut d1 = BigFloatNum::new(); 89 | d1.m[0] = 4560; 90 | d1.m[1] = 123; 91 | d1.m[2] = 6789; 92 | d1.m[3] = 2345; 93 | d1.m[4] = 651; 94 | d1.m[5] = 41; 95 | d1.m[6] = 671; 96 | d1.m[7] = 100; 97 | d1.m[8] = 0; 98 | d1.m[9] = 0; 99 | d1.n = 32; 100 | d1.e = -36; 101 | epsilon.e = -epsilon.n as i8 + 3 - (DECIMAL_POSITIONS as i8); 102 | for i in 1..8000 { 103 | d1.m[8] = 10 + i; 104 | d1.m[9] = i; 105 | d1.n = if i < 10 { 106 | 1 107 | } else if i < 100 { 108 | 2 109 | } else if i < 1000 { 110 | 3 111 | } else { 112 | 4 113 | } + 36; 114 | ret = d1.sqrt().unwrap(); 115 | ret = ret.mul(&ret).unwrap(); 116 | assert!( 117 | ret.div(&d1) 118 | .unwrap() 119 | .sub(&BigFloatNum::one()) 120 | .unwrap() 121 | .abs() 122 | .cmp(&epsilon) 123 | <= 0 124 | ); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/ops/trig.rs: -------------------------------------------------------------------------------- 1 | //! Trigonometric functions and inverse trigonometric functions. 2 | 3 | use crate::defs::BigFloatNum; 4 | use crate::defs::Error; 5 | 6 | impl BigFloatNum { 7 | /// Returns sine of a number. Argument is an angle in radians. 8 | /// 9 | /// # Errors 10 | /// 11 | /// ExponentOverflow - when result is too big. 12 | pub fn sin(&self) -> Result { 13 | let arg = Self::to_big_float_inc(self); 14 | let ret = arg.sin()?; 15 | Self::from_big_float_inc(ret) 16 | } 17 | 18 | /// Returns cosine of a number. Argument is an angle in radians. 19 | /// 20 | /// # Errors 21 | /// 22 | /// ExponentOverflow - when result is too big. 23 | pub fn cos(&self) -> Result { 24 | let arg = Self::to_big_float_inc(self); 25 | let ret = arg.cos()?; 26 | Self::from_big_float_inc(ret) 27 | } 28 | 29 | /// Returns tangent of a number. Argument is an angle in radians. 30 | /// 31 | /// # Errors 32 | /// 33 | /// ExponentOverflow - when result is too big. 34 | pub fn tan(&self) -> Result { 35 | let arg = Self::to_big_float_inc(self); 36 | let ret = arg.tan()?; 37 | Self::from_big_float_inc(ret) 38 | } 39 | 40 | /// Returns arcsine of a number. Result is an angle in radians ranging from `-pi` to `pi`. 41 | /// 42 | /// # Errors 43 | /// 44 | /// ExponentOverflow - when result is too big. 45 | /// InvalidArgument - when |`self`| > 1. 46 | pub fn asin(&self) -> Result { 47 | let arg = Self::to_big_float_inc(self); 48 | let ret = arg.asin()?; 49 | Self::from_big_float_inc(ret) 50 | } 51 | 52 | /// Returns arccosine of a number. 53 | /// 54 | /// # Errors 55 | /// 56 | /// ExponentOverflow - when result is too big. 57 | /// InvalidArgument - when |`self`| > 1. 58 | pub fn acos(&self) -> Result { 59 | let arg = Self::to_big_float_inc(self); 60 | let ret = arg.acos()?; 61 | Self::from_big_float_inc(ret) 62 | } 63 | 64 | /// Returns arctangent of a number. 65 | /// 66 | /// # Errors 67 | /// 68 | /// ExponentOverflow - when result is too big. 69 | pub fn atan(&self) -> Result { 70 | let arg = Self::to_big_float_inc(self); 71 | let ret = arg.atan()?; 72 | Self::from_big_float_inc(ret) 73 | } 74 | } 75 | 76 | #[cfg(test)] 77 | mod tests { 78 | 79 | use super::*; 80 | use crate::defs::DECIMAL_POSITIONS; 81 | use crate::defs::DECIMAL_SIGN_NEG; 82 | use crate::defs::DECIMAL_SIGN_POS; 83 | 84 | #[test] 85 | fn test_trig_fun() { 86 | let mut d1; 87 | let one = BigFloatNum::one(); 88 | let mut epsilon = BigFloatNum::one(); 89 | epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8); 90 | 91 | // 92 | // sin, cos, asin, acos 93 | // 94 | 95 | d1 = BigFloatNum::new(); 96 | d1.e = -39; 97 | d1.m[0] = 123; 98 | d1.m[3] = 123; 99 | d1.m[7] = 123; 100 | epsilon.e = -epsilon.n as i8 + 2 - (DECIMAL_POSITIONS as i8); 101 | for i in 1..1572 { 102 | d1.m[8] = i; 103 | d1.sign = if i & 1 == 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }; 104 | d1.n = if i < 10 { 105 | 1 106 | } else if i < 100 { 107 | 2 108 | } else if i < 1000 { 109 | 3 110 | } else { 111 | 4 112 | } + 36; 113 | let s = d1.sin().unwrap(); 114 | let c = d1.cos().unwrap(); 115 | let p = s.mul(&s).unwrap().add(&c.mul(&c).unwrap()).unwrap(); 116 | assert!(p.sub(&one).unwrap().abs().cmp(&epsilon) < 0); 117 | } 118 | 119 | // asin 120 | d1 = BigFloatNum::new(); 121 | d1.e = -39; 122 | d1.m[0] = 123; 123 | d1.m[3] = 123; 124 | d1.m[7] = 123; 125 | epsilon.e = -epsilon.n as i8 + 4 - (DECIMAL_POSITIONS as i8); 126 | for i in 1..1571 { 127 | // -pi/2..pi/2 128 | d1.m[9] = i; 129 | d1.sign = if i & 1 == 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }; 130 | d1.n = if i < 10 { 131 | 1 132 | } else if i < 100 { 133 | 2 134 | } else if i < 1000 { 135 | 3 136 | } else { 137 | 4 138 | } + 36; 139 | let s = d1.sin().unwrap(); 140 | let asn = s.asin().unwrap(); 141 | assert!(d1.sub(&asn).unwrap().abs().cmp(&epsilon) < 0); 142 | } 143 | 144 | // acos 145 | d1 = BigFloatNum::new(); 146 | d1.e = -39; 147 | d1.m[8] = 123; 148 | epsilon.e = -epsilon.n as i8 + 4 - (DECIMAL_POSITIONS as i8); 149 | for i in 1..3142 { 150 | // 0..pi 151 | d1.m[9] = i; 152 | d1.sign = if i & 1 == 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }; 153 | d1.n = if i < 10 { 154 | 1 155 | } else if i < 100 { 156 | 2 157 | } else if i < 1000 { 158 | 3 159 | } else { 160 | 4 161 | } + 36; 162 | let c = d1.cos().unwrap(); 163 | let acs = c.acos().unwrap(); 164 | assert!(d1.abs().sub(&acs).unwrap().abs().cmp(&epsilon) <= 0); 165 | } 166 | 167 | // 168 | // tan, atan 169 | // 170 | 171 | d1 = BigFloatNum::new(); 172 | d1.e = -39; 173 | d1.m[0] = 5678; 174 | d1.m[7] = 1234; 175 | epsilon.e = -77; // 1*10^(-38) for arguments close to pi/2 the precision is lost 176 | for i in 1..9999 { 177 | d1.m[8] = i; 178 | d1.sign = if i & 1 == 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }; 179 | d1.n = if i < 10 { 180 | 1 181 | } else if i < 100 { 182 | 2 183 | } else if i < 1000 { 184 | 3 185 | } else { 186 | 4 187 | } + 32; 188 | let t1 = d1.tan().unwrap(); 189 | let t2 = d1.sin().unwrap().div(&d1.cos().unwrap()).unwrap(); 190 | let p = t1.div(&t2).unwrap(); 191 | assert!(p.sub(&one).unwrap().abs().cmp(&epsilon) <= 0); 192 | } 193 | 194 | d1 = BigFloatNum::new(); 195 | d1.e = -39; 196 | d1.m[0] = 5678; 197 | d1.m[7] = 1234; 198 | epsilon.e = -78; // 1*10^(-39) for arguments close to pi/2 the precision is lost 199 | for i in 1..1571 { 200 | d1.m[8] = i; 201 | d1.sign = if i & 1 == 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }; 202 | d1.n = if i < 10 { 203 | 1 204 | } else if i < 100 { 205 | 2 206 | } else if i < 1000 { 207 | 3 208 | } else { 209 | 4 210 | } + 32; 211 | let t1 = d1.tan().unwrap(); 212 | let atn = t1.atan().unwrap(); 213 | assert!(atn.sub(&d1).unwrap().abs().cmp(&epsilon) <= 0); 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/ops/trigh.rs: -------------------------------------------------------------------------------- 1 | //! Hyperbolic trigonometric functions and inverse hyperbolic trigonometric functions. 2 | 3 | use crate::defs::BigFloatNum; 4 | use crate::defs::Error; 5 | 6 | impl BigFloatNum { 7 | /// Returns hyperbolic sine of a number. 8 | /// 9 | /// # Errors 10 | /// 11 | /// ExponentOverflow - when result is too big. 12 | pub fn sinh(&self) -> Result { 13 | let arg = Self::to_big_float_inc(self); 14 | let ret = arg.sinh()?; 15 | Self::from_big_float_inc(ret) 16 | } 17 | 18 | /// Returns hyperbolic cosine of a number. 19 | /// 20 | /// # Errors 21 | /// 22 | /// ExponentOverflow - when result is too big. 23 | pub fn cosh(&self) -> Result { 24 | let arg = Self::to_big_float_inc(self); 25 | let ret = arg.cosh()?; 26 | Self::from_big_float_inc(ret) 27 | } 28 | 29 | /// Returns hyperbolic tangent of a number. 30 | /// 31 | /// # Errors 32 | /// 33 | /// ExponentOverflow - when result is too big. 34 | pub fn tanh(&self) -> Result { 35 | let arg = Self::to_big_float_inc(self); 36 | let ret = arg.tanh()?; 37 | Self::from_big_float_inc(ret) 38 | } 39 | 40 | /// Returns inverse hyperbolic sine of a number. 41 | /// 42 | /// # Errors 43 | /// 44 | /// ExponentOverflow - when result is too big. 45 | pub fn asinh(&self) -> Result { 46 | let arg = Self::to_big_float_inc(self); 47 | let ret = arg.asinh()?; 48 | Self::from_big_float_inc(ret) 49 | } 50 | 51 | /// Returns inverse hyperbolic cosine of a number. 52 | /// 53 | /// # Errors 54 | /// 55 | /// ExponentOverflow - when result is too big. 56 | /// InvalidArgument - when `self` is less than 1. 57 | pub fn acosh(&self) -> Result { 58 | let arg = Self::to_big_float_inc(self); 59 | let ret = arg.acosh()?; 60 | Self::from_big_float_inc(ret) 61 | } 62 | 63 | /// Returns inverse hyperbolic tangent of a number. 64 | /// 65 | /// # Errors 66 | /// 67 | /// ExponentOverflow - when result is too big. 68 | /// InvalidArgument - when |`self`| >= 1. 69 | pub fn atanh(&self) -> Result { 70 | let arg = Self::to_big_float_inc(self); 71 | let ret = arg.atanh()?; 72 | Self::from_big_float_inc(ret) 73 | } 74 | } 75 | 76 | #[cfg(test)] 77 | mod tests { 78 | 79 | use super::*; 80 | use crate::defs::DECIMAL_POSITIONS; 81 | use crate::defs::DECIMAL_SIGN_NEG; 82 | use crate::defs::DECIMAL_SIGN_POS; 83 | 84 | #[test] 85 | fn test_trigh() { 86 | let mut d1; 87 | let mut epsilon = BigFloatNum::one(); 88 | epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8); 89 | 90 | // 91 | // sinh, asinh 92 | // 93 | 94 | d1 = BigFloatNum::new(); 95 | d1.m[7] = 123; 96 | d1.e = -37; 97 | epsilon.e = -76; // 1*10^(-37) 98 | for i in 1..100 { 99 | d1.m[8] = i; 100 | d1.sign = if i & 1 == 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }; 101 | d1.n = if i < 10 { 102 | 1 103 | } else if i < 100 { 104 | 2 105 | } else if i < 1000 { 106 | 3 107 | } else { 108 | 4 109 | } + 32; 110 | let s = d1.sinh().unwrap(); 111 | let c = s.asinh().unwrap(); 112 | assert!(d1.sub(&c).unwrap().abs().cmp(&epsilon) <= 0); 113 | } 114 | 115 | // 116 | // cosh, acosh 117 | // 118 | 119 | d1 = BigFloatNum::new(); 120 | d1.m[7] = 123; 121 | d1.e = -37; 122 | epsilon.e = -74; // 1*10^(-35) 123 | for i in 0..100 { 124 | d1.m[8] = 10 + i; 125 | d1.sign = if i & 1 == 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }; 126 | d1.n = BigFloatNum::num_digits(&d1.m); 127 | let s = d1.cosh().unwrap(); 128 | let mut c = s.acosh().unwrap(); 129 | assert!(c.sign == DECIMAL_SIGN_POS); 130 | c.sign = d1.sign; 131 | assert!(d1.sub(&c).unwrap().abs().cmp(&epsilon) <= 0); 132 | } 133 | // arg < 1 134 | d1 = BigFloatNum::new(); 135 | d1.m[9] = 1; 136 | d1.n = 37; 137 | d1.e = -37; 138 | assert!(d1.acosh().unwrap_err() == Error::InvalidArgument); 139 | 140 | // 141 | // tanh and atanh 142 | // 143 | 144 | d1 = BigFloatNum::new(); 145 | d1.m[7] = 123; 146 | d1.e = -37; 147 | epsilon.e = -75; // 1*10^(-36) 148 | for i in 0..1000 { 149 | d1.m[8] = i; 150 | d1.sign = if i & 1 == 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG }; 151 | d1.n = if i < 10 { 152 | 1 153 | } else if i < 100 { 154 | 2 155 | } else if i < 1000 { 156 | 3 157 | } else { 158 | 4 159 | } + 32; 160 | let s = d1.tanh().unwrap(); 161 | let c = s.atanh().unwrap(); 162 | assert!(d1.sub(&c).unwrap().abs().cmp(&epsilon) <= 0); 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/ops/util.rs: -------------------------------------------------------------------------------- 1 | //! Utility functions. 2 | 3 | use crate::defs::BigFloatNum; 4 | use crate::defs::Error; 5 | use crate::defs::RoundingMode; 6 | use crate::defs::DECIMAL_BASE; 7 | use crate::defs::DECIMAL_BASE_LOG10; 8 | use crate::defs::DECIMAL_MAX_EXPONENT; 9 | use crate::defs::DECIMAL_PARTS; 10 | use crate::defs::DECIMAL_POSITIONS; 11 | use crate::defs::DECIMAL_SIGN_POS; 12 | use crate::inc::inc::BigFloatInc; 13 | 14 | impl BigFloatNum { 15 | // compare absolute values of two big floats 16 | // return positive if d1 > d2, negative if d1 < d2, 0 otherwise 17 | pub(super) fn abs_cmp(d1: &[i16], d2: &[i16]) -> i16 { 18 | let mut i: i32 = DECIMAL_PARTS as i32 - 1; 19 | while i >= 0 { 20 | if d1[i as usize] != d2[i as usize] { 21 | return d1[i as usize] - d2[i as usize]; 22 | } 23 | i -= 1; 24 | } 25 | 0 26 | } 27 | 28 | // shift m to the right by n digits 29 | pub(crate) fn shift_right(m: &mut [i16], mut n: usize) { 30 | assert!(n > 0 && n <= DECIMAL_POSITIONS); 31 | 32 | let mut s: i16; 33 | let mut t: i16; 34 | let mut x: i32 = (n % DECIMAL_BASE_LOG10) as i32; 35 | n /= DECIMAL_BASE_LOG10; 36 | if x == 0 { 37 | if n > 0 { 38 | for i in 0..DECIMAL_PARTS - n { 39 | m[i] = m[i + n]; 40 | } 41 | } 42 | } else { 43 | s = 10; 44 | t = DECIMAL_BASE as i16 / 10; 45 | x -= 1; 46 | while x > 0 { 47 | s *= 10; 48 | t /= 10; 49 | x -= 1; 50 | } 51 | 52 | let mut i = 0; 53 | while i < DECIMAL_PARTS - n - 1 { 54 | m[i] = (m[i + n + 1] % s) * t + m[i + n] / s; 55 | i += 1; 56 | } 57 | m[i] = m[i + n] / s; 58 | } 59 | for i in 0..n { 60 | m[i + DECIMAL_PARTS - n] = 0; 61 | } 62 | } 63 | 64 | // return number of digits taken in mantissa 65 | pub(crate) fn num_digits(m: &[i16]) -> i16 { 66 | let mut n: i16 = DECIMAL_POSITIONS as i16; 67 | let mut t: i16; 68 | let mut p: i16 = DECIMAL_PARTS as i16 - 1; 69 | 70 | while p >= 0 && 0 == m[p as usize] { 71 | p -= 1; 72 | n -= DECIMAL_BASE_LOG10 as i16; 73 | } 74 | 75 | if n > 0 { 76 | t = m[p as usize]; 77 | n -= DECIMAL_BASE_LOG10 as i16; 78 | loop { 79 | n += 1; 80 | t /= 10; 81 | if t == 0 { 82 | break; 83 | } 84 | } 85 | } 86 | n 87 | } 88 | 89 | // Convert to BigFloatInc. 90 | pub(super) fn to_big_float_inc(d1: &Self) -> BigFloatInc { 91 | let mut ret = BigFloatInc::new(); 92 | (&mut ret.m[0..DECIMAL_PARTS]).copy_from_slice(&d1.m); 93 | ret.n = d1.n; 94 | ret.e = d1.e; 95 | ret.sign = d1.sign; 96 | ret 97 | } 98 | 99 | // Convert from BigFloatInc. 100 | pub(super) fn from_big_float_inc(mut d1: BigFloatInc) -> Result { 101 | let mut ret = Self::new(); 102 | if d1.n == 0 { 103 | return Ok(ret); 104 | } 105 | d1.maximize_mantissa(); 106 | let mut additional_shift = 0; 107 | if d1.n < DECIMAL_POSITIONS as i16 + DECIMAL_BASE_LOG10 as i16 { 108 | // d1 is subnormal, but it's mantissa still can be shifted 109 | // because resulting number exponent will be incremented by DECIMAL_BASE_LOG10 110 | additional_shift = DECIMAL_POSITIONS + DECIMAL_BASE_LOG10 - d1.n as usize; 111 | if additional_shift > DECIMAL_BASE_LOG10 { 112 | additional_shift = DECIMAL_BASE_LOG10; 113 | } 114 | BigFloatInc::shift_left(&mut d1.m, additional_shift); 115 | } 116 | if BigFloatInc::round_mantissa( 117 | &mut d1.m, 118 | DECIMAL_BASE_LOG10 as i16, 119 | RoundingMode::ToEven, 120 | true, 121 | ) { 122 | if d1.e == DECIMAL_MAX_EXPONENT { 123 | return Err(Error::ExponentOverflow(d1.sign)); 124 | } else { 125 | d1.e += 1; 126 | } 127 | } 128 | (&mut ret.m).copy_from_slice(&d1.m[1..]); 129 | ret.n = Self::num_digits(&ret.m); 130 | if d1.e > DECIMAL_MAX_EXPONENT - DECIMAL_BASE_LOG10 as i8 { 131 | return Err(Error::ExponentOverflow(d1.sign)); 132 | } 133 | ret.e = d1.e + DECIMAL_BASE_LOG10 as i8 - additional_shift as i8; 134 | ret.sign = d1.sign; 135 | Ok(ret) 136 | } 137 | 138 | // fractional part of d1 139 | pub(super) fn extract_fract_part(d1: &Self) -> Self { 140 | let mut fractional = Self::new(); 141 | let e = -(d1.e as i16); 142 | if e >= d1.n { 143 | fractional = *d1; 144 | fractional.sign = DECIMAL_SIGN_POS; 145 | } else if e > 0 { 146 | let mut i = 0; 147 | while i + (DECIMAL_BASE_LOG10 as i16) <= e { 148 | fractional.m[i as usize / DECIMAL_BASE_LOG10] = 149 | d1.m[i as usize / DECIMAL_BASE_LOG10]; 150 | i += DECIMAL_BASE_LOG10 as i16; 151 | } 152 | if i < e { 153 | let mut t = 1; 154 | while i < e { 155 | t *= 10; 156 | i += 1; 157 | } 158 | fractional.m[i as usize / DECIMAL_BASE_LOG10] += 159 | d1.m[i as usize / DECIMAL_BASE_LOG10 as usize] % t; 160 | } 161 | fractional.n = Self::num_digits(&fractional.m); 162 | if fractional.n > 0 { 163 | fractional.e = d1.e; 164 | } 165 | } 166 | fractional 167 | } 168 | 169 | // integer part of d1 170 | pub(super) fn extract_int_part(d1: &Self) -> Self { 171 | if d1.e >= 0 { 172 | return *d1; 173 | } 174 | if d1.e as i16 + d1.n < 0 { 175 | return Self::new(); 176 | } 177 | let mut int = Self::new(); 178 | let mut i = -(d1.e as i16); 179 | let mut t = Self::get_div_factor(i); 180 | if i < 0 { 181 | i = 0; 182 | } 183 | let mut t2 = 1; 184 | while i < d1.n { 185 | int.m[int.n as usize / DECIMAL_BASE_LOG10] += 186 | (d1.m[i as usize / DECIMAL_BASE_LOG10 as usize] / t % 10) * t2; 187 | int.n += 1; 188 | i += 1; 189 | t *= 10; 190 | if t == DECIMAL_BASE as i16 { 191 | t = 1; 192 | } 193 | t2 *= 10; 194 | if t2 == DECIMAL_BASE as i16 { 195 | t2 = 1; 196 | } 197 | } 198 | if int.n > 0 { 199 | int.e = d1.e + (i - int.n) as i8; 200 | } 201 | int 202 | } 203 | 204 | // factor to divide by to get a digit at position n 205 | pub(crate) fn get_div_factor(n: i16) -> i16 { 206 | let mut x = n % DECIMAL_BASE_LOG10 as i16; 207 | let mut t = 1; 208 | while x > 0 { 209 | t *= 10; 210 | x -= 1; 211 | } 212 | t 213 | } 214 | 215 | // Round n positons to even, return true if exponent is to be incremented. 216 | pub(crate) fn round_mantissa( 217 | m: &mut [i16], 218 | n: i16, 219 | rm: RoundingMode, 220 | is_positive: bool, 221 | ) -> bool { 222 | if n > 0 && n <= DECIMAL_POSITIONS as i16 { 223 | let n = n - 1; 224 | let mut rem_zero = true; 225 | // anything before n'th digit becomes 0 226 | for i in 0..n as usize / DECIMAL_BASE_LOG10 { 227 | if m[i] != 0 { 228 | rem_zero = false; 229 | } 230 | m[i] = 0; 231 | } 232 | 233 | // analyze digits at n and at n+1 234 | // to decide if we need to add 1 or not. 235 | let mut c = false; 236 | let np1 = n + 1; 237 | let mut i = n as usize / DECIMAL_BASE_LOG10; 238 | let i1 = np1 as usize / DECIMAL_BASE_LOG10; 239 | let t = Self::get_div_factor(n); 240 | let t2 = Self::get_div_factor(np1); 241 | let num = m[i] / t % 10; 242 | if m[i] % t != 0 { 243 | rem_zero = false; 244 | } 245 | 246 | let num2 = if i1 < m.len() { m[i1] / t2 % 10 } else { 0 }; 247 | 248 | let eq5 = num == 5 && rem_zero; 249 | let gt5 = num > 5 || (num == 5 && !rem_zero); 250 | let gte5 = gt5 || eq5; 251 | 252 | match rm { 253 | RoundingMode::Up => { 254 | if gte5 && is_positive || gt5 && !is_positive { 255 | // add 1 256 | c = true; 257 | } 258 | } 259 | RoundingMode::Down => { 260 | if gt5 && is_positive || gte5 && !is_positive { 261 | // add 1 262 | c = true; 263 | } 264 | } 265 | RoundingMode::FromZero => { 266 | if gte5 { 267 | // add 1 268 | c = true; 269 | } 270 | } 271 | RoundingMode::ToZero => { 272 | if gt5 { 273 | // add 1 274 | c = true; 275 | } 276 | } 277 | RoundingMode::ToEven => { 278 | if gt5 || (eq5 && num2 & 1 != 0) { 279 | // add 1 280 | c = true; 281 | } 282 | } 283 | RoundingMode::ToOdd => { 284 | if gt5 || (eq5 && num2 & 1 == 0) { 285 | // add 1 286 | c = true; 287 | } 288 | } 289 | }; 290 | 291 | if c { 292 | // add 1 at (n+1)'th position 293 | if i1 > i { 294 | m[i] = 0; 295 | } 296 | i = i1; 297 | if i < m.len() { 298 | if m[i] / t2 + 1 < DECIMAL_BASE as i16 / t2 { 299 | m[i] = (m[i] / t2 + 1) * t2; 300 | return false; 301 | } else { 302 | m[i] = 0; 303 | } 304 | } 305 | 306 | // process overflows 307 | i += 1; 308 | while i < m.len() { 309 | if m[i] < DECIMAL_BASE as i16 - 1 { 310 | m[i] += 1; 311 | return false; 312 | } else { 313 | m[i] = 0; 314 | } 315 | i += 1; 316 | } 317 | m[m.len() - 1] = DECIMAL_BASE as i16 / 10; 318 | return true; 319 | } else { 320 | // just remove trailing digits 321 | let t = t * 10; 322 | m[i] = (m[i] / t) * t; 323 | } 324 | } 325 | false 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | //! Parser parses numbers represented in scientific format. 2 | 3 | use crate::defs::{DECIMAL_POSITIONS, DECIMAL_SIGN_NEG, DECIMAL_SIGN_POS}; 4 | #[cfg(not(feature = "std"))] 5 | use core::str::Chars; 6 | #[cfg(feature = "std")] 7 | use std::str::Chars; 8 | 9 | pub struct ParserState<'a> { 10 | chars: Chars<'a>, 11 | cur_ch: Option, 12 | sign: i8, 13 | mantissa_bytes: [u8; DECIMAL_POSITIONS], 14 | n: usize, 15 | e: i32, 16 | inf: bool, 17 | nan: bool, 18 | valid: bool, 19 | } 20 | 21 | impl<'a> ParserState<'a> { 22 | fn new(s: &'a str) -> Self { 23 | ParserState { 24 | chars: s.chars(), 25 | cur_ch: None, 26 | sign: DECIMAL_SIGN_POS, 27 | mantissa_bytes: [0; DECIMAL_POSITIONS], 28 | n: 0, 29 | e: 0, 30 | inf: false, 31 | nan: false, 32 | valid: false, 33 | } 34 | } 35 | 36 | /// Returns next character of a string in lower case, 37 | /// or None if string end reached. 38 | fn next_char(&mut self) -> Option { 39 | self.cur_ch = self.chars.next().map(|c| c.to_ascii_lowercase()); 40 | self.cur_ch 41 | } 42 | 43 | fn cur_char(&self) -> Option { 44 | self.cur_ch 45 | } 46 | 47 | pub fn is_valid(&self) -> bool { 48 | self.valid 49 | } 50 | 51 | pub fn is_inf(&self) -> bool { 52 | self.inf 53 | } 54 | 55 | pub fn is_nan(&self) -> bool { 56 | self.nan 57 | } 58 | 59 | pub fn sign(&self) -> i8 { 60 | self.sign 61 | } 62 | 63 | /// Returns mantissa digits, mantissa length, sign, exponent. 64 | pub fn raw_parts(&self) -> ([u8; DECIMAL_POSITIONS], usize, i8, i32) { 65 | (self.mantissa_bytes, self.n, self.sign, self.e) 66 | } 67 | } 68 | 69 | /// Parse BigFloat. 70 | pub fn parse(s: &str) -> ParserState { 71 | let mut parser_state = ParserState::new(s); 72 | let mut ch = parser_state.next_char(); 73 | 74 | // sign 75 | if let Some(c) = ch { 76 | match c { 77 | '+' => ch = parser_state.next_char(), 78 | '-' => { 79 | parser_state.sign = DECIMAL_SIGN_NEG; 80 | ch = parser_state.next_char() 81 | } 82 | _ => {} 83 | }; 84 | } 85 | 86 | if let Some(c) = ch { 87 | match c { 88 | 'i' => parse_inf(&mut parser_state), 89 | 'n' => parse_nan(&mut parser_state), 90 | '.' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => { 91 | parse_num(&mut parser_state) 92 | } 93 | _ => {} 94 | }; 95 | } 96 | parser_state 97 | } 98 | 99 | fn parse_inf(parser_state: &mut ParserState) { 100 | let n = parser_state.next_char(); 101 | let f = parser_state.next_char(); 102 | if Some('n') == n && Some('f') == f { 103 | parser_state.inf = true; 104 | parser_state.valid = true; 105 | } 106 | } 107 | 108 | fn parse_nan(parser_state: &mut ParserState) { 109 | let a = parser_state.next_char(); 110 | let n = parser_state.next_char(); 111 | if Some('n') == n && Some('a') == a { 112 | parser_state.nan = true; 113 | parser_state.valid = true; 114 | } 115 | } 116 | 117 | fn parse_num(parser_state: &mut ParserState) { 118 | let (int_len, skip_cnt1) = parse_digits(parser_state, true, true); 119 | if Some('.') == parser_state.cur_char() { 120 | parser_state.next_char(); 121 | } 122 | let (frac_len, skip_cnt2) = parse_digits(parser_state, int_len == 0, false); 123 | if frac_len > 0 || int_len > 0 { 124 | parser_state.valid = true; 125 | if Some('e') == parser_state.cur_char() { 126 | parser_state.next_char(); 127 | parse_exp(parser_state); 128 | } 129 | if int_len == 0 { 130 | parser_state.e -= DECIMAL_POSITIONS as i32 - parser_state.n as i32 + frac_len as i32; 131 | } else { 132 | parser_state.e -= DECIMAL_POSITIONS as i32 - int_len as i32; 133 | } 134 | } else if skip_cnt1 > 0 || skip_cnt2 > 0 { 135 | // just zeroes 136 | parser_state.valid = true; 137 | } 138 | } 139 | 140 | fn parse_digits(parser_state: &mut ParserState, skip_zeroes: bool, int: bool) -> (usize, usize) { 141 | let mut ch = parser_state.cur_char(); 142 | let mut len = 0; 143 | let mut skip_cnt = 0; 144 | if skip_zeroes { 145 | // skip leading zeroes 146 | while let Some(c) = ch { 147 | if c.is_ascii_digit() && c.to_digit(10).unwrap() == 0 { 148 | skip_cnt += 1; 149 | if !int { 150 | len += 1; // for fractionl part count length 151 | } 152 | } else { 153 | break; 154 | } 155 | ch = parser_state.next_char(); 156 | } 157 | } 158 | while let Some(c) = ch { 159 | if c.is_ascii_digit() { 160 | if parser_state.n < parser_state.mantissa_bytes.len() { 161 | parser_state.mantissa_bytes[parser_state.n] = c.to_digit(10).unwrap() as u8; 162 | parser_state.n += 1; 163 | len += 1; 164 | } else { 165 | break; 166 | } 167 | } else { 168 | break; 169 | } 170 | ch = parser_state.next_char(); 171 | } 172 | if !int && skip_cnt == len { 173 | // just zeroes 174 | len = 0; 175 | } 176 | (len, skip_cnt) 177 | } 178 | 179 | fn parse_exp(parser_state: &mut ParserState) { 180 | let mut neg = false; 181 | let mut ch = parser_state.cur_char(); 182 | if let Some(c) = ch { 183 | match c { 184 | '+' => { 185 | ch = parser_state.next_char(); 186 | } 187 | '-' => { 188 | neg = true; 189 | ch = parser_state.next_char(); 190 | } 191 | _ => {} 192 | }; 193 | } 194 | while let Some(c) = ch { 195 | if c.is_ascii_digit() { 196 | if parser_state.e >= i32::MAX / 10 { 197 | break; 198 | } 199 | parser_state.e *= 10; 200 | parser_state.e += c.to_digit(10).unwrap() as i32; 201 | } else { 202 | break; 203 | } 204 | ch = parser_state.next_char(); 205 | } 206 | if neg { 207 | parser_state.e = -parser_state.e; 208 | } 209 | } 210 | 211 | #[cfg(test)] 212 | mod tests { 213 | 214 | use super::*; 215 | 216 | #[test] 217 | pub fn test_parser() { 218 | let mut buf = [0u8; 64]; 219 | 220 | // combinations of possible valid components of a number and expected resulting characteristics. 221 | let mantissas = 222 | ["0.0", "0", ".000", "00.", "00123", "456.", "789.012", ".3456", "0.0078", "01"]; 223 | let expected_mantissas = [ 224 | [ 225 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227 | ], 228 | [ 229 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231 | ], 232 | [ 233 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235 | ], 236 | [ 237 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 238 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239 | ], 240 | [ 241 | 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243 | ], 244 | [ 245 | 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247 | ], 248 | [ 249 | 7, 8, 9, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251 | ], 252 | [ 253 | 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255 | ], 256 | [ 257 | 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259 | ], 260 | [ 261 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 262 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 263 | ], 264 | ]; 265 | let expected_mantissa_len = [0, 0, 0, 0, 3, 3, 6, 4, 2, 1]; 266 | let expected_exp_shifts = [0, 0, 0, 0, -37, -37, -37, -40, -42, -39]; 267 | 268 | let signs = ["", "+", "-"]; 269 | let expected_signs = [1, 1, -1]; 270 | 271 | let exponents = ["", "E", "e", "e123", "e+345", "e-678", "e901", "E+234", "E-567"]; 272 | let expected_exponents = [0, 0, 0, 123, 345, -678, 901, 234, -567]; 273 | 274 | let infs = ["inf", "INF", "Inf"]; 275 | let nans = ["nan", "NaN", "NAN"]; 276 | 277 | // test numbers. 278 | for i in 0..signs.len() { 279 | for j in 0..mantissas.len() { 280 | for k in 0..exponents.len() { 281 | let s = signs[i]; 282 | let m = mantissas[j]; 283 | let e = exponents[k]; 284 | let numstr = crate::util::concat_str(&mut buf, &[s, m, e]); 285 | 286 | let ps = parse(&numstr); 287 | 288 | assert!(!ps.is_inf()); 289 | assert!(!ps.is_nan()); 290 | assert!(ps.is_valid()); 291 | 292 | let (m, n, s, e) = ps.raw_parts(); 293 | assert!(s == expected_signs[i]); 294 | assert!(m == expected_mantissas[j]); 295 | assert!(n == expected_mantissa_len[j]); 296 | if expected_mantissa_len[j] > 0 { 297 | assert!(e == expected_exponents[k] + expected_exp_shifts[j]); 298 | } else { 299 | assert!(e == 0); 300 | } 301 | } 302 | } 303 | } 304 | 305 | // test inf 306 | for i in 0..signs.len() { 307 | for inf in infs { 308 | let s = signs[i]; 309 | let numstr = crate::util::concat_str(&mut buf, &[s, inf]); 310 | 311 | let ps = parse(&numstr); 312 | 313 | assert!(ps.is_inf()); 314 | assert!(ps.sign() == expected_signs[i]); 315 | assert!(!ps.is_nan()); 316 | assert!(ps.is_valid()); 317 | } 318 | } 319 | 320 | // test nan 321 | for nan in nans { 322 | let ps = parse(nan); 323 | assert!(!ps.is_inf()); 324 | assert!(ps.is_nan()); 325 | assert!(ps.is_valid()); 326 | } 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /src/serde.rs: -------------------------------------------------------------------------------- 1 | //! Serialization and deserialization using different formats and data types. 2 | //! 3 | //! # Examples 4 | //! 5 | //! Suppose you have a struct that you want to serialize to json and you want the BigFloat values contained in the struct to be exported as formatted strings. 6 | //! The following is an example of how this can be achieved using `serde` field attributes and `num_bigfloat::serde::str` module: 7 | //! 8 | //! ``` rust 9 | //! use num_bigfloat::BigFloat; 10 | //! use serde::{Serialize, Deserialize}; 11 | //! 12 | //! // A struct with a field of type BigFloat 13 | //! #[derive(Serialize, Deserialize)] 14 | //! struct SomeStruct { 15 | //! 16 | //! #[serde(with = "num_bigfloat::serde::str")] 17 | //! pub f: BigFloat, 18 | //! } 19 | //! 20 | //! // Value to be serialized 21 | //! let f = BigFloat::parse("-1.234567890123456789012345678901234567890e-12").unwrap(); 22 | //! let val = SomeStruct { 23 | //! f, 24 | //! }; 25 | //! 26 | //! // Serialization 27 | //! let json = serde_json::to_string(&val).unwrap(); 28 | //! 29 | //! // Result 30 | //! assert_eq!("{\"f\":\"-1.234567890123456789012345678901234567890e-12\"}", json); 31 | //! ``` 32 | 33 | pub mod str { 34 | 35 | //! Serialization to string and deserialization from string. 36 | 37 | use crate::util::WritableBuf; 38 | use crate::BigFloat; 39 | use core::str::from_utf8_unchecked; 40 | use serde::Deserializer; 41 | use serde::Serializer; 42 | 43 | use serde::de::{self, Visitor}; 44 | 45 | struct StrVisitor; 46 | 47 | impl<'de> Visitor<'de> for StrVisitor { 48 | type Value = BigFloat; 49 | 50 | fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { 51 | formatter.write_str("a string representation of BigFloat") 52 | } 53 | 54 | fn visit_str(self, value: &str) -> Result 55 | where 56 | E: de::Error, 57 | { 58 | BigFloat::parse(value).ok_or_else(|| de::Error::custom("Failed to parse BigFloat")) 59 | } 60 | } 61 | 62 | /// Serialize `f` to a string using given serializer. 63 | pub fn serialize(f: &BigFloat, serializer: S) -> Result 64 | where 65 | S: Serializer, 66 | { 67 | let mut buf = [0; 64]; 68 | let mut w = WritableBuf::new(&mut buf); 69 | 70 | f.write_str(&mut w).unwrap(); 71 | 72 | let written_len = w.len(); 73 | 74 | let s = unsafe { from_utf8_unchecked(&buf[..written_len]) }; 75 | 76 | serializer.serialize_str(s) 77 | } 78 | 79 | /// Deserialize BigFloat from a string using given deserializer. 80 | pub fn deserialize<'de, D>(deserializer: D) -> Result 81 | where 82 | D: Deserializer<'de>, 83 | { 84 | deserializer.deserialize_str(StrVisitor) 85 | } 86 | } 87 | 88 | #[cfg(test)] 89 | mod tests { 90 | 91 | use crate::BigFloat; 92 | use serde::{Deserialize, Serialize}; 93 | 94 | #[derive(Serialize, Deserialize)] 95 | struct Stub { 96 | #[serde(with = "crate::serde::str")] 97 | pub f: BigFloat, 98 | } 99 | 100 | #[test] 101 | fn test_serde_str() { 102 | // serialize 103 | let f = BigFloat::parse("-1.234567890123456789012345678901234567890e-12").unwrap(); 104 | let stub = Stub { f }; 105 | 106 | let json = serde_json::to_string(&stub).unwrap(); 107 | 108 | assert_eq!( 109 | "{\"f\":\"-1.234567890123456789012345678901234567890e-12\"}", 110 | json 111 | ); 112 | 113 | // deserialize 114 | let f = BigFloat::parse("+9.123456789012345678901234567890123456789e+12").unwrap(); 115 | let json = "{ 116 | \"f\": \"9.123456789012345678901234567890123456789e+12\" 117 | }"; 118 | 119 | let stub: Stub = serde_json::from_str(json).unwrap(); 120 | 121 | assert!(stub.f.cmp(&f) == Some(0)); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | //! Utility components. 2 | 3 | /// writable buffer. 4 | pub struct WritableBuf<'a> { 5 | buf: &'a mut [u8], 6 | offset: usize, 7 | } 8 | 9 | impl<'a> WritableBuf<'a> { 10 | pub fn new(buf: &'a mut [u8]) -> Self { 11 | WritableBuf { buf, offset: 0 } 12 | } 13 | 14 | pub fn len(&self) -> usize { 15 | self.offset 16 | } 17 | } 18 | 19 | impl<'a> core::fmt::Write for WritableBuf<'a> { 20 | fn write_str(&mut self, s: &str) -> core::fmt::Result { 21 | let bytes = s.as_bytes(); 22 | let rem = &mut self.buf[self.offset..]; 23 | if rem.len() < bytes.len() { 24 | Err(core::fmt::Error) 25 | } else { 26 | let rem = &mut rem[..bytes.len()]; 27 | rem.copy_from_slice(bytes); 28 | self.offset += bytes.len(); 29 | Ok(()) 30 | } 31 | } 32 | } 33 | 34 | /// Concatenate several &str instances from `str_list` into one unsing buffer `buf`. 35 | pub fn concat_str<'a>(buf: &'a mut [u8], str_list: &[&str]) -> &'a str { 36 | let mut p = 0; 37 | for s in str_list { 38 | let bytes = s.as_bytes(); 39 | buf[p..p + bytes.len()].copy_from_slice(bytes); 40 | p += bytes.len(); 41 | } 42 | if buf.len() > p + 1 { 43 | buf[p] = 0; 44 | } 45 | core::str::from_utf8(&buf[0..p]).unwrap() 46 | } 47 | --------------------------------------------------------------------------------