Как проверить, делится ли число u64 больше 2 ^ 54 на f64 с минимальной потерей точности? - PullRequest
3 голосов
/ 28 мая 2020

Для числа u64 меньше 2 ^ 54 это можно сделать без особой потери точности путем преобразования в f64:

((6 as f64) % 1.5) < f64::EPSILON

Для больших чисел будет значительная потеря точности :

1u64 << 63           // 9223372036854775808
(1u64 << 63) as f64  // 9223372036854776000

и делимость будет проверена для другого числа.

Контекст : реализация ключевого слова JSONSchema multipleOf

Вопрос : как наиболее эффективно проверить делимость чисел u64 / i64, не соответствующих размеру мантиссы f64 (f64::MANTISSA_DIGITS 53)?

1 Ответ

5 голосов
/ 28 мая 2020

Вот решение, учитывая, что u - некоторое целое число, а x - конечное ненулевое двоичное число IEEE-754, с которым мы выполняем арифметические операции c IEEE-754. Предполагается, что x представляет одно конкретное число c, как указано в IEEE-754, и предыдущие ошибки округления, возникшие при получении x, не рассматриваются. Этот ответ относится к задействованной математике, а не к семантике Rust, поскольку я не знаком с Rust.

Сначала найдите представление x = F • 2 E, где F - нечетное целое, а E - целое. Простой способ для этого:

  • Установить F на x и E на 0.
  • Хотя F не является целым числом, умножьте F на два и вычтите единицу из E.
  • Пока F четное, разделите F на два и прибавьте единицу к E.

Все вышеперечисленное операции могут выполняться в арифметических c IEEE-754 * без ошибок округления. Если Rust предлагает метод разделения мантиссы и экспоненты числа с плавающей запятой, сродни функции C frexp, то включение его в приведенное выше может повысить эффективность.

Теперь подумайте, является ли u кратно x = F • 2 E. По определению, это тогда и только тогда, когда существует целое число k такое, что u = kF • 2 E. Мы увидим, что это так, если и только если u кратно F и кратно 2 E, и каждое из них можно проверить.

Если 2 E является целым числом (E неотрицательно) и такое k существует, то u кратно F и кратно 2 E. И наоборот, если u не кратно F или не кратно 2 E, то такого k не существует (в соответствии с основной теоремой арифметики c

F обязательно находится в границах запрошенного целочисленного формата (это не более 53 бит), и мы предполагаем, что F можно преобразовать в этот формат. Затем можно проверить делимость u на F. Если 2 E превышает максимальное значение целочисленного формата, в котором представлено u, то u не является кратным 2 E. В противном случае 2 E можно преобразовать в формат, и можно проверить делимость u на 2 E.

Если 2 E не является целым числом (E отрицательно), то, если требуемое k существует (поэтому u кратно F), оно кратно 2 - E. И наоборот, если k не кратно 2 - E, тогда kF • 2 E не является целым числом, поэтому он не может равно u. Таким образом, u кратно x тогда и только тогда, когда u кратно F.

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