Detectando estouro na soma


8

Suponha que eu receba uma matriz de números inteiros de largura fixa (ou seja, eles se encaixam em um registro de largura ), . Eu quero calcular a soma em uma máquina com aritmética de complemento 2, que executa adições do módulo com semântica envolvente. Isso é fácil - mas a soma pode exceder o tamanho do registro e, se o fizer, o resultado estará errado.nwa1,a2,anS=a1++an2w

Se a soma não exceder, desejo calculá-la e verificar se não há excedência o mais rápido possível. Se a soma exceder, quero apenas saber que sim, não me importo com nenhum valor.

Adicionar ingenuamente números na ordem não funciona, porque uma soma parcial pode estourar. Por exemplo, com registradores de 8 bits, é válido e possui uma soma de , mesmo que a soma parcial(120,120,115)125120+120 excede o intervalo de registro [128,127].

Obviamente, eu poderia usar um registro maior como um acumulador, mas vamos assumir o caso interessante em que já estou usando o maior tamanho de registro possível.

Existe uma técnica conhecida para adicionar números com o sinal oposto à soma parcial atual . Essa técnica evita estouros a cada etapa, com o custo de não ser compatível com o cache e não aproveitar muito a previsão de ramificação e a execução especulativa.

Existe uma técnica mais rápida que talvez aproveite a permissão para estourar somas parciais e seja mais rápida em uma máquina típica com um sinalizador de estouro, um cache, um preditor de ramificação e execução e cargas especulativas?

(Este é um acompanhamento da soma segura de estouro )


Por que a solução de Dave não funciona bem com caches e pipelines na sua opinião? Se você fizer algo semelhante ao particionamento do Quicksort no local com o pivô virtual0 0, você trata bem os caches durante o particionamento e o seguinte somatório. Eu não sei sobre previsões incorretas de ramificação durante o particionamento, mas a fase de soma deve se sair bem nesse sentido também.
Raphael

@ Rafael Na minha aplicação, o excesso é o caso excepcional. Condicionais correspondentes a "isso transborda?" são, portanto, bem servidos pela previsão de ramificações Condicionais correspondentes a "este número é positivo?" não pode ser previsto. O efeito do cache é realmente leve, pois você tem dois cursores em vez de um.
Gilles 'SO- stop be evil'

Respostas:


3

Você pode adicionar n números de tamanho W sem qualquer excesso se você estiver usando registron+Wbits aritméticos. Minha sugestão é fazer exatamente isso e depois verificar se o resultado está no intervalo. Os algoritmos para a aritmética de multiprecisão são bem conhecidos (consulte a seção 4.3 do TAOCP, se você precisar de uma referência); geralmente há suporte de hardware para adição ( sinalizador de transporte e inclusão com instruções de transporte ), mesmo sem esse suporte, você pode implementá-lo sem salto dependente de dados ( o que é bom para os preditores de salto) e você precisa de apenas uma transmissão dos dados e pode visitá-los na ordem mais conveniente (o que é bom para o cache).

Se os dados não couberem na memória, o fator limitante será o pedido de veiculação e quão bem você conseguirá sobrepor o pedido de veiculação à computação.

Se os dados couberem na memória, você provavelmente terá registronW(a única exceção que consigo pensar é no microprocessador de 8 bits, que geralmente possui 64 K de memória), o que significa que você está fazendo uma aritmética de precisão dupla. A sobrecarga ao longo de um loop fazendoWA aritmética de bits pode ser apenas duas instruções (uma para assinar estender, outra para adicionar com carry) e um leve aumento da pressão do registro (mas, se eu estiver certo, até o registro faminto do x86 tem registros suficientes que o único acesso à memória no o loop interno pode buscar os dados). Eu acho que é provável que um processador OO seja capaz de agendar operações adicionais durante a latência de carga da memória, para que o loop interno seja executado na velocidade da memória e, portanto, o exercício será o de maximizar o uso da largura de banda disponível (pré-busca técnicas de intercalação podem ajudar, dependendo da arquitetura da memória).

Considerando o ponto mais recente, é difícil pensar em outros algoritmos com melhor desempenho. Os saltos dependentes de dados (e, portanto, não previsíveis) estão fora de questão, assim como várias passagens nos dados. Mesmo tentar usar os vários núcleos do processador de hoje seria difícil, pois a largura de banda da memória provavelmente ficará saturada, mas poderia ser uma maneira fácil de implementar o acesso intercalado.


Não posso aumentar o tamanho dos registros na minha máquina. Suponha que eu já esteja usando o maior tamanho de registro possível.
Gilles 'SO- stop be evil'

@Gilles, processadores que eu sei que têm o sinalizador de estouro que você deseja que tiremos vantagem, também têm uma instrução carry one e add com carry . Mesmo para aqueles que não possuem (algo além do MIPS?), A aritmética de multiprecisão seria uma candidata séria (ela tem apenas uma passagem de dados - boa para cache -, acessa-a sequencialmente - boa para pré-preenchimento de cache - -, e pode ser implementado sem salto dependente de dados - bom para preditores de salto).
APROGRAMMER #

O que você quer dizer com "aritmética de multiprecisão"? Eu pensei que você quis dizer ponto flutuante. Mas muitas arquiteturas não têm registros de ponto flutuante grandes o suficiente, se houver. Digamos que eu esteja adicionando números inteiros de 64 bits no amd64 ou números inteiros de 32 bits no ARM sem VFP.
Gilles 'SO- stop being evil'

@Gilles, eu quis dizer o que está descrito na seção 4.3 do TAOCP: o uso de várias palavras para representar valores que não podem ser mantidos em uma palavra. Bignum é uma variante em que o número de palavras é ajustado dinamicamente, meu palpite é que aqui você pode determinar um limite máximo para o número de palavras necessárias (ou seja, 2 se seus dados estiverem na memória; se não, trabalhando na sobreposição de E / S com computação será o primeiro ponto de ação, você estará vinculado a E / S) e apenas use-o; será baixo o suficiente para que lidar com um número variável de palavras seja mais caro.
AProgramador

Ah ok. Você poderia esclarecer isso na sua resposta? Você tem referências com horários e comparações com outros métodos?
Gilles 'SO- stop be evil'

1

Em uma máquina onde tipos inteiros se comportam como um anel algébrico abstrato [basicamente significando que eles envolvem], pode-se calcular as somas dos itens [i] e (item [i] >> 16) para até 32767 itens. O primeiro valor daria os 32 bits inferiores da soma correta. O último valor produziria os bits 16-47 de algo próximo à soma correta e, usando o valor anterior, ele pode ser facilmente ajustado para produzir os bits 16-47 da soma correta exata.

O pseudocódigo seria algo como:

Sum1=0 : Sum2 = 0
For up to 32768 items L[i] in list
  Sum1 = Sum1 +L[i]
  Sum2 = Sum2 +(L[i] >> 16) ' Use sign-extending shift
Loop
Sum1MSB = Sum1 >> 16 ' Cannot use division of numbers can be negative--see below
Sum2Mid = Sum2 and 65535
Sum2Adj = Sum1MSB - Sum2Mid
If Sum2Adj >= 32768 then Sum2Adj = Sum2Adj - 65536
Sum2 += Sum2Adj

Após o código acima, Sum2 e Sum1 juntos devem gerar a soma correta, independentemente dos estouros intermediários. Se for necessário totalizar mais de 32768 números, eles podem ser divididos em grupos de 32768 e, após calcular Sum2 para cada grupo, é possível adicioná-lo a uma "grande soma" de duas variáveis ​​para todos os grupos como um todo.

Em alguns idiomas, o operador shift right right pode ser substituído por uma divisão por 65536. Isso geralmente funciona ao calcular o Sum2, mas não ao extrair o Sum1MSB. O problema é que alguns idiomas arredondam as divisões para zero, enquanto aqui é necessário executar um arredondamento de divisão para o próximo número mais baixo (em direção ao infinito negativo). Os erros na computação do Sum2 seriam corrigidos mais tarde, mas os erros na computação do Sum2LSB afetariam o resultado final.

Observe que nada nos resultados finais indicaria se algum dos cálculos envolvendo Sum1 havia "transbordado", mas se os valores são garantidos para quebrar o código de forma limpa, não é necessário se preocupar se ocorreu algum transbordamento.

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.