Как я уже говорил ранее в посте 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