Skip to main content

zenith_float/
lib.rs

1//! zenith-float implements arbitrary-precision software floating-point numbers
2//! (`ExactNum`) and software IEEE-754 binary32/binary64 (`Ieee32` / `Ieee64`).
3//! All arithmetic uses integer limbs. The library does not use hardware floating-point for calculations.
4//!
5//! Repository guides: `doc/GETTING_STARTED.md` (short path) and `doc/HELP.md` (longer tutorial).
6//!
7//! ## Introduction
8//!
9//! **Numbers**
10//!
11//!
12//! The number is defined by the data type `ExactNum`.
13//! Each finite number consists of an array of words representing the mantissa, exponent, and sign.
14//! `ExactNum` can also be `Inf` (positive infinity), `-Inf` (negative infinity) or `NaN` (not-a-number).
15//!
16//!
17//! `ExactNum` creation operations take bit precision as an argument.
18//! Precision is always rounded up to the nearest word.
19//! For example, if you specify a precision of 1 bit, then it will be converted to 64 bits when one word has a size of 64 bits.
20//! If you specify a precision of 65 bits, the resulting precision will be 128 bits (2 words), and so on.
21//!
22//!
23//! Most operations take the rounding mode as an argument.
24//! The operation will typically internally result in a number with more precision than necessary.
25//! Before the result is returned to the user, the result is rounded according to the rounding mode and reduced to the expected precision.
26//!
27//!
28//! The result of an operation is marked as inexact if some of the bits were rounded when producing the result,
29//! or if any of the operation's arguments were marked as inexact. The information about exactness is used to achieve correct rounding.
30//!
31//!
32//! `ExactNum` can be parsed from a string and formatted into a string using binary, octal, decimal, or hexadecimal representation.
33//!
34//!
35//! Numbers can be subnormal. Usually any number is normalized: the most significant bit of the mantissa is set to 1.
36//! If the result of the operation has the smallest possible exponent, then normalization cannot be performed,
37//! and some significant bits of the mantissa may become 0. This allows for a more gradual transition to zero.
38//!
39//! **Error handling**
40//!
41//! In case of an error, such as memory allocation error, `ExactNum` takes the value `NaN`.
42//! `ExactNum::err()` can be used to get the associated error in this situation.
43//!
44//! **Constants**
45//!
46//! Constants such as pi or the Euler number have arbitrary precision and are evaluated lazily and then cached in the constants cache.
47//! Some functions expect constants cache as parameter.
48//!
49//! **Rounding**
50//!
51//! `ExactNum` methods that take a rounding mode other than `RoundingMode::None` round to the requested precision.
52//! `RoundingMode::None` skips that step and may keep extra bits.
53//! `expr!` raises working precision to compensate cancellation; it does not itself perform correct rounding.
54//!
55//! ## Examples
56//!
57//! The example below computes Pi with precision 1024, rounding to even, using `expr!`.
58//!
59//! ```
60//! use zenith_float::Consts;
61//! use zenith_float::RoundingMode;
62//! use zenith_float::ctx::Context;
63//! use zenith_float::expr;
64//!
65//! // Create a context with precision 1024, rounding to the nearest even,
66//! // and exponent range from -100000 to 100000.
67//! let mut ctx = Context::new(1024, RoundingMode::ToEven,
68//!     Consts::new().expect("Constants cache initialized"),
69//!     -100000, 100000);
70//!
71//! // Compute pi: pi = 6*arctan(1/sqrt(3))
72//! let pi = expr!(6 * atan(1 / sqrt(3)), &mut ctx);
73//!
74//! // Use library's constant value for verifying the result.
75//! let pi_lib = ctx.const_pi();
76//!
77//! // Compare computed constant with library's constant
78//! assert_eq!(pi.cmp(&pi_lib), Some(0));
79//!
80//! // Print using decimal radix.
81//! #[cfg(feature="std")]
82//! println!("{}", pi);
83//!
84//! // output: 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458699748e+0
85//! ```
86//!
87//! The example below computes value of Pi with precision 1024 rounded to the nearest even number using `ExactNum` directly.
88//! We will take care of the error in this case.
89//!
90//! ``` rust
91//! use zenith_float::ExactNum;
92//! use zenith_float::Consts;
93//! use zenith_float::RoundingMode;
94//!
95//! // Precision with some space for error.
96//! let p = 1024 + 8;
97//!
98//! // The results of computations will not be rounded.
99//! // That will be more performant, even though it may give an incorrectly rounded result.
100//! let rm = RoundingMode::None;
101//!
102//! // Initialize mathematical constants cache
103//! let mut cc = Consts::new().expect("An error occured when initializing constants");
104//!
105//! // Compute pi: pi = 6*arctan(1/sqrt(3))
106//! let six = ExactNum::from_word(6, 1);
107//! let three = ExactNum::from_word(3, p);
108//!
109//! let n = three.sqrt(p, rm);
110//! let n = n.reciprocal(p, rm);
111//! let n = n.atan(p, rm, &mut cc);
112//! let mut pi = six.mul(&n, p, rm);
113//!
114//! // Reduce precision to 1024 and round to the nearest even number.
115//! pi.set_precision(1024, RoundingMode::ToEven).expect("Precision updated");
116//!
117//! // Use library's constant for verifying the result
118//! let pi_lib = cc.pi(1024, RoundingMode::ToEven);
119//!
120//! // Compare computed constant with library's constant
121//! assert_eq!(pi.cmp(&pi_lib), Some(0));
122//!
123//! // Print using decimal radix.
124//! #[cfg(feature="std")]
125//! println!("{}", pi);
126//!
127//! // output: 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458699748e+0
128//! ```
129//!
130//! ## Performance recommendations
131//!
132//! When small error is acceptable because of rounding it is recommended to do all computations with `RoundingMode::None`, and use `ExactNum::set_precision` or `ExactNum::round` with a specific rounding mode just once for the final result.
133//!
134//! ## no_std
135//!
136//! The library can work without the standard library provided there is a memory allocator. The standard library dependency is activated by the feature `std`.
137//! The feature `std` is active by default and must be excluded when specifying dependency, e.g.:
138//!
139//! ``` toml
140//! [dependencies]
141//! zenith-float = { version = "1.0.1", default-features = false }
142//! ```
143//!
144
145#![deny(missing_docs)]
146#![deny(unused)]
147#![deny(clippy::suspicious)]
148#![deny(clippy::float_arithmetic)]
149#![allow(clippy::manual_div_ceil)]
150#![allow(clippy::manual_is_multiple_of)]
151#![cfg_attr(not(feature = "std"), no_std)]
152
153/// Computes an expression with the specified precision and rounding mode.
154///
155/// Macro takes into account 2 aspects.
156///
157/// 1. Code simplification. Macro simplifies code and improves its readability by allowing to specify simple and concise expression
158///    and process input arguments transparently.
159///
160/// 2. Error compensation. Macro compensates error caused by catastrophic cancellation
161///    and some other situations where precision can be lost by automatically increasing the working precision internally.
162///
163/// The macro does not take care of correct rounding, because the completion of the rounding algorithm in finite time depends on the macro's input.
164///
165/// The macro accepts an expression to compute and a context.
166/// The expression can include:
167///
168///  - Path expressions: variable names, constant names, etc.
169///  - Integer literals, e.g. `123`, `-5`.
170///  - Floating point literals, e.g. `1.234e-567`.
171///  - String literals, e.g. `"-1.234_e-567"`.
172///  - Binary operators.
173///  - Unary `-` operator.
174///  - Mathematical functions.
175///  - Grouping with `(` and `)`.
176///  - Constants `pi`, `e`, `ln_2`, `ln_10`, `sqrt2`, `phi`, and `euler_gamma`.
177///
178/// Binary operators:
179///
180///  - `+`: addition.
181///  - `-`: subtraction.
182///  - `*`: multiplication.
183///  - `/`: division.
184///  - `%`: modular division.
185///
186/// Mathematical functions:
187///
188///  - `recip(x)`: reciprocal of `x`.
189///  - `sqrt(x)`: square root of `x`.
190///  - `cbrt(x)`: cube root of `x`.
191///  - `ln(x)`: natural logarithm of `x`.
192///  - `log2(x)`: logarithm base 2 of `x`.
193///  - `log10(x)`: logarithm base 10 of `x`.
194///  - `log(x, b)`: logarithm with base `b` of `x`.
195///  - `log1p(x)`: `ln(1 + x)`.
196///  - `exp(x)`: `e` to the power of `x`.
197///  - `exp2(x)`: `2` to the power of `x`.
198///  - `exp10(x)`: `10` to the power of `x`.
199///  - `expm1(x)`: `e^x - 1`.
200///  - `pow(b, x)`: `b` to the power of `x`.
201///  - `rem_pi(x)`: reduce `x` modulo `2π` into `(-2π, 2π)`.
202///  - `sin(x)`: sine of `x`.
203///  - `cos(x)`: cosine of `x`.
204///  - `tan(x)`: tangent of `x`.
205///  - `asin(x)`: arcsine of `x`.
206///  - `acos(x)`: arccosine of `x`.
207///  - `atan(x)`: arctangent of `x`.
208///  - `atan2(y, x)`: quadrant-aware arctangent of `y / x`.
209///  - `hypot(x, y)`: `sqrt(x² + y²)`.
210///  - `fma(x, y, z)`: `x * y + z` with a single final rounding.
211///  - `mul_add(x, y, z)`: alias of `fma`.
212///  - `erf(x)`, `erfc(x)`: error function and complement.
213///  - `gamma(x)`, `ln_gamma(x)`, `digamma(x)`: gamma, log-gamma, and digamma.
214///  - `gammainc(s, x)`: lower incomplete gamma \(\gamma(s,x)\).
215///  - `gammainc_upper(s, x)`: upper incomplete gamma \(\Gamma(s,x)\).
216///  - `ei(x)`, `si(x)`, `ci(x)`, `li(x)`: exponential / sine / cosine / logarithmic integrals.
217///  - `fresnel_s(x)`, `fresnel_c(x)`: Fresnel integrals.
218///  - `bessel_j(x, n)`: Bessel J of integer order `n`.
219///  - `bessel_j_nu(x, nu)`, `bessel_y(x, nu)`, `bessel_i(x, nu)`, `bessel_k(x, nu)`: real-order Bessel.
220///  - `elliptic_k(m)`, `elliptic_e(m)`, `elliptic_f(x, m)`, `elliptic_e_inc(x, m)`, `elliptic_pi(n, m)`, `elliptic_pi_inc(n, x, m)`: elliptic integrals (\(m=k^2\), \(x=\sin\varphi\)).
221///  - `jacobi_am(u, m)`, `jacobi_sn(u, m)`, `jacobi_cn(u, m)`, `jacobi_dn(u, m)`, `jacobi_cd(u, m)`, `jacobi_ns`, `jacobi_nc`, `jacobi_nd`, `jacobi_sc`, `jacobi_sd`, `jacobi_cs`, `jacobi_ds`, `jacobi_dc`: Jacobi elliptic functions (\(m=k^2\in[0,1]\)).
222///  - `legendre_p(x, n)`, `legendre_p_assoc(x, n, m)`: Legendre / associated (Condon–Shortley).
223///  - `hypergeom_2f1(a, b, c, z)`: Gaussian \({}_2F_1\).
224///  - `betainc(a, b, x)`: regularized incomplete beta \(I_x(a,b)\).
225///  - `normal_pdf(x, mu, sigma)`, `normal_cdf(x, mu, sigma)`: normal density and CDF.
226///  - `gamma_pdf(x, alpha, beta)`, `beta_pdf(x, alpha, beta)`: gamma (scale \(\beta\)) and beta densities.
227///  - `poisson_pmf(k, lambda)`, `binomial_pmf(k, n, prob)`: discrete PMFs.
228///  - `chi_squared_cdf(x, k)`, `student_t_pdf(x, nu)`: chi-squared CDF and Student-\(t\) density.
229///  - `ldexp(x, n)`, `scalb(x, n)`: `x · 2^n` (`n` is an integer literal or expression).
230///  - `logb(x)`: `floor(log2(|x|))` as a float.
231///  - `sinh(x)`: hyperbolic sine of `x`.
232///  - `cosh(x)`: hyperbolic cosine of `x`.
233///  - `tanh(x)`: hyperbolic tangent of `x`.
234///  - `asinh(x)`: hyperbolic arcsine of `x`.
235///  - `acosh(x)`: hyperbolic arccosine of `x`.
236///  - `atanh(x)`: hyperbolic arctangent of `x`.
237///
238/// Constants:
239///  - `pi`: pi number.
240///  - `e`: Euler number.
241///  - `ln_2`: natural logarithm of 2.
242///  - `ln_10`: natural logarithm of 10.
243///  - `sqrt2`: √2.
244///  - `phi`: golden ratio (1+√5)/2.
245///  - `euler_gamma`: Euler–Mascheroni constant γ.
246///
247/// The context determines the precision, the rounding mode of the result, and also contains the cache of constants.
248///
249/// Also, the macro uses minimum and maximum exponent values from the context to limit possible exponent range of the result and to set the limit of precision required for error compensation.
250/// It is recommended to set the smallest exponent range to increase the performance of computations (the internal precision may be as large as the exponent of a number).
251///
252/// Per-operation rounding (what is rounded when, and what is not guaranteed) is documented in `doc/EXPR.md`.
253///
254/// A tuple `(usize, RoundingMode, &mut Consts)`, or `(usize, RoundingMode, &mut Consts, Exponent, Exponent)` can be used as a temporary context (see examples below).
255///
256/// Any input argument in the expression is interpreted as exact
257/// (i.e. if an argument of an expression has type ExactNum and it is an inexact result of a previous computation).
258///
259/// ## Examples
260///
261/// ```
262/// # use zenith_float_macro::expr;
263/// # use zenith_float::RoundingMode;
264/// # use zenith_float::Consts;
265/// # use zenith_float::ExactNum;
266/// # use zenith_float::ctx::Context;
267/// // Precision, rounding mode, constants cache, and exponent range.
268/// let p = 128;
269/// let rm = RoundingMode::Up;
270/// let mut cc = Consts::new().expect("Failed to allocate constants cache");
271/// let emin = -10000;
272/// let emax = 10000;
273///
274/// // Create a context.
275/// let mut ctx = Context::new(p, rm, cc, emin, emax);
276///
277/// let x = 1;
278/// let y = 4;
279/// let z = 7;
280///
281/// // Compute an expression.
282/// let ret = expr!(x + y / z - ("120" - 120), &mut ctx);
283///
284/// let (p, rm, mut cc, emin, emax) = ctx.to_raw_parts();
285///
286/// // Compute an expression using a temporary context.
287/// let ret = expr!(x + y / z, (p, rm, &mut cc, emin, emax));
288/// ```
289///
290/// ## Compile-time literals
291///
292/// [`exact`] and [`fbig`] parse a string literal at compile time into an exact [`ExactNum`]:
293///
294/// ```
295/// use zenith_float::{exact, fbig, ExactNum, RoundingMode};
296///
297/// let a = exact!("3.25");
298/// let b = fbig!("3.25");
299/// assert_eq!(a.cmp(&b), Some(0));
300/// assert_eq!(a.cmp(&ExactNum::from_word(13, 64).div(&ExactNum::from_word(4, 64), 64, RoundingMode::ToEven)), Some(0));
301/// ```
302///
303/// ## Complex expressions
304///
305/// [`cexpr`] is the same working-precision loop as [`expr`], for [`ExactComplex`].
306/// Cancellation is measured on both the real and imaginary parts.
307/// The imaginary unit in the expression is `I` (so `i` remains a variable name).
308/// Leaves include roots, logs/exps, elementary and inverse functions, `hypot`/`fma`,
309/// `abs`/`arg`/`conj`, `ldexp`/`scalb`/`logb`, `erf`/`erfc`/`gamma`/`ln_gamma`/`digamma`,
310/// `ei`/`si`/`ci`/`li`/`fresnel_s`/`fresnel_c`, and `bessel_j_nu`/`bessel_y`/`bessel_i`/`bessel_k`.
311/// Cancellation is tracked per part.
312/// There is no `atan2` or `rem_pi` in `cexpr!`.
313/// Use `cexpr!` when the expression is complex; `expr!` stays real-valued.
314pub use zenith_float_macro::{cexpr, exact, expr, fbig};
315
316pub use zenith_float_num::*;