|
4 | 4 | //! a struct named `Operation` that implements [`MpOp`].
|
5 | 5 |
|
6 | 6 | use std::cmp::Ordering;
|
| 7 | +use std::ffi::{c_int, c_long}; |
7 | 8 |
|
8 | 9 | use az::Az;
|
| 10 | +use gmp_mpfr_sys::mpfr::rnd_t; |
9 | 11 | use rug::Assign;
|
10 | 12 | pub use rug::Float as MpFloat;
|
| 13 | +use rug::float::Round; |
11 | 14 | use rug::float::Round::Nearest;
|
12 | 15 | use rug::ops::{PowAssignRound, RemAssignRound};
|
13 | 16 |
|
@@ -361,6 +364,32 @@ macro_rules! impl_op_for_ty {
|
361 | 364 | }
|
362 | 365 | }
|
363 | 366 |
|
| 367 | + impl MpOp for crate::op::[<remquo $suffix>]::Routine { |
| 368 | + type MpTy = (MpFloat, MpFloat, MpFloat); |
| 369 | + |
| 370 | + fn new_mp() -> Self::MpTy { |
| 371 | + ( |
| 372 | + new_mpfloat::<Self::FTy>(), |
| 373 | + new_mpfloat::<Self::FTy>(), |
| 374 | + new_mpfloat::<Self::FTy>() |
| 375 | + ) |
| 376 | + } |
| 377 | + |
| 378 | + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { |
| 379 | + this.0.assign(input.0); |
| 380 | + this.1.assign(input.1); |
| 381 | + let (ord, ql) = mpfr_remquo(&mut this.2, &this.0, &this.1, Nearest); |
| 382 | + |
| 383 | + // `remquo` integer results are sign-magnitude representation. Transfer the |
| 384 | + // sign bit from the long result to the int result. |
| 385 | + let clear = !(1 << (c_int::BITS - 1)); |
| 386 | + let sign = ((ql >> (c_long::BITS - 1)) as i32) << (c_int::BITS - 1); |
| 387 | + let q = (ql as i32) & clear | sign; |
| 388 | + |
| 389 | + (prep_retval::<Self::FTy>(&mut this.2, ord), q) |
| 390 | + } |
| 391 | + } |
| 392 | + |
364 | 393 | impl MpOp for crate::op::[<yn $suffix>]::Routine {
|
365 | 394 | type MpTy = MpFloat;
|
366 | 395 |
|
@@ -441,3 +470,24 @@ impl MpOp for crate::op::lgammaf_r::Routine {
|
441 | 470 | (ret, sign as i32)
|
442 | 471 | }
|
443 | 472 | }
|
| 473 | + |
| 474 | +/// `rug` does not provide `remquo` so this exposes `mpfr_remquo`. See rug#76. |
| 475 | +fn mpfr_remquo(r: &mut MpFloat, x: &MpFloat, y: &MpFloat, round: Round) -> (Ordering, c_long) { |
| 476 | + let r = r.as_raw_mut(); |
| 477 | + let x = x.as_raw(); |
| 478 | + let y = y.as_raw(); |
| 479 | + let mut q: c_long = 0; |
| 480 | + |
| 481 | + let round = match round { |
| 482 | + Round::Nearest => rnd_t::RNDN, |
| 483 | + Round::Zero => rnd_t::RNDZ, |
| 484 | + Round::Up => rnd_t::RNDU, |
| 485 | + Round::Down => rnd_t::RNDD, |
| 486 | + Round::AwayZero => rnd_t::RNDA, |
| 487 | + _ => unreachable!(), |
| 488 | + }; |
| 489 | + |
| 490 | + // SAFETY: mutable and const pointers are valid and do not alias, by Rust's rules. |
| 491 | + let ord = unsafe { gmp_mpfr_sys::mpfr::remquo(r, &mut q, x, y, round) }; |
| 492 | + (ord.cmp(&0), q) |
| 493 | +} |
0 commit comments