int total = (int) Math.ceil(157/32);
Почему все равно возвращается 4? 157/32 = 4.90625
, Мне нужно округлить, я огляделась и, кажется, это правильный метод.
Пробовал total
как double
типа, но получилось 4.0.
Что я делаю не так?
Ответы:
Вы делаете то, 157/32
что делите два целых числа друг на друга, что всегда приводит к округленному целому числу. Следовательно, (int) Math.ceil(...)
ничего не делает. Есть три возможных решения для достижения желаемого. Я рекомендую использовать либо вариант 1, либо вариант 2 . Пожалуйста, НЕ используйте опцию 0 .
## Вариант 0
Преобразуйте a
и b
в двойное, и вы сможете использовать деление и Math.ceil
как хотите, чтобы оно работало. Однако я категорически не рекомендую использовать этот подход, потому что двойное деление может быть неточным. Чтобы узнать больше о неточности двойников, смотрите этот вопрос .
int n = (int) Math.ceil((double) a / b));
##Опция 1
int n = a / b + ((a % b == 0) ? 0 : 1);
Вы делаете a / b
с всегда пол, если a
и b
оба являются целыми числами. Затем у вас есть встроенный if-оператор, который проверяет, следует ли вам использовать ceil вместо floor. Итак, +1 или +0, если есть остаток от деления, вам нужен +1. a % b == 0
проверяет остаток.
## Вариант 2
Этот вариант очень короткий, но, возможно, для некоторых менее интуитивно понятных. Я думаю, что этот менее интуитивный подход будет быстрее, чем подход двойного деления и сравнения:
обратите внимание, что это не работает b < 0
.
int n = (a + b - 1) / b;
Чтобы уменьшить вероятность переполнения, вы можете использовать следующее. Однако обратите внимание, что это не работает для a = 0
и b < 1
.
int n = (a - 1) / b + 1;
## Объяснение «менее интуитивного подхода»
Поскольку деление двух целых чисел в Java (и большинстве других языков программирования) всегда приводит к результату. Так:
int a, b;
int result = a/b (is the same as floor(a/b) )
Но мы не хотим floor(a/b)
, но ceil(a/b)
, используя определения и графики из Википедии :
С помощью этих графиков функции пола и потолка вы можете увидеть взаимосвязь.
Вы это видите floor(x) <= ceil(x)
. Нам нужно floor(x + s) = ceil(x)
. Итак, нам нужно найти s
. Если мы возьмем, 1/2 <= s < 1
это будет в самый раз (попробуйте несколько цифр, и вы увидите, что это так, мне самому трудно это доказать). И 1/2 <= (b-1) / b < 1
так
ceil(a/b) = floor(a/b + s)
= floor(a/b + (b-1)/b)
= floor( (a+b-1)/b) )
Это не настоящее доказательство, но я надеюсь, что вы удовлетворены им. Если кто-то может объяснить это лучше, я тоже был бы признателен. Может быть, спросите об этом на MathOverflow .
157/32 int/int
, что приводит к расширению int
.
Попробуйте использовать двойной Литерал - 157/32d
, которая int/double
, что приводит к double
.
157/32
является целочисленным делением, потому что все числовые литералы являются целыми числами, если иное не указано с суффиксом ( d
для double l
для long)
деление округляется в меньшую сторону (до 4) перед преобразованием в двойное (4,0), которое затем округляется в большую сторону (до 4,0)
если вы используете переменные, вы можете избежать этого
double a1=157;
double a2=32;
int total = (int) Math.ceil(a1/a2);
Никто не упомянул самые интуитивные:
int x = (int) Math.round(Math.ceil((double) 157 / 32));
Это решение устраняет неточность двойного деления.
В Java добавление .0 сделает его двойным ...
int total = (int) Math.ceil(157.0 / 32.0);
При делении двух целых чисел, например,
int c = (int) a / (int) b;
результатом является int
значение, a
деленное на b
, округленное до нуля. Поскольку результат уже округлен, ceil()
ничего не делает. Обратите внимание, что это округление отличается от floor()
, которое округляется до отрицательной бесконечности. Итак, 3/2
равно 1
(и floor(1.5)
равно 1.0
, но (-3)/2
равно -1
(но floor(-1.5)
равно -2.0
).
Это очень важно , потому что если a/b
всегда были такими же , как floor(a / (double) b)
, то можно просто реализовать ceil()
в a/b
качестве -( (-a) / b)
.
Предложение получить ceil(a/b)
от
int n = (a + b - 1) / b;
, что эквивалентно a / b + (b - 1) / b
, или(a - 1) / b + 1
работает, потому что ceil(a/b)
всегда на единицу больше floor(a/b)
, кроме a/b
целых чисел. Итак, вы хотите перебросить его (или пройти) до следующего целого числа, если a/b
это не целое число. Добавление 1 - 1 / b
сделает это. Для целых чисел это не совсем подтолкнет их к следующему целому числу. Во всем остальном так и будет.
Ой. Надеюсь, это имеет смысл. Я уверен, что есть более математически элегантный способ объяснить это.
Также, чтобы преобразовать число из целого в действительное, вы можете добавить точку:
int total = (int) Math.ceil(157/32.);
И результат (157/32.) Тоже будет реальным. ;)
Проверьте решение своего вопроса ниже:
int total = (int) Math.ceil(157/32);
Здесь вы должны умножить числитель на 1.0, тогда он даст ваш ответ.
int total = (int) Math.ceil(157*1.0/32);
/
По умолчанию в Java предусмотрено только разделение этажей . Но мы можем обозначить потолок полом . Посмотрим:
В y
форме можно записать любое целое число y == q*k+r
. Согласно определению разделения этажей (здесь floor
), которое округляется r
,
floor(q*k+r, k) == q , where 0 ≤ r ≤ k-1
и разделение потолка (здесь ceil
), которое округляется вверх r₁
,
ceil(q*k+r₁, k) == q+1 , where 1 ≤ r₁ ≤ k
где мы можем заменить r+1
на r₁
:
ceil(q*k+r+1, k) == q+1 , where 0 ≤ r ≤ k-1
Затем мы подставляем первое уравнение в третье, чтобы q
получить
ceil(q*k+r+1, k) == floor(q*k+r, k) + 1 , where 0 ≤ r ≤ k-1
Наконец, учитывая любое целое число , y
где y = q*k+r+1
для некоторых q
, k
, r
мы имеем
ceil(y, k) == floor(y-1, k) + 1
И мы закончили. Надеюсь это поможет.
ceil
определяется как таковое из интуитивного определения, в частности, когда мы берем ceil целого числа, т.е. r1 = k. Поскольку крайние случаи - это то, что здесь сложно, я думаю, что это нужно разъяснить немного подробнее.
Есть два метода округления двойного значения.
Если вы хотите, чтобы ваш ответ 4,90625 был равен 4, вам следует использовать Math.floor, а если вы хотите, чтобы ваш ответ 4,90625 был равен 5, вы можете использовать Math.ceil
Для этого вы можете сослаться на следующий код.
public class TestClass {
public static void main(String[] args) {
int floorValue = (int) Math.floor((double)157 / 32);
int ceilValue = (int) Math.ceil((double)157 / 32);
System.out.println("Floor: "+floorValue);
System.out.println("Ceil: "+ceilValue);
}
}
Я знаю, что это старый вопрос, но, на мой взгляд, у нас есть лучший подход, который использует BigDecimal, чтобы избежать потери точности. Кстати, с помощью этого решения у нас есть возможность использовать несколько стратегий округления и масштабирования.
final var dividend = BigDecimal.valueOf(157);
final var divisor = BigDecimal.valueOf(32);
final var result = dividend.divide(divisor, RoundingMode.CEILING).intValue();
int total = (157-1)/32 + 1
или более общий
(a-1)/b +1