← Назад к вопросам

Что такое знаковые числа?

2.0 Middle🔥 191 комментариев
#Другое

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Знаковые числа (Signed Numbers)

Знаковые числа (Signed Numbers) — это целые числа, которые могут быть как положительными, так и отрицательными. Они используют один бит для обозначения знака числа, а остальные биты — для представления абсолютного значения.

Противоположность: беззнаковые числа

Беззнаковые числа (Unsigned Numbers) — используют все биты для представления только положительных значений.

В Java

Java работает только со знаковыми числами для целочисленных типов.

Целочисленные типы в Java

// Знаковые целые типы
byte value1 = -128;        // 8 бит: от -128 до 127
short value2 = -32768;     // 16 бит: от -32768 до 32767
int value3 = -2147483648;  // 32 бита: от -2147483648 до 2147483647
long value4 = -9223372036854775808L; // 64 бита: от -2^63 до 2^63-1

// Положительные значения
int positive = 100;
int negative = -100;
int zero = 0;

Таблица границ типов

Тип     | Размер  | Минимум              | Максимум
--------|---------|----------------------|----------------------
byte    | 8 бит   | -128                 | 127
short   | 16 бит  | -32,768              | 32,767
int     | 32 бита | -2,147,483,648       | 2,147,483,647
long    | 64 бита | -9.22e18             | 9.22e18

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

Дополнительный код (Two's Complement) — это метод, используемый в современных компьютерах.

Пример: число 5 в 8 битах

5 = 00000101

Пример: число -5 в 8 битах

Шаг 1: Инвертируем биты числа 5
  00000101 → 11111010

Шаг 2: Добавляем 1
  11111010 + 1 = 11111011

-5 = 11111011

Проверка:

11111011 + 00000101 = 100000000
(переполнение игнорируется, остаётся 0)

Практические примеры в Java

public class SignedNumbersExample {
    
    public static void main(String[] args) {
        // Положительные и отрицательные числа
        int positive = 42;
        int negative = -42;
        
        System.out.println("Положительное: " + positive);  // 42
        System.out.println("Отрицательное: " + negative);  // -42
        
        // Границы int
        int max = Integer.MAX_VALUE;        // 2147483647
        int min = Integer.MIN_VALUE;        // -2147483648
        
        System.out.println("Max int: " + max);
        System.out.println("Min int: " + min);
        
        // Переполнение
        int overflow = max + 1;
        System.out.println("Max + 1: " + overflow);  // -2147483648 (обойдёт вокруг)
        
        // Бинарное представление
        System.out.println(Integer.toBinaryString(5));   // 101
        System.out.println(Integer.toBinaryString(-5));  // 11111111111111111111111111111011
    }
}

Проблемы при работе со знаковыми числами

1. Переполнение (Integer Overflow)

int max = Integer.MAX_VALUE;  // 2147483647
int overflow = max + 1;        // -2147483648 ("обнулился")

// Это может привести к ошибкам
public int multiply(int a, int b) {
    return a * b;  // Может переполниться!
}

// Решение: использовать long
public long multiply(int a, int b) {
    return (long) a * b;
}

2. Неправильное сравнение

int negative = -1;
int positive = 1;

System.out.println(negative < positive);   // true (правильно)
System.out.println(negative < 0);          // true (правильно)
System.out.println(Integer.compare(negative, positive)); // -1 (правильно)

3. Побитовые операции

int value = -5;

// Побитовое НЕ (NOT)
int notValue = ~value;
System.out.println(~(-5));  // 4

// Сдвиг вправо (арифметический)
int rightShift = value >> 1;
System.out.println((-5) >> 1);  // -3 (знак сохраняется)

// Сдвиг вправо (логический)
int logicalShift = value >>> 1;
System.out.println((-5) >>> 1);  // 2147483645

Когда нужны беззнаковые числа

Java не имеет встроенных беззнаковых типов, но в Java 8+ добавлены методы для работы с беззнаковыми значениями:

public class UnsignedExample {
    public static void main(String[] args) {
        // Эмуляция беззнакового int
        int unsignedValue = -1;  // В памяти: 0xFFFFFFFF
        
        // Преобразуем в строку как беззнаковое
        String unsignedString = Integer.toUnsignedString(unsignedValue);
        System.out.println(unsignedString);  // 4294967295
        
        // Сравнение беззнаковых значений
        int a = -1;    // 0xFFFFFFFF
        int b = 1;
        
        System.out.println(a < b);  // true (как знаковые)
        System.out.println(Integer.compareUnsigned(a, b));  // 1 (a > b как беззнаковые)
        
        // Деление беззнаковых значений
        int dividend = -1;    // 0xFFFFFFFF (4294967295 как беззнаковое)
        int divisor = 2;
        
        System.out.println(Integer.divideUnsigned(dividend, divisor));  // 2147483647
    }
}

Сравнение: знаковые vs беззнаковые

Бинарное представление | Знаковое | Беззнаковое
----------------------|----------|------------
00000101              | 5        | 5
11111011              | -5       | 251
11111111              | -1       | 255

Практическое применение

public class PaymentProcessor {
    
    // Правильно: используем долгие для денег
    public long calculateTotal(int price, int quantity) {
        return (long) price * quantity;  // Избегаем переполнения
    }
    
    // Проверка диапазонов
    public boolean isValidAge(int age) {
        return age >= 0 && age <= 120;
    }
    
    // Работа с битами
    public boolean isBitSet(byte value, int bitIndex) {
        return (value & (1 << bitIndex)) != 0;
    }
    
    // Установка бита
    public byte setBit(byte value, int bitIndex) {
        return (byte) (value | (1 << bitIndex));
    }
}

Ключевые моменты

  1. Java использует знаковые числа для всех целых типов
  2. Дополнительный код — метод хранения отрицательных чисел
  3. Переполнение может привести к ошибкам — нужна проверка границ
  4. Побитовые операции работают иначе с отрицательными числами
  5. Для больших значений используйте long или BigInteger
  6. Для беззнаковых операций используйте методы Integer.compareUnsigned и т.д.

Понимание знаковых чисел критично для работы с низкоуровневыми операциями, оптимизацией памяти и предотвращением ошибок переполнения.