为什么从C(来自维基百科)移植的希尔伯特曲线实现似乎失败了?



我在维基百科上找到了以下绘制希尔伯特曲线的代码:

//convert (x,y) to d
int xy2d (int n, int x, int y) {
int rx, ry, s, d=0;
for (s=n/2; s>0; s/=2) {
rx = (x & s) > 0;
ry = (y & s) > 0;
d += s * s * ((3 * rx) ^ ry);
rot(s, &x, &y, rx, ry);
}
return d;
}
//convert d to (x,y)
void d2xy(int n, int d, int *x, int *y) {
int rx, ry, s, t=d;
*x = *y = 0;
for (s=1; s<n; s*=2) {
rx = 1 & (t/2);
ry = 1 & (t ^ rx);
rot(s, x, y, rx, ry);
*x += s * rx;
*y += s * ry;
t /= 4;
}
}
//rotate/flip a quadrant appropriately
void rot(int n, int *x, int *y, int rx, int ry) {
if (ry == 0) {
if (rx == 1) {
*x = n-1 - *x;
*y = n-1 - *y;
}
//Swap x and y
int t  = *x;
*x = *y;
*y = t;
}
}

我把它放到 c2rust.com,并将 rot(( 的定义作为第一个函数,并得到以下代码:

#![allow(dead_code,
mutable_transmutes,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unused_mut)]
#![feature(libc)]
extern crate libc;
// rotate/flip a quadrant appropriately
#[no_mangle]
pub unsafe extern "C" fn rot(mut n: libc::c_int,
mut x: *mut libc::c_int,
mut y: *mut libc::c_int,
mut rx: libc::c_int,
mut ry: libc::c_int)
-> () {
if ry == 0i32 {
if rx == 1i32 {
*x = n - 1i32 - *x;
*y = n - 1i32 - *y
}
// Swap x and y
let mut t: libc::c_int = *x;
*x = *y;
*y = t
};
}
// convert (x,y) to d
#[no_mangle]
pub unsafe extern "C" fn xy2d(mut n: libc::c_int,
mut x: libc::c_int,
mut y: libc::c_int)
-> libc::c_int {
let mut rx: libc::c_int = 0;
let mut ry: libc::c_int = 0;
let mut s: libc::c_int = 0;
let mut d: libc::c_int = 0i32;
s = n / 2i32;
while s > 0i32 {
rx = (x & s > 0i32) as libc::c_int;
ry = (y & s > 0i32) as libc::c_int;
d += s * s * (3i32 * rx ^ ry);
rot(s, &mut x, &mut y, rx, ry);
s /= 2i32
}
return d;
}
// convert d to (x,y)
#[no_mangle]
pub unsafe extern "C" fn d2xy(mut n: libc::c_int,
mut d: libc::c_int,
mut x: *mut libc::c_int,
mut y: *mut libc::c_int)
-> () {
let mut rx: libc::c_int = 0;
let mut ry: libc::c_int = 0;
let mut s: libc::c_int = 0;
let mut t: libc::c_int = d;
*y = 0i32;
*x = *y;
s = 1i32;
while s < n {
rx = 1i32 & t / 2i32;
ry = 1i32 & (t ^ rx);
rot(s, x, y, rx, ry);
*x += s * rx;
*y += s * ry;
t /= 4i32;
s *= 2i32
}
}
fn main() {
let mut x: libc::c_int = 0;
let mut y: libc::c_int = 0;
let d: libc::c_int = 10;
unsafe {
for n in 1..10 {
d2xy(n, d, &mut x, &mut y);
println!("n={}, x={}, y={}", n, x, y);
}
}
}

问题是结果似乎毫无意义:

Compiling x v0.1.0 (file:///tmp/x)
warning: value assigned to `rx` is never read                            ] 0/1: x                                                                                                                
--> src/main.rs:34:13
|
34 |     let mut rx: libc::c_int = 0;
|             ^^
|
= note: #[warn(unused_assignments)] on by default
warning: value assigned to `ry` is never read
--> src/main.rs:35:13
|
35 |     let mut ry: libc::c_int = 0;
|             ^^
warning: value assigned to `s` is never read
--> src/main.rs:36:13
|
36 |     let mut s: libc::c_int = 0;
|             ^
warning: value assigned to `rx` is never read
--> src/main.rs:55:13
|
55 |     let mut rx: libc::c_int = 0;
|             ^^
warning: value assigned to `ry` is never read
--> src/main.rs:56:13
|
56 |     let mut ry: libc::c_int = 0;
|             ^^
warning: value assigned to `s` is never read
--> src/main.rs:57:13
|
57 |     let mut s: libc::c_int = 0;
|             ^
Finished dev [unoptimized + debuginfo] target(s) in 0.25s                                                                                                                                    
Running `target/debug/x`
n=1, x=0, y=0
n=2, x=1, y=1
n=3, x=3, y=3
n=4, x=3, y=3
n=5, x=3, y=3
n=6, x=3, y=3
n=7, x=3, y=3
n=8, x=3, y=3
n=9, x=3, y=3

我绝对没想到不同的 Ns 会重复坐标。可能出了什么问题?以下是用于比较的 C 测试代码:

int main() {
int n=32, d=0, x=0, y=0;
for (d=0; d<10; d++) {
d2xy(n, d, &x, &y);
printf("d=%d, x=%d, y=%dn", d, x, y);
}
}

和预期输出(由 C 生成(:

d=0, x=0, y=0
d=1, x=0, y=1
d=2, x=1, y=1
d=3, x=1, y=0
d=4, x=2, y=0
d=5, x=3, y=0
d=6, x=3, y=1
d=7, x=2, y=1
d=8, x=2, y=2
d=9, x=3, y=2

好吧,如果你改变测试代码,你自然会得到不同的输出。 原始 C 测试代码修复了nd变化;您修复d并改变n.

一旦我更改了 Rust 测试代码以执行与 C 测试代码相同的操作,我就会得到相同的输出。

fn main() {
let mut x: libc::c_int = 0;
let mut y: libc::c_int = 0;
let d: libc::c_int = 10;
unsafe {
for n in 1..10 {
d2xy(n, d, &mut x, &mut y);
println!("n={}, x={}, y={}", n, x, y);
}
}
}

最新更新