2016-11-13 13 views
1

私が取り組んでいるプログラムの一部は、パッケージ重量を引数として取り入れ、その重量に基づいて配送コストを計算する関数を実装しています。次のようにコスト/ポンドのための基準は、次のとおりです。C++重量に基づいて配送料を計算する

 Package Weight    Cost 
     --------------    ---- 
     25 lbs & under    $5.00 (flat rate) 
     26 - 50 lbs     above rate + 0.10/lb over 25 
     50 + lbs     above rate + 0.07/lb over 50 

私は計算を行うが、そのビットの繰り返しのように感じるようにした場合、もし他に-IFを使用:

const int TIER_2_WEIGHT = 25; 
const int TIER_3_WEIGHT = 50; 

const float TIER_1_RATE = 5.00; 
const float TIER_2_RATE = 0.10; 
const float TIER_3_RATE = 0.07; 

float shipPriceF; 


if(shipWeightF <= TIER_2_WEIGHT) 
{ 
    shipPriceF = TIER_1_RATE; 
} 
else if(shipWeightF <= TIER_3_WEIGHT) 
{ 
    shipPriceF = ((shipWeightF - TIER_2_WEIGHT) * TIER_2_RATE) + 
        TIER_1_RATE; 
} 
else 
{ 
    shipPriceF = ((shipWeightF - TIER_3_WEIGHT) * TIER_3_RATE) + 
       ((TIER_3_WEIGHT - TIER_2_WEIGHT) * TIER_2_RATE) + 
        TIER_1_RATE; 
} 

return shipPriceF; 

ので、質問は...これはこの作業を達成する最良の方法ですか、別の解決策を探しているべきですか?

+3

あなたが持っているものは、良い実践の点では真実です。 if-else if-elseが使用されている限り、繰り返しはありません。 – VHS

+0

さらに、ここには再帰的なものはありません。 –

+0

これらが唯一の層だとすれば、これはうまく見えます。 – Qix

答えて

2

まず、コードは明らかに見えます。もちろん

、あなたは累積的なアプローチを使用して式の冗長な部分を重複排除できます

float shipPriceF = TIER_1_RATE; // to be paid anyway 

if (shipWeightF > TIER_2_WEIGHT) // add the tier 2 if necessary 
{ 
    shipPriceF += (min(shipWeightF, TIER_3_WEIGHT) - TIER_2_WEIGHT) * TIER_2_RATE; 
} 
if(shipWeightF > TIER_3_WEIGHT) // add the tier 3 if really necessary 
{ 
    shipPriceF += (shipWeightF - TIER_3_WEIGHT) * TIER_3_RATE); 
} 

をまあ、これはさらに簡単にすることができます:3つのスケールの

float shipPriceF = TIER_1_RATE 
        + max(min(shipWeightF,TIER_3_WEIGHT)-TIER_2_WEIGHT,0) * TIER_2_RATE 
        + max(shipWeightF-TIER_3_WEIGHT,0) * TIER_3_RATE; 

を、それはですおそらくこの合成式でOKです。しかし、より柔軟にしたい場合は、定数を使用する代わりに反復率のベクトルを繰り返し考えることができます。これは、可変数のスケールを可能にする。数式が常に漸進的であることを確信しているならば(例えば、「上回るもの+新しい単価」)、累積的なアプローチを使用します。

+0

フィードバックをありがとう!これは私が心に持っていたものの多くであり、それを通して考えることができませんでした。とても有難い! – jslice

+0

あなたのソリューションは簡素化されていますが、効率的なトレードオフはありますか?最初のものは、私のオリジナルのものよりも1つ少ない比較操作を使用しますが、あなたが投稿した最後のものは数分/最大値を使用します..レートの進展がより大きいスケールにあるならば、それは違いをもたらすでしょうか? – jslice

+0

あなたは本当に正しいですが、それはオプティマイザに大きく依存します。たとえば、GCC 6.2の場合、私の[最初の提案](https://godbolt.org/g/pPQCgO)は、[オリジナルコード](https://godbolt.org/g/sbkze7)より1つ少ないasm命令です。そして、私の[ultraslim機能](https://godbolt.org/g/x3wxeA)は4つの命令よりです。しかし、全体の実行パフォーマンスは、命令の数だけでなく、重みの統計分布(多かれ少なかれジャンプを必要とする)にも依存する。したがって、私のアドバイス "早すぎる最適化はすべての悪の根源です"。 – Christophe

0

コードにはほとんど同じ行がありますが、実際の重複はありません。より多くのレートを追加すると、間違ったマクロ定義を簡単にコピーしたり、間違ったレートの値を混在させたりすることができます。

自分のコード自体がif/elseの複製を削除し、正しいグローバル定義を使用する必要性を避けます。コードに新しいレートを追加すると、テーブルにローを追加するだけです。

#include <iostream> 
#include <functional> 
#include <limits> 

// first we define a entry of a table. This table contains the limit to which the ratio is valid and 
// a function which calculates the price for that part of the weight. 
struct RateTableEntry 
{ 
    double max; 
    std::function<double(double, double)> func; 
}; 

// only to shrink the table width :-) 
constexpr double MAX = std::numeric_limits<double>::max(); 

// and we define a table with the limits and the functions which calculates the price 
RateTableEntry table[]= 
{ 
    // first is flate rate up to 25 
    { 25, [](double , double  )->double{ double ret=      5.00; return ret; }}, 
    // next we have up to 50 the rate of 0.10 (use min to get only the weight up to next limit 
    { 50, [](double max, double weight)->double{ double ret= std::min(weight,max)*0.10; return ret; }}, 
    // the same for next ratio. std::min not used, bedause it is the last entry 
    { MAX, [](double , double weight)->double{ double ret=   weight  *0.07; return ret; }} 
}; 

double CalcRate(double weight) 
{ 
    std::cout << "Price for " << weight; 
    double price = 0; 
    double offset = 0; 
    for (auto& step: table) 
    { 
     // call each step, until there is no weight which must be calculated 
     price+=step.func(step.max- offset, weight); 
     // reduce the weight for that amount which allready is charged for 
     weight-=step.max-offset; 
     // make the table more readable, if not used this way, we have no max values but amount per step value 
     offset+=step.max; 
     if (weight <= 0) break; // stop if all the weight was paid for 
    } 

    std::cout << " is " << price << std::endl; 

    return price; 
} 

int main() 
{ 
    CalcRate(10); 
    CalcRate(26); 
    CalcRate(50); 
    CalcRate(51); 
    CalcRate(52); 
    CalcRate(53); 
} 

C++ 11あなたはまた、代わりにラムダとstd ::機能の正常な機能と関数ポインタを使用することができ、使用できない場合:のみ行うことができます他に何のアイデアを与えるために

関連する問題