Как вычислить минимум разности вектора значений? - PullRequest
0 голосов
/ 15 мая 2018

Как вычислить минимальную разницу вектора в Rust?

следующий код:

fn main() {
    let vector: Vec<f64> = vec![1.025, 1.028, 1.03, 1.05, 1.051];

    let mut result: Vec<f64> = Vec::new();
    for i in 0..vector.len() - 1 {
        result.push(vector[i] - vector[i + 1]);
    }
    println!("{:?}", result);

    let minimum = std::cmp::min(&result[0], &result[1]);
    println!("{}", minimum)
}

Результат:

error[E0277]: the trait bound `f64: std::cmp::Ord` is not satisfied
  --> src/main.rs:10:19
   |
10 |     let minimum = std::cmp::min(&result[0], &result[1]);
   |                   ^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `f64`
   |
   = note: required because of the requirements on the impl of `std::cmp::Ord` for `&f64`
   = note: required by `std::cmp::min`

Проблемы:

  • нет сравнения между типами f32 / f64

  • только два значения можно сравнить одновременно; как я могу вычислить все значения? Можно ли использовать фолд или это должен быть макрос?

  • Что такое эффективный для памяти способ выполнить различие по вектору? Например, создание диапазона и итерация по вектору (for i in 0..5 { vector[i] }) обходится дороже, чем создание итератора по самому вектору for i in &vector.

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Вы можете сделать это так:

let v = vec![1.025f64, 1.028, 1.03, 1.05, 1.051];
let min = (0..v.len() - 1)
    .map(|i| (v[i] - v[i + 1]).abs())
    .min_by(|a, b| a.partial_cmp(b).unwrap());  // panic on `NaN`

println!("{:?}", min);

Этот код не использует временный вектор для хранения различий.Вместо этого он вычисляет все на лету благодаря ленивым итераторам.Также обратите внимание, что я использую abs() для вычисления абсолютной разницы (это, вероятно, то, что вы хотели).

Чтобы найти минимум, Iterator предлагает ряд методов: min(), min_by_key и min_by.Я использовал позже, чтобы иметь дело с проблемой несопоставимых поплавков.Мой код просто паникует, если мы встречаем значение NaN.Это может быть хорошо для вашего варианта использования, но вы можете ожидать NaN значений и хотите иметь дело с ошибкой.

Результирующая переменная min представляет собой Option<f64>, что равно None, если векторимеет длину 1. Если вектор имеет длину 0, он паникует при индексации v[i + 1].

По поводу вашей проблемы "поплавки неточны": Да, это правда.Единственный способ действительно решить эту проблему - использовать произвольный тип точности.Вероятно, есть пара ящиков, предлагающих такие типы.Но это больше не входит в сферу этого вопроса.

0 голосов
/ 15 мая 2018

Используйте итераторы!

На слайсах можно использовать метод windows() для получения последовательных пар элементов.В вашем случае vector.windows(2) даст: [1.025, 1.028], [1.028, 1.03], [1.03, 1.05] и, наконец, [1.05, 1.051].

Это итератор, поэтому вы можете применить к нему преобразование.В вашем случае я бы предложил map, чтобы сопоставить каждую пару с разницей между двумя элементами пары: .map(|slice| slice[0] - slice[1]).И, возможно, возьмите абсолютную разницу, используя (slice[0] - slice[1]).abs().

Это все еще итератор, так что, наконец, вы можете применить min_by, который даст только минимум всех элементов.Плавает только орудие PartialOrd 1 , поэтому: .min_by(|x, y| x.partial_cmp(y).unwrap()).

В общей сложности на детской площадке :

fn main() {
    let vector = vec![1.025_f64, 1.028, 1.03, 1.05, 1.051];

    let minimum =
        vector.windows(2)
            .map(|slice| (slice[0] - slice[1]).abs())
            .min_by(|x, y| x.partial_cmp(y).unwrap());

    println!("{:?}", minimum);
}

1 Как видно, поплавки МОГУТ сравниваться.Однако из-за присутствия NaN результат составляет Option<Ordering>.В этом случае, предполагая, что во входных данных нет NaN, я просто использовал unwrap, чтобы добраться до основного порядка;если проникнет NaN, он запаникует.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...