Как оптимизировать класс-оболочку простого числового типа в C ++? - PullRequest
11 голосов
/ 19 июля 2011

Я пытаюсь реализовать класс с фиксированной запятой в C ++, но у меня проблемы с производительностью.Я уменьшил проблему до простой оболочки типа float, и она все еще медленная.У меня вопрос - почему компилятор не может полностью его оптимизировать?

Версия с плавающей точкой на 50% быстрее, чем с плавающей точкой.Почему?!

(я использую Visual C ++ 2008, все возможные варианты компилятора проверены, конечно же, конфигурацию выпуска).

См. Код ниже:

#include <cstdio>
#include <cstdlib>
#include "Clock.h"      // just for measuring time

#define real Float      // Option 1
//#define real float        // Option 2

struct Float
{
private:
    float value;

public:
    Float(float value) : value(value) {}
    operator float() { return value; }

    Float& operator=(const Float& rhs)
    {
        value = rhs.value;
        return *this;
    }

    Float operator+ (const Float& rhs) const
    {
        return Float( value + rhs.value );
    }

    Float operator- (const Float& rhs) const
    {
        return Float( value - rhs.value );
    }

    Float operator* (const Float& rhs) const
    {
        return Float( value * rhs.value );
    }

    bool operator< (const Float& rhs) const
    {
        return value < rhs.value;
    }
};

struct Point
{
    Point() : x(0), y(0) {}
    Point(real x, real y) : x(x), y(y) {}

    real x;
    real y;
};

int main()
{
    // Generate data
    const int N = 30000;
    Point points[N];
    for (int i = 0; i < N; ++i)
    {
        points[i].x = (real)(640.0f * rand() / RAND_MAX);
        points[i].y = (real)(640.0f * rand() / RAND_MAX);
    }

    real limit( 20 * 20 );

    // Check how many pairs of points are closer than 20
    Clock clk;

    int count = 0;
    for (int i = 0; i < N; ++i)
    {
        for (int j = i + 1; j < N; ++j)
        {
            real dx = points[i].x - points[j].x;
            real dy = points[i].y - points[j].y;
            real d2 = dx * dx + dy * dy;
            if ( d2 < limit )
            {
                count++;
            }
        }
    }

    double time = clk.time();

    printf("%d\n", count);
    printf("TIME: %lf\n", time);

    return 0;
}

Ответы [ 3 ]

4 голосов
/ 19 июля 2011

Попробуйте , а не , передавая по ссылке.Ваш класс достаточно мал, так что затраты на его передачу по ссылке (да, если компилятор не оптимизирует его), могут быть выше, чем просто копирование класса.Таким образом, это ...

Float operator+ (const Float& rhs) const
{
   return Float( value + rhs.value );
}

становится примерно таким ...

Float operator+ (Float rhs) const
{
   rhs.value+=value;
   return rhs;
}

, что позволяет избежать временного объекта и может избежать некоторой косвенной разыменования указателя.

4 голосов
/ 19 июля 2011

IMO, это связано с флагами оптимизации . Я проверил вашу программу в g ++ linux-64 machine. Без какой-либо оптимизации, он дает тот же результат, что вы сказали, который 50% меньше.

При включении максимальной оптимизации (т. Е. -O4). Обе версии одинаковы. Включите оптимизацию и проверьте.

2 голосов
/ 19 июля 2011

После дальнейшего изучения я полностью убежден, что это проблема конвейера оптимизации компилятора. Код, сгенерированный в этом случае, значительно плохой по сравнению с использованием неинкапсулированного float . Я предлагаю сообщить об этой потенциальной проблеме в Microsoft и посмотреть, что они скажут об этом. Я также предлагаю вам перейти к реализации запланированной версии этого класса с фиксированной запятой, поскольку код, сгенерированный для целых чисел, выглядит оптимальным.

...