如何为浮点数实现三个中两个最大数的平方和?

时间:2015-04-07 16:11:56

标签: rust

本书Structure and Interpretation of Computer Programs的练习1.3要求如下:

  

定义一个过程,该过程将三个数字作为参数,并返回两个较大数字的平方和。

我设法回答了这个问题,但只针对整数:

use std::cmp;

fn sum_square_largest(x:isize, y:isize, z:isize) -> isize {
    x * x + y * y + z * z - min_three(x, y, z) * min_three(x, y, z)
}

fn min_three<T>(v1: T, v2: T, v3: T) -> T where T: Ord {
    cmp::min(v1, cmp::min(v2, v3))
}

但是当我将sum_square_largest函数更改为:

fn sum_square_largest(x:f64, y:f64, z:f64) -> f64 {
    x * x + y * y + z * z - min_three(x, y, z) * min_three(x, y, z)
}

它提供以下error: the trait 'core::cmp::Ord' is not implemented for the type 'f64' [E0277]

这是什么?如何定义此函数以使用浮点数?

2 个答案:

答案 0 :(得分:3)

浮点数不会实现Ord,因为它们没有总排序。 NaN与任何值进行比较都是错误的,包括另一个NaN

如果您每晚使用Rust,可以使用partial_min,这会使这些案例明确。

您还可以决定在NaN之类的情况下做什么,然后在f64上实现包装器类型,并为其实现Ord,以便它处理情况下。

答案 1 :(得分:0)

如果要避免致命的舍入错误,则需要根据需要编写代码:通过添加三个数字中的两个的平方。否则,如果您有例如x = y = 1和z = -1e100,那么您将遇到灾难性的舍入错误。三个方块的总和四舍五入为1e200,减去相同,结果为0而不是2.

可能更糟糕:如果z = -1e200,那么z * z溢出,三个正方形加起来+ inf,你减去+ inf并得到NaN。

let x1 = if x > y { x } else { y };
let mut x2 = if x > y { y } else { x };
if z > x2 { x2 = z; }

x1 * x1 + x2 * x2;

如果您考虑使用NaN,情况会稍微复杂一些。显然,如果你有两个或三个NaN,结果将是NaN。如果你有一个NaN,你需要决定(a)你不关心,(b)结果应该是NaN还是(c)结果应该是两个数字的平方和NaN的。在情况(b)或(c)中,结果应仅取决于三个值,而不取决于它们的使用顺序。

上述代码涵盖(a)。如果你想要(b),那么你需要确保z如果是NaN则存储到x2中,如果是NaN则x2保持不变。您可以通过将最后一行更改为

来实现此目的
if z > x2 || z != z { x2 = z };

如果你想要(c)它有点复杂。

let x1 = if x > y || y != y { x } else { y };
let mut x2 = if x > y || y != y { y } else { x };
if z > x2 || x2 != x2 { x2 = z; }