我正在通过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值较小,则此函数应返回负数 但不是这样,函数除以零和崩溃(一个 “未知错误”,不是因为恐慌!()致电)
答案 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
相比失败了。)
问题是int
和long
不一定相同:在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头生成正确的东西。