简体   繁体   English

Rust:f32 上奇怪的基于状态的舍入行为

[英]Rust: Strange state-based rounding behaviour on f32

When computing the dot-product of two nalgebra::Vector3 structs using specific values, I get the following behaviour ( link to playground ):当使用特定值计算两个nalgebra::Vector3结构的点积时,我得到以下行为( 链接到操场):

use nalgebra::{Point3, Vector3}; // 0.31.0

fn dot(v1: Vector3<f32>, v2: Vector3<f32>) -> f32 {
    v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
    
}

fn main() {
    println!("Run 1:");
    let u = Vector3::new(1000., -1000., 0.);
    let v = Vector3::new(-0.69294637441651, 0.720989108085632, 0.);
    println!(
        "self-written dot-product: \t{:.32}",
        dot(u, v)
    );
    println!(
        "nalgebra dot-product: \t\t{:.32}",
        u.dot(&v)
    );
    println!("\nRun2:");
    let u = Vector3::new(1000., -1000., 0.);
    let v = Vector3::new(-0.69294637441651, 0.720989108085632, 0.);
    println!(
        "nalgebra dot-product: \t\t{:.32}",
        u.dot(&v)
    );
}

Output:输出:

Run 1:
self-written dot-product:   -1413.93554687500000000000000000000000
nalgebra dot-product:       -1413.93554687500000000000000000000000
Run2:
nalgebra dot-product:       -1413.93548250214189465623348951339722

I must be able to rely on the computation to always be the same.我必须能够依靠计算始终保持不变。 Any thoughts?有什么想法吗?

Related to my previous question, which I closed due to non-working examples previous question与我之前的问题相关,由于非工作示例,我关闭了之前的问题

As @aedm has mentioned in the comment, your dot() function is the cause for this behavior.正如@aedm 在评论中提到的那样,您的dot()函数是导致这种行为的原因。 As a beginner rustacean it wasn't quite obvious to me how it is exactly a cause, so I put an explanation here.作为一个初学者,我不太清楚这到底是什么原因,所以我在这里解释一下。

When you define variables for the first time,第一次定义变量时,

 9| println!("Run 1:");
10| let u = Vector3::new(1000., -1000., 0.);
11| let v = Vector3::new(-0.69294637441651, 0.720989108085632, 0.);

Rust compiler doesn't know exact type of the values, it only understands that it's float . Rust 编译器不知道值的确切类型,它只知道它是float And if there would be no extra information, the compiler would fall for f64 as a default float type in Rust .如果没有额外的信息,编译器会选择f64作为Rust 中的默认浮点类型

When you call dot(u, v) - you're letting the compiler know the exact types because you specified them on function declaration:当您调用dot(u, v) - 您让编译器知道确切的类型,因为您在函数声明中指定了它们:

 3| fn dot(v1: Vector3<f32>, v2: Vector3<f32>) -> f32 {

The compiler is now certain that the values of u and v are of a type f32 .编译器现在可以确定uv的值属于f32类型。

Then you're using .dot() method, which can handle both f32 and f64 .然后你使用.dot()方法,它可以处理f32f64 The type of u and v is already defined as f32 , and the type of variables cannot be changed, but cause .dot() can handle f32 , it makes the compiler happy. uv的类型已经定义为f32 ,变量的类型不能改变,但是由于.dot()可以处理f32 ,这让编译器很高兴。 At this point you get:此时你得到:

Run 1:
-1413.93554687500000000000000000000000
-1413.93554687500000000000000000000000

After that you're defining new variables with the same names - again the compiler has no explicit information about the type of the variables.之后,您将定义具有相同名称的新变量 - 编译器再次没有关于变量类型的明确信息。 But this time there's no dot(u, v) call, only .dot() and the latter one doesn't require f32 , so the compiler goes for the default f64 .但是这次没有dot(u, v)调用,只有.dot()并且后者不需要f32 ,所以编译器使用默认的f64 In the end you get:最后你得到:

Run2:
-1413.93548250214189465623348951339722

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM