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