Статьи

Выпуск 11 в Guava IntMath

Как я уже говорил ранее в посте Sneaking a Peek at Guava Release 11 , Guava Release 11 предоставляет множество новых классов, включая несколько классов, специально связанных с математическими операциями. В этой статье я расскажу об одном из них, который нацелен на целочисленную математику: Guava ‘s IntMath .

Как указано в моем предыдущем посте, com.google.common.math.IntMath в значительной степени основана на Генри С. Уоррен, младший «S Хакера Delight . Как указывает имя класса, операции этого класса сосредоточены на «арифметике значений типа int».

На следующем снимке экрана показаны методы и статические атрибуты, поддерживаемые IntMath, как указано в javap :

Для удобства я перечислил текстовую версию вышеупомянутого вывода javap здесь.

Compiled from "IntMath.java"
public final class com.google.common.math.IntMath {
  static final int MAX_POWER_OF_SQRT2_UNSIGNED;
  static final int[] POWERS_OF_10;
  static final int[] HALF_POWERS_OF_10;
  static final int FLOOR_SQRT_MAX_INT;
  static final int[] FACTORIALS;
  static int[] BIGGEST_BINOMIALS;
  public static boolean isPowerOfTwo(int);
  public static int log2(int, java.math.RoundingMode);
  public static int log10(int, java.math.RoundingMode);
  public static int pow(int, int);
  public static int sqrt(int, java.math.RoundingMode);
  public static int divide(int, int, java.math.RoundingMode);
  public static int mod(int, int);
  public static int gcd(int, int);
  public static int checkedAdd(int, int);
  public static int checkedSubtract(int, int);
  public static int checkedMultiply(int, int);
  public static int checkedPow(int, int);
  public static int factorial(int);
  public static int binomial(int, int);
  static {};
}

Как показывают вышеприведенные изображения и текстовые данные, класс IntMath может многое предложить с точки зрения функциональности, связанной с целочисленной арифметикой. Остальная часть этого поста продемонстрирует это.

Факторный расчет обычно применяется в примерах разработки программного обеспечения, особенно в академических контекстах, таких как иллюстрирование рекурсии . Сообщение в блоге Реализация факториальной функции с использованием Java и Guava посвящено различным реализациям факториала, реализованным в Java и Guava. Guava Release 11 теперь предоставляет метод вычисления факториала в IntMath.factorial (int) .

Guava’s IntMath.factorial (int), продемонстрированный

   /**
    * Demonstrate factorial calculation.
    */
   public static void demoFactorial()
   {
      final int x = 5;
      final int factorial = IntMath.factorial(x);
      out.println("Factorial of x=" + x + " is " + factorial);
   }

Другой часто математической операцией, поддерживаемой Guava Release 11, является вычисление биномиального коэффициента через IntMath.binomial (int, int) .

Guava’s IntMath.binomial (int, int), продемонстрированный

   /**
    * Demonstrate binomial Coefficient calculation
    * (http://en.wikipedia.org/wiki/Binomial_coefficient).
    */
   public static void demoBinomialCoefficient()
   {
      final int n = 5;
      final int k = 3;
      final int binomialCoefficient = IntMath.binomial(n, k);
      out.println(
           "Binomial Coefficient of n=" + n + " and k=" + k + " is "
         + binomialCoefficient);  
   }

Guava Release 11 также добавляет метод для вычисления наибольшего общего делителя двух предоставленных целых чисел.

Guava’s IntMath.gcd (int, int), продемонстрированный

   /**
    * Demonstrate calculation of greatest common factor (GCF) [called greatest
    * common divisor here].
    */
   public static void demoGreatestCommonFactor()
   {
      final int x = 30;
      final int y = 45;
      final int gcf = IntMath.gcd(x, y);
      out.println("GCF of " + x + " and " + y + " is " + gcf);
   }

Релиз 11 в Guava предоставляет метод для вычисления целочисленного квадратного корня из предоставленного целого числа, округляя до целочисленного результата, когда это необходимо, на основе предоставленного RoundingMode . Тот факт, что результатом функции квадратного корня является целое число, отличает этот метод от Math.sqrt (double) .

Guava’s IntMath.sqrt (int) продемонстрировано

   /**
    * Demonstrate calculation of square roots.
    */
   public static void demoSquareRoot()
   {
      final int x = 16;
      final int sqrtX = IntMath.sqrt(x, RoundingMode.HALF_EVEN);
      out.println("Square root of " + x + " is " + sqrtX);
      final int y = 25;
      final int sqrtY = IntMath.sqrt(y, RoundingMode.HALF_EVEN);
      out.println("Square root of " + y + " is " + sqrtY);  
   }

IntMath в версии 11 релиза Guava предоставляет метод pow (int, int) для первого целого числа, умноженного на себя число раз, выраженное вторым целым числом (аналогично Math.pow (double, double)) , но принимающее и возвращающее целые числа, а не удваивающиеся. ). Метод IntMath.pow (int, int) обеспечивает обработку ситуаций, в которых операция обычно приводит к переполнению. В такой ситуации, согласно Javadoc метода , метод вернет результат, который «будет равен BigInteger.valueOf (b) .pow (k) .intValue ()».

Guava’s IntMath.pow (int, int), продемонстрированный

   /**
    * Demonstrate exponential power calculation.
    */
   public static void demoExponentialPower()
   {
      final int base = 2;
      final int exponent = 5;
      final int result = IntMath.pow(base, exponent);
      out.println(base + " to power of " + exponent + " is " + result);
   }

Особенно интересный метод, который предоставляет Guava Release 11, который может быть особенно полезен в определенных разработках программного обеспечения и компьютерных контекстах, — это метод IntMath.isPowerOfTwo (int) . Этот метод возвращает логическое значение, указывающее, является ли предоставленное целое число равномерно делимым (без остатка) на два.

Guava’s IntMath.isPowerOfTwo (int) Демонстрируется

   /**
    * Demonstrate determination of whether an integer is a power of two.
    */
   public static void demoIsPowerOfTwo()
   {
      final int x = 16;
      out.println(x + (IntMath.isPowerOfTwo(x) ? " IS " : " is NOT " ) + " a power of two.");
      final int y = 31;
      out.println(y + (IntMath.isPowerOfTwo(y) ? " IS " : " is NOT " ) + " a power of two.");
   }

Класс IntMath в Guava предоставляет два метода для выполнения логарифмических вычислений, уделяя особое внимание общему логарифму (основание 10) и двоичному логарифму (основание 2). Оба из них продемонстрированы в следующем листинге кода.

IntMath.log10 в Guava (int, RoundingMode) и IntMath.log2 (int, RoundingMode) продемонстрированы

   /**
    * Demonstrate IntMath.log10 and IntMath.log2.
    */
   public static void demoLogarithmicFunctions()
   {
      final int x = 10000000;
      final int resultX = IntMath.log10(x, RoundingMode.HALF_EVEN);
      out.println("Logarithm (base 10) of " + x + " is " + resultX);
      final int y = 32;
      final int resultY = IntMath.log2(y, RoundingMode.HALF_EVEN);
      out.println("Logarithm (base 2) of " + y + " is " + resultY);
   }

IntMath.divide версии 11 для Guava (int, int, RoundingMode) допускает целочисленное деление, при котором тип округления, используемый в делении, может быть указан как часть вызова. Это более гибко, чем прямое целочисленное деление Java, которое всегда округляет частное до нижнего целого (минимальное).

IntMath.divide в Guava (int, int, RoundingMode) Демонстрируется

   /**
    * Demonstrate division using IntMath.divide.
    */
   public static void demoDivision()
   {
      final int dividend = 30;
      final int divisor = 10;
      final int quotient = IntMath.divide(dividend, divisor, RoundingMode.HALF_EVEN);
      out.println(dividend + " / " + divisor + " = " + quotient);
   }

Ранее я упоминал, что IntMath.pow (int, int) в Guava версии 11 будет обрабатывать ситуации переполнения, возвращая «BigInteger.valueOf (b) .pow (k) .intValue ()», где «b» — это первое целое число (основание) и ‘k’ — второе целое число (степень / показатель степени). В некоторых случаях может быть предпочтительным создать исключение при возникновении ситуации переполнения, а не «скрывать» проблему. В таких случаях желательно использовать IntMath.checkedPow (int, int) из Guava Release 11, поскольку он вызывает исключение ArithmeticException, если операция приводит к переполнению.

IntMath.checkedPow (int, int) Демонстрируется

   /**
    * Demonstrate Guava Release 11's checked power method and compare it to
    * other common approaches for determining base multiplied by itself exponent
    * number of times.
    */
   public static void demoCheckedPower()
   {
      try
      {
         final int base = 2;
         final int exponent = 4;
         final int result = IntMath.checkedPow(base, exponent);
         out.println("IntMath.checkedPow: " + base + "^" + exponent + " = " + result);

         out.println(
              "IntMath.pow: " + Integer.MAX_VALUE + "^2 = " +
            + IntMath.pow(Integer.MAX_VALUE, 2));
         out.println(
              "Math.pow(int,int): " + Integer.MAX_VALUE + "^2 = "
            + Math.pow(Integer.MAX_VALUE, 2));
         out.println("Multiplied: " + Integer.MAX_VALUE*Integer.MAX_VALUE);
         out.print("IntMath.checkedPow: " + Integer.MAX_VALUE + "^2 = ");
         out.println(IntMath.checkedPow(Integer.MAX_VALUE, 2));
      }
      catch (Exception ex)
      {
         err.println("Exception during power: " + ex.toString());
      }
   }

Класс IntMath версии 11 в Guava предоставляет еще три «проверенных» метода, которые выдают исключение ArithmeticException, когда данная математическая операция приводит к состоянию переполнения. Эти методы предназначены для сложения, вычитания и умножения и соответственно называются IntMath.checkedAdd (int, int) , IntMath.checkedSubtract (int, int) и IntMath.checkedMultiply (int, int) . Как обсуждалось в связи с IntMath.checkedPow (int, int), преимущество этого происходит в ситуациях, когда лучше иметь исключение и знать, что произошло переполнение, чем слепо работать с ошибочным значением из-за условия переполнения.

Демонстрация в Guava: selectedAdd (int, int), checkedSubtract (int, int) и checkMultiply (int, int)

   /**
    * Demonstrate Guava Release 11's checked addition method.
    */
   public static void demoCheckedAddition()
   {
      try
      {
         final int augend = 20;
         final int addend = 10;
         final int sum = IntMath.checkedAdd(augend, addend);
         out.println(augend + " + " + addend + " = " + sum);

         final int overflowSum = IntMath.checkedAdd(Integer.MAX_VALUE, 1);
         out.println(Integer.MAX_VALUE + " + 1 = " + overflowSum);
      }
      catch (Exception ex)
      {
         err.println("Exception during addition: " + ex.toString());
      }
   }

   /**
    * Demonstrate Guava Release 11's checked subtraction method.
    */
   public static void demoCheckedSubtraction()
   {
      try
      {
         final int minuend = 30;
         final int subtrahend = 20;
         final int difference = IntMath.checkedSubtract(minuend, subtrahend);
         out.println(minuend + " - " + subtrahend + " = " + difference);

         final int overflowDifference = IntMath.checkedSubtract(Integer.MIN_VALUE, 1);
         out.println(Integer.MIN_VALUE + " - 1 = " + overflowDifference);
      }
      catch (Exception ex)
      {
         err.println("Exception during subtraction: " + ex.toString());
      }
   }

   /**
    * Demonstrate Guava Release 11's checked multiplication method.
    */
   public static void demoCheckedMultiplication()
   {
      try
      {
         final int factor1 = 3;
         final int factor2 = 10;
         final int product = IntMath.checkedMultiply(factor1, factor2);
         out.println(factor1 + " * " + factor2 + " = " + product);

         final int overflowProduct = IntMath.checkedMultiply(Integer.MAX_VALUE, 2);
         out.println(Integer.MAX_VALUE + " * 2 = " +  overflowProduct);
      }
      catch (Exception ex)
      {
         err.println("Exception during multiplication: " + ex.toString());
      }
   }

В блоге « Обработка очень больших чисел в Java» рассказывается о проблемах с большими числами в Java и возможном переполнении. Как рекомендует этот пост, для таких ситуаций часто рекомендуется использовать BigInteger и BigDecimal . Однако эти новые «проверенные» методы Guava IntMath предоставляют другую альтернативу для разработчика Java, который хочет иметь дело с целыми числами, но знает, когда произошло переполнение.

Я показал простые примеры использования большинства методов нового класса IntMath в выпуске Guava 11 [я не обсуждал и не показывал IntMath.mod (int, int) ]. Следующий листинг кода связывает все вышеприведенные примеры вместе и сопровождается выводом из этого листинга.

UsingIntMath.java

package dustin.examples;

import static java.lang.System.err;
import static java.lang.System.out;

import com.google.common.math.IntMath;
import java.math.RoundingMode;

/**
 * Simple examples of using Guava Release 11's {@code IntMath} class.
 * 
 * @author Dustin
 */
public class UsingIntMath
{
   /**
    * Demonstrate binomial Coefficient calculation
    * (http://en.wikipedia.org/wiki/Binomial_coefficient).
    */
   public static void demoBinomialCoefficient()
   {
      final int n = 5;
      final int k = 3;
      final int binomialCoefficient = IntMath.binomial(n, k);
      out.println(
           "Binomial Coefficient of n=" + n + " and k=" + k + " is "
         + binomialCoefficient);  
   }

   /**
    * Demonstrate factorial calculation.
    */
   public static void demoFactorial()
   {
      final int x = 5;
      final int factorial = IntMath.factorial(x);
      out.println("Factorial of x=" + x + " is " + factorial);
   }

   /**
    * Demonstrate calculation of greatest common factor (GCF) [called greatest
    * common divisor here].
    */
   public static void demoGreatestCommonFactor()
   {
      final int x = 30;
      final int y = 45;
      final int gcf = IntMath.gcd(x, y);
      out.println("GCF of " + x + " and " + y + " is " + gcf);
   }

   /**
    * Demonstrate calculation of square roots.
    */
   public static void demoSquareRoot()
   {
      final int x = 16;
      final int sqrtX = IntMath.sqrt(x, RoundingMode.HALF_EVEN);
      out.println("Square root of " + x + " is " + sqrtX);
      final int y = 25;
      final int sqrtY = IntMath.sqrt(y, RoundingMode.HALF_EVEN);
      out.println("Square root of " + y + " is " + sqrtY);  
   }

   /**
    * Demonstrate determination of whether an integer is a power of two.
    */
   public static void demoIsPowerOfTwo()
   {
      final int x = 16;
      out.println(x + (IntMath.isPowerOfTwo(x) ? " IS " : " is NOT " ) + " a power of two.");
      final int y = 31;
      out.println(y + (IntMath.isPowerOfTwo(y) ? " IS " : " is NOT " ) + " a power of two.");
   }

   /**
    * Demonstrate exponential power calculation.
    */
   public static void demoExponentialPower()
   {
      final int base = 2;
      final int exponent = 5;
      final int result = IntMath.pow(base, exponent);
      out.println(base + " to power of " + exponent + " is " + result);
   }

   /**
    * Demonstrate IntMath.log10 and IntMath.log2.
    */
   public static void demoLogarithmicFunctions()
   {
      final int x = 10000000;
      final int resultX = IntMath.log10(x, RoundingMode.HALF_EVEN);
      out.println("Logarithm (base 10) of " + x + " is " + resultX);
      final int y = 32;
      final int resultY = IntMath.log2(y, RoundingMode.HALF_EVEN);
      out.println("Logarithm (base 2) of " + y + " is " + resultY);
   }

   /**
    * Demonstrate Guava Release 11's checked addition method.
    */
   public static void demoCheckedAddition()
   {
      try
      {
         final int augend = 20;
         final int addend = 10;
         final int sum = IntMath.checkedAdd(augend, addend);
         out.println(augend + " + " + addend + " = " + sum);

         final int overflowSum = IntMath.checkedAdd(Integer.MAX_VALUE, 1);
         out.println(Integer.MAX_VALUE + " + 1 = " + overflowSum);
      }
      catch (Exception ex)
      {
         err.println("Exception during addition: " + ex.toString());
      }
   }

   /**
    * Demonstrate Guava Release 11's checked subtraction method.
    */
   public static void demoCheckedSubtraction()
   {
      try
      {
         final int minuend = 30;
         final int subtrahend = 20;
         final int difference = IntMath.checkedSubtract(minuend, subtrahend);
         out.println(minuend + " - " + subtrahend + " = " + difference);

         final int overflowDifference = IntMath.checkedSubtract(Integer.MIN_VALUE, 1);
         out.println(Integer.MIN_VALUE + " - 1 = " + overflowDifference);
      }
      catch (Exception ex)
      {
         err.println("Exception during subtraction: " + ex.toString());
      }
   }

   /**
    * Demonstrate Guava Release 11's checked multiplication method.
    */
   public static void demoCheckedMultiplication()
   {
      try
      {
         final int factor1 = 3;
         final int factor2 = 10;
         final int product = IntMath.checkedMultiply(factor1, factor2);
         out.println(factor1 + " * " + factor2 + " = " + product);

         final int overflowProduct = IntMath.checkedMultiply(Integer.MAX_VALUE, 2);
         out.println(Integer.MAX_VALUE + " * 2 = " +  overflowProduct);
      }
      catch (Exception ex)
      {
         err.println("Exception during multiplication: " + ex.toString());
      }
   }

   /**
    * Demonstrate Guava Release 11's checked power method and compare it to
    * other common approaches for determining base multiplied by itself exponent
    * number of times.
    */
   public static void demoCheckedPower()
   {
      try
      {
         final int base = 2;
         final int exponent = 4;
         final int result = IntMath.checkedPow(base, exponent);
         out.println("IntMath.checkedPow: " + base + "^" + exponent + " = " + result);

         out.println(
              "IntMath.pow: " + Integer.MAX_VALUE + "^2 = " +
            + IntMath.pow(Integer.MAX_VALUE, 2));
         out.println(
              "Math.pow(int,int): " + Integer.MAX_VALUE + "^2 = "
            + Math.pow(Integer.MAX_VALUE, 2));
         out.println("Multiplied: " + Integer.MAX_VALUE*Integer.MAX_VALUE);
         out.print("IntMath.checkedPow: " + Integer.MAX_VALUE + "^2 = ");
         out.println(IntMath.checkedPow(Integer.MAX_VALUE, 2));
      }
      catch (Exception ex)
      {
         err.println("Exception during power: " + ex.toString());
      }
   }

   /**
    * Demonstrate division using IntMath.divide.
    */
   public static void demoDivision()
   {
      final int dividend = 30;
      final int divisor = 10;
      final int quotient = IntMath.divide(dividend, divisor, RoundingMode.HALF_EVEN);
      out.println(dividend + " / " + divisor + " = " + quotient);
   }

   /**
    * Main function for demonstrating Guava Release 11's {@code IntMath} class.
    * 
    * @param arguments Command-line arguments; none expected.
    */
   public static void main(final String[] arguments)
   {
      demoBinomialCoefficient();
      demoFactorial();
      demoGreatestCommonFactor();
      demoSquareRoot();
      demoIsPowerOfTwo();
      demoExponentialPower();
      demoLogarithmicFunctions();
      demoCheckedAddition();
      demoCheckedSubtraction();
      demoCheckedMultiplication();
      demoCheckedPower();
      demoDivision();
   }
}

В этом сообщении была предпринята попытка продемонстрировать полезность и простоту использования, предоставляемые классом IntMath в версии 11 для Guava. Этот класс предоставляет множество удобных методов для упрощения общих математических операций над целыми числами. 11-й выпуск Guava предоставляет в основном те же методы в пакете com.google.common.math для longs ( LongMath ) и аналогичные методы для double ( DoubleMath ) и BigIntegers ( BigIntegerMath ).

 

 

От http://marxsoftware.blogspot.com/2011/12/guava-release-11s-intmath.html