1#[cfg(feature = "integer")]
18use crate::Integer;
19use crate::ext::xmpfr;
20#[allow(deprecated)]
21use crate::float::SmallFloat;
22use crate::float::big;
23use crate::float::big::{ExpFormat, Format};
24use crate::float::{Constant, MiniFloat, OrdFloat, Round, Special};
25use crate::misc::StringLike;
26use crate::ops::AssignRound;
27use crate::{Assign, Float};
28#[cfg(feature = "rational")]
29use crate::{Rational, rational::TryFromFloatError};
30#[cfg(feature = "rational")]
31use az::CheckedCast;
32use az::{StrictAs, StrictCast};
33use core::cmp::Ordering;
34use core::fmt::{
35 Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, Result as FmtResult, UpperExp,
36 UpperHex,
37};
38use gmp_mpfr_sys::mpfr;
39
40impl Clone for Float {
41 #[inline]
42 fn clone(&self) -> Float {
43 let mut ret = Float::new_nan(self.prec());
44 if !self.is_nan() {
45 ret.assign(self);
46 }
47 ret
48 }
49
50 #[inline]
51 fn clone_from(&mut self, source: &Float) {
52 xmpfr::set_prec_nan(self, source.prec().strict_cast());
53 if !source.is_nan() {
54 self.assign(source);
55 }
56 }
57}
58
59impl Drop for Float {
60 #[inline]
61 fn drop(&mut self) {
62 unsafe {
64 mpfr::clear(self.as_raw_mut());
65 }
66 }
67}
68
69impl Display for Float {
70 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
71 let format = Format {
72 exp: ExpFormat::Point,
73 ..Format::default()
74 };
75 fmt_radix(self, f, format, "")
76 }
77}
78
79impl Debug for Float {
80 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
81 let format = Format {
82 exp: ExpFormat::Point,
83 ..Format::default()
84 };
85 fmt_radix(self, f, format, "")
86 }
87}
88
89impl LowerExp for Float {
90 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
91 let format = Format {
92 exp: ExpFormat::Exp,
93 ..Format::default()
94 };
95 fmt_radix(self, f, format, "")
96 }
97}
98
99impl UpperExp for Float {
100 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
101 let format = Format {
102 to_upper: true,
103 exp: ExpFormat::Exp,
104 ..Format::default()
105 };
106 fmt_radix(self, f, format, "")
107 }
108}
109
110impl Binary for Float {
111 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
112 let format = Format {
113 radix: 2,
114 exp: ExpFormat::Point,
115 ..Format::default()
116 };
117 fmt_radix(self, f, format, "0b")
118 }
119}
120
121impl Octal for Float {
122 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
123 let format = Format {
124 radix: 8,
125 exp: ExpFormat::Point,
126 ..Format::default()
127 };
128 fmt_radix(self, f, format, "0o")
129 }
130}
131
132impl LowerHex for Float {
133 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
134 let format = Format {
135 radix: 16,
136 exp: ExpFormat::Point,
137 ..Format::default()
138 };
139 fmt_radix(self, f, format, "0x")
140 }
141}
142
143impl UpperHex for Float {
144 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
145 let format = Format {
146 radix: 16,
147 to_upper: true,
148 exp: ExpFormat::Point,
149 ..Format::default()
150 };
151 fmt_radix(self, f, format, "0x")
152 }
153}
154
155impl AsRef<OrdFloat> for Float {
156 #[inline]
157 fn as_ref(&self) -> &OrdFloat {
158 self.as_ord()
159 }
160}
161
162impl<T> Assign<T> for Float
163where
164 Self: AssignRound<T, Round = Round, Ordering = Ordering>,
165{
166 #[inline]
167 fn assign(&mut self, src: T) {
168 self.assign_round(src, Round::Nearest);
169 }
170}
171
172impl AssignRound<Constant> for Float {
173 type Round = Round;
174 type Ordering = Ordering;
175 #[inline]
176 fn assign_round(&mut self, src: Constant, round: Round) -> Ordering {
177 match src {
178 Constant::Log2 => xmpfr::const_log2(self, round),
179 Constant::Pi => xmpfr::const_pi(self, round),
180 Constant::Euler => xmpfr::const_euler(self, round),
181 Constant::Catalan => xmpfr::const_catalan(self, round),
182 }
183 }
184}
185
186assign_round_deref! { Constant => Float }
187
188impl AssignRound<Special> for Float {
189 type Round = Round;
190 type Ordering = Ordering;
191 #[inline]
192 fn assign_round(&mut self, src: Special, _round: Round) -> Ordering {
193 xmpfr::set_special(self, src);
194 Ordering::Equal
195 }
196}
197
198assign_round_deref! { Special => Float }
199
200impl AssignRound for Float {
201 type Round = Round;
202 type Ordering = Ordering;
203 #[inline]
204 fn assign_round(&mut self, src: Float, round: Round) -> Ordering {
205 if self.prec() == src.prec() {
206 *self = src;
207 if self.is_nan() {
208 xmpfr::set_nanflag();
209 }
210 Ordering::Equal
211 } else {
212 self.assign_round(&src, round)
213 }
214 }
215}
216
217impl AssignRound<&Float> for Float {
218 type Round = Round;
219 type Ordering = Ordering;
220 #[inline]
221 fn assign_round(&mut self, src: &Float, round: Round) -> Ordering {
222 xmpfr::set(self, src, round)
223 }
224}
225
226impl AssignRound<MiniFloat> for Float {
227 type Round = Round;
228 type Ordering = Ordering;
229 #[inline]
230 fn assign_round(&mut self, mut src: MiniFloat, round: Round) -> Ordering {
231 self.assign_round(src.borrow_excl(), round)
232 }
233}
234
235impl AssignRound<&MiniFloat> for Float {
236 type Round = Round;
237 type Ordering = Ordering;
238 #[inline]
239 fn assign_round(&mut self, src: &MiniFloat, round: Round) -> Ordering {
240 self.assign_round(&*src.borrow(), round)
241 }
242}
243
244#[allow(deprecated)]
245impl AssignRound<SmallFloat> for Float {
246 type Round = Round;
247 type Ordering = Ordering;
248 #[inline]
249 fn assign_round(&mut self, src: SmallFloat, round: Round) -> Ordering {
250 self.assign_round(&*src, round)
251 }
252}
253
254#[allow(deprecated)]
255impl AssignRound<&SmallFloat> for Float {
256 type Round = Round;
257 type Ordering = Ordering;
258 #[inline]
259 fn assign_round(&mut self, src: &SmallFloat, round: Round) -> Ordering {
260 self.assign_round(&**src, round)
261 }
262}
263
264#[cfg(feature = "integer")]
265macro_rules! assign {
266 ($T:ty, $func:path) => {
267 impl AssignRound<&$T> for Float {
268 type Round = Round;
269 type Ordering = Ordering;
270 #[inline]
271 fn assign_round(&mut self, src: &$T, round: Round) -> Ordering {
272 $func(self, src, round)
273 }
274 }
275
276 impl AssignRound<$T> for Float {
277 type Round = Round;
278 type Ordering = Ordering;
279 #[inline]
280 fn assign_round(&mut self, src: $T, round: Round) -> Ordering {
281 self.assign_round(&src, round)
282 }
283 }
284 };
285}
286
287#[cfg(feature = "integer")]
288assign! { Integer, xmpfr::set_z }
289#[cfg(feature = "rational")]
290assign! { Rational, xmpfr::set_q }
291
292macro_rules! conv_ops {
293 ($T:ty, $set:path) => {
294 impl AssignRound<$T> for Float {
295 type Round = Round;
296 type Ordering = Ordering;
297 #[inline]
298 fn assign_round(&mut self, src: $T, round: Round) -> Ordering {
299 $set(self, src.into(), round)
300 }
301 }
302
303 assign_round_deref! { $T => Float }
304 };
305}
306
307macro_rules! conv_ops_cast {
308 ($New:ty, $Existing:ty) => {
309 impl AssignRound<$New> for Float {
310 type Round = Round;
311 type Ordering = Ordering;
312 #[inline]
313 fn assign_round(&mut self, src: $New, round: Round) -> Ordering {
314 self.assign_round(src.strict_as::<$Existing>(), round)
315 }
316 }
317
318 assign_round_deref! { $New => Float }
319 };
320}
321
322conv_ops! { i8, xmpfr::set_si }
323conv_ops! { i16, xmpfr::set_si }
324conv_ops! { i32, xmpfr::set_si }
325conv_ops! { i64, xmpfr::set_sj }
326conv_ops! { i128, xmpfr::set_i128 }
327#[cfg(target_pointer_width = "32")]
328conv_ops_cast! { isize, i32 }
329#[cfg(target_pointer_width = "64")]
330conv_ops_cast! { isize, i64 }
331
332conv_ops! { bool, xmpfr::set_ui }
333conv_ops! { u8, xmpfr::set_ui }
334conv_ops! { u16, xmpfr::set_ui }
335conv_ops! { u32, xmpfr::set_ui }
336conv_ops! { u64, xmpfr::set_uj }
337conv_ops! { u128, xmpfr::set_u128 }
338#[cfg(target_pointer_width = "32")]
339conv_ops_cast! { usize, u32 }
340#[cfg(target_pointer_width = "64")]
341conv_ops_cast! { usize, u64 }
342
343#[cfg(feature = "nightly-float")]
344conv_ops! { f16, xmpfr::set_f16 }
345conv_ops! { f32, xmpfr::set_f32 }
346conv_ops! { f64, xmpfr::set_f64 }
347#[cfg(feature = "nightly-float")]
348conv_ops! { f128, xmpfr::set_f128 }
349
350#[cfg(feature = "rational")]
351impl TryFrom<Float> for Rational {
352 type Error = TryFromFloatError;
353 #[inline]
354 fn try_from(value: Float) -> Result<Self, TryFromFloatError> {
355 TryFrom::try_from(&value)
356 }
357}
358
359#[cfg(feature = "rational")]
360impl TryFrom<&Float> for Rational {
361 type Error = TryFromFloatError;
362 #[inline]
363 fn try_from(value: &Float) -> Result<Self, TryFromFloatError> {
364 value
365 .checked_cast()
366 .ok_or(TryFromFloatError { _unused: () })
367 }
368}
369
370fn fmt_radix(flt: &Float, fmt: &mut Formatter<'_>, format: Format, prefix: &str) -> FmtResult {
372 let format = Format {
373 precision: fmt.precision(),
374 ..format
375 };
376 let mut s = StringLike::new_malloc();
377 big::append_to_string(&mut s, flt, format);
378 let st = s.as_str();
379 let (neg, buf) = if let Some(stripped) = st.strip_prefix('-') {
380 (true, stripped)
381 } else {
382 (false, st)
383 };
384 let prefix = if flt.is_finite() { prefix } else { "" };
385 fmt.pad_integral(!neg, prefix, buf)
386}
387
388unsafe impl Send for Float {}
390unsafe impl Sync for Float {}
391
392#[cfg(test)]
393#[allow(clippy::float_cmp)]
394mod tests {
395 use crate::float;
396 use crate::float::{FreeCache, Round};
397 use crate::ops::AssignRound;
398 use crate::{Assign, Float};
399 use core::cmp::Ordering;
400
401 #[test]
402 fn check_assign() {
403 let mut f = Float::with_val(4, 1.0);
404 assert_eq!(f, 1.0);
405
406 let other = Float::with_val(53, 14.75);
407 let mut dir = f.assign_round(&other, Round::Nearest);
408 assert_eq!(f, 15.0);
409 assert_eq!(dir, Ordering::Greater);
410
411 dir = f.assign_round(14.25, Round::Nearest);
412 assert_eq!(f, 14.0);
413 assert_eq!(dir, Ordering::Less);
414
415 f.assign(other);
416 assert_eq!(f, 15.0);
417
418 float::free_cache(FreeCache::All);
419 }
420
421 #[cfg(feature = "rational")]
422 #[test]
423 fn check_fallible_conversions() {
424 use crate::float::Special;
425 use crate::{Float, Rational};
426 let large = [
427 Float::with_val(20, Special::Zero),
428 Float::with_val(20, Special::NegZero),
429 Float::with_val(20, Special::Infinity),
430 Float::with_val(20, Special::NegInfinity),
431 Float::with_val(20, Special::Nan),
432 Float::with_val(20, 1),
433 Float::with_val(20, -1),
434 Float::with_val(20, 999_999e100),
435 Float::with_val(20, 999_999e-100),
436 Float::with_val(20, -999_999e100),
437 Float::with_val(20, -999_999e-100),
438 ];
439 for f in &large {
440 let r = Rational::try_from(f);
441 assert_eq!(r.is_ok(), f.is_finite());
442 if let Ok(r) = r {
443 assert_eq!(r, *f);
444 }
445 }
446
447 float::free_cache(FreeCache::All);
448 }
449}