#java #absolute
#java #абсолютный
Вопрос:
Я использую код, подобный:
Double getabsValue(final Object[] value){
if (value==null) return null;
if (value.lengt==0) return null;
final Double absValue=Maths.abs(value[0]);
if (absValue>0) return absValue
else return null;
Но в моем приложении у меня проблемы с производительностью.
Как это можно оптимизировать?
Может быть, лучше использовать?
if (absValue>0) return absValue
else return absValue<0?-absValue:null;
Спасибо
Комментарии:
1. Насколько вы уверены, что
Math.abs()
это узкое место в производительности?2. Компилируется ли этот код? Это не должно быть, поскольку
java.math.Math#abs(...)
не допускает параметраObject
as.3. это не становится быстрее, чем ваше последнее редактирование, т.е.
if (absValue>0) return absValue else return -1*absValue;
4. @Shahzeb: На самом деле, это может … использование
>= 0
позволит избежатьDouble.valueOf
вызова в случае 0, а также может быть более быстрым сравнением (я подозреваю, что для этого нужно проверить только один бит). Я не знаю, есть ли кэшированное значение дляDouble.valueOf(0)
, но если его нет, бокс может иметь существенное значение, если значение часто равно 0.5. @JonSkeet Спасибо, что подняли этот вопрос, именно такие люди, как вы, делают ТАК, как есть сегодня.
Ответ №1:
Ну, код, который у вас есть на данный момент, даже не будет компилироваться — Math.abs(Object)
насколько мне известно, вызова нет. Однако, предполагая, что у вас действительно есть приведение к Double
нему, вы все время будете боксировать. Вы могли бы избежать бокса, когда значение уже больше 0, и избежать вызова, когда значение равно 0, например:
static Double getAbsValue(Object[] values) {
if (values == null || values.length == 0) {
return null;
}
Double value = (Double) values[0];
return value > 0 ? value
: value == 0 ? null
: -value;
}
К тому времени, когда мы переходим к последнему варианту, мы уже знаем, что значение отрицательное, поэтому нам больше не нужен вызов abs
.
Не совсем понятно, в чем здесь контекст. Вы говорите, что у вас проблема с производительностью, но это определенно в этом коде?
РЕДАКТИРОВАТЬ: ваш последний код показывает:
if (absValue>0) return absValue
else return -1*absValue;
Это не делает то же самое — оно не возвращает null, если массив содержит значение 0 в штучной упаковке, как это делает ваш исходный код.
Вы должны сосредоточиться на правильности перед производительностью.
Что вы хотите, чтобы ваш код делал с вводом 0? Если вы хотите, чтобы оно возвращало 0, я бы использовал:
return value >= 0 ? value : -value;
Если вы хотите, чтобы он возвращал значение null, используйте код, который я предоставил изначально.
Кстати, зачем включать умножение на -1, а не просто использовать оператор унарного отрицания? Я бы ожидал, что либо компилятор, либо JIT все равно избавятся от этого, но в принципе вы не хотите выполнять умножение — вы хотите выполнить отрицание. Сделайте так, чтобы ваш код читался как можно ближе к тому, как вы описали бы свои цели.
Комментарии:
1. Извините, я забыл о приведении к (Double)
2. @user710818: Если вы выполняете кастинг to
Double
, то, скорее всего, автоупаковка и автоматическая распаковка, выполняемые в этом методе (и, вероятно , во всем вашем коде), оказывают гораздо большее влияние на вашу производительность, чем любые вызовы toMath.abs()
. Профилируйте его и убедитесь сами.3. @Joachim Sauer это, безусловно, верно, но есть ли способ обойти это, хотя для OP.
4. @Shahzeb: если он настаивает на изменении только опубликованного кода, то он далеко не уйдет. Ему, вероятно , потребуется внести некоторые большие изменения. Тем не менее: он должен профилировать его, прежде чем что-либо менять.
5. 1: правильность важнее производительности. Не имеет значения, как быстро вы можете сделать что-то, что неверно в 99,9% случаев. Я бы отметил, что использование
double
быстрее, чем использованиеDouble
илиObject
, но я подозреваю, что здесь это не имеет значения,
Ответ №2:
Я использую код, подобный:
Double getabsValue(final Object[] value){
Почему?
Первое, что я бы сделал с этим, это переопределил подпись.
- Бессмысленно указывать
Object[]
, когда оно в основном должно быть aDouble[]
или, по крайней мере, anObject[]
, которое содержит Double , иначе оно вызовет ClassCastException . - Зачем указывать массив, когда вы используете только первый элемент?
- Почему a
Double
, когда вам действительно нужно adouble
?
Поэтому я бы переопределил его, чтобы принять один аргумент типа double
. Это перемещает накладные расходы на получение данных из массива обратно вызывающему, где он может это видеть. У него может даже не быть массива, поэтому ему придется создать его для вызова этого метода. И у него уже может быть double, а не Double, и в этом случае ему или компилятору снова придется преобразовать его в Double.
Второе, что я бы сделал с этим, — это просмотреть, что осталось после этого изменения. Изменение избавляет от проверок null и length и приведения типов, поэтому все, что вам остается, — это return Math.abs(d);
то, что становится ясно, что весь метод в принципе бессмыслен.
Итак, третье, что я бы сделал с ним, это удалить его.