GARANTIR DESCONTO

Fórum O que é mais rápido na divisão, Inteiros ou Reais? #269762

23/02/2005

0

Eu sempre achei que trabalhar com numeros Inteiros fosse mais rápido do que com números reais, sei lá, são cheios de casas depois da virgula,e achei que fossem mais complicados de processar, enfim, fiz uns testes comparando o código 1 com o código2:

Código1
function SomaInteiros: Integer;
var
  I: Integer;
  Valor1, valor2, Valor3: Integer;
begin
  Valor1 := 2;
  Valor2 := 20000;
  for I := 100000000 - 1 downto 0 do //repete cem milhões de vezes
    Valor3 := Valor2 div Valor1;
  Result := Valor3;
end;


Código2
function SomaReais: Double;
var
  I: Integer;
  Valor1, valor2, Valor3: Double;
begin
  Valor1 := 2.0;
  Valor2 := 20000.0;
  for I := 100000000 - 1 downto 0 do //repete cem milhões de vezes
    Valor3 := Valor2/Valor1;
  Result := Valor3;
end;


As duas funções dão o mesmo resultado, mais uma usar números de ponto flutuante para fazer os calculos e a outra números inteiros, mas a função que usa ponto flutuante(Double) foi 2 vezes mais rápida que a outra que usa integer.

Agora eu pergunto, não deveria ser o contrário?

Depois alterei a primeira função:
ao invéz de
Valor3 := Valor2 div Valor1;

dessa forma
Valor3 := Round(Valor2/Valor1);


e com o Round ficou coma mesma performance da 1º função, mais rápido do que tava antes com o div.

sempre achei que usar esse Round seria disperdício se poderia usar o div, ou o Trunc, que achava que era mais rápido, mas não é.

fazer Round(V1/V2) foi mais rápido que usar o [b:ecb54e0e51]div[/b:ecb54e0e51], alguém saberia dizer porque?

para outras operações, somar, subtrair, multiplicar, os Inteiros guanharam, mas na divisão os Reais triunfaram, achei muito estranho isso, será que fiz alguma coisa de errado?

Agradeço qualquer palpite :)

PS: Fiz o teste num Durom 1.3.


Marcelo Saviski

Marcelo Saviski

Responder

Posts

23/02/2005

Massuda

Mais uma peça para seu quebra cabeças... Experimentei fazer uma modificação na sua função SomaInteiros...
function SomaInteiros: Longword; 
var 
  I: Integer; 
  Valor1, valor2, Valor3: Longword; 
begin 
  Valor1 := 2; 
  Valor2 := 20000; 
  for I := 100000000 - 1 downto 0 do //repete cem milhões de vezes 
    Valor3 := Valor2 div Valor1; 
  Result := Valor3; 
end;
desse modo, os inteiros não tem sinal e, como era esperado inicialmente, SomaInteiros é mais rápido que SomaReais.


Responder

Gostei + 0

23/02/2005

Marcelo Saviski

Hum, vou testar isso quando chegar em casa, mas de qualquer forma a SomaReais ainda me parace sair ´guanhando´, já que independe de sinal


Responder

Gostei + 0

23/02/2005

Motta

O Help do D5 fala isto :

An integer type represents a subset of the whole numbers. The generic integer types are Integer and Cardinal; use these whenever possible, since they result in the best performance for the underlying CPU and operating system. The table below gives their ranges and storage formats for the current 32-bit Object Pascal compiler.


Mas uma olhada nos tipos ...

TypeRangeSignificant digitsSize in bytes
Real482.9 x 10^–39 .. 1.7 x 10^3811–126
Single1.5 x 10^–45 .. 3.4 x 10^387–84
Double5.0 x 10^–324 .. 1.7 x 10^30815–168

TypeRangeFormat
Integer–2147483648..2147483647signed 32-bit

Qual o tamanho da palavra em Delphi , teria algo a ver ?

Por esta não esperava Marcelo.


Responder

Gostei + 0

23/02/2005

Beppe

[quote:05c64cfef1=´Marcelo Saviski´]O que é mais rápido na divisão, Inteiros ou Reais?[/quote:05c64cfef1]
Depende.

Para divisão inteira, a operação é a mesma tanto faz quais forem os valores dos operandos. Para a divisão de flutuantes, como você presumiu, o algoritmo é *bem* maior(em números de portas lógicas), e com tratamento especial para casos simples. Mas esta complexidade fica fora do loop principal do algoritmo.

A disparidade pode ser grande em favor dos flutuantes se você usar como divisor um poder de dois e seus negativos, que se transforma em uma réles subtração. Pode observar isto na janela da FPU.

O que afetou também resultados foram resultados externos como mudança de threads, e o fato que a FPU é ociosa a maior parte do tempo, ao contrário da ULA(unidade que executa operações em inteiros, uns 99¬ das instruções).

Sobre o tamanho da palavra...não testei isto, mas pode ter variações. Byte´s devem ter a mesma performance de Integer(que no meu teste foi superioir a Cardinal), mas Word´s deve ser mais lento porque a instrução exige um prefixo de 1 byte. Para flutuantes, a performance é semelhante.

Aqui segue o método que eu desenvolvi para chegar próximo a performance absoluta.

Basicamente, o número de iterações não pode ser grande, pq cairia fora do ´time slice´. Eu usei um segundo loop, externo, mas este não deve fazer diferença.

const
  Divisor = 81;
  Dividendo = 10000000;
  Iteracoes1 = 10000;
  Iteracoes2 = 1000;

function SomaInteiros: Integer;
var
  I: Integer;
  Valor1, Valor2, Valor3: Integer;
begin
  Valor1 := Divisor;
  Valor2 := Dividendo;
  for I := 0 to Iteracoes2 - 1 do
    Valor3 := Valor2 div Valor1;
  Result := Valor3;
end;

function SomaReais: Double;
var
  I: Integer;
  Valor1, Valor2, Valor3: Double;
begin
  Valor1 := Divisor;
  Valor2 := Dividendo;
  for I := 0 to Iteracoes2 - 1 do
    Valor3 := Valor2 / Valor1;
  Result := Valor3;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  S, F, Total: Int64;
  I: Integer;
begin
  // processa eventos na fila, como WM_PAINT, WM_LBUTTONDOWN, WM_WM_KEYUP
  for I := 0 to 9 do
    Application.ProcessMessages;

  // ganha fatias de tempo maiores
  SetPriorityClass(0, REALTIME_PRIORITY_CLASS);
  SetThreadPriority(0, THREAD_PRIORITY_TIME_CRITICAL);
  SetThreadPriorityBoost(0, False);
  SetProcessPriorityBoost(0, False);

  Total := 0;
  for I := 0 to Iteracoes1 - 1 do
  begin
    Application.ProcessMessages;
    // começa a contagem no início da nova fatia de tempo
    Sleep(0);
    QueryPerformanceCounter(S);
    SomaInteiros;
//    SomaReais;
    QueryPerformanceCounter(F);
    Total := Total - S + F;
  end;
  Caption := IntToStr(Total);
end;


Substituindo Valor3 por Valor2, tem-se resultados mais dinâmicos e interessantes, e que representa melhor padrões de uso.


Responder

Gostei + 0

23/02/2005

Massuda

De uma velha documentação do MASM sobre o chip Pentium...
Instrução   Descrição             Ciclos de Máquina
DIV         divisão sem sinal     byte=17
                                  word=25
                                  dword=41

IDIV        divisão com sinal     byte=22
                                  word=30
                                  dword=46

FDIV        divisão em PF         39
Por esses números, faz sentido dizer que a divisão em PF foi otimizada no chip e que pode ser mais rápida do que dividir inteiros 32-bits com sinal.


Responder

Gostei + 0

23/02/2005

Beppe

Infelizmente estas tabelas não existem mais...acho que pq existe uma boa diferenças entre implementações.


Responder

Gostei + 0

24/02/2005

Marcelo Saviski

Testei com Cardinal ou LongWord no lugar de Integer mas acabou ficando igual.
Ainda não pude testar o código do Beppe, mas o que significa?:), num código qualquer, por exemplo, pra processar uma imagem e aplicar um filtro, seria melhor como?

Cor e Filtro entre 0 e 255

  Cor := (Cor*Filtro) div 255;
-ou-
  Cor := Round((Cor/255)*Filtro);


vlw pelas respostas, e outra coisa, o processador influenciaria nessa diferença? Por exemplo num Intel ou num AMD o tempo decorrido entre Inteiros e Reais seria maior em um do que no outro? ou isso é meio padrão?


Responder

Gostei + 0

24/02/2005

Massuda

[quote:28fdb25faf=´Marcelo Saviski´]Testei com Cardinal ou LongWord no lugar de Integer mas acabou ficando igual.[/quote:28fdb25faf]Interessante... na máquina que uso no trabalho (Intel P4 2.66GHz), seu teste usando LongWord foi mais rápido do que usando Double.

[quote:28fdb25faf=´Marcelo Saviski´]o processador influenciaria nessa diferença? Por exemplo num Intel ou num AMD o tempo decorrido entre Inteiros e Reais seria maior em um do que no outro? ou isso é meio padrão?[/quote:28fdb25faf]Você está se referindo aos tempos em si (resultado quantitativo) ou ao fato de dividir Integer´s demorar mais que dividir Double´s?


Responder

Gostei + 0

24/02/2005

Massuda

Infelizmente estas tabelas não existem mais...acho que pq existe uma boa diferenças entre implementações.
Acho que isso tem relação com o fato das CPUs modernas usarem pipelines e execução especulativa (acho que era esse o nome que estava no manual da Intel) e outros bichos para agilizar a execução do código; com isso tudo, fica difícil prever quantos ciclos de máquina uma instrução irá efetivamente gastar.


Responder

Gostei + 0

24/02/2005

Marcelo Saviski

Dizia a proporção de quantas vezes um era mais rápido que o outro.
Mas muda sim, pelo teste que vc fez com LongWord ai ser diferente daqui


Responder

Gostei + 0

24/02/2005

Beppe

[quote:e0edd5dc70=´Marcelo Saviski´]...num código qualquer, por exemplo, pra processar uma imagem e aplicar um filtro, seria melhor como?

Cor e Filtro entre 0 e 255

  Cor := (Cor*Filtro) div 255;
-ou-
  Cor := Round((Cor/255)*Filtro);

[/quote:e0edd5dc70]
Não estou certo sobre divisões, mas multiplicações por constantes, são transformadas em sequencias mais simples(ADD, SUB, SHL, LEA) e mais eficientes...

Se o caso não se repetir para divisões, e vc não precisar de exatidão, posso sugerrir uma modificação. (Cor * (Filtro + 1)) div 256. Divisão por poder de 2 se torna em um SHR.

[quote:e0edd5dc70=´Marcelo Saviski´]vlw pelas respostas, e outra coisa, o processador influenciaria nessa diferença? Por exemplo num Intel ou num AMD o tempo decorrido entre Inteiros e Reais seria maior em um do que no outro? ou isso é meio padrão?[/quote:e0edd5dc70]

O que é padrão são os resultados, a qualidade da implementação varia entre modelaos diferentes(586, 686, Celeron, Athlon, Opteron...).

Acho que isso tem relação com o fato das CPUs modernas usarem pipelines e execução especulativa (acho que era esse o nome que estava no manual da Intel) e outros bichos para agilizar a execução do código; com isso tudo, fica difícil prever quantos ciclos de máquina uma instrução irá efetivamente gastar.

É verdade, tem isso também. Eu tentei medir, mas são truques demais pra considerar...


Responder

Gostei + 0

25/02/2005

Marcelo Saviski

ow, agora que vi que coloque o nome de Soma na função que divide dois números...

E comigo, o código que o Beppe passou, fica na mesma, com os Reais fica quase que ´exatamente´ a metade dos ciclos dos Inteiros, mesmop trocando o valor3 por Valor2

Eu sempre procurava evitar colocar ponto flutuante no meio dos códigos pra otimizar, mas acho que vou repensar antes de fazer assim daqui pra frente.


Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar