0

テンプレートメソッドに関する部分は、どの時点でコンパイラによって最適化されますか? 到達不能なコードを削除し、不要なループをアンラップしますか? (Bits はunsigned intブロックを使用し、Integer はunsigned longブロックを使用します)

さらに、「私はあなたのプロセッサレジストリのサイズの整数です」という意味の c++ データ型はありますか?

template<size_t bits> class IntegerFactoryImpl : public IntegerFactory<Integer<bits>>{
private:
    template<int sizeOfLong, int sizeOfInt> Integer<bits> getOne(const Bits& b) const{

        Integer<bits> integer = this->getOne();
        size_t roof = (b.blocks() > integer.size()*(sizeOfLong/sizeOfInt))? integer.size()*(sizeOfLong/sizeOfInt) : b.blocks();
        for(size_t i = 0; i < roof; ++i){
            integer.at(i/(sizeOfLong/sizeOfInt)) = 0;
            for(size_t j = 0; j < (sizeOfLong/sizeOfInt); ++j){
                if(i % (sizeOfLong/sizeOfInt) == j){
                    integer.at(i/(sizeOfLong/sizeOfInt)) |= ((unsigned long)b.block(b.blocks()-i-1)) << (sizeOfInt*j);
                    break;
                }
            }
        }
        for(size_t i = roof; i < integer.size()*(sizeOfLong/sizeOfInt); ++i){
            if(i % (sizeOfLong/sizeOfInt) == 0){
                integer.at(i/(sizeOfLong/sizeOfInt)) = 0;
            }
        }
        return integer;
    }

public:

    virtual ~IntegerFactoryImpl() throw(){}

    virtual Integer<bits> getOne() const{
        return Integer<bits>();
    }

    virtual Integer<bits> getOne(const Bits& b) const{
        return this->getOne<sizeof(unsigned long)*8, sizeof(unsigned int)*8>(b);
    }
};

このコードに違いはありますか(テンプレートメソッドなし):

template<size_t bits> class IntegerFactoryImpl : public IntegerFactory<Integer<bits>>{

public:

    virtual ~IntegerFactoryImpl() throw(){}

    virtual Integer<bits> getOne() const{
        return Integer<bits>();
    }

    virtual Integer<bits> getOne(const Bits& b) const{

        Integer<bits> integer = this->getOne();
        size_t roof = (b.blocks() > integer.size()*((sizeof(unsigned long)/sizeof(unsigned int)))? integer.size()*((sizeof(unsigned long)/sizeof(unsigned int)) : b.blocks();
        for(size_t i = 0; i < roof; ++i){
            integer.at(i/((sizeof(unsigned long)/sizeof(unsigned int))) = 0;
            for(size_t j = 0; j < ((sizeof(unsigned long)/sizeof(unsigned int)); ++j){
                if(i % ((sizeof(unsigned long)/sizeof(unsigned int)) == j){
                    integer.at(i/((sizeof(unsigned long)/sizeof(unsigned int))) |= ((unsigned long)b.block(b.blocks()-i-1)) << ((sizeof(unsigned int)*8)*j);
                    break;
                }
            }
        }
        for(size_t i = roof; i < integer.size()*((sizeof(unsigned long)/sizeof(unsigned int)); ++i){
            if(i % ((sizeof(unsigned long)/sizeof(unsigned int)) == 0){
                integer.at(i/((sizeof(unsigned long)/sizeof(unsigned int))) = 0;
            }
        }
        return integer;
    }
};

(編集:コードがうまく機能しないことを発見しました(修正しました)が、元の質問はまだ適用されます..)

4

1 に答える 1

1

そうです、コンパイラはコンパイル時に計算できるものを最適化し、1 回だけ反復するループがある場合 (たとえばfor(i = 0; i < 1; i++)、ループを完全に削除します。

long整数サイズに関しては、またはを使用する方が良いかどうかは、何を達成しようとしているかによって異なりますint。たとえば、x86-64 では、64 ビット操作では、後続の命令が 32 ビット命令ではなく 64 ビット命令であることを示すために余分なバイトが必要になります。コンパイラが作成した場合int64 ビット長の場合、コードは (少し) 大きくなり、キャッシュなどにうまく収まらなくなります。演算、乗算、除算は明らかな例外の一部です。数値が大きいほど、除算または乗算に時間がかかります ((実際には、数値に設定されているビットの数が乗算時間に影響し、除算も同様だと思います)。 ) ] x86-64 で。もちろん、たとえば値を使用してビットマスク操作などを実行している場合、を使用longすると 64 ビット操作が得られ、同じことを実行するのに半分の操作が必要になります。これは明らかに利点です。longしたがって、命令ごとに余分なバイトが追加されたとしても、この場合に使用するのは「正しい」です。

また、非常に頻繁にint「より小さい数」に使用されるため、多くの場合、余分なサイズintが無駄になり、余分なデータキャッシュスペースを占有するなど、int32 ビットのままです。大きな整数配列などのサイズを妥当なサイズに保つため。

于 2013-02-21T22:12:29.437 に答える