1use core::cmp::Ordering;
12use core::fmt;
13
14use crate::float::{Float, RoundingMode};
15use crate::int::{Int, Sign};
16
17#[derive(Clone)]
19pub struct FixedFloat {
20 value: Float,
21 mode: RoundingMode,
22}
23
24impl FixedFloat {
25 #[inline]
27 pub fn from_float(value: Float, mode: RoundingMode) -> FixedFloat {
28 FixedFloat { value, mode }
29 }
30
31 pub fn from_int(n: &Int, precision: u64, mode: RoundingMode) -> FixedFloat {
33 FixedFloat {
34 value: Float::from_int(n, precision, mode),
35 mode,
36 }
37 }
38
39 pub fn from_f64(x: f64, precision: u64, mode: RoundingMode) -> FixedFloat {
41 FixedFloat {
42 value: Float::from_f64(x, precision, mode),
43 mode,
44 }
45 }
46
47 pub fn zero(precision: u64, mode: RoundingMode) -> FixedFloat {
49 FixedFloat {
50 value: Float::zero(precision),
51 mode,
52 }
53 }
54
55 pub fn nan(precision: u64, mode: RoundingMode) -> FixedFloat {
57 FixedFloat {
58 value: Float::nan(precision),
59 mode,
60 }
61 }
62 pub fn infinity(precision: u64, mode: RoundingMode) -> FixedFloat {
64 FixedFloat {
65 value: Float::infinity(precision),
66 mode,
67 }
68 }
69 pub fn neg_infinity(precision: u64, mode: RoundingMode) -> FixedFloat {
71 FixedFloat {
72 value: Float::neg_infinity(precision),
73 mode,
74 }
75 }
76
77 pub fn pi(precision: u64, mode: RoundingMode) -> FixedFloat {
79 FixedFloat {
80 value: Float::pi(precision, mode),
81 mode,
82 }
83 }
84 pub fn e(precision: u64, mode: RoundingMode) -> FixedFloat {
86 FixedFloat {
87 value: Float::e(precision, mode),
88 mode,
89 }
90 }
91
92 #[inline]
96 pub fn precision(&self) -> u64 {
97 self.value.precision()
98 }
99
100 #[inline]
102 pub fn rounding_mode(&self) -> RoundingMode {
103 self.mode
104 }
105
106 #[inline]
108 pub fn as_float(&self) -> &Float {
109 &self.value
110 }
111
112 #[inline]
114 pub fn into_float(self) -> Float {
115 self.value
116 }
117
118 #[inline]
120 pub fn to_f64(&self) -> f64 {
121 self.value.to_f64()
122 }
123
124 #[inline]
126 pub fn to_shortest_string(&self) -> alloc::string::String {
127 self.value.to_shortest_string()
128 }
129
130 #[inline]
132 pub fn is_nan(&self) -> bool {
133 self.value.is_nan()
134 }
135 #[inline]
137 pub fn is_infinite(&self) -> bool {
138 self.value.is_infinite()
139 }
140 #[inline]
142 pub fn is_finite(&self) -> bool {
143 self.value.is_finite()
144 }
145 #[inline]
147 pub fn is_zero(&self) -> bool {
148 self.value.is_zero()
149 }
150 #[inline]
152 pub fn sign(&self) -> Sign {
153 self.value.sign()
154 }
155
156 pub fn with_precision(&self, precision: u64) -> FixedFloat {
158 FixedFloat {
159 value: self.value.round(precision, self.mode),
160 mode: self.mode,
161 }
162 }
163
164 fn combine(
167 &self,
168 rhs: &FixedFloat,
169 op: fn(&Float, &Float, u64, RoundingMode) -> Float,
170 ) -> FixedFloat {
171 let precision = self.value.precision().max(rhs.value.precision());
172 FixedFloat {
173 value: op(&self.value, &rhs.value, precision, self.mode),
174 mode: self.mode,
175 }
176 }
177
178 pub fn neg(&self) -> FixedFloat {
180 FixedFloat {
181 value: self.value.neg(),
182 mode: self.mode,
183 }
184 }
185
186 pub fn abs(&self) -> FixedFloat {
188 FixedFloat {
189 value: self.value.abs(),
190 mode: self.mode,
191 }
192 }
193
194 pub fn sqrt(&self) -> FixedFloat {
196 self.unary(Float::sqrt)
197 }
198 pub fn exp(&self) -> FixedFloat {
200 self.unary(Float::exp)
201 }
202 pub fn ln(&self) -> FixedFloat {
204 self.unary(Float::ln)
205 }
206 pub fn sin(&self) -> FixedFloat {
208 self.unary(Float::sin)
209 }
210 pub fn cos(&self) -> FixedFloat {
212 self.unary(Float::cos)
213 }
214 pub fn tan(&self) -> FixedFloat {
216 self.unary(Float::tan)
217 }
218 pub fn atan(&self) -> FixedFloat {
220 self.unary(Float::atan)
221 }
222
223 pub fn pow(&self, exp: &FixedFloat) -> FixedFloat {
225 let precision = self.value.precision().max(exp.value.precision());
226 FixedFloat {
227 value: self.value.pow(&exp.value, precision, self.mode),
228 mode: self.mode,
229 }
230 }
231
232 fn unary(&self, op: fn(&Float, u64, RoundingMode) -> Float) -> FixedFloat {
233 FixedFloat {
234 value: op(&self.value, self.value.precision(), self.mode),
235 mode: self.mode,
236 }
237 }
238}
239
240impl PartialEq for FixedFloat {
241 #[inline]
242 fn eq(&self, other: &Self) -> bool {
243 self.value == other.value
244 }
245}
246
247impl PartialOrd for FixedFloat {
248 #[inline]
249 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
250 self.value.partial_cmp(&other.value)
251 }
252}
253
254impl fmt::Display for FixedFloat {
255 #[inline]
256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 fmt::Display::fmt(&self.value, f)
258 }
259}
260
261impl fmt::Debug for FixedFloat {
262 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263 write!(f, "FixedFloat({:?}, {:?})", self.value, self.mode)
264 }
265}
266
267macro_rules! fixed_binop {
268 ($tr:ident, $m:ident, $atr:ident, $am:ident, $call:path) => {
269 impl core::ops::$tr for FixedFloat {
270 type Output = FixedFloat;
271 #[inline]
272 fn $m(self, rhs: FixedFloat) -> FixedFloat {
273 self.combine(&rhs, $call)
274 }
275 }
276 impl core::ops::$tr<&FixedFloat> for &FixedFloat {
277 type Output = FixedFloat;
278 #[inline]
279 fn $m(self, rhs: &FixedFloat) -> FixedFloat {
280 self.combine(rhs, $call)
281 }
282 }
283 impl core::ops::$atr for FixedFloat {
284 #[inline]
285 fn $am(&mut self, rhs: FixedFloat) {
286 *self = self.combine(&rhs, $call);
287 }
288 }
289 };
290}
291
292fixed_binop!(Add, add, AddAssign, add_assign, Float::add);
293fixed_binop!(Sub, sub, SubAssign, sub_assign, Float::sub);
294fixed_binop!(Mul, mul, MulAssign, mul_assign, Float::mul);
295fixed_binop!(Div, div, DivAssign, div_assign, Float::div);
296
297impl core::ops::Neg for FixedFloat {
298 type Output = FixedFloat;
299 #[inline]
300 fn neg(self) -> FixedFloat {
301 FixedFloat::neg(&self)
302 }
303}