Проверьте, является ли число точно представимым как `f32` - PullRequest
0 голосов
/ 20 февраля 2019

Мне было интересно, точно ли представляются значения 1/256, 2/256, 3/256, ... 254/256 и 255/256 как f32.Теперь кто-то умный подумает о том, как работают числа с плавающей запятой, и выяснит это.Но я хотел бы проверить это в программе.Все числа, которые я хочу проверить, являются дробями, и я управляю значениями (т.е. без ввода данных пользователем).

Я начал с этого:

for n in 1u8..=255 {
    let f = (n as f32) / 256.0;
    println!("{}", f);
}

Но что теперь?Я попытался напечатать число, чтобы увидеть, было ли большое количество повторяющихся цифр, но это не всегда работает.Например, 0,4, которое не совсем представимо:

println!("{}", 0.4);     // prints "0.4"
println!("{:.20}", 0.4); // prints "0.40000000000000002220"

Здесь мы должны вручную повысить точность, чтобы увидеть проблемы.И в любом случае, просмотр выходных данных в любом случае кажется неоптимальным решением.

Сначала я подумал, что может быть метод для f32, но это не имеет большого смысла, не так ли?Потому что, когда f32 уже существует, нет способа узнать, предназначено ли его значение или нет.Таким образом, мы как-то должны выяснить при создании значения с плавающей запятой и сравнить с «идеализированным» значением?

Есть ли способ проверить, может ли значение быть точно представлено как f32?

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Тип Rational из rug ящика может точно представлять дроби.Он также реализует PartialEq<f32>, так что вы можете сравнить точное представление с вашим f32 напрямую, чтобы проверить, равны ли они.

for n in 1u8..=255u8 {
    let rat = Rational::from((n, 256));
    let f = (n as f32) / 256.0;
    println!("{}/256 -> {}", n, rat == f);
}

И, как видно из вывода, числа, которые вы хотите проверить, действительно точно представлены как f32.

Чтобы получить более интересный вывод, попробуйте 1 / n:

for n in 1u8..=255u8 {
    let rat = Rational::from((1, n));
    let f = 1.0 / (n as f32);
    println!("1/{} -> {}", n, rat == f);
}

Это показывает, что только дроби со знаменателем степени 2 точно представимы.

0 голосов
/ 20 февраля 2019

Выполните необходимые вычисления с более высокой точностью (f64 является очевидным и быстрым, но есть альтернативы: например, f128, BigDecimal, rug s rational или float, и т. Д. ), а затем проверьте, что результат равен самому себе, преобразованному в f32 и обратно.

Предполагая f64 ради примера

d.is_finite() && (d as f32) as f64 == d

Конечно, результат этих вычислений может в конечном итоге быть точно представлен как f32, даже если точный результат не будет, как отмечается в комментарии Жожонете.Таким образом, тип данных, который вы хотите, будет зависеть от расчетов.Например, для

1/256, 2/256, 3/256, ... 254/256 и 255/256

rug::rational будет точно точно (так будет f64, но тогда вам нужно «хотя бы немного подумать о том, как работают числа с плавающей точкой и выяснить это»).

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