Чому Math.floor повертає подвійний?


103

Офіційний Javadoc каже, що Math.floor()повертає a, doubleщо "дорівнює математичному цілому", але чому він не повинен повертати int?

Відповіді:


80

Згідно з тим же Javadoc:

Якщо аргумент - NaNце нескінченний чи позитивний нуль або від’ємний нуль, то результат такий же, як аргумент. Неможливо зробити це з int.

Найбільше doubleзначення також більше, ніж найбільше int, тому воно повинно бути а long.


40
видається невідповідним функціям Math.Round, які повертаються до int / long і по-різному обробляють спеціальні випадки.
zod

1
Зауважте, Javadoc говорить, що він повертає "найбільше (найближче до позитивної нескінченності) * значення з плаваючою комою *, яке менше аргументу або дорівнює і дорівнює математичному цілому" . Дано значення x> 2 ^ 53, яке не буде таким, як значення з усіченою його дробовою частиною. Це може бути зовсім трохи менше, ніж це.
Джим Гаррісон

16

Це для точності. Подвійний тип даних має 53-бітну мантісу. Крім усього іншого, це означає, що подвійний може представляти всі цілі до 2 ^ 53 без втрати точності.

Якщо ви збережете таку велику кількість в цілому числі, ви отримаєте переповнення. Цілі числа мають лише 32 біти.

Повернення цілого числа як подвійного - це правильна справа, оскільки воно пропонує набагато ширший корисний діапазон чисел, ніж ціле число.


Звичайно, це може повернутися довго, щоб впоратися з такими цінностями. Вам все одно доведеться розібратися, що робити з парними> 2 ^ 63, хоча.
Джон Скіт

1
@Jon, правда, але це призведе до впливу продуктивності (жодна інструкція перетворення від довгої до подвійної в будь-якому наборі інструкцій, про який я знаю). Цікаво, що Math.floor робить з парними> 2 ^ 53 в першу чергу. Деякі результати не є репрезентативними.
Нілс Піпенбрінк

Але тоді псевдоідіоматична форма (int) Math.floor (foo), яка з'являється і в офіційному javadoc, є небезпечною, оскільки результат може не вписатись у int, чи я прав? І знову ж таки, яка безпечна форма використання Math.floor, оскільки результат може не вписатися навіть у довгі?
Райбаз

10

Інші сказали вам, чому я збираюся сказати вам, як правильно округлити, якщо ви хочете це зробити. Якщо ви збираєтесь використовувати лише додатні цифри, ви можете використовувати цей вислів:

int a=(int) 1.5;

Однак (int) завжди округляється до 0. Таким чином, якщо ви хочете зробити від'ємне число:

int a=(int) -1.5; //Equal to -1

У моєму випадку я цього не хотів робити. Я використовував наступний код для округлення, і, здається, добре обробляє всі крайові випадки:

private static long floor(double a)
{
    return (int) Math.floor(a);
}

7
Чому б не використовувати (int) Math.floor(a)? Це, мабуть, більш ефективно і коротше.
Соломон Учко

@Solomon Ucko замість (int) Math.floor(a)вас може просто написати (int) a, якщо a є позитивним.
Лев Леонтьєв

3

Що б ви хотіли, щоб він повернувся, якби ви дали йому вдвічі більше, ніж найбільший int або long?

(Правда, якщо вона більша, ніж найбільша довга, точність все одно буде низькою - це може бути не найближче теоретичне ціле число - але навіть так ...)


0

Так само, як у Яві є ділення на ціле число і плаваючу крапку, існують способи виконання підлоги на цілі та плаваючі точки:

double f = Math.floor(x);

або

int k = (int) x; 

але завжди потрібно бути обережним при використанні підлоги з обмеженою арифметикою точності: ваш розрахунок x може отримати щось на зразок 1.99999999, яке буде порівну до 1, а не 2 в обох формах. Існує багато алгоритмів, які потребують подолання цього обмеження, щоб уникнути отримання помилкових результатів для деяких вхідних значень.


0

Отже, помилка та інші не цілі значення можуть правильно каскадуватись через ряд обчислень.

Наприклад, якщо ви подаєте не номер (NaN) в Math.floor, він передасть це разом.

Якщо він повернув ціле число, він не міг би передати ці статуси або помилки, і ви можете отримати погані результати від попереднього обчислення, які виглядають добре, але помиляються після подальшої обробки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.