Float vs Double Performance


91

Eu fiz alguns testes de tempo e também li alguns artigos como este (último comentário), e parece que no Release build, os valores float e double levam a mesma quantidade de tempo de processamento.

Como isso é possível? Quando a flutuação é menos precisa e menor em comparação com os valores duplos, como o CLR pode obter dobras no mesmo tempo de processamento?


10
Eu não acho que seja uma duplicata exata, pois este está perguntando o motivo por trás disso, enquanto o outro usuário está perguntando se é realmente mais rápido, mas não necessariamente por quê,
Joan Venge

Supostamente uma duplicata exata de Are doubles mais rápido que floats em C #? (reivindicado em 2009 por outro usuário).
Peter Mortensen

Respostas:


153

Em processadores x86, pelo menos, floate doublecada um será convertido em um real de 10 bytes pela FPU para processamento. A FPU não possui unidades de processamento separadas para os diferentes tipos de ponto flutuante que suporta.

O conselho antigo que floaté mais rápido do que o doubleaplicado há 100 anos, quando a maioria das CPUs não tinha FPUs embutidos (e poucas pessoas tinham chips FPU separados), então a maior parte da manipulação de ponto flutuante era feita em software. Nessas máquinas (que eram movidas a vapor gerado pelos poços de lava), era mais rápido usar floats. Agora, o único benefício real para floats é que eles ocupam menos espaço (o que só importa se você tiver milhões deles).


9
Talvez não 100 anos atrás ... Algumas FPUs suportam manipulação nativa em níveis flutuantes, duplos e de 80 bits e serão executadas mais rapidamente em comprimentos mais curtos. Alguns vão realmente executar algumas coisas mais lentamente em comprimentos mais curtos também ... :-)
Brian Knoblauch

4
Possível exceção: acho que o tempo para as divisões depende do número de bits (1 ciclo de clock / 2 bits). Os tempos que fiz de float vs divisão dupla parecem corresponder a isso.
Neil Coffey

21
Advertência para código SIMD - uma vez que você pode embalar 2x flutuantes do que duplas em um registro SIMD (por exemplo, SSE), operar potencialmente em flutuadores pode ser mais rápido. Mas, como é C #, isso provavelmente não acontecerá.
Calyth de

13
@P Daddy: Eu diria que a vantagem de espaço é importante em todos os níveis da hierarquia do cache. Quando o cache de dados de primeiro nível tem 16 KB e você está processando uma matriz de 4.000 números, o float pode ser facilmente mais rápido.
Peter G.

4
@artificialidiot Nunca diga nunca;). SIMD é compatível com .NET desde 4.6
ghord

13

Tive um pequeno projeto em que usei CUDA e lembro que o float era mais rápido que o dobro também. Por uma vez, o tráfego entre o Host e o Dispositivo é menor (o Host é a CPU e a RAM "normal" e o Dispositivo é a GPU e a RAM correspondente ali). Mas mesmo que os dados residam no dispositivo o tempo todo, é mais lento. Acho que li em algum lugar que isso mudou recentemente ou deve mudar com a próxima geração, mas não tenho certeza.

Portanto, parece que a GPU simplesmente não consegue lidar com precisão dupla nativamente nesses casos, o que também explicaria porque o GLFloat é geralmente usado em vez do GLDouble.

(Como eu disse, só consigo me lembrar, apenas descobri isso enquanto procurava por float vs. double em uma CPU.)


5
GPUs são animais totalmente diferentes de FPUs. Como outros mencionaram, o formato nativo da FPU é a precisão dupla de 80 bits. E isso já faz muito tempo. As GPUs, entretanto, abordam esse campo com uma precisão única. É bem conhecido que o desempenho do DP FP (ponto flutuante de precisão dupla) é frequentemente exatamente a metade do desempenho do SP FP. Parece que muitas vezes eles têm unidades de ponto flutuante SP e precisam reutilizar a unidade para cobrir a precisão dupla. O que produz exatamente dois ciclos em comparação com um. Essa é uma enorme diferença de desempenho , que me surpreendeu quando me deparei com isso.
Csaba Toth

1
Alguns cálculos científicos exigem DP FP, e os principais fabricantes de GPU não anunciaram a penalidade de desempenho em torno disso. Agora eles (AMD, nVidia) parecem melhorar um pouco no tópico DP vs SP. Os vários núcleos do Intel Xeon Phi contêm FPUs do Pentium e observe que a Intel enfatizou seus recursos de precisão dupla . É aí que ele pode realmente competir com monstros GPGPU.
Csaba Toth

12

Ainda existem alguns casos onde floats são preferidos - com a codificação OpenGL, por exemplo, é muito mais comum usar o tipo de dados GLFloat (geralmente mapeado diretamente para float de 16 bits), pois é mais eficiente na maioria das GPUs do que GLDouble.


3
Talvez devido ao maior rendimento de dados? Se você tiver uma matriz de números (z-buffer etc.), o tamanho dos dados se torna mais importante, e evitar conversões entre float e double acelera o manuseio. Meu palpite.
Lucero,

2
Sem dúvida, rendimento. Além disso, dado o contexto especializado, é improvável que algo visível seja ganho com o uso de dobras sobre os flutuadores, então por que desperdiçar memória - especialmente porque ela é menor em GPUs do que em CPUs
Cruachan,

1
Taxa de transferência e também o fato de que SP FP (ponto flutuante de precisão única) é mais o formato nativo das FPUs internas da GPU do que DP FP (precisão dupla). Veja meu comentário à resposta de @Mene. GPU's e CPU FPUs são animais muito diferentes, a FPU da CPU está pensando em DP FP.
Csaba Toth


12

Depende do sistema de 32 ou 64 bits . Se você compilar para 64 bits, o dobro será mais rápido. Compilado para 32 bits em 64 bits (máquina e sistema operacional) fez flutuar cerca de 30% mais rápido:

    public static void doubleTest(int loop)
    {
        Console.Write("double: ");
        for (int i = 0; i < loop; i++)
        {
            double a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = Math.Sin(a);
            b = Math.Asin(b);
            c = Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    public static void floatTest(int loop)
    {
        Console.Write("float: ");
        for (int i = 0; i < loop; i++)
        {
            float a = 1000, b = 45, c = 12000, d = 2, e = 7, f = 1024;
            a = (float) Math.Sin(a);
            b = (float) Math.Asin(b);
            c = (float) Math.Sqrt(c);
            d = d + d - d + d;
            e = e * e + e * e;
            f = f / f / f / f / f;
        }
    }

    static void Main(string[] args)
    {
        DateTime time = DateTime.Now;
        doubleTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        time = DateTime.Now;
        floatTest(5 * 1000000);
        Console.WriteLine("milliseconds: " + (DateTime.Now - time).TotalMilliseconds);

        Thread.Sleep(5000);
    }

2
Você já considerou que esses 30% podem ser por causa dos casts extras que você usa ??
Rasmus Damgaard Nielsen

@RasmusDamgaardNielsen Os elencos são parte do problema já que Mathfunciona com duplo. Mas você interpretou mal minha postagem: meus testes me mostraram flutuar melhor no desempenho.
Bitterblue de

2
Os resultados postados acima são falsos. Meus testes mostram que em uma máquina de 32 bits mais antiga com .NET 4.0 no modo Release, o desempenho floate doublesão virtualmente idênticos. Menos de 0,3% de diferença quando calculada a média de muitos testes independentes, onde cada teste exerceu operações de multiplicação, divisão e adição em variáveis ​​encadeadas consecutivamente (para evitar que qualquer otimização do compilador atrapalhe). Eu tentei um segundo conjunto de testes com Math.Sin()e Math.Sqrt()e também tem resultados idênticos.
Molho Especial
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.