Как узнать разницу между двумя целыми числами

Диапазоны значений и знак целочисленных типов данных

Как вы уже знаете из предыдущего урока, переменная с n-ным количеством бит может хранить 2n возможных значений. Но что это за значения? Это значения, которые находятся в диапазоне. Диапазон — это значения от и до, которые может хранить определенный тип данных. Диапазон целочисленной переменной определяется двумя факторами: её размером (измеряется в битах) и её знаком (который может быть signed или unsigned).

Целочисленный тип signed (со знаком) означает, что переменная может содержать как положительные, так и отрицательные числа. Чтобы объявить переменную как signed, используйте ключевое слово :

signed char c;
signed short s;
signed int i;
signed long l;
signed long long ll;

1
2
3
4
5

signedcharc;

signedshorts;

signedinti;

signedlongl;

signedlonglongll;

По умолчанию, ключевое слово пишется перед типом данных.

1-байтовая целочисленная переменная со знаком (signed) имеет диапазон значений от -128 до 127, т.е. любое значение от -128 до 127 (включительно) может храниться в ней безопасно.

В некоторых случаях мы можем заранее знать, что отрицательные числа в программе использоваться не будут. Это очень часто встречается при использовании переменных для хранения количества или размера чего-либо (например, ваш рост или вес не может быть отрицательным).

Целочисленный тип unsigned (без знака) может содержать только положительные числа. Чтобы объявить переменную как unsigned, используйте ключевое слово :

unsigned char c;
unsigned short s;
unsigned int i;
unsigned long l;
unsigned long long ll;

1
2
3
4
5

unsignedcharc;

unsignedshorts;

unsignedinti;

unsignedlongl;

unsignedlonglongll;

1-байтовая целочисленная переменная без знака (unsigned) имеет диапазон значений от 0 до 255.

Обратите внимание, объявление переменной как unsigned означает, что она не сможет содержать отрицательные числа (только положительные). Теперь, когда вы поняли разницу между signed и unsigned, давайте рассмотрим диапазоны значений разных типов данных:

Теперь, когда вы поняли разницу между signed и unsigned, давайте рассмотрим диапазоны значений разных типов данных:

Размер/Тип Диапазон значений
1 байт signed от -128 до 127
1 байт unsigned от 0 до 255
2 байта signed от -32 768 до 32 767
2 байта unsigned от 0 до 65 535
4 байта signed от -2 147 483 648 до 2 147 483 647
4 байта unsigned от 0 до 4 294 967 295
8 байтов signed от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807
8 байтов unsigned от 0 до 18 446 744 073 709 551 615

Для математиков: Переменная signed с n-ным количеством бит имеет диапазон от -(2n-1) до 2n-1-1. Переменная unsigned с n-ным количеством бит имеет диапазон от 0 до (2n)-1.

Для нематематиков: Используем таблицу

Начинающие программисты иногда путаются между signed и unsigned переменными. Но есть простой способ запомнить их различия. Чем отличается отрицательное число от положительного? Правильно! Минусом спереди. Если минуса нет, значит число — положительное. Следовательно, целочисленный тип со знаком (signed) означает, что минус может присутствовать, т.е. числа могут быть как положительными, так и отрицательными. Целочисленный тип без знака (unsigned) означает, что минус спереди отсутствует, т.е. числа могут быть только положительными.

Основные математические функции

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

Math.abs()

Функция Math.abs() возвращает абсолютное положительное значение переданного ей параметра. Если значение параметра является отрицательным, знак “-” удаляется и возвращается положительное значение, соответствующее отрицательному значению без знака. Вот два примера:

int abs1 = Math.abs(10);  // abs1 = 10

int abs2 = Math.abs(-20); // abs2 = 20

Абсолютное значение 10 равно 10. Абсолютное значение -20 равно 20.

Метод Math.abs() представлен в 4 версиях:

Math.abs(int)
Math.abs(long)
Math.abs(float)
Math.abs(double)

Какой из этих методов вызывается, зависит от типа параметра, передаваемого методу Math.abs().

Math.ceil()

Функция округляет значение с плавающей запятой до ближайшего целого числа. Округленное значение возвращается как двойное. Вот пример:

double ceil = Math.ceil(7.343);  // ceil = 8.0

После выполнения этого Java-кода переменная ceil будет содержать значение 8.0.

Math.floor()

Функция Math.floor() округляет значение с плавающей запятой до ближайшего целочисленного значения. Округленное значение возвращается как двойное. Вот пример:

double floor = Math.floor(7.343);  // floor = 7.0

После выполнения ceil будет содержать значение 8.0.

Math.floorDiv()

Метод Math.floorDiv() делит одно целое число (int или long) на другое и округляет результат до ближайшего целочисленного значения. Если результат положительный, эффект такой же, как при использовании оператора “/” (деления), описанного ранее в этом тексте.

Однако, если результат отрицательный, результат не тот же. С помощью оператора “/” дроби просто усекаются. Для положительных чисел это соответствует округлению в меньшую сторону, для отрицательных – в большую. Метод floorDiv() округляет до ближайшего отрицательного целого числа, вместо того, которое будет происходить при усечении дроби.

Вот пример:

double result3 = Math.floorDiv(-100,9);
System.out.println("result3: " + result3);

double result4 = -100 / 9;
System.out.println("result4: " + result4);

Выходные данные:

result3: -12.0
result4: -11.0

Это показывает разницу между оператором “/” и Math.floorDiv().

Math.min()

Метод Math.min() возвращает наименьшее из двух значений, переданных ему в качестве параметра:

int min = Math.min(10, 20);

После выполнения этого кода переменная min будет содержать значение 10.

Math.max()

Метод Math.max() возвращает наибольшее из двух значений, переданных ему в качестве параметра:

int max = Math.max(10, 20);

После выполнения этого кода переменная max будет содержать значение 20.

Где нужны логические операторы

Если коротко, то в условных выражениях, которые могут включать в себя и операторы сравнения (<, >, <=, >=, ==, !=). При вычислении они возвращают значение булева типа.

Условные выражения, в свою очередь, применяются в операторах ветвления (if-else, switch, тернарном). Подробнее об этих операторах тут.

Как применять

Допустим, мы хотим проверить, что значение переменной a больше значений в переменных b и c. То есть сравнить операнд a с двумя другими. Нам поможет логический оператор && (И).

Логический оператор && (И) возвращает true, если слева и справа от него стоят значения true, а иначе — false.

Иными словами, если оба логических высказывания истинны, то и операция && (И) возвращает истину.

Первый пример

Как вычисляется значение выражения (a > b) && (a > c):

Сначала проверяется условие (a > b). Оно вернёт true, так как 6 больше 4. Далее проверяется условие (a > c), которое также вернёт true, ведь 6 больше 3.

Теперь у нас с двух сторон от логического оператора && стоят значения true.

По определению выше или по таблице ещё выше, результат вычисления логического выражения (true && true) равен true.

Второй пример

Результат операции (a > b) вернёт true, так как 6 больше 4, а операция (a > c) уже вернёт false, так как 6 не больше 7.

Значит, слева от логического оператора && стоит true, а справа — false. Следовательно, результат вычисления логического выражения (мы присвоили его булевой переменной d) будет false.

Третий пример

Результат операции сравнения (a > b) равен false, а что вернёт операция (a > c), уже значения не имеет (смотрите определение выше) — результат вычисления логического выражения (мы присвоили его булевой переменной d) будет равен false.

Количество цифр в целочисленном числе

Для методов, обсуждаемых здесь, мы рассматриваем только положительные целые числа. Если мы ожидаем каких-либо отрицательных входных данных, то мы можем сначала использовать Math.abs(число) перед использованием любого из этих методов.

2.1. Решение На основе строк

Возможно , самый простой способ получить количество цифр в Integer – это преобразовать его в String и вызвать метод length () . Это вернет длину Строки представления нашего числа:

int length = String.valueOf(number).length();

Но это может быть неоптимальным подходом, так как этот оператор включает выделение памяти для строки для каждой оценки . JVM должен сначала проанализировать наш номер и скопировать его цифры в отдельную Строку , А также выполнить ряд различных операций (например, сохранение временных копий, обработка преобразований Юникода и т. Д.).

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

2.2. Логарифмический Подход

Для чисел, представленных в десятичной форме, если мы возьмем их логин в базе 10 и округлим его, то получим количество цифр в этом числе:

int length = (int) (Math.log10(number) + 1);

Обратите внимание, что log 10 какого-либо числа не определено. Итак, если мы ожидаем каких-либо входных данных со значением , тогда мы можем проверить и это

Логарифмический подход значительно быстрее, чем подход на основе String , поскольку ему не нужно проходить процесс преобразования данных. Это просто включает в себя простой, простой расчет без какой-либо дополнительной инициализации объекта или циклов.

2.3. Повторное Умножение

В этом методе мы возьмем временную переменную (инициализированную в 1) и будем непрерывно умножать ее на 10, пока она не станет больше нашего числа. Во время этого процесса мы также будем использовать переменную length , которая будет отслеживать длину числа:

int length = 0;
long temp = 1;
while (temp <= number) {
    length++;
    temp *= 10;
}
return length;

В этом коде строка temp совпадает с записью temp = (temp << 3) + (temp << 1) . Поскольку умножение обычно является более дорогостоящей операцией на некоторых процессорах по сравнению с операторами сдвига, последние могут быть немного более эффективными.

2.4. Деление на две степени

Если мы знаем о диапазоне нашего числа, то мы можем использовать вариацию, которая еще больше сократит наши сравнения. Этот метод делит число на степени двух (например, 1, 2, 4, 8 и т. Д.):

Этот метод делит число на степени двух (например, 1, 2, 4, 8 и т. Д.):

int length = 1;
if (number >= 100000000) {
    length += 8;
    number /= 100000000;
}
if (number >= 10000) {
    length += 4;
    number /= 10000;
}
if (number >= 100) {
    length += 2;
    number /= 100;
}
if (number >= 10) {
    length += 1;
}
return length;

Он использует тот факт, что любое число может быть представлено сложением степеней 2. Например, 15 можно представить в виде 8+4+2+1, которые все являются степенями 2.

Для 15-значного числа мы бы провели 15 сравнений в нашем предыдущем подходе, который мы сократили до 4 в этом методе.

2.5. Разделяй и властвуй

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

Мы получаем наш ответ всего в трех или четырех простых утверждениях if :

if (number < 100000) {
    if (number < 100) {
        if (number < 10) {
            return 1;
        } else {
            return 2;
        }
    } else {
        if (number < 1000) {
            return 3;
        } else {
            if (number < 10000) {
                return 4;
            } else {
                return 5;
            }
        }
    }
} else {
    if (number < 10000000) {
        if (number < 1000000) {
            return 6;
        } else {
            return 7;
        }
    } else {
        if (number < 100000000) {
            return 8;
        } else {
            if (number < 1000000000) {
                return 9;
            } else {
                return 10;
            }
        }
    }
}

Подобно предыдущему подходу, мы можем использовать этот метод только в том случае, если мы знаем о диапазоне нашего числа.

3 ответа

Лучший ответ

— это поэлементная операция над ; как таковой, он часто сохраняет форму данных. нет: он берет всю структуру — здесь матрицу — и преобразует ее в одномерный целочисленный вектор.

Тем не менее, в общем случае я настоятельно рекомендую использовать и не рекомендую как умный прием (помните: часто, умно ≠ хорошо). Если вы хотите сохранить форму данных, я предлагаю использовать метод Дэвида из комментариев, а не хак :

Здесь используется обычное значение , но результат присваивается отдельным элементам , а не самому . Другими словами, форма остается нетронутой.

16

Konrad Rudolph
9 Фев 2015 в 14:33

Добавление переводит в целое число, как описано в :

Как следствие, любая арифметическая операция с использованием и элемента идентификации для этой операции (но не обязательно в какой-то момент переходить к числовому, например и ) будет работать:

Унарные операции также будут работать, поэтому, возможно, «лучшая» версия кода для гольфа:

Это имеет параллель с обычным приемом использования для преобразования числового объекта в логический.

Преобразование обратно в логическое:

Альтернативный и, возможно, более ясный подход — напрямую изменить :

12

James
9 Фев 2015 в 15:25

(Этот ответ не добавляет другой альтернативы к уже имеющимся, но я публикую просто для того, чтобы привести в порядок комментарии в этой ветке.)

, по определению , ведет себя как , т. Е. Удаляет все атрибуты (включая «тусклый») для создания вектора R. Он не будет просто возвращать тот же объект с измененным . Чтобы восстановить атрибуты после принуждения, , , и т. Д. Необходимо вызвать явно или через функцию, которая хранит атрибуты своих аргументов (например, ). Например. или или . Тест:

В приведенном выше примере justs добавляет атрибут к созданному , выделяет новый вектор для хранения созданных и изменений «x «, чтобы он мог принимать значения созданного , а затем перебирает» x «, чтобы вставить свои новые значения.

Однако у метода есть недостаток:

Или же:

Но:

Т.е. не изменит заменяемого объекта, если заменяемого объекта больше. Дополнительное назначение (т. е. ) принуждает либо объект, подлежащий замене , либо заменяющий объект , либо ничего в зависимости от их {{X4} } s (это делается с помощью ). @Josh O’Brien отмечает возможность различий в поведении , если индексы отсутствуют. Честно говоря, я не смог найти конкретное лечение в таком случае, например, в (), который косвенно обрабатывает недостающие данные.

Как уже упоминалось, существует также для изменения объекта:

По эффективности аналогичен , поскольку они оба приводят к однократному принуждению и сохраняют атрибут.

Бинарные операции (как упоминалось Джеймсом и Конрадом Рудольфом) приводят свои аргументы к подходящему и сохраняют атрибуты («тусклый», «имена», «класс» и т. Д.) В зависимости от правил, касающихся двух аргументов. (Раздел «Стоимость» в )

5

alexis_laz
15 Фев 2015 в 12:02

Сравнение числа bigdecimal и другого числа

Найти числа, которые являются квадратами некоторого другого числаПомогите написать программу на С++ Вот условие: Даны целые положительные числа а1, а2 . а n.

Программа которая суммирует вводимые числа до тех пор, пока они не являются степенями другого целого числаПомогите пожалуйста написать программу. Желательно с объяснениями.

Составление числа из цифр другого числаДано натуральное число, содержащее до 50 разрядов. Составить из этого числа наименьшее число.

Лучше через .compareTo() , поскольку equals не всегда корректно отображает.

Добавлено через 3 минуты Вот из некой документации. Про compareTo:

Сообщение от 4eDo Сообщение от xoraxax

На значениях 1.5 и 1.50, например. К тому же compareTo выдаёт и результат, что больше, а что меньше. Тоже удобно.

Добавлено через 1 минуту xoraxax, к тому же у автора не просто равенство. a — BigDecimal , если что.

Сообщение от da_da_ya

Добавлено через 1 минуту

Сообщение от 4eDo Сообщение от da_da_ya Сообщение от xoraxax Сообщение от 4eDo

Mimilun, м-да, неочевидное решение в реализации

Ни за что бы не подумал, что оно так работает.

Добавлено через 2 минуты

Сообщение от xoraxax

И, видимо, не меняют ради обратной совместимости =(

Составление числа из цифр другого числаДано натуральное число, содержащее до 50 разрядов. Составить из этого числа наибольшее число.

Составление числа из цифр другого числаДано натуральное число, содержащее до 50 разрядов. Составить из этого числа наибольшее число.

Составление числа из цифр другого числаможете помочь, ни разу на этом не делали, вот задали. Дано натуральное число, содержащее до 50.

Для заданного целого числа проверьте, является ли оно логарифмом по основанию 2 от другого целого числа1)Для заданного целого числа проверьте,является ли оно логарифмом по основанию 2 от другого целого.

Сравнение 1 и 2 цифр числа и проверка числа на наличие одинаковых цифрнужно создать заголовочный файл, в котором будет функция сравнивающая первую и вторую цифру числа.

Что используется по умолчанию: signed или unsigned?

Так что же произойдет, если мы объявим переменную без указания signed или unsigned?

Тип По умолчанию
Символьный тип данных char signed или unsigned (в большинстве случаев signed)
Целочисленный тип данных short signed
int signed
long signed
long long signed

Все целочисленные типы данных, кроме char, являются signed по умолчанию. Тип char может быть как signed, так и unsigned (но, обычно, signed).

В большинстве случаев ключевое слово signed не пишется (оно и так используется по умолчанию).

Программисты, как правило, избегают использования целочисленных типов unsigned, если в этом нет особой надобности, так как с переменными unsigned ошибок, по статистике, возникает больше, нежели с переменными signed.

Правило: Используйте целочисленные типы signed, вместо unsigned.

Гуава

Теперь давайте взглянем на Гуава . Прежде всего, давайте импортируем зависимость :

com.google.guavaguava29.0-jre

8.1. Объекты#равный метод

Подобно библиотеке Apache Commons, Google предоставляет нам метод определения равенства двух объектов, Объекты#равны . Хотя они имеют разные реализации, они возвращают одни и те же результаты:

String a = new String("Hello!");
String b = new String("Hello!");

assertThat(Objects.equal(a, b)).isTrue();

Хотя он не помечен как устаревший, JavaDoc этого метода говорит, что его следует считать устаревшим, поскольку Java 7 предоставляет метод Objects#equals .

8.2. Методы сравнения

Теперь библиотека Guava не предлагает метод для сравнения двух объектов (мы увидим в следующем разделе, что мы можем сделать для этого), но она предоставляет нам методы для сравнения примитивных значений . Давайте возьмем вспомогательный класс Ints и посмотрим, как работает его метод compare() :

assertThat(Ints.compare(1, 2)).isNegative();

Как обычно, он возвращает целое число , которое может быть отрицательным, нулевым или положительным, если первый аргумент меньше, равен или больше второго, соответственно. Аналогичные методы существуют для всех примитивных типов, за исключением bytes .

8.3. Класс сравнительной цепи

Наконец, библиотека Guava предлагает класс ComparisonChain , который позволяет нам сравнивать два объекта с помощью цепочки сравнений. Мы можем легко сравнить два Человека объекта по имени и фамилии:

Person natalie = new Person("Natalie", "Portman");
Person joe = new Person("Joe", "Portman");

int comparisonResult = ComparisonChain.start()
  .compare(natalie.getLastName(), joe.getLastName())
  .compare(natalie.getFirstName(), joe.getFirstName())
  .result();

assertThat(comparisonResult).isPositive();

Базовое сравнение достигается с помощью метода compareTo () , поэтому аргументы, передаваемые методам compare () , должны быть либо примитивами, либо Сопоставимыми s.

Форматирование различных типов чисел

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

4.1. Форматирование Больших Целых Чисел Запятыми

Всякий раз, когда у нас есть большое целое число в нашем приложении, мы можем захотеть отобразить его с запятыми, используя DecimalFormat с предопределенным шаблоном:

public static String withLargeIntegers(double value) {
    DecimalFormat df = new DecimalFormat("###,###,###");
    return df.format(value);
}

int value = 123456789;
assertThat(withLargeIntegers(value)).isEqualTo("123,456,789");

4.2. Заполнение номера

В некоторых случаях мы можем захотеть дополнить число нулями заданной длины. Здесь мы можем использовать метод String#format , как описано ранее:

public static String byPaddingZeros(int value, int paddingLength) {
    return String.format("%0" + paddingLength + "d", value);
}

int value = 1;
assertThat(byPaddingOutZeros(value, 3)).isEqualTo("001");

4.3. Форматирование чисел С Двумя Нулями После запятой

Чтобы иметь возможность печатать любое заданное число с двумя нулями после десятичной точки, мы будем использовать еще один раз DecimalFormat класс с предопределенным шаблоном:

public static double withTwoDecimalPlaces(double value) {
    DecimalFormat df = new DecimalFormat("#.00");
    return new Double(df.format(value));
}

int value = 12; 
assertThat(withTwoDecimalPlaces(value)).isEqualTo(12.00);

В этом случае мы создали новый формат с шаблоном, указывающим два нуля после десятичной точки .

4.4. Форматирование и проценты

Время от времени нам может понадобиться отображать проценты.

В этом случае мы можем использовать метод . Этот метод позволяет нам указать Locale для печати значения в формате, соответствующем указанной вами стране:

public static String forPercentages(double value, Locale locale) {
    NumberFormat nf = NumberFormat.getPercentInstance(locale);
    return nf.format(value);
}

double value = 25f / 100f;
assertThat(forPercentages(value, new Locale("en", "US"))).isEqualTo("25%");

4.5. Форматирование Номера Валюты

Распространенным способом хранения валют в нашем приложении является использование BigDecimal . Что делать, если мы хотим отобразить их пользователю? В этом случае мы можем использовать класс NumberFormat :

public static String currencyWithChosenLocalisation(double value, Locale locale) {
    NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
    return nf.format(value);
}

Мы получаем экземпляр валюты для заданного Locale , а затем просто вызываем метод format со значением. Результатом является число, отображаемое в качестве валюты для указанной страны:

double value = 23_500;
assertThat(currencyWithChosenLocalisation(value, new Locale("en", "US"))).isEqualTo("$23,500.00");
assertThat(currencyWithChosenLocalisation(value, new Locale("zh", "CN"))).isEqualTo("¥23,500.00");
assertThat(currencyWithChosenLocalisation(value, new Locale("pl", "PL"))).isEqualTo("23 500 zł");

Метод Object#equals

Теперь давайте поговорим о более широкой концепции равенства с помощью метода equals () .

Этот метод определен в классе Object , так что каждый объект Java наследует его. По умолчанию его реализация сравнивает адреса памяти объектов, поэтому он работает так же, как оператор == //. Однако мы можем переопределить этот метод, чтобы определить, что означает равенство для наших объектов.

Во-первых, давайте посмотрим, как он ведет себя для существующих объектов, таких как Integer :

Integer a = new Integer(1);
Integer b = new Integer(1);

assertThat(a.equals(b)).isTrue();

Метод по-прежнему возвращает true , когда оба объекта одинаковы.

Следует отметить, что мы можем передать объект null в качестве аргумента метода, но, конечно, не в качестве объекта, на котором мы вызываем метод.

Мы можем использовать метод equals() с нашим собственным объектом. Допустим, у нас есть Человек класс:

public class Person {
    private String firstName;
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

Мы можем переопределить метод equals() для этого класса, чтобы мы могли сравнить два Person s на основе их внутренних данных:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Person that = (Person) o;
    return firstName.equals(that.firstName) &&
      lastName.equals(that.lastName);
}

Для получения дополнительной информации см. статья на эту тему .

2.

Давайте начнем с операторов == и != , которые могут определить, являются ли два объекта Java одинаковыми или нет, соответственно.

2.1. Примитивы

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

assertThat(1 == 1).isTrue();

Благодаря автоматической распаковке это также работает при сравнении примитивного значения с его аналогом типа оболочки :

Integer a = new Integer(1);
assertThat(1 == a).isTrue();

Если два целых числа имеют разные значения, оператор == вернет false , а оператор != вернет true .

2.2. Объекты

Допустим, мы хотим сравнить два типа Integer wrapper с одним и тем же значением:

Integer a = new Integer(1);
Integer b = new Integer(1);

assertThat(a == b).isFalse();

При сравнении двух объектов значение этих объектов не равно 1. Скорее, это их адреса памяти в стеке , которые отличаются, поскольку оба объекта были созданы с использованием оператора new . Если бы мы назначили a |//b , то у нас был бы другой результат:

Integer a = new Integer(1);
Integer b = a;

assertThat(a == b).isTrue();

Теперь давайте посмотрим, что происходит, когда мы используем Integer#значение метода factory:

Integer a = Integer.valueOf(1);
Integer b = Integer.valueOf(1);

assertThat(a == b).isTrue();

В этом случае они считаются одинаковыми. Это связано с тем, что метод valueOf() хранит Целое число в кэше, чтобы избежать создания слишком большого количества объектов-оболочек с одним и тем же значением. Поэтому метод возвращает один и тот же экземпляр Integer для обоих вызовов.

Java также делает это для String :

assertThat("Hello!" == "Hello!").isTrue();

Однако, если бы они были созданы с помощью оператора new , то они не были бы одинаковыми.

Наконец, две null ссылки считаются одинаковыми, в то время как любой объект, не являющийся null , будет считаться отличным от null :

assertThat(null == null).isTrue();

assertThat("Hello!" == null).isFalse();

Конечно, поведение операторов равенства может быть ограничивающим. Что делать, если мы хотим сравнить два объекта, сопоставленные с разными адресами, и все же считать их равными на основе их внутренних состояний? Мы увидим это в следующих разделах.

Как изменить порядок вычисления

Порядок вычисления логических операторов меняют круглые скобки — так же, как в арифметике:

Добавив круглые скобки, мы поменяли приоритеты для вычисления. Теперь сперва будет определено выражение (true ^ true), которое вернёт false. А после — вычислится выражение false & false, которое тоже вернёт false.

То есть скобки повышают приоритет стоящего внутри выражения, а внутри самих скобок действуют прежние приоритеты.

Пример посложнее — выражение !(true && (false || true)) ^ !false.

Порядок вычисления:

  1. !(true && (false || true)) ^ !false
  2. !(true && true) ^ !false
  3. !true ^ !false
  4. false ^ !false
  5. false ^ true
  6. true

Java Integer Math

Математические операции, выполняемые с целочисленными типами Java (byte, short, int и long), ведут себя немного иначе, чем обычные математические операции. Поскольку целочисленные типы не могут содержать дроби, в каждом вычислении с одним или несколькими целочисленными типами все дроби в результате обрезаются. Посмотрите на это математическое выражение:

int result = 100 / 8;

Результат этого деления будет 12,5, но так как два числа являются целыми числами, фракция .5 обрезается. Результат, следовательно, всего 12.

Округление также происходит в подрезультатах больших вычислений.

С плавающей точкой Math

Java содержит два типа данных с плавающей точкой: float и double. Они могут содержать дроби в числах. Если нужны дробные выражения в математических выражениях, вы должны использовать один из этих типов данных. Вот пример математического выражения с плавающей точкой:

double result = 100 / 8;

Несмотря на то, что переменная результата теперь имеет тип с плавающей запятой (double), конечный результат по-прежнему равен 12 вместо 12,5. Причина в том, что оба значения в математическом выражении (100 и 8) оба являются целыми числами. Таким образом, результат деления одного на другое сначала преобразуется в целое число (12), а затем присваивается переменной результата.

Чтобы избежать округления вычислений, необходимо убедиться, что все типы данных, включенные в математическое выражение, являются типами с плавающей запятой. Например, вы могли бы сначала присвоить значения переменным с плавающей запятой следующим образом:

double no1 = 100;
double no2 = 8;

double result = no1 / no2;

Теперь переменная результата будет иметь значение 12,5.

В Java есть способ заставить все числа в расчете быть переменными с плавающей точкой. Вы ставите числа с большой буквы F или D. Вот пример:

double result = 100D / 8D;

Обратите внимание на прописные буквы D после каждого числа. Этот верхний регистр D говорит Java, что эти числа должны интерпретироваться как числа с плавающей запятой, и, таким образом, деление должно быть делением с плавающей запятой, которое сохраняет дроби вместо их обрезания

На самом деле вы также можете сделать число длинным, добавив суффикс числа к верхнему регистру L, но long по-прежнему является целочисленным типом, поэтому он не будет сохранять дробные части в вычислениях.

Точность с плавающей точкой

Типы данных с плавающей точкой не являются точными на 100%. Вы можете столкнуться с ситуациями, когда числа со многими дробями не складываются с ожидаемым числом. Если вычисление с плавающей запятой приводит к числу с большим количеством дробей, чем может обработать число с плавающей запятой или двойное число, дроби могут быть обрезаны. Конечно, заданная точность может быть более чем достаточной для многих типов вычислений, но имейте в виду, что дроби могут фактически быть отсечены.

Посмотрите:

double resultDbl3 = 0D;
System.out.println("resultDbl3 = " + resultDbl3);

for(int i=0; i<100; i++){
    resultDbl3 += 0.01D;
}
System.out.println("resultDbl3 = " + resultDbl3);

Вывод выводится при выполнении этого кода с Java 8:

resultDbl3 = 0.0
resultDbl3 = 1.0000000000000007

Первый оператор System.out.println() правильно печатает значение 0.0, которое является начальным значением переменной resultDbl3.

Однако второй оператор System.out.println() выводит несколько странный результат. Добавление значения 0,01 к 0 всего 100 раз должно привести к значению 1,0, верно? Но каким-то образом окончательный результат 1.0000000000000007. Как видите, что-то не так во фракциях.

Обычно неточность с плавающей запятой незначительна, но все же важно знать об этом

Инвертировать целое число

титульный

Учитывая 32-разрядное целое число со знаком, обратное число в целом числе.

Пример 1: Введите: 123 Вывод: 321

Пример 2: Введите: -123 Вывод: -321

Пример 3: Введите: 120 Вывод: 21

Примечание: Предположим, что наша среда может хранить только 32-разрядные целые числа со знаком, а диапазон значений составляет . Согласно этому предположению, если перевернутое целое число переполняется, возвращается 0.

Точка знаний

Целое, длинное целое, граничное значение с плавающей точкой

  • Максимальное значение границы int: Integer.MAX_VALUE
  • Минимальное значение границы Int: Integer.MIN_VALUE
  • Максимальный максимальный предел: Long.MAX_VALUE
  • Минимальное значение самой длинной границы: Long.MIN_VALUE
  • Максимальное значение границы типа с плавающей точкой: Float.MAX_VALUE
  • Минимальное значение типа Float: Float.MIN_VALUE

Преобразование между целым и длинным целым

Не форсируйте напрямую преобразование категорий данных, это приведет к ошибкам компиляции. Есть два лучших способа (long a = 23;)

  1. С помощью длинного класса: int new_a = new Long(a).intValue();
  2. Со строками: int new_a = Integer.parseInt(String.valueOf(y));

решение

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

Решение 1: Сравните значение после обратного порядка непосредственно с граничным значением.

Решение 2. Сначала представьте обратное целое число с типом long и посмотрите, согласуются ли обратные значения long и int.

Apache Commons

Теперь давайте взглянем на библиотеку Apache Commons . Прежде всего, давайте импортируем зависимость Maven :

org.apache.commonscommons-lang33.11

7.1. Метод ObjectUtils#NotEqual

Во-первых, давайте поговорим о методе ObjectUtils#NotEqual . Требуется два аргумента Object , чтобы определить, не равны ли они, в соответствии с их собственной реализацией метода equals () . Он также обрабатывает значения null .

Давайте повторно используем наши примеры String :

String a = new String("Hello!");
String b = new String("Hello World!");

assertThat(ObjectUtils.notEqual(a, b)).isTrue();

Следует отметить, что ObjectUtils имеет метод equals () . Однако это устарело с Java 7, когда появились Objects#equals

7.2. Метод сравнения объектов#

Теперь давайте сравним порядок объектов с методом ObjectUtils#compare . Это универсальный метод, который принимает два Сопоставимых аргумента этого универсального типа и возвращает Целое число .

Давайте еще раз посмотрим, как использовать Strings :

String first = new String("Hello!");
String second = new String("How are you?");

assertThat(ObjectUtils.compare(first, second)).isNegative();

По умолчанию метод обрабатывает значения null , считая их большими. Он предлагает перегруженную версию, которая предлагает инвертировать это поведение и считать их меньшими, принимая аргумент boolean .

Math.round()

Метод Math.round() округляет число с плавающей точкой или удваивается до ближайшего целого числа, используя обычные правила математического округления (вверх или вниз):

double roundedDown = Math.round(23.445);
double roundedUp   = Math.round(23.545);

После выполнения этих двух операторов Java переменная roundedDown будет содержать значение 23,0, а переменная roundndedUp будет содержать значение 24,0.

Math.random()

Метод Math.random() возвращает случайное число с плавающей запятой в диапазоне от 0 до 1. Конечно, это число не полностью случайное, но результат некоторого вычисления, которое должно сделать его настолько непредсказуемым, насколько это возможно. Вот пример:

double random = Math.random();

Чтобы получить случайное значение между 0 и, например, 100, умножьте значение, возвращаемое Math.random(), на максимальное число (например, 100). Вот пример того, как это может выглядеть:

double random = Math.random() * 100D;

Если вам нужно целочисленное значение, используйте метод round(), floor() или ceil().

вывод

При сравнении чисел с плавающей запятой необходимо учитывать три основных фактора:

  • NaN
  • Бесконечность / бесконечно маленький
  • Ошибка округления

Возможные сценарии NaN и бесконечности выглядят следующим образом

Итак, чтобы сравнить, равны ли числа с плавающей запятой, вам нужно сделать следующее:

  • Исключить NaN и бесконечность
  • Сравнить с точностью

Например, следующий пример:

  1. public boolean isEqual(double a, double b) {  
  2.     if (Double.isNaN(a) || Double.isNaN(b) || Double.isInfinite(a) || Double.isInfinite(b)) {  
  3.         return false;  
  4.     }  
  5.     return (a — b) < .001d;  
  6. }  

Конечно, если вам нужны точные ситуации, такие как финансовые расчеты, вы можете рассмотреть BigDecimal.

Это хорошо для всего, но немного неэффективно. Вам нужно выбирать между производительностью и точностью.  

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: