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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! This module contains the `Num` trait and its implementations.
//!
//! The `Num` trait defines the inner workings of this library. Any type that implements the `Num` trait
//! can be used to represent a number in an equation. There are currently five predefined implementors
//! of the `Num` trait, but that number is subject to change (with additions and removals). You can also
//! define your own `Num`, but hopefully a fitting one already exists for you here.
//!
//! The five nums are:
//! - `f64`
//! - `ComplexFloat`
//! - `ComplexRugRat`
//! - `rug::Complex`
//! - `rug::Rational`
//!
//! Each have different strengths and weaknesses.
//!
//! `f64` implements all functions, but suffers the limitations `f64`s usually suffer from (low precision,
//!  NaN/infinity errors, etc).
//!
//! `ComplexFloat` is just two `f64`s representing a real part and an imaginary part, but doesn't
//! support nearly as many operations as `f64`.
//!
//! `ComplexRugRat` is two `rug::Rationals` representing a real and an imaginary part. This supports
//! even fewer operations than `ComplexFloat`.
//!
//! `rug::Complex` is the next best after `f64`. It's a complex multiple precision floating point
//! number. It's precision can be defined in the `Context` and equation is parsed an evaluated with.
//!
//! `rug::Rational` is just a rational number, and also supports very few operations.
//!
//! To see the progress on implementations of `Num` types, see the the [issues on GitHub](https://github.com/IntrepidPig/mexprp/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Anumber)
//! with the label "number"

use std::fmt;
use std::marker::Sized;
use std::cmp::Ordering;

#[cfg(feature = "rug")]
mod complexrugrat;
#[cfg(feature = "rug")]
mod rugrat;
#[cfg(feature = "rug")]
mod rugcomplex;
mod complexfloat;
mod float64;

#[cfg(feature = "rug")]
pub use self::complexrugrat::ComplexRugRat;
#[cfg(feature = "rug")]
pub use self::complexfloat::ComplexFloat;

use opers::Calculation;
use errors::MathError;
use context::Context;

/// A `Num` represents any type that can be used in an expression. It requires lots of operations to
/// be implemented for it, any of which can fail, as well as the traits: Debug, Clone, Display, PartialOrd,
/// and PartialEq.
#[allow(missing_docs)]
pub trait Num: fmt::Debug + fmt::Display + Clone + PartialEq
where
	Self: Sized,
{
	/// Attempts to create an instance of the number from an f64
	fn from_f64(t: f64, ctx: &Context<Self>) -> Calculation<Self>;
	/// Attempts to create an instance of the number from complex parts. It's possible the imaginary
	/// part will be ignored for Numbers that don't support it.
	fn from_f64_complex(t: (f64, f64), ctx: &Context<Self>) -> Calculation<Self>;

	/// Returns the name of this Num type (used for errors)
	fn typename() -> String;

	fn tryord(&self, other: &Self, ctx: &Context<Self>) -> Result<Ordering, MathError> {
		Err(MathError::Unimplemented {
			op: "Comparison".to_string(),
			num_type: Self::typename(),
		})
	}
	fn add(&self, other: &Self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Addition".to_string(),
			num_type: Self::typename(),
		})
	}
	fn sub(&self, other: &Self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Subtraction".to_string(),
			num_type: Self::typename(),
		})
	}
	fn mul(&self, other: &Self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Multiplication".to_string(),
			num_type: Self::typename(),
		})
	}
	fn div(&self, other: &Self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Division".to_string(),
			num_type: Self::typename(),
		})
	}
	fn pow(&self, other: &Self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Exponent".to_string(),
			num_type: Self::typename(),
		})
	}
	fn sqrt(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Square Root".to_string(),
			num_type: Self::typename(),
		})
	}
	fn nrt(&self, other: &Self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Nth Root".to_string(),
			num_type: Self::typename(),
		})
	}
	fn abs(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Absolute Value".to_string(),
			num_type: Self::typename(),
		})
	}
	fn sin(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Sine".to_string(),
			num_type: Self::typename(),
		})
	}
	fn cos(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Cosine".to_string(),
			num_type: Self::typename(),
		})
	}
	fn tan(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Tangent".to_string(),
			num_type: Self::typename(),
		})
	}
	fn asin(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Arc Sine".to_string(),
			num_type: Self::typename(),
		})
	}
	fn acos(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Arc Cosine".to_string(),
			num_type: Self::typename(),
		})
	}
	fn atan(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Arc Tangent".to_string(),
			num_type: Self::typename(),
		})
	}
	fn atan2(&self, other: &Self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Atan2".to_string(),
			num_type: Self::typename(),
		})
	}
	fn floor(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Flooring".to_string(),
			num_type: Self::typename(),
		})
	}
	fn ceil(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Ceiling".to_string(),
			num_type: Self::typename(),
		})
	}
	fn round(&self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Rounding".to_string(),
			num_type: Self::typename(),
		})
	}
	fn log(&self, other: &Self, ctx: &Context<Self>) -> Calculation<Self> {
		Err(MathError::Unimplemented {
			op: "Logarithm".to_string(),
			num_type: Self::typename(),
		})
	}
}