Класс Math

Вступление.

Практически любые исполняемые операции являются математическими вычисления каких-либо величин. Чаще всего приходится иметь дело с простейшими операциями, такими как вычитание, сложение, умножение и деление. Но в более сложных программах иногда требуются сложные операции (поиск большего/меньшего числа, вычисление степени числа и т.п.). В этих случаях целесообразно использование класса Math, который предоставляет различные способы работы с числовыми данными, упрощая написание кода.

В данной статье будут рассмотрены все методы публичного (public) абстрактного (abstract) класса Math.

Конструктор.

Экземпляр этого класса создать нельзя. Единственный конструктор помечен модификатором private и снабжён комментарием от создателей класса: «Никому не позволяйте создать экземпляр этого класса».

Переменные.

Данный класс обладает четырьмя доступными константами и двумя внутренними переменными:

· public static final double E = 2.7182818284590452354; — число «E» (основание натурального логарифма);

· public static final double PI = 3.14159265358979323846; — число «Пи» (соотношение диаметра и окружности);

· private static final double DEGREES_TO_RADIANS = 0.017453292519943295; — отношение градусов к радианам;

· private static final double RADIANS_TO_DEGREES = 57.29577951308232; — отношение радианов к градусам.

· static double twoToTheDoubleScaleUp – внутренняя переменная для работы метода scalb(), вычисляется при помощи метода powerOfTwoD(512);

· static double twoToTheDoubleScaleDown – внутренняя переменная для работы метода scalb(), вычисляется при помощи метода powerOfTwoD(-512);

Классы.

Содержит внутренний класс private static final class RandomNumberGeneratorHolder, внутри которого находится переменная типа Random.

Методы.

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

Работа с углами.

· public static double sin(double a) – возвращает синус указанного в радианах значения.

· public static double cos(double a) – возвращает косинус указанного в радианах значения.

· public static double tan(double a) – возвращает тангенс указанного в радианах значения.

· public static double asin(double a) – возвращает арксинус указанного в радианах значения.

· public static double acos(double a) – возвращает арккосинус указанного в радианах значения.

· public static double atan(double a) – возвращает арктангенс указанного в радианах значения.

· public static double sinh(double x) – возвращает гиперболический синус двойного значения;

· public static double cosh(double x) – возвращает гиперболический косинус двойного значения;

· public static double tanh(double x) – возвращает гиперболический тангенс двойного значения;

· public static double hypot(double x, double y) – возвращает корень из x2 + y2 («евклидову норму»);

· public static double atan2(double y, double x) — возвращает double значение от -π до π, представляющее угол тета точки (x, y). Это угол в радианах, отсчитываемый против часовой стрелки от положительного направления оси X до точки (x, y). Внимание! Первой в методе передаётся координата y, второй — координата x.

Перевод в радианы и градусы.

· public static double toRadians(double angdeg) – перевод градусов в радианы.

· public static double toDegrees(double angrad) – перевод радиан в градусы.

Примечание: при переводе из градусов в радианы и из радиан в градусы возможна потеря точности из-за особенностей работы типа Double.

Простые математические операции.

· public static double random() – возвращает случайное число от 0 (включая) до 1 (исключая);

· public static int addExact(int x, int y)

public static long addExact(long x, long y) – возвращает результат сложения x и y;

· public static int subtractExact(int x, int y)

public static long subtractExact(long x, long y) – возвращает результат вычитания y из x;

· public static int multiplyExact(int x, int y)

public static long multiplyExact(long x, int y) –

public static long multiplyExact(long x, long y) – возвращает результат умножения x на y;

· public static long negateExact(long a) – меняет положительное значение числа на отрицательное, а отрицательное – на положительное.

· public static int toIntExact(long value) – превращает входящее значение в тип int и возвращает значение;

· public static long multiplyFull(int x, int y) – возвращает произведение x и y в формате long;

· public static int floorDiv(int x, int y)

public static long floorDiv(long x, int y)

public static long floorDiv(long x, long y) – возвращает результат деления x на y без возможной дробной части;

· public static int abs(int a)

public static long abs(long a)

public static float abs(float a)

public static double abs(double a) – возвращает абсолютное значение числа «a»;

· public static int max(int a, int b)

public static long max(long a, long b)

public static float max(float a, float b)

public static double max(double a, double b) – возвращает максимальное из двух чисел («a» и «b»);

· public static int min(int a, int b)

public static long min(long a, long b)

public static float min(float a, float b)

public static double min(double a, double b) – возвращает минимальное из двух чисел («a» и «b»).

Примечание: по сравнению со стандартными операторами сложения, вычитания, умножения и деления работает медленно при небольшом количестве операций. Но при количестве операций, превышающих 1 млрд., быстродействие методов класса Math становится более эффективным, чем использование стандартных математических операторов.

Сложные математические операции.

· public static double exp(double a) – возвращает натуральный логарифм по основанию числа Е и аргументу — показателю степени;

· public static double log(double a) – возвращает натуральный логарифм аргумента;

· public static double log10(double a) – возвращает десятичный (по основанию 10) логарифм числа. Если значение <= 0, то возвращаемое значение всегда будет равным NaN;

· public static double expm1(double x) – возвращает «ex – 1» (основание натурального логарифма в степени переданного аргумента минус 1);

· public static double log1p(double x) – возвращает натуральный логарифм суммы аргументов и 1;

· public static int getExponent(float f)

public static int getExponent(double d) – возвращает натуральный логарифм по основанию числа E и аргументу – показателю степени.

Работа со степенями.

· public static double sqrt(double a) – возвращает корень переданного числа;

· public static double cbrt(double a) – возвращает кубический корень переданного числа;

· public static double pow(double a, double b) – возвращает число ‘a’ в степени ‘b’.

Примечание: быстродействие метода pow(double a, double b) при целом и невысоком значении параметра b достаточно низкое по сравнению с операцией умножения; но при высоких (больше 7) значениях b метод pow(double a, double b) более эффективен, чем «вручную» прописанное перемножение.

Округления.

· public static double ceil(double a) – округление к большему целому числу;

· public static double floor(double a) – округление к меньшему целому числу;

· public static double rint(double a) – округление до ближайшего целого числа. Внимание! Значение 0.50 будет округлено в меньшую сторону (до 0); значение 0.51 будет округлено в большую сторону (до 1);

· public static long round(double a)

public static int round(float a) – округление до ближайшего целого числа. Внимание! Теперь значение 0.50 будет округлено в большую сторону (до 1).

Инкременты.

· public static int incrementExact(int a)

public static long incrementExact(long a) – увеличивает значение «a» на один и возвращает изменённое значение;

· public static int decrementExact(int a)

public static long decrementExact(long a) – уменьшает значение «a» на один и возвращает изменённое значение;

· public static double nextAfter(double start, double direction)

public static float nextAfter(float start, float direction) – возвращает число, максимально близкое к start, но при этом увеличенное/уменьшенное в сторону direction, в том числе может вернуть и само direction;

· public static double nextUp(double d)

public static float nextUp(float f) – возвращает число, максимально близкое к d(f), но при этом больше, чем d(f);

· public static double nextDown(double d)

public static float nextDown(float f) – возвращает число, максимально близкое к d(f), но при этом больше, чем d(f).

Примечание: методы incrementExact(int a) и decrementExact(int a) работают быстрее, чем синтаксис “a++” и “a—“.

Разное.

· public static double IEEEremainder(double f1, double f2) — вычисляет остаток для двух аргументов в соответствии со стандартом IEEE 754. Имеет схожие черты со стандартным делением с остатком и также по формуле «x – y * n», где x и y – переданные аргументы; но значение «n» при делении с остатком – целая часть от выражения «x/y», а при использовании метода IEEEremainder значение «n» — ближайшее целое число к выражению «x/y»;

· public static long multiplyHigh(long x, long y) — возвращает наиболее значимые 64 бит из 128-битного произведения двух 64-битных аргументов (типа long).

· public static int floorMod(int x, int y)

public static int floorMod(long x, int y)

public static long floorMod(long x, long y) – возвращает модуль основания целочисленных аргументов;

· public static double fma(double a, double b, double c)

public static float fma(float a, float b, float c) – возвращает исчисление a * b + c;

· public static double ulp(double d)

public static float ulp(float d) – возвращает размер «ulp-аргумента» («единицу наименьшей точности»);

· public static double signum(double d)

public static float signum(float d) – возвращает 0, если входящий аргумент = 0; 1, если входящий аргумент больше 0; -1, если входящий аргумент меньше 0.

· public static double copySign(double magnitude, double sign)

public static float copySign(float magnitude, float sign) – возвращает первый аргумент со знаком второго аргумента;

· public static double scalb(double d, int scaleFactor)

· public static float scalb(float f, int scaleFactor) – возвращает d*2scaleFactor (d умножить на 2 в степени scaleFactor);

· static double powerOfTwoD(int n) – внутренний метод, обеспечивающий работу методов scalb(double/float d, int scaleFactor).

Итоги.

Библиотека Math представляет собой инструментарий, значительно упрощающий работу с большим количеством однотипных вычислений. Не рекомендуется использовать эту библиотеку для вычисления простых операций (например, поиск числа в степени два), так как это приведёт к усложнению читаемости кода и снижению его быстродействия. Но при операциях, в которых требуется многократное количество повторений одной и той же операции – Math может оказаться весьма полезным ресурсом, так как внутри реализации методов содержит инструменты для ускорения работы кода. То же вычисление числа в степени 100 будет значительно быстрее выполнено библиотекой, чем в цикле. Или вычисление дробной степени числа, альтернативы которому в стандартных библиотеках Java просто нет.

Также библиотека Math предоставляет пользователю возможность работать с достаточно тонкими и редко используемыми вычислениями (как, например, вычисление ulp), что может оказаться весьма полезным при написании специфических программ, основанных на арифметических вычислениях.

Примеры кода.

Задача нижеприведенных примеров – не показать оптимальную работу кода, а продемонстрировать различные возможности библиотеки Math. Уверен, что некоторые из методов могут быть написаны в ином формате, а в некоторых случаях использование данной библиотеки не является обязательным.

/**
 * 1. Вывод различной информации о представленном угле
 *
 * @param num   - значение угла в радианах или градусах
 * @param isRad - введено значение в радианах (true) или градусах (false)?
 * @return - строка с информацией
 */
public String getInfo(double num, boolean isRad) {
	StringBuilder sb = new StringBuilder();
	String separator = String.format("-----------------------%s", System.lineSeparator());
	if (isRad) {
    	sb.append(String.format("Представлена информация по углу %.2f радиан (%f градусов).%s", num, Math.toDegrees(num), System.lineSeparator()));
	} else {
    	sb.append(String.format("Представлена информация по углу %.2f градусов (%f радиан).%s", num, num = Math.toRadians(num), System.lineSeparator()));
	}
	sb.append(separator);
	sb.append(String.format("Cинус угла = %f;%s", Math.sin(num), System.lineSeparator()));
	sb.append(String.format("Косинус угла = %f;%s", Math.cos(num), System.lineSeparator()));
	sb.append(String.format("Tангенс угла = %f;%s", Math.tan(num), System.lineSeparator()));
	sb.append(separator);
	sb.append(String.format("Арксинус угла = %s;%s", Math.asin(num) != Math.asin(num) ? "невозможное значение" : String.valueOf(Math.asin(num)), System.lineSeparator()));
	sb.append(String.format("Арккосинус угла = %s;%s", Math.acos(num) != Math.acos(num) ? "невозможное значение" : String.valueOf(Math.acos(num)), System.lineSeparator()));
	sb.append(String.format("Арктангенс угла = %f;%s", Math.atan(num), System.lineSeparator()));
	sb.append(separator);
	sb.append(String.format("Гиперболический синус двойного значения = %s;%s", Double.isInfinite(Math.sinh(num)) ? Character.toString((char) 8734) : String.valueOf(Math.sinh(num)), System.lineSeparator()));
	sb.append(String.format("Гиперболический косинус двойного значения  = %s;%s", Double.isInfinite(Math.cosh(num)) ? Character.toString((char) 8734) : String.valueOf(Math.cosh(num)), System.lineSeparator()));
	sb.append(String.format("Гиперболический тангенс двойного значения  = %f;%s", Math.tanh(num), System.lineSeparator()));
	return sb.toString();
}
 
 
/**
 * 2. Вывод информации о прямоугольном треугольнике по двум катетам
 *
 * @param a - длина одного катета
 * @param b - длина другого катета
 * @return - строка с информацией
 */
public String triangoloInfo(double a, double b) {
	StringBuilder sb = new StringBuilder();
	return sb.append(String.format("Длина гипотенузы = %.2f; периметр треугольника = %.2f; площадь треугольника = %.2f.", Math.hypot(a, b), Math.hypot(a, b) + a + b, a * b / 2)).toString();
}
 
 
/**
 * 3. Сложение всех передаваемых значений
 *
 * @param args - значения
 * @return - сумма значений
 */
public int manyAdds(int... args) {
	int result = 0;
	for (int arg : args) {
    	result = Math.addExact(result, arg);
	}
	return result;
}
 
 
/**
 * 4. Ответ на вопрос - является ли корень из модуля данного числа целым числом
 *
 * @param number - число для проверки
 * @return - является (true) или нет (false)
 */
public boolean rootInt(long number) {
	return Math.sqrt(Math.abs(number)) == (int) Math.sqrt(Math.abs(number));
}
 
 
/**
 * 5. Возврат псевдослучайного значения в диапазоне от -rand до rand.
 *
 * @param rand - число для создания ограничения
 * @return - псевдослучайное число
 */
public int randomizeValue(int rand) {
	return (int) (Math.random() * Math.abs(rand) * 2) - Math.abs(rand);
}
 
 
/**
 * 6. Вывод информации о числе, является ли оно больше, меньше или равным нолю.
 *
 * @param f - число для проверки
 */
public void printValue(float f) {
	f = Math.signum(f);
	switch ((int) f) {
    	case -1 -> System.out.println("Число меньше 0.");
    	case 0 -> System.out.println("Число равно 0.");
    	default -> System.out.println("Число больше 0.");
	}
}
 
 
/**
 * 7. Возврат массива, который содержит наименьшее и наибольшее значение из переданных
 * @param arr - передаваемое значение
 * @return - массив с наименьшим и наибольшим числами
 */
public int[] minMax(int... arr) {
	int[] result = new int[]{Integer.MAX_VALUE, Integer.MIN_VALUE};
	for (int i = 0; i < arr.length; i++) {
    	result[0] = Math.min(result[0], arr[i]);
    	result[1] = Math.max(result[1], arr[i]);
	}
	return result;
}

Маслов Василий, после окончания базового курса, февраль 2021