Поплавок проти подвійної продуктивності


91

Я провів кілька тестів синхронізації, а також прочитав деякі статті, подібні до цієї (останній коментар), і схоже, що у версії build, float і double значення займають однакову кількість часу обробки.

Як це можливо? Коли float менш точний і менший порівняно з подвійними значеннями, як CLR може отримати подвоєння за той самий час обробки?


10
Я не думаю, що це точний дублікат, оскільки цей запитує причину, за якою інший користувач запитує, чи це насправді швидше, але не обов'язково чому,
Джоан Венге

Нібито точний дублікат Чи подвоюється швидкість, ніж плаваючі в C #? (заявлено в 2009 році іншим користувачем).
Пітер Мортенсен

Відповіді:


154

На процесорах x86, принаймні, floatі doubleкожен з них буде перетворений у 10-байтовий реальний FPU для обробки. FPU не має окремих блоків обробки для різних типів плаваючих крапок, які він підтримує.

Вікова порада, яка floatшвидша, ніж doubleзастосовувалася 100 років тому, коли більшість процесорів не мали вбудованих FPU (а у деяких людей були окремі мікросхеми FPU), тому більшість маніпуляцій з плаваючою точкою виконувались у програмному забезпеченні. На цих машинах (які живилися від пари, що утворюється в ямах лави) було швидше використовувати floats. Тепер єдиною реальною перевагою floats є те, що вони займають менше місця (що важливо лише у тому випадку, якщо їх у вас мільйони).


9
Можливо, не 100 років тому ... Деякі FPU підтримують власну обробку на плаваючому, подвійному та 80-бітному рівнях і будуть виконуватися швидше при меншій довжині. Деякі фактично будуть виконувати деякі речі повільніше також на меншій довжині ... :-)
Брайан Ноблауч

4
Можливий виняток: я думаю, що час поділів залежить від кількості бітів (1 тактовий цикл / 2 біти). Терміни, які я зробив з поплавка проти подвійного поділу, здається, збігаються з цим.
Ніл Коффі

21
Застереження щодо коду SIMD - оскільки ви можете упакувати в реєстр SIMD вдвічі більше, ніж вдвічі (наприклад, SSE), потенційно робота на поплавках може бути швидшою. Але оскільки це C #, це, швидше за все, не відбудеться.
Calyth

13
@P Daddy: Я б сказав, що космічна перевага має значення на кожному рівні ієрахії кешу. Коли ваш кеш даних першого рівня великий 16 КБ, і ви обробляєте масив з 4000 чисел, плаваюча операція може бути швидшою.
Пітер Г.

4
@artificialidiot Ніколи не кажи ніколи;). SIMD підтримується в .NET з 4.6
ghord

13

У мене був невеликий проект, де я використовував CUDA, і я пам’ятаю, що плаваючий показник там теж був швидшим, ніж подвійний. Одного разу трафік між хостом і пристроєм стає нижчим (хост - це центральний процесор і "звичайна" оперативна пам'ять, а пристрій - це графічний процесор і відповідна оперативна пам'ять). Але навіть якщо дані постійно зберігаються на Пристрої, це повільніше. Здається, я десь читав, що це нещодавно змінилося або має змінитися з наступним поколінням, але я не впевнений.

Отже, здається, що в цих випадках графічний процесор просто не може обробляти подвійну точність, що також пояснює, чому зазвичай використовується GLFloat, а не GLDouble.

(Як я вже говорив, це лише наскільки я пам’ятаю, просто натрапив на це під час пошуку float проти double на центральному процесорі.)


6
GPU - це абсолютно різні тварини, ніж FPU. Як згадували інші, рідний формат FPU - це 80-бітна подвійна точність. І це вже давно. Однак графічні процесори підходять до цього поля з однієї точності. Це добре відомо , що їх DP FP (подвійний точності з плаваючою точкою) продуктивність часто точно половину продуктивності SP FP. Здається, що у них часто є одиниці з плаваючою комою SP, і їм доводиться використовувати повторно одиницю для покриття подвійної точності. Що дає рівно два цикли порівняно з одним. Це величезна різниця в продуктивності , яка приголомшила мене, коли я зіткнувся з нею.
Csaba Toth

1
Деякі наукові обчислення вимагають DP FP, і провідні виробники графічних процесорів не рекламували покарання за продуктивність навколо цього. Зараз вони (AMD, nVidia), здається, дещо покращують цю тему щодо DP та SP. Багато ядер Intel Xeon Phi містять FPU Pentium, і зверніть увагу, що Intel наголосила на своїх подвійних точних можливостях. Ось де він, можливо, справді здатний скласти конкуренцію монстрам GPGPU.
Csaba Toth

12

Проте все ще існують випадки, коли переважно плаваючі коди - наприклад, з кодуванням OpenGL набагато частіше застосовується тип даних GLFloat (як правило, що відображається безпосередньо на 16-бітний плаваючий), оскільки він є більш ефективним на більшості графічних процесорів, ніж GLDouble.


3
Може, через більшу пропускну здатність даних? Якщо у вас є матриця чисел (z-буфер тощо), розмір даних стає більш важливим, і уникнення перетворень між float та double прискорює обробку. Моя здогадка.
Lucero

2
Безсумнівно, пропускна здатність. Крім того, враховуючи спеціалізований контекст, навряд чи щось видиме можна отримати від використання подвійних над поплавцями, так навіщо витрачати пам'ять - тим більше, що вона на графічних процесорах менше, ніж на центральних процесорах
Cruachan

1
Пропускна здатність, а також той факт, що SP FP (одинарна точність із плаваючою комою) є більше рідним форматом внутрішніх FPU графічних процесорів, ніж DP FP (подвійна точність). Дивіться мій коментар до відповіді @ Mene. GPU та CPU FPU - це дуже різні тварини, FPU CPU думає в DP FP.
Csaba Toth


12

Це залежить від 32-розрядної або 64-розрядної системи. Якщо ви компілюєте до 64-розрядної, подвійне буде швидшим. Компільований до 32-розрядних на 64-розрядних (машина та ОС) змусив плавати близько 30% швидше:

    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
Ви вважали, що ці 30% можуть бути через додаткові закиди, які ви використовуєте ??
Расмус Дамгаард Нільсен,

@RasmusDamgaardNielsen Актори - це частина проблеми, оскільки Mathпрацює з подвійним. Але ви неправильно прочитали мою публікацію: мої тести показали мені кращі показники в роботі.
Bitterblue

2
Опубліковані вище результати є фіктивними. Мої тести показують, що на старій 32-розрядної машині з .NET 4.0 у режимі випуску продуктивність floatі doubleпродуктивність практично однакові. Різниця менше 0,3% при усередненні для багатьох незалежних випробувань, де кожне випробування здійснювало операції множення, ділення та додавання послідовно прив’язаних змінних (щоб уникнути будь-яких оптимізацій компілятора). Я спробував другий набір тестів з Math.Sin()і Math.Sqrt()а також отримали однакові результати.
Спеціальний соус
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.