1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
/*!
# twofloat
This library provides an implementation of double-double arithmetic for the
Rust language. Note that this is not the same as the IEEE quadruple-precision
floating-point format. Instead, higher precision is obtained by representing
the value as the sum of two non-overlapping `f64` values.
## Usage
The basic type is `TwoFloat` which represents the sum of two non-overlapping
`f64` values, which may be initialized from a single `f64` or by calling a
constructor that performs an arithmetic operation on a pair of `f64` values.
```
extern crate twofloat;
use twofloat::TwoFloat;
let a = TwoFloat::from(3.4);
let b = TwoFloat::new_add(1.0, 1.0e-300);
let c = TwoFloat::new_sub(1.0, 1.0e-300);
let d = TwoFloat::new_mul(5.0, 0.7);
let e = TwoFloat::new_div(1.0, 7.0);
```
Basic arithmetic operators and comparisons are available, together with the
utility functions `abs()`, `is_positive_sign()` and `is_negative_sign()`.
Mathematical functions are provided if the `math_funcs` feature is enabled
(this is enabled by default), though the implementations should be regarded
as preliminary.
Operations on non-finite values are not supported. At the moment this is not
automatically checked. The `is_valid()` method is provided for this purpose.
If the `serde` feature is enabled, serialization and deserialization is
possible through the Serde library.
## Known issues
* The MinGW `fma` implementation appears to give incorrect results in some
cases, so the libm implementation is always used on this platform.
## References
* Mioara Joldes, Jean-Michel Muller, Valentina Popescu. Tight and rigourous
error bounds for basic building blocks of double-word arithmetic. ACM
Transactions on Mathematical Software, Association for Computing Machinery,
2017, 44 (2), pp.1 - 27. 10.1145/3121432. hal-01351529v3
* Alan H. Karp, Peter Markstein. High Precision Division and Square Root. ACM
Transactions on Mathematical Software, Association for Computing Machinery,
1997, 23 (4), pp. 561-589. 10.1145/279232.279237.
* S. Chevillard, M. Joldeș and C. Lauter. Sollya: an environment for the
development of numerical codes. Mathematical Software - ICMS 2010, pp.
28–31.
*/
#![forbid(unsafe_code)]
// Disable irrelevant lints
#![allow(clippy::approx_constant)]
#![allow(clippy::excessive_precision)]
#![allow(clippy::float_cmp)]
#![allow(clippy::suspicious_arithmetic_impl)]
#![allow(clippy::suspicious_op_assign_impl)]
#![cfg_attr(not(feature = "std"), no_std)]
use core::fmt;
mod math_util;
#[macro_use]
mod ops_util;
#[cfg(test)]
#[macro_use]
mod test_util;
mod arithmetic;
mod base;
/// Basic mathematical constants.
///
/// Values determined using Sollya.
pub mod consts;
mod convert;
mod format;
mod functions;
mod num_integration;
pub use base::no_overlap;
#[cfg(feature = "serde")]
mod serde_helper {
use super::{TwoFloat, TwoFloatError};
#[derive(serde::Deserialize)]
#[serde(rename = "TwoFloat")]
pub(super) struct TwoFloatDeserializeHelper {
hi: f64,
lo: f64,
}
impl core::convert::TryFrom<TwoFloatDeserializeHelper> for TwoFloat {
type Error = TwoFloatError;
fn try_from(value: TwoFloatDeserializeHelper) -> Result<Self, Self::Error> {
TwoFloat::try_from((value.hi, value.lo))
}
}
}
/// Represents a two-word floating point type, represented as the sum of two
/// non-overlapping f64 values.
#[derive(Debug, Default, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
serde(try_from = "serde_helper::TwoFloatDeserializeHelper")
)]
pub struct TwoFloat {
pub(crate) hi: f64,
pub(crate) lo: f64,
}
/// The error type for `TwoFloat` operations.
#[non_exhaustive]
#[derive(Debug)]
pub enum TwoFloatError {
/// Indicates invalid conversion to/from `TwoFloat`
ConversionError,
ParseError,
}
impl fmt::Display for TwoFloatError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::ConversionError => f.pad("invalid TwoFloat conversion"),
Self::ParseError => f.pad("parsing not supported"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for TwoFloatError {}