Fórum O que é mais rápido na divisão, Inteiros ou Reais? #269762
23/02/2005
0
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
Curtir tópico
+ 0Posts
23/02/2005
Massuda
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;
Gostei + 0
23/02/2005
Marcelo Saviski
Gostei + 0
23/02/2005
Motta
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.
Gostei + 0
23/02/2005
Beppe
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.
Gostei + 0
23/02/2005
Massuda
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
Gostei + 0
23/02/2005
Beppe
Gostei + 0
24/02/2005
Marcelo Saviski
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?
Gostei + 0
24/02/2005
Massuda
[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?
Gostei + 0
24/02/2005
Massuda
Gostei + 0
24/02/2005
Marcelo Saviski
Mas muda sim, pelo teste que vc fez com LongWord ai ser diferente daqui
Gostei + 0
24/02/2005
Beppe
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...).
É verdade, tem isso também. Eu tentei medir, mas são truques demais pra considerar...
Gostei + 0
25/02/2005
Marcelo Saviski
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.
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)