Более быстрая реализация математики.круглый?


Есть ли какие-либо недостатки в этом коде, который, по-видимому, является более быстрой (и правильной) версией java.lang.Math.round?

public static long round(double d) {

    if (d > 0) {
        return (long) (d + 0.5d);
    } else {
        return (long) (d - 0.5d);
    }
}

Он использует тот факт, что в Java усечение до длинных раундов равно нулю.

3 5

3 ответа:

Есть некоторые особые случаи, которые обрабатываются встроенным методом, но не обрабатываются вашим кодом. Из документации:

  • если аргумент равен NaN, то результат равен 0.
  • Если аргумент равен отрицательной бесконечности или любому значению, меньшему или равному значению Integer.MIN_VALUE, то результат равен значению Integer.MIN_VALUE.
  • если аргументом является положительная бесконечность или любое значение больше или равный значению Integer.MAX_VALUE, результат равен значению Integer.MAX_VALUE.

Да; вы не учитываете недостаточный поток или переполнение. Прагматически говоря, это может не иметь значения для вашего приложения.

Я проверял это, и есть один ключевой потенциальный недостаток, который еще не был описан здесь: вы меняете метод округления tie-breaking.

Math.round() реализует правило "округлить половину вверх", в то время как ваш метод round() реализует правило" округлить половину от нуля".

Например:

  • Math.round(-0.5d) => 0L
  • Your.round(-0.5d) => -1L

Это может быть или не быть проблемой для вас, но вы должны понимать, что вышесказанное метод не является падающей заменой для Math.round(), даже после уже описанных соображений NaN и бесконечности.

Еще один важный вопрос: округление отрицательных чисел в Java

Что касается производительности, то нет никаких сомнений в том, что описанный выше метод значительно быстрее, чем Math.round() - он работает примерно в 35% случаев для случайно генерируемых положительных и отрицательных значений. Это может быть полезной оптимизацией при вызове этого метода в узком цикле. Это даже лучше. (25% времени выполнения), когда заданы только положительные значения, возможно, из-за процессора, использующего предсказание ветвей.

Math.round() в конечном счете реализуется собственным вызовом JNI, который может быть причиной разницы в производительности. эта ошибка Sun/Oracle предполагает, что в j6u22 может быть версия pure-Java, но я не вижу, где, и действительно Math.round() в j6u23 выполняет аналогично j6u16 в моих тестах. Я не тестировал на других версиях.