GMP - mpf_cmp_si无法正确处理负值

时间:2015-11-19 11:42:53

标签: rust gmp

我正在通过Rust使用GNU多精度库,我正在尝试为mpf_sqrt()函数编写一个包装器。 为了做到这一点,我需要确保数字是正数,但iframe { position: relative; z-index: 100; /*or higher*/ } 没有表现。

编辑:新例子

mpf_cmp_si()

返回:

extern crate libc;
use libc::{c_double, c_int, c_long, c_ulong, c_void,c_char};
use std::mem::uninitialized;

type mp_limb_t = usize; // TODO: Find a way to use __gmp_bits_per_limb instead.
type mp_bitcnt_t = c_ulong;
type mp_exp_t = c_long;

#[link(name = "gmp")]
extern "C" {
    fn __gmpf_init2(x: mpf_ptr, prec: mp_bitcnt_t);
    fn __gmpf_set_si(rop: mpf_ptr,op: c_int);
    fn __gmpf_cmp_si(op1: mpf_srcptr, op2: c_long) -> c_int;
}

#[repr(C)]
pub struct mpf_struct {
    _mp_prec: c_int,
    _mp_size: c_int,
    _mp_exp: mp_exp_t,
    _mp_d: *mut c_void
}

pub type mpf_srcptr = *const mpf_struct;
pub type mpf_ptr = *mut mpf_struct;

fn main() {
    let mut ten:mpf_struct;
    unsafe{
        ten = uninitialized();
        __gmpf_init2(&mut ten,512);
        __gmpf_set_si(&mut ten,10);
    }
    let mut minus_ten:mpf_struct;
    unsafe{
        minus_ten = uninitialized();
        __gmpf_init2(&mut minus_ten,512);
        __gmpf_set_si(&mut minus_ten,-10);
    }


    // compare things
    unsafe{
        println!("Result of comparison of -10 (mpf) and 10 (signed int) = {}",
            __gmpf_cmp_si(&minus_ten,10));
        println!("Result of comparison of -10 (mpf) and 0 (signed int) = {}",
            __gmpf_cmp_si(&minus_ten,0));
        println!("Result of comparison of 10 (mpf) and 0 (signed int) = {}",
            __gmpf_cmp_si(&ten,0));
    }


}

根据文档,这是行为:

Running `target/debug/so_test`
Result of comparison of -10 (mpf) and 10 (signed int) = 1
Result of comparison of -10 (mpf) and 0 (signed int) = 1
Result of comparison of 10 (mpf) and 0 (signed int) = 1

我在x64 Linux上运行了防锈1.4.0和GMP 6.1.0-1

旧代码:

Function: int mpf_cmp_si (const mpf_t op1, signed long int op2)
Compare op1 and op2. Return a positive value if op1 > op2, zero if op1 = op2, and a negative value if op1 < op2.
     

mpf结构的定义如下:

    pub fn sqrt(self) -> Mpf {
    let mut retval:Mpf;
    unsafe {
        retval = Mpf::new(__gmpf_get_prec(&self.mpf) as usize);
        retval.set_from_si(0);
        if __gmpf_cmp_ui(&self.mpf,0) > 0 {
            __gmpf_sqrt(&mut retval.mpf,&self.mpf);
        } else {
            panic!("Square root of negative/zero");
        }
    }
    retval
}
     

我遇到的问题是#[repr(C)] pub struct mpf_struct { _mp_prec: c_int, _mp_size: c_int, _mp_exp: mp_exp_t, _mp_d: *mut c_void } and the function from gmp is imported like this: #[link(name = "gmp")] extern "C" { fn __gmpf_cmp_si(op1: mpf_srcptr, op2: c_long) -> c_int; } (暴露给Rust   因为mpf_cmp_si)在它应该的时候不会返回负数。

     

如果我的mpf值较小,则此函数应返回负数   但不是这样,函数除以零和崩溃(一个   “未知错误”,不是因为恐慌!()致电)

1 个答案:

答案 0 :(得分:3)

__gmpf_set_si的签名不正确。 C定义是:

void mpf_set_si (mpf_t rop, signed long int op)

因此Rust FFI声明应该使用c_long,而不是c_int

fn __gmpf_set_si(rop: mpf_ptr,op: c_long);

进行此更改会使输出(加上一些额外的打印)如下所示:

Result of comparison of -10 (mpf) and -10 (signed int) = 0
Result of comparison of -10 (mpf) and 0 (signed int) = -1
Result of comparison of -10 (mpf) and 10 (signed int) = -1
Result of comparison of 10 (mpf) and -10 (signed int) = 1
Result of comparison of 10 (mpf) and 0 (signed int) = 1
Result of comparison of 10 (mpf) and 10 (signed int) = 0

(注意:添加与-10 / 10的比较是我如何理解这一点:-10-10相比失败了。)

问题是intlong不一定相同:在64位平台上,它们通常分别是32位和64位。在任何一种情况下,参数都在相同的(64位)寄存器中传递,但类型不匹配意味着寄存器仅使用32位-10进行初始化,这与64位寄存器非常不同。每个的位模式是:

0000000000000000000000000000000011111111111111111111111111110110
1111111111111111111111111111111111111111111111111111111111110110

当被解释为带符号的64位整数(如内部gmpf_set_si那样)时,第一个是2 32 - 10 = 4294967286,这正是minus_ten初始化为:

extern crate libc;
use libc::{c_double, c_int, c_long, c_ulong, c_void,c_char};
use std::mem::uninitialized;

type mp_limb_t = usize; // TODO: Find a way to use __gmp_bits_per_limb instead.
type mp_bitcnt_t = c_ulong;
type mp_exp_t = c_long;

#[link(name = "gmp")]
extern "C" {
    fn __gmpf_init2(x: mpf_ptr, prec: mp_bitcnt_t);
    fn __gmpf_set_si(rop: mpf_ptr,op: c_int);
    fn __gmp_printf(x: *const c_char, ...);
}

#[repr(C)]
pub struct mpf_struct {
    _mp_prec: c_int,
    _mp_size: c_int,
    _mp_exp: mp_exp_t,
    _mp_d: *mut c_void
}
pub type mpf_ptr = *mut mpf_struct;


fn main() {
    unsafe{
        let mut ten = uninitialized();
        __gmpf_init2(&mut ten,512);
        __gmpf_set_si(&mut ten,10);

        let mut minus_ten = uninitialized();
        __gmpf_init2(&mut minus_ten,512);
        __gmpf_set_si(&mut minus_ten,-10);

        __gmp_printf(b"10 == %Ff\n-10 == %Ff\n".as_ptr() as *const c_char,
                     &ten, &minus_ten);
    }
}

输出:

10 == 10.000000
-10 == 4294967286.000000

最后一点,rust-bindgen是一个很好的工具,可以避免像这样的机械转录中的错误:它会根据C头生成正确的东西。