Como um ponto flutuante de 80 bits pode ser usado por um sistema de 32 bits? [duplicado]


13

Como um sistema de 32 bits não pode gerenciar um número de 2 ^ 33 (devido ao óbvio limite de 32 bits), como gerenciar um número de ponto flutuante de 80 bits ?

Deve exigir "80 bits" ...


8
Da mesma forma que um número de ponto flutuante de 64 bits. Ele usa 3 ou (2) registradores de 32 bits. Como o número de ponto flutuante de 80 bits nem sequer é um tamanho padrão, na verdade seria um número de 96 bits, com apenas 80 bits sendo usados.
Ramhound 30/07

5
Quando você se preocupa com a vulnerabilidade da plataforma, está preocupado com o funcionamento interno da CPU, como já foi dito, e com a maneira como as instruções são executadas nativamente no sistema. Os números IEEE754 geralmente são processáveis ​​diretamente nas unidades de execução de FPUs da sua CPU, enquanto um número de 128 bits exigiria o uso de várias instruções programadas para que possam agregar o significado do valor que o aplicativo está avaliando. que deixa o processamento do número até o aplicativo.
30514 Frank Frank Thomas

2
@ Ƭᴇcʜιᴇ007 Não é um idiota disso . Essa é mais sobre a diferença entre um número e sua representação em texto / ASCII, embora algumas dessas respostas também possam abordar isso.
30714 Bob

3
Em praticamente todas as máquinas modernas, o ponto flutuante é tratado por um processador separado (embora geralmente no mesmo chip que o processador principal). Todos esses processadores sabem como lidar com 80 bits (embora alguns o façam muito mais rápido que outros). ( E a "largura" de um processador é algo de uma ficção de qualquer maneira. )
Daniel R Hicks

6
@ Ramhound: Não, 80 bits é uma peculiaridade do 8087 e usa 1 registro FP. Definitivamente, não é um número de 96 bits.
MSalters

Respostas:


35

Um dos significados de uma CPU de 32 bits é que seus registradores têm 32 bits de largura. Isso não significa que ele não possa lidar com, digamos, números de 64 bits, apenas que ele precisa lidar com os 32 bits inferiores primeiro e depois com os 32 bits superiores e meio. (É por isso que as CPUs têm um sinalizador de transporte .) É mais lento do que se a CPU pudesse carregar os valores em um registro de 64 bits mais amplo, mas ainda possível.

Portanto, o "número mínimo" de um sistema não limita necessariamente o tamanho dos números com os quais um programa pode lidar, porque você sempre pode interromper as operações que não cabem nos registros da CPU em várias operações. Portanto, isso torna as operações mais lentas, consome mais memória (se você precisar usar a memória como um "bloco de notas") e mais difícil de programar, mas as operações ainda são possíveis.

No entanto, nada disso importa com, por exemplo, processadores Intel de 32 bits e ponto flutuante, pois a parte do ponto flutuante da CPU possui seus próprios registros e eles têm 80 bits de largura. (No início da história do x86, o recurso de ponto flutuante era um chip separado, foi integrado ao CPU a partir do 80486DX.)


A resposta da @ Breakthrough me inspirou a adicionar isso.

Os valores de ponto flutuante, na medida em que são armazenados nos registros da FPU, funcionam muito diferentes dos valores inteiros binários.

Os 80 bits de um valor de ponto flutuante são divididos entre uma mantissa e expoente (também existe a "base" nos números de ponto flutuante que é sempre 2). A mantissa contém os dígitos significativos e o expoente determina o tamanho desses dígitos significativos. Portanto, não há "transbordamento" em outro registro, se seu número for grande demais para caber na mantissa, seu expoente aumentará e você perderá precisão - ou seja, ao convertê-lo em um número inteiro, você perderá casas decimais à direita - é por isso que é chamado ponto flutuante.

Se o seu expoente for muito grande, você terá um estouro de ponto flutuante, mas não poderá estendê-lo facilmente para outro registrador, pois o expoente e a mantissa estão ligados.

Eu poderia estar impreciso e errado sobre um pouco disso, mas acredito que é a essência disso. (Este artigo da Wikipedia ilustra o exposto um pouco mais sucintamente.)

Não há problema em que isso funcione de maneira totalmente diferente, já que toda a parte de "ponto flutuante" da CPU está em seu próprio mundo - você usa instruções especiais da CPU para acessá-la e tal. Além disso, no ponto da questão, por ser separado, a testemunha da FPU não está intimamente associada à testemunha da CPU nativa.


4
Tudo o que você adicionou da minha inspiração está correto, então não se preocupe :) Apenas um ponto que devo mencionar, embora você possa usar instruções nativas da CPU onde existe uma unidade de ponto flutuante, também é possível executar operações de ponto flutuante no software (com o equivalente bit a bit operações matemáticas inteiras). Para estender até esse ponto, com memória suficiente, você também pode ter números de precisão arbitrários (em oposição aos nossos 64 bits fixos ou 80 bits nesse caso) usando algoritmos / bibliotecas de software (um usado com freqüência é o GNU Multiple Precision biblioteca ).
Breakout

1
Nitpick: primeiro Intel integrado FPU estava no 80486DX, não a 80386.
spudone

2
@ markzzz: Nada é louco, se for necessário. O uso de flutuadores de 16 bits para simular uma bomba atômica para avaliar seu estoque nuclear é uma loucura, porque não é preciso o suficiente para você ter certeza do resultado. Nesse caso, são necessários 32 bits (e sim, antigamente, esses cálculos eram feitos em PDPs de 16 bits). Da mesma forma, o uso de folatos de 32 bits para simular o clima não é preciso o suficiente devido à natureza caótica dos cálculos.
slebetman

2
FWIW, a maneira comum de implementar operações de ponto flutuante em máquinas sem unidades FP do tamanho desejado é fazê-lo em software usando instruções inteiras. Porque, no final do dia, o expoente e a mantissa do número de ponto flutuante são meramente números inteiros. É como nós os interpretamos que lhes dá significados especiais.
slebetman

2
@PTwr no x86, você realmente tem 7 GPRs utilizáveis ​​para dados, EBP incluído. É que a ABI da maioria das implementações de idiomas reserva esse registro para ponteiro de quadro de pilha. Mas, por exemplo, com o GCC, você pode usar -fomit-frame-pointerpara recuperar esse registro.
Ruslan

13

Todos os 32 bits, 64 bits e 128 bits se referem ao tamanho da palavra do processador, que pode ser considerado o "tipo de dados fundamental". Freqüentemente, esse é o número de bits transferidos para / da RAM do sistema e a largura dos ponteiros (embora nada o impeça de usar o software para acessar mais RAM do que um único ponteiro pode acessar).

Assumindo uma velocidade de clock constante (assim como tudo na arquitetura sendo constante) e assumindo que as leituras / gravações de memória sejam a mesma velocidade (assumimos 1 ciclo de clock aqui, mas isso está longe de ser o caso na vida real), você pode adicione dois números de 64 bits em um único ciclo de clock em uma máquina de 64 bits (três se você contar buscando os números da RAM):

ADDA [NUM1], [NUM2]
STAA [RESULT]

Também podemos fazer o mesmo cálculo em uma máquina de 32 bits ... No entanto, em uma máquina de 32 bits, precisamos fazer isso em software, pois os 32 bits inferiores devem ser adicionados primeiro, compensar o estouro e adicionar os 64 bits superiores:

     ADDA [NUM1_LOWER], [NUM2_LOWER]
     STAA [RESULT_LOWER]
     CLRA          ; I'm assuming the condition flags are not modified by this.
     BRNO CMPS     ; Branch to CMPS if there was no overflow.
     ADDA #1       ; If there was overflow, compensate the value of A.
CMPS ADDA [NUM1_UPPER], [NUM2_UPPER]
     STAA [RESULT_UPPER]

Analisando minha sintaxe de montagem composta, é possível ver facilmente como as operações de maior precisão podem levar um tempo exponencialmente maior em uma máquina com menor comprimento de palavra. Essa é a chave real dos processadores de 64 e 128 bits: eles nos permitem lidar com um número maior de bits em uma única operação. Algumas máquinas incluem instruções para adicionar outras quantidades com um transporte (por exemplo, ADCem x86), mas o exemplo acima tem valores de precisão arbitrários em mente.


Agora, para estender isso à questão, é simples ver como podemos adicionar números maiores que os registros que temos disponíveis - apenas dividimos o problema em pedaços do tamanho dos registros e trabalhamos a partir daí. Embora como mencionado pelo @MatteoItalia , a pilha FP87 x87 tenha suporte nativo para quantidades de 80 bits, em sistemas sem esse suporte (ou nos processadores sem uma unidade de ponto flutuante inteiramente!), Os cálculos / operações equivalentes devem ser executados no software .

Portanto, para um número de 80 bits, depois de adicionar cada segmento de 32 bits, também seria possível verificar o estouro no 81-bit e, opcionalmente, zerar os bits de ordem superior. Essas verificações / zeros são executados automaticamente para determinadas instruções x86 e x86-64, onde os tamanhos dos operandos de origem e destino são especificados (embora sejam especificados apenas em potências de 2 a partir de 1 byte de largura).

Obviamente, com números de ponto flutuante, não se pode simplesmente executar a adição binária, pois a mantissa e os dígitos significativos são agrupados em forma de deslocamento. Na ALU em um processador x86, há um circuito de hardware para fazer isso para flutuadores IEEE de 32 e 64 bits; no entanto , mesmo na ausência de uma unidade de ponto flutuante (FPU), os mesmos cálculos podem ser realizados em software (por exemplo, através do uso da GNU Scientific Library , que usa uma FPU quando compilada em arquiteturas, voltando aos algoritmos de software se nenhum hardware de ponto flutuante estiver disponível [por exemplo, para microcontroladores incorporados sem FPUs]).

Se houver memória suficiente, também é possível realizar cálculos em números de precisão arbitrária (ou "infinita" - dentro de limites realistas), usando mais memória, pois é necessária mais precisão. Uma implementação disso existe na biblioteca GNU Multiple Precision , permitindo precisão ilimitada (até que a RAM esteja cheia, é claro) em operações inteiras, racionais e de ponto flutuante.


2
Você não mencionou os detalhes mais importantes: a FPU x87 na plataforma x86 possui registradores de ponto flutuante de 80 bits de largura; portanto, seus cálculos nativos são realmente feitos em flutuadores de 80 bits, sem necessidade de emular nada no software.
Matteo Italia

@MatteoItalia Vejo isso agora, obrigado. Eu pensei que a pergunta original estava pedindo uma visão geral mais genérica de como alguém poderia executar operações em números maiores que o tamanho da palavra do processador, e não a implementação específica de flutuações estendidas de 80 bits no x86 (também porque meu exemplo foi 90 bits em vez de 80 ...). Atualizei a resposta agora para refletir melhor isso, obrigado pelo alerta.
Breakthrough

5

A arquitetura da memória do sistema pode permitir que você mova 32 bits de uma só vez - mas isso não impede o uso de números maiores.

Pense em multiplicação. Você pode conhecer suas tabelas de multiplicação de até 10x10, mas provavelmente não tem problemas para executar 123x321 em um pedaço de papel: basta dividi-lo em muitos pequenos problemas, multiplicando dígitos individuais e cuidando do transporte, etc.

Os processadores podem fazer a mesma coisa. Nos "velhos tempos", você tinha processadores de 8 bits que podiam fazer cálculos de ponto flutuante. Mas eles eram slooooooow.


1
Eles foram lentos apenas após um certo ponto. Você pode escrever operações de ponto flutuante "rápidas" se se limitar a uma determinada especificação.
Ramhound

3

"32 bits" é realmente uma maneira de categorizar processadores, não uma decisão definitiva. um processador de "32 bits" normalmente possui registradores de uso geral de 32 bits para trabalhar.

No entanto, não há um requisito básico de que tudo no processador seja feito em 32 bits. Por exemplo, não era algo inédito para um computador de "32 bits" ter um barramento de endereços de 28 bits, porque era mais barato fabricar o hardware. Os computadores de 64 bits geralmente têm apenas um barramento de memória de 40 ou 48 bits pelo mesmo motivo.

A aritmética de ponto flutuante é outro local em que os tamanhos variam. Muitos processadores de 32 bits são compatíveis com números de ponto flutuante de 64 bits. Eles fizeram isso armazenando os valores de ponto flutuante em registros especiais que eram mais largos que os registros de uso geral. Para armazenar um desses grandes números de ponto flutuante nos registros especiais, primeiro se deve dividir o número entre dois registros de uso geral e depois emitir uma instrução para combiná-los em um ponto flutuante nos registros especiais. Uma vez nesses registros de ponto flutuante, os valores seriam manipulados como flutuadores de 64 bits, e não como um par de metades de 32 bits.

A aritmética de 80 bits que você mencionou é um caso especial disso. Se você trabalhou com números de ponto flutuante, está familiarizado com a imprecisão resultante de problemas de arredondamento de ponto flutuante. Uma solução para o arredondamento é ter mais bits de precisão, mas você precisa armazenar números maiores e forçar os desenvolvedores a usar valores de ponto flutuante incomumente grandes na memória.

A solução da Intel é que os registradores de ponto flutuante são todos de 80 bits, mas as instruções para mover valores de / para esses registradores funcionam primariamente com números de 64 bits. Desde que você opere inteiramente na pilha de pontos flutuantes x87 da Intel, todas as suas operações são feitas com 80 bits de precisão. Se o seu código precisar extrair um desses valores dos registros de ponto flutuante e armazená-lo em algum lugar, ele o truncará para 64 bits.

Moral da história: categorizações como "32 bits" são sempre mais perigosas quando você se aprofunda nas coisas!


Mas se eu usar valores de ponto flutuante de 32 bits em um sistema de 16 bits (ou valores de ponto flutuante de 64 bits em um sistema de 32 bits), será necessária apenas mais memória (já que é necessário registrar duas vezes)? Ou o processamento das informações aumentará a sobrecarga, portanto levará mais tempo?
markzzz

@markzzz: Trabalhar com vários registros quase sempre leva mais tempo #
Mooing Duck

Carregar o valor do ponto flutuante de 32 bits nos registros de finalidade especial levará mais tempo. No entanto, uma vez armazenados como flutuadores de 32 bits nos registros de ponto flutuante para fins especiais, o hardware operará nesses valores de ponto flutuante em velocidade máxima. Lembre-se, "16 bits" refere-se apenas ao tamanho dos registros de finalidade GERAL. Os registros de ponto flutuante são especialmente feito sob medida para sua tarefa, e pode ser mais larga (32 bits de largura no seu caso)
Cort Ammon - Reintegrar Monica

2

Uma CPU de "32 bits" é aquela em que a maioria dos registradores de dados é de 32 bits e a maioria das instruções opera com dados nesses registradores de 32 bits. Também é provável que uma CPU de 32 bits transfira dados de e para a memória de 32 bits por vez. A maioria dos registros com 32 bits não significa que todos os registros sejam de 32 bits. A resposta curta é que uma CPU de 32 bits pode ter alguns recursos que usam outras contas de bits, como registros de ponto flutuante de 80 bits e instruções correspondentes.

Como a @spudone disse em um comentário à resposta da @ ultrasawblade, a primeira CPU x86 a ter operações de ponto flutuante integradas foi o Intel i486 (especificamente o 80486DX, mas não o 80486SX), que, de acordo com a Página 15-1 dos programadores de microprocessador i486 Manual de Referência , inclui em seus registros numéricos "Oito registros numéricos de 80 bits endereçáveis ​​individualmente". O i486 possui um barramento de memória de 32 bits, portanto, a transferência de um valor de 80 bits levaria três operações de memória.

O antecessor da geração 486, o i386, não possuía operações integradas de ponto flutuante. Em vez disso, tinha suporte para o uso de um "coprocessador" de ponto flutuante externo, o 80387. Esse coprocessador tinha quase a mesma funcionalidade que foi integrada ao i486, como você pode ver na Página 2-1 do Manual de Referência do Programador 80387 .

O formato de ponto flutuante de 80 bits parece ter se originado no 8087, o coprocessador matemático para o 8086 e o ​​8088. O 8086 e o ​​8088 eram CPUs de 16 bits (com barramentos de memória de 16 e 8 bits) e ainda eram capazes para usar o formato de ponto flutuante de 80 bits, aproveitando os registros de 80 bits no coprocessador.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.