дубликаты — 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-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;

Итак, вопрос в том … это лучший способ выполнить эту задачу, или я должен искать другое решение?

1

Решение

Во-первых, ваш код выглядит ясно и нормально, как есть.

Конечно, вы можете дедуплицировать избыточные части формул, используя кумулятивный подход:

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 шкал, это, вероятно, хорошо с этой синтетической формулой. Однако, если вы хотите большей гибкости, вы можете подумать об итерации по вектору скоростей вместо использования констант. Это позволило бы варьировать количество шкал. Если вы уверены, что формула всегда прогрессивна (например, «выше + новая цена за единицу товара»), используйте кумулятивный подход.

2

Другие решения

Я думаю, что в коде много почти одинаковых строк, но нет реальных дубликатов. Если вы добавите больше ставок, вы можете легко скопировать неправильные определения макросов или смешать значения с неверной ставкой.

Мой код сам удаляет репликации 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.

0