Округление чисел с использованием правила округления 4/5

В настоящее время я изучаю C ++.

Я должен написать простую class Money который выполняет вычисления с использованием долларов и центов, где арифметика должна быть с точностью до последнего цента с использованием правила округления 4/5.

Я никогда не имел дело с денежными суммами, поэтому у меня возникли проблемы с пониманием того, как получить максимум от своего класса. Я знаю, что я не должен представлять денежные суммы с float, Поэтому я использую два члена данных для своего класса, чтобы хранить отдельно доллары и центы:

long int dollars
long int cents

Моя проблема в том, что я не знаю, когда и как мне округлять числа. Я задавал себе этот вопрос, пытаясь реализовать оператор ввода для этого класса. Предположим, что пользователь вводит в качестве входных данных значения: 12.456, 45.999, 9.54,

  1. Когда я должен округлить эти числа?

  2. Должен ли я сначала использовать их в арифметических операциях, а затем округлять результаты или округлять их непосредственно по мере их ввода в программу?

1

Решение

Наличие отдельных членов в долларах и центах только сделает код более сложным, чем необходимо. Просто используйте центы, затем перегрузите арифметические и операторы присваивания, конструктор и, возможно, << и >> для ввода / вывода.

Сложение и вычитание тривиальны, в этом случае обычные целочисленные операции масштабируются на 100. В общем случае деление / умножение с фиксированной запятой требует повторного масштабирования; Вы можете игнорировать это в этом случае, потому что деление или умножение денег на деньги не имеет смысла; однако вы можете захотеть перегрузить деньги, умноженные или разделенные на целые числа и типы с плавающей запятой (например, для расчета налога, дисконта или процента).

Перегружая << и >> операторы за деньги, вы можете контролировать, как вводится или представляется значение центов — путем его преобразования в / из dollars.cents,

Существует ряд сценариев, в которых может потребоваться округление, но в большинстве случаев они могут быть обработаны перегрузкой оператора. Например, пользовательский ввод в долларах может быть обработан оператором присваивания и конструкторами, в то время как вычисления распределения процентов, налогов или долей, которые могут привести к долям цента, могут быть обработаны путем перегрузки операторов * и / (хотя, вероятно, внутренне с использованием присвоения конструктор, так что вам нужно только округление в одном месте).

Удержание значения в центах и ​​округление значения с плавающей запятой или промежуточного значения в долларах до цента с обработкой положительного / отрицательного значения может быть достигнуто следующим образом:

long long cents = static_cast<long long>((std::abs(dollars_fp) + 0.005) * 100) ;
if( dollars_fp < 0 )
{
cents = -cents ;
}
2

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

Я бы посоветовал вам выполнить операции на cents и используйте округление только для вывода суммы в стандартный вывод.

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

Вот пример перевода между центами и долларами:

int sum_in_cents = 10000;

// stringstream imbued with the local configuration
std::stringstream ss;
ss.imbue(std::locale(""));

// ss contains $100.00 (assuming a en_US locale configuration)
ss << std::showbase << std::put_money(sum_in_cents);

Кроме того, есть библиотека повышения для форматирования валюты.


Примечание: обычное округление 4/5 выполняется стандартной библиотечной функцией round(). Если вы хотите реализовать что-то самостоятельно, вы можете сделать:

double round (double n)
{
return (n > 0.0) ? floor(n + 0.5) : ceil(n - 0.5);
}

если вы хотите получить целочисленный результат округления, вам не нужно ceil() или же floor():

int round (double i)
{
return (i > 0.0) ? (i + 0.5) : (i - 0.5);
}

1

  1. Лучшее, что я могу сказать, это прочитать значения в виде строки. На этом этапе вы можете манипулировать каждым элементом / числом, так как строки по сути являются массивами символов.

  2. Другой вариант — набрать приведение, например

    поплавок х = 10,01; // x = 10.01

    (int) y = x; // у = 10

читать значения в виде числа с плавающей запятой и разбивать их оттуда.

Надеюсь это поможет!

0

Я бы порекомендовал умножить ввод на 1000 или около того, чтобы сделать ввод целым числом, чтобы операции, которые вы над ним выполняли, были более точными. После округления вы можете использовать целочисленное деление, чтобы найти доллары, а оператор остатка, чтобы получить центы (раз 10). Что касается вашего второго вопроса, вы должны по крайней мере преобразовать число в целые числа в долларах и центах перед округлением, а затем вы можете выбрать, какой вы предпочитаете. Вот пример округления ввода:

/* Note: Code untested */
double x;
std::cin >> x;    // x = 45.999
long y = x * 1000;        // y = 45999

int dollars = y / 1000;    // dollars = 45
int cents = y % 1000       // cents = 999 (divide by 10 to get real # of cents)

if (cents % 10 >= 5) {   // if last digit should be rounded up (true)
cents += 10;            // add 10 (cents = 1009)
cents -= (cents % 10);   // remove the last digit (cents = 1000)
}
else if (cents % 10 < 5) {  // if last digit should be rounded down (false)
cents -= (cents % 10);   // remove last digit
}

cents /= 10;        // make cents a factor of 100 instead of 1000 (cents = 100)

if (cents >= 100) {    // if cents more than $1 (true)
dollars++;       // adjust dollars (dollars = 46)
cents -= 100;     // remove 100 from cents (cents = 0)
}

// prints "Amount is $46.0"std::cout << "Amount is $" << dollars << "." << cents << "\n";

Что касается типов, они не лучший вариант для округления. Если бы вы использовали следующий код:

double x = 45.999;
int y = (int)x;

Вы бы получили y == 45 потому что при приведении любого типа с плавающей точкой к любому целочисленному типу дробная часть полностью игнорируется.

Надеюсь это поможет.

0
По вопросам рекламы [email protected]