Почему в Android API так много поплавков? - PullRequest
16 голосов
/ 19 марта 2010

Тип с плавающей точкой по умолчанию в Java - double. Если вы жестко закодируете константу типа 2.5 в своей программе, Java автоматически удваивает ее. Когда вы выполняете операцию над числами с плавающей запятой или целыми числами, которые потенциально могут получить большую точность, тип «повышается» до двойного.

Но в Android API все кажется плавным: от громкости звука до координат прямоугольника. Есть структура под названием RectF, используемая в большинстве рисунков; F для поплавка. Это действительно боль для программистов, которые часто переводят продвинутые парные значения обратно в (float). Разве мы все не согласны с тем, что Java-код достаточно грязный и многословный?

Обычно математические сопроцессоры и ускорители предпочитают double в Java, поскольку он соответствует одному из внутренних типов. Есть ли что-то в Android Dalvik VM, которое по какой-то причине предпочитает поплавки? Или все поплавки являются результатом извращения в дизайне API?

Ответы [ 5 ]

43 голосов
/ 19 марта 2010

На устройствах без FPU операции с плавающей запятой одинарной точности выполняются намного быстрее, чем эквиваленты двойной точности.Из-за этого платформа Android предоставляет класс FloatMath, который реплицирует некоторые функции java.lang.Math, но с аргументами float вместо double.

На последних устройствах Android с FPU - время, необходимое дляОперации двойной точности примерно одинаковы и значительно быстрее, чем программная реализация.(Страница «Проектирование для повышения производительности» была написана для G1 и требует обновления, чтобы отразить различные изменения.)

Кстати, написание «2.5f» или «(float) 2.5» не имеет значения.В любом случае, javac знает, что вы хотите использовать константу с плавающей точкой одинарной точности, и именно это она генерирует.В этом можно убедиться, написав пример программы и изучив сгенерированный байт-код.

8 голосов
/ 19 марта 2010

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

7 голосов
/ 19 марта 2010

Для метрик, которым не нужно слишком много значащих цифр (например, смещения экрана), было бы неэффективно использовать память double с вместо float с. Максимизация эффективности в отношении потребления памяти жизненно важна для мобильных устройств, где практически все ресурсы имеют высокую цену. И, когда имеешь дело с такими объектами, как Rect s - которые потенциально могут быть выделены тысячами - явно важно сократить лишние биты.

Я уверен, что есть и другие причины: -)

3 голосов
/ 19 марта 2010

Weird. Проектирование производительности в руководстве, похоже, гласит: «.... Обычная практика в настольных системах заключается в свободном использовании плавающей запятой ...... поэтому все операции над« float »и« double »выполняются программно ... . "в http://developer.android.com/guide/practices/design/performance.html#avoidfloat

Это может иметь некоторый смысл: «.... Инструкции не ограничены безвозмездно определенным типом. Например, инструкции, которые перемещают 32-битные значения регистров без интерпретации, не должны указывать, являются ли они движущимися числами или плавающими .....» в http://www.netmite.com/android/mydroid/dalvik/docs/dalvik-bytecode.html

1 голос
/ 19 марта 2010

Я думаю, что Роман прав, потому что причина скорее всего в том, чтобы уменьшить использование памяти. Учтите, что, когда предельная точность не важна, вы вдвое уменьшите объем памяти, необходимый для числовых переменных.

Помните, что нет необходимости использовать кастинг. Просто добавьте F к вашему литералу (так что 2.5 становится 2.5f). Я не знаю, достаточно ли умен компилятор, чтобы выполнить следующую замену, но если нет, это также сделает ваш код немного более эффективным.

Рассмотрим

float x = (float) 2.5;

и

float x = 2.5f;

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

...