Почему непоследовательность?
Почему Math.round возвращает длинный, но Math.floor возвращает двойной?
Ответ 1
Не существует несогласованности: методы просто разработаны для соответствия различным спецификациям.
-
long round(double a)
- Возвращает ближайший
long
к аргументу.
- Возвращает ближайший
-
double floor(double a)
- Возвращает наибольшее (самое близкое к положительному бесконечности) значение
double
, которое меньше или равно аргументу и равно математическому целому числу. - Сравните с
double ceil(double a)
- Возвращает наибольшее (самое близкое к положительному бесконечности) значение
-
double rint(double a)
- Возвращает значение
double
, которое является самым близким по значению к аргументу и равно математическому целому числу
- Возвращает значение
Итак, по дизайну round
округляет до раундов long
и rint
до double
. Это всегда имело место с JDK 1.0.
Другие методы были добавлены в JDK 1.2 (например, toRadians
, toDegrees
); другие были добавлены в 1.5 (например, log10
, ulp
, signum
и т.д.), и еще некоторые были добавлены в 1.6 (например, copySign
, getExponent
, nextUp
и т.д.) (найдите Так как: метаданные в документации); но round
и rint
всегда были друг с другом так, как они есть сейчас с самого начала.
Возможно, возможно, вместо long round
и double rint
было бы более "согласованным" назвать их double round
и long rlong
, но это аргументировано. Тем не менее, если вы настаиваете на категорическом названии этого "несогласованности", то причина может быть столь же неудовлетворительной, как "потому что это неизбежно".
Здесь цитата из Effective Java 2nd Edition, пункт 40: тщательно подпишитесь на методы метода:
Если вы сомневаетесь, обратитесь к API-интерфейсам библиотеки Java для руководства. Несмотря на то, что существует множество несоответствий - неизбежно, учитывая размер и объем этих библиотек, также существует достаточное количество консенсуса.
Отдаленные вопросы
Ответ 2
floor
был бы выбран в соответствии со стандартной процедурой c в math.h (rint
, упомянутый в другом ответе, также присутствует в этой библиотеке и возвращает double
, как в java).
но round
не был стандартной функцией в c в то время (он не упоминается в C89 - c идентификаторы и стандарты; c99 определяет round
и возвращает double
, как и следовало ожидать). для дизайнеров языков это нормально, чтобы "заимствовать" идеи, так что, возможно, это происходит на каком-то другом языке? fortran 77 не имеет функции этого имени, и я не уверен, что еще было бы использовано тогда в качестве ссылки. возможно, vb - имеет round
, но, к сожалению, для этой теории он возвращает a double
(php тоже). интересно, perl преднамеренно избегает определения раунда.
[обновление: hmmm. выглядит как smalltalk возвращает целые числа. я не знаю достаточно о smalltalk, чтобы узнать, является ли это правильным и/или общим, и метод называется rounded
, но он может быть источником. smalltalk действительно влиял на java в некотором роде (хотя более концептуально, чем подробно).]
если он не маленький, то мы остаемся с гипотезой о том, что кто-то просто выбрал плохо (учитывая, что явные конверсии возможны в java, мне кажется, что возвращение double
было бы более полезным, поскольку тогда это может быть используется как при преобразовании типов, так и при вычислениях с плавающей запятой).
Другими словами: функции, общие для java и c, как правило, согласуются с стандартом библиотеки c в то время; остальные кажутся произвольными, но эта определенная морщина, возможно, исходила из небольшого количества.
Ответ 3
Я согласен, что нечетно, что Math.round(double)
возвращает long
. Если большие значения double
приведены к long
(что неявно Math.round
), возвращается Long.MAX_VALUE
. Альтернатива использует Math.rint()
, чтобы этого избежать. Однако Math.rint()
имеет несколько странное поведение округления: привязки усекаются округлением до четного целого числа, то есть 4.5 округляется до 4.0, а 5.5 округляется до 6.0). Другой вариант - использовать Math.floor(x+0.5)
. Но имейте в виду, что 1.5 округляется до 2, а -1,5 округляется до -1, а не -2. Еще одна альтернатива - использовать Math.round
, но только если число находится в диапазоне между Long.MIN_VALUE и Long.MAX_VALUE. Значения с плавающей запятой с двойной точностью вне этого диапазона целые числа.
К сожалению, почему Math.round()
возвращает long
неизвестно. Кто-то принял это решение, и он, вероятно, никогда не дал интервью, чтобы рассказать нам, почему. Я предполагаю, что Math.round был разработан, чтобы обеспечить лучший способ (т.е. С округлением) для преобразования удвоений в longs.