Float vs Double Performance

91

J'ai fait des tests de synchronisation et j'ai également lu des articles comme celui-ci (dernier commentaire), et il semble que dans Release build, les valeurs flottantes et doubles prennent le même temps de traitement.

Comment est-ce possible? Lorsque le flottant est moins précis et plus petit que les valeurs doubles, comment le CLR peut-il obtenir des doubles dans le même temps de traitement?

Joan Venge
la source
10
Je ne pense pas que ce soit un doublon exact, car celui-ci demande la raison derrière, alors que l'autre utilisateur demande si c'est réellement plus rapide, mais pas nécessairement pourquoi,
Joan Venge
Soi-disant un duplicata exact de Are double plus rapide que floats en C #? (revendiqué en 2009 par un autre utilisateur).
Peter Mortensen

Réponses:

154

Sur les processeurs x86, au moins, floatet doubleseront chacun convertis en un réel de 10 octets par le FPU pour traitement. Le FPU n'a pas d'unités de traitement distinctes pour les différents types à virgule flottante qu'il prend en charge.

Le conseil séculaire qui floatest plus rapide qu'il y a double100 ans, lorsque la plupart des processeurs n'avaient pas de FPU intégrés (et peu de gens avaient des puces FPU distinctes), de sorte que la plupart des manipulations en virgule flottante étaient effectuées dans un logiciel. Sur ces machines (qui étaient alimentées par la vapeur générée par les fosses de lave), il était plus rapide d'utiliser floats. Maintenant, le seul avantage réel des floats est qu'ils prennent moins de place (ce qui n'a d'importance que si vous en avez des millions).

Papa
la source
9
Il n'y a peut-être pas 100 ans ... Certains FPU prennent en charge la gestion native aux niveaux float, double et 80 bits et s'exécuteront plus rapidement aux longueurs les plus courtes. Certains exécuteront également certaines choses plus lentement à des longueurs plus courtes ... :-)
Brian Knoblauch
4
Exception possible: je pense que le temps des divisions dépend du nombre de bits (1 cycle d'horloge / 2 bits). Les temps que j'ai faits entre la division flottante et la division double semblent correspondre à cela.
Neil Coffey
21
Mise en garde pour le code SIMD - puisque vous pouvez emballer 2x flotteurs que doubles dans un registre SIMD (par exemple SSE), potentiellement fonctionner sur des flotteurs pourrait être plus rapide. Mais comme il s'agit de C #, cela ne se produira probablement pas.
Calyth
13
@P Daddy: Je dirais que l'avantage spatial compte à tous les niveaux de la hiérarchie du cache. Lorsque votre cache de données de premier niveau fait 16 Ko et que vous utilisez un tableau de 4000 nombres, float pourrait facilement être plus rapide.
Peter G.
4
@artificialidiot Ne dites jamais jamais;). SIMD est pris en charge dans .NET depuis 4.6
ghord
13

J'avais un petit projet où j'utilisais CUDA et je me souviens que le flotteur était plus rapide que le double là aussi. Pour une fois, le trafic entre l'hôte et le périphérique est plus faible (l'hôte est le CPU et la RAM "normale" et le périphérique est le GPU et la RAM correspondante). Mais même si les données résident sur l'appareil tout le temps, elles sont plus lentes. Je pense avoir lu quelque part que cela a changé récemment ou est censé changer avec la prochaine génération, mais je ne suis pas sûr.

Il semble donc que le GPU ne puisse tout simplement pas gérer la double précision de manière native dans ces cas, ce qui expliquerait également pourquoi GLFloat est généralement utilisé plutôt que GLDouble.

(Comme je l'ai dit, ce n'est que pour autant que je me souvienne, je suis tombé sur cela en recherchant un flotteur ou un double sur un processeur.)

Mene
la source
6
Les GPU sont des animaux totalement différents des FPU. Comme d'autres l'ont mentionné, le format natif de FPU est la double précision 80 bits. Et ça fait longtemps maintenant. Les GPU abordent cependant ce domaine en simple précision. Il est bien connu que leurs performances DP FP (virgule flottante double précision) sont souvent exactement la moitié des performances de SP FP. Il semble qu'ils aient souvent des unités à virgule flottante SP, et qu'ils doivent réutiliser l'unité pour couvrir la double précision. Ce qui donne exactement deux cycles par rapport à un. C'est une énorme différence de performance , qui m'a étonné quand j'y ai fait face.
Csaba Toth
1
Certains calculs scientifiques nécessitent DP FP, et les principaux fabricants de GPU n'ont pas annoncé la pénalité de performance à ce sujet. Maintenant, ils (AMD, nVidia) semblent s'améliorer quelque peu sur ce sujet DP vs SP. Les nombreux cœurs d'Intel Xeon Phi contiennent les FPU de Pentium, et notez qu'Intel a souligné ses capacités de double précision . C'est là qu'il est peut-être vraiment capable de rivaliser avec les monstres GPGPU.
Csaba Toth
12

Cependant, il existe encore des cas où les flottants sont préférés - avec le codage OpenGL par exemple, il est beaucoup plus courant d'utiliser le type de données GLFloat (généralement mappé directement en flottant 16 bits) car il est plus efficace sur la plupart des GPU que GLDouble.

Cruachan
la source
3
Peut-être en raison d'un débit de données plus élevé? Si vous avez une matrice de nombres (z-buffer, etc.), la taille des données devient plus importante et éviter les conversions entre float et double accélère la manipulation. Ma conjecture.
Lucero
2
Sans aucun doute le débit. Compte tenu également du contexte spécialisé, il est peu probable que l'utilisation de doubles sur les flottants
Cruachan
1
Le débit et aussi le fait que SP FP (virgule flottante simple précision) est plus le format natif des FPU internes GPU que DP FP (double précision). Voir mon commentaire sur la réponse de @ Mene. Les GPU et les CPU FPU sont des animaux très différents, pense le FPU du CPU dans DP FP.
Csaba Toth
12

Cela dépend du système 32 bits ou 64 bits . Si vous compilez en 64 bits, le double sera plus rapide. Compilé en 32 bits sur 64 bits (machine et système d'exploitation), le flottement a été 30% plus rapide:

    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);
    }
Bleu amer
la source
2
Avez-vous pensé que ces 30% pourraient être dus aux lancers supplémentaires que vous utilisez?
Rasmus Damgaard Nielsen
@RasmusDamgaardNielsen Les moulages font partie du problème puisque Mathfonctionne avec double. Mais vous avez mal lu mon message: mes tests m'ont montré que je flottais mieux en performance.
Bitterblue
2
Les résultats affichés ci-dessus sont faux. Mes tests montrent que sur une ancienne machine 32 bits avec .NET 4.0 en mode Release, les performances floatet doublesont pratiquement identiques. Moins de 0,3% de différence en moyenne sur de nombreux essais indépendants, où chaque essai s'exerçait à multiplier, diviser et ajouter des opérations sur des variables chaînées consécutivement (pour éviter que les optimisations du compilateur ne gênent). J'ai essayé une deuxième série de tests avec Math.Sin()et Math.Sqrt()et j'ai également obtenu des résultats identiques.
Special Sauce