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" ...
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" ...
Respostas:
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.
-fomit-frame-pointer
para recuperar esse registro.
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, ADC
em 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.
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.
"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!
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.