2016-11-13 28 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的if else,如果做出的计算,但感觉它有点重复:

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); 
} 

那么,这甚至可以进一步简化:

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个尺度,它的大概可以用这个合成公式。如果你想要更多的灵活性,你可以考虑通过速率向量迭代,而不是使用常量。这将允许可变数量的比例。如果你确定公式总是渐进式的(例如,“高于+新单价”),则使用累积方法。

+0

感谢您的反馈!这更多的是我心中的想法,但无法想象。非常感激! – jslice

+0

虽然简化了您的解决方案,但效率会有什么折衷吗?第一个使用的是比原来少一个的比较操作,但是最后一个使用的是最小/最大值。如果费率变化的规模更大,它是否会有所作为? – jslice

+0

你确实是对的,但它很大程度上取决于优化器。例如,对于GCC 6.2,我的[第一个提议](https://godbolt.org/g/pPQCgO)只是一个比你的[原始代码](https://godbolt.org/g/sbkze7)少的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不可用,你也可以用正常的函数和函数指针,而不是lambda表达式和std ::功能。