Как оптимизировать простой класс оболочки класса в С++?

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

Версия "float" на 50% быстрее, чем "Float". Почему?

(я использую Visual С++ 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;
}

Ответ 1

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

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

Ответ 2

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

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

становится чем-то вроде этого...

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

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

Ответ 3

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