Por que o Java converte números inteiros maiores que 127 para valores negativos em castings do tipo byte?
Tags: java, bytecode, twoscomplement, henriqueotogami
Published: 2023-05-23 00:48:49

<figure>
<img width="auto" src="https://raw.githubusercontent.com/henriqueotogami/gist-otogami-tips/main/src/main/resources/com/otogamidev/gist/images/Medium-TwosComplement-Image-01.png">
<figcaption>Imagem 01 — Exemplo de “modelagem” de um número inteiro em um byte.
</figcaption>
</figure>

---

## Pegue um cafézinho, vamos conversar


#### Tropecei na conversão e continuei (~andando~) programando


Durante meu dia a dia no trabalho, é recorrente trabalhar com conjuntos de dados em bytes. Em um desses dias, armazenei um número inteiro "modelando-o" (casting) em uma variável que esperava receber um byte, semelhantemente ao exemplo da Imagem 01.

Quando fui verificar o valor contido nessa variável, percebi o valor negativo, convertido e armazenado nela.

**A princípio, não entendi a razão disso.**

Depois de pesquisar, descobri que, internamente, o Java implementa o algoritmo do Complemento de Dois para alguns tipos primitivos de dados, como o de bytes.

Resumidamente, a função dele é converter um número inteiro positivo para outro número inteiro negativo, mantendo fixo o comprimento máximo de sua representação binária.

<figure>
<img width="auto" src="https://images.unsplash.com/46/nQZcA7PRTyuduZPSZQ88_wanderlust.jpg">
<figcaption>Photo by Amanda Sandlin on Unsplash.</figcaption>
</figure>

---

## Acabou o cafézinho, vamos a obra

#### Definição do algoritmo original do Complemento de Dois

Antes de entender como o Java está implementando o algoritmo, vamos conhecer um pouquinho da definição do algoritmo original, no trecho abaixo.

> "Two’s complement is a mathematical operation to reversibly convert a positive binary number into a negative binary number with equivalent negative value, using the binary digit with the greatest place value as the sign to indicate whether the binary number is positive or negative.
> It is used in computer science as the most common method of representing signed (positive, negative, and zero) integers on computers, and more generally, fixed point binary values.
> When the most significant bit is 1, the number is signed as negative; and when the most significant bit is 0 the number is signed as positive."

[Fonte [1]](en.wikipedia.org/wiki/Two’s_complement
Documentação oficial do Java |
docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)

---

<figure>
<img width="auto" src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExOWM1YzMxOGFjNDlkYjVhNDY3OTAyNGYxOWI3MzdhNWYzNDc5MWI4NyZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PWc/BmmfETghGOPrW/giphy.gif">
<figcaption>GIF 01 — Imagem animada contendo uma pessoa com a mente caótica após ler a explicação técnica.</figcaption>
</figure>

<hr>

Se você não entendeu a definição do algoritmo, não se preocupe. Vamos ver a estrutura lógica, detalhada abaixo.

### Lógica do algoritmo original do Complemento de Dois

> Observação: Vamos considerar o nome “decimalToParser” para o número inteiro.

1. O decimalToParser deve ser inteiro (positivo ou negativo);

2. Utilize a Equação 01:
    
    <iframe src="https://math.embed.fun/embed/pJeGoYeUdzipFrJZUKUJKM" frameborder="0" width="420" height="135"></iframe>
    
    {% katex %}  secondComplement = [ (2 ^ n) - | decimalToParser | ] {% endkatex %}
    
    <figure>
    <figcaption>Equação 01 — Fórmula para calcular o segundo complemento do algoritmo de Complemento de Dois.</figcaption>
    </figure>

3. Obtenha o valor binário do resultado da Equação 01;

4. Inverta o valor binário do resultado;

5. Identifique o bit mais significativo (MSB) do valor binário invertido. O bit mais significativo está posicionado na extremidade esquerda;

6. Verificar o valor do bit mais significativo:
    - Se for zero (“0”), o valor final do segundo complemento deve ser positivo;
    - Se for zero (“1”), o valor final do segundo complemento deve ser negativo;

Parâmetros da Equação 01:

- secondComplement é o valor calculado do segundo complemento;
- 2 é o número indicativo de um sistema binário;
- n é o número indicativo do tamanho de bits (explicado abaixo);

> Observação: O valor de decimalToParser está em módulo na equação 01.

---

Ainda não entendeu?
Não se preocupe, eu trouxe exemplos abaixo 😂 😂 😂 😂

<figure>
<img width="auto" src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExMTBhOGQxMWViYzM1ZjExODJjZmFmNTU5MjVhNmIxNTg3YjkwOGNiMSZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PWc/l1J9NRpOeS7i54xnW/giphy.gif">
<figcaption>GIF 02 — Imagem animada mostrando uma pessoa tranquilizando alguém em estado de desespero.</figcaption>
</figure>

<hr>

#### Algoritmo original: Exemplo da lógica de cálculo

Utilizando o valor (207 em decimal) que foi convertido (-49 em bytes) na Imagem 01, acompanhe a demonstração de cálculo do algoritmo em seis etapas, conforme mencionado acima, na Imagem 02 abaixo.

<figure>
<img width="auto" src="https://raw.githubusercontent.com/henriqueotogami/gist-otogami-tips/main/src/main/resources/com/otogamidev/gist/images/Medium-TwosComplement-Image-02.png">
<figcaption>Imagem 02 — Demonstração de cálculo em seis etapas do algoritmo original do Complemento de Dois.
</figcaption>
</figure>

<hr>

#### Algoritmo original: Exemplo de implementação de cálculo no Java
Utilizando a mesma estrutura da demonstração da Imagem 02, acompanhe abaixo a implementação em Java.

{% gist https://gist.github.com/henriqueotogami/ec1fc3e2a5b1349b22ae6eb02a198551 %}

<figcaption>Código 01 — Implementação em Java da demonstração realizada na Imagem 02.
</figcaption>

---

Se você quiser contribuir com o código acima no Gist, acesse:
[TwosComplement.java](https://gist.github.com/henriqueotogami/ec1fc3e2a5b1349b22ae6eb02a198551)

---

## A implementação do algoritmo utilizada no Java

### Definição do tipo de dados primitivo de byte

Primeiramente, é necessário entender a estrutura de dados primitivos, por isso considere a definição de byte na documentação do Java:

> “byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive).
> The byte data type can be useful for saving memory in large arrays, where the memory savings actually matters.
> They can also be used in place of int where their limits help to clarify your code; the fact that a variable's range is limited can serve as a form of documentation."

[Fonte [2]](medium.com/@jeanvillete/java-makes-use-of-the-twos-complement-for-representing-signed-numbers-31e421725c04)

<br>

Para ficar mais fácil de perceber a diferença, podemos resumir a definição acima comparando os tamanhos de tipos de dados mencionados:

<figure>
<img width="auto" src="https://raw.githubusercontent.com/henriqueotogami/gist-otogami-tips/main/src/main/resources/com/otogamidev/gist/images/Medium-TwosComplement-Image-03.png">
<figcaption>Imagem 03 — Exemplo do tamanho em bits dos tipos primitivos int e byte no Java.</figcaption>
</figure>

---

Então, como diz no trecho citado da documentação, o objetivo da utilização do tipo de dados de byte é para economizar a memória interna disponível no hardware. Além disso, limitar a largura de bits dos dados implica em aumentar a performance do processamento ou de cálculos em baixo nível.

---

### Algoritmo implementado no java: Exemplo em código

{% gist https://gist.github.com/henriqueotogami/8befc39d52d4ded25a85c131f27dc161 %}

<figcaption>Código 02 — Implementação do algoritmo conforme padrão do Java.
</figcaption>

---

Se você quiser contribuir com o código acima no Gist, acesse:
[JavaTwosComplement.java](https://gist.github.com/henriqueotogami/8befc39d52d4ded25a85c131f27dc161)

---

## Exemplo executável

A vida do dev não se resume a teoria, não é mesmo? 😂 😂 😂 😂

Por isso, eu também trouxe um exemplo executável para simular a estrutura explicada acima, dos dois algoritmos.

{% replit https://replit.com/@henriqueotogami/JavaTwosComplement %}

<figcaption>Código 03 — Classe em Java com método de cálculo do complemento de dois implementado.
</figcaption>

> Se você quiser contribuir com o código acima, basta clicar em "Open on Replit".

---

### Tá, mas qual é a vantagem de utilizar esse algoritmo?

#### 1. Padronização para menor consumo de dados

Conforme foi explicado anteriormente, o Java define que o tipo primitivo byte possui o tamanho de oito bits, por padrão.

Ou seja, quando necessários, os cálculos a serem realizados com esses dados serão mais simples de serem realizados e exigirão bem pouco do hardware.

---

#### 2. Soma e subtração sem verificar o sinal dos operandos

O algoritmo original do Complemento de Dois considera que todo número positivo será representado por um número negativo e vice-versa. Esse número negativo corresponde a outro decimal calculado pela Equação 01.

---

Considerando a afirmação acima do algoritmo original, a Imagem 04 abaixo mostra o exemplo do cálculo entre um número positivo e outro negativo.

Para realizar esse cálculo, não é necessário verificar o sinal de cada operando. Basta apenas encontrar o complemento de dois do número negativo e realizar a soma com o valor binário do número positivo, considerando as regras de soma binária.

O algoritmo ainda diz que a soma de um valor binário de um número decimal com o binário do seu complemento de dois deve resultar em zero. E essa verificação é demonstrada no item 1.2 da Imagem 04.

<figure>
<img width="auto" src="https://raw.githubusercontent.com/henriqueotogami/gist-otogami-tips/main/src/main/resources/com/otogamidev/gist/images/Medium-TwosComplement-Image-04.png">
<figcaption>Imagem 04 — Exemplo de operação de soma / subtração utilizando o Complemento de Dois.</figcaption>
</figure>

---

## Fontes

[ 01 - Artigo na Wikipedia ]( en.wikipedia.org/wiki/Two’s_complement
Documentação oficial do Java |
docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html);

[ 02 - Java makes use of the "two's complement" for representing signed numbers | by Jean Villete ]( medium.com/@jeanvillete/java-makes-use-of-the-twos-complement-for-representing-signed-numbers-31e421725c04);

[ 03 - Two's complement solution very detailed explanation | by kapkan ](leetcode.com/problems/sum-of-two-integers/solutions/1561732/Two's-complement-solution-very-detailed-explanation);

---

<figure>
<img width="auto" src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExY2E1OTI1OTM4NjVjYzVmM2U4OGFlNjViNzM4ZDAzN2NjNjEyMWFhMiZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PWc/BOXEslaIrwS8jXuVeZ/giphy.gif">
</figure>

### Ficou alguma dúvida ou tem sugestões?

### Comente aqui embaixo ou me chame em alguma das minhas redes.

### Valeu! ✌🏻