C ++根据重量计算运费

时间:2016-11-13 00:15:02

标签: c++ duplicates control-flow

我正在处理的程序的一部分实现了一个函数,该函数将包重量作为参数,并根据该权重计算运费。费用/磅的标准如下:

        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-if else-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;

所以,问题是......这是完成这项任务的最佳方式,还是我应该寻找不同的解决方案?

2 个答案:

答案 0 :(得分: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);
}

嗯,甚至可以进一步简化:

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; 

对于3个量表,这个合成配方可能没问题。如果你想要更多的灵活性,你可以考虑通过速率向量迭代而不是使用常量。这将允许可变数量的尺度。如果您确定该公式始终是渐进的(例如“高于+超出新单位价格”),则使用累积方法。

答案 1 :(得分: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不可用,你也可以使用普通函数和函数指针代替lambdas和std :: function。