Переполняемый метод расчета процента от двух длин в Java

У меня есть два неотрицательных длин. Они могут быть большими, рядом с Long.MAX_VALUE. Я хочу рассчитать процент от двух чисел.

Обычно я бы это сделал:

    long numerator = Long.MAX_VALUE / 3 * 2;
    long denominator = Long.MAX_VALUE;

    int percentage = (int) (numerator * 100 / denominator);
    System.out.println("percentage = " + percentage);

Это неверно, если числитель находится в двух порядках от Long.MAX_VALUE.

Какой правильный, простой и быстрый способ сделать это?

Ответ 1

Я бы использовал:

int percentage = (int)(numerator * 100.0 / denominator + 0.5);

100.0 принудительно вычисляет математику с плавающей запятой с этой точки, а раунды + 0.5 округляются до ближайшего целого числа вместо усечения.

Ответ 2

int percentage = (int) (0.5d + ((double)numerator/(double)denominator) * 100);

Если вы разделите long на long, вы получите long, что не подходит для процентов.

Ответ 3

Если мне не хватает чего-то очевидного, вы не можете просто написать:

public class round {
  public static void main(String[] argv) {
    long numerator = Long.MAX_VALUE / 3 * 2;
    long denominator = Long.MAX_VALUE;

    int percentage = (int) (numerator / (denominator / 100));
    System.out.println("percentage = " + percentage);

  }
}

вместо этого? То есть Вместо того, чтобы сделать числитель больше перед делением, уменьшите знаменатель. Поскольку вы знаете, что знаменатель большой, нет никакого риска, что деление даст 0, что является причиной обычно записи (n * 100) / d, когда вы не используете числа с плавающей запятой.

Ответ 4

Тривиальный способ состоит в том, чтобы преобразовать оба значения в float или double, прежде чем выполнять вычисления, за счет небольшой потери точности. Он также медленный, по сравнению с альтернативами.

Один из вариантов состоит в том, чтобы разделить каждое значение на две 32-битные компоненты и сделать длинное умножение и длительное разделение.

Ответ 5

Ребята реализуют следующим образом, потому что предлагается делать вычисления с помощью BigDecimal и BigInteger. Вот реализация:

    BigDecimal n = new BigDecimal(Long.MAX_VALUE);
    BigDecimal d = new BigDecimal(Long.MAX_VALUE);
    BigDecimal i = new BigDecimal(100);
    int percentage = n.multiply(i).divide(d).intValue();
    System.out.println(percentage);