5. Rounding
This chapter rounds the strength to a tenth of a megapascal as part of the formula, the way a test method prescribes it. It shows how a rounding names its unit, its places and its mode, and what the mode decides for a value exactly halfway.
The program is chapter 4's first case, with the strength formula rounded, a second rounding that differs only in its mode, and two loads.
Rounding is part of the formula
A test method states its rounding: here, the strength to 0.1 MPa, with a
value exactly halfway rounded away from zero. A formula::DecimalRounding
names such a rule once: the unit the places are counted in, how many places,
and the rounding mode. The program names two rules that differ only in the
mode:
constexpr formula::DecimalRounding tenthMpa { unit::Megapascal,
formula::DecimalPlaces { 1 },
formula::RoundingMode::HalfAwayFromZero };
constexpr formula::DecimalRounding tenthMpaHalfEven { unit::Megapascal,
formula::DecimalPlaces { 1 },
formula::RoundingMode::HalfEven };
Always name the mode: no single mode is right for every method, so the method's own rule belongs in the declaration. Places count in a unit, because one decimal place of a megapascal and one decimal place of a pascal are different roundings.
formula::rounded<R>(operand) rounds its operand by the rule R, at that
position in the formula. The strength formula rounds the quotient:
constexpr auto loadedArea = formula::yields<Area>(var<SideA> * var<SideB>);
constexpr auto strength = formula::yields<Strength>(formula::rounded<tenthMpa>(var<Load> / loadedArea));
constexpr auto strengthHalfEven = formula::yields<Strength>(formula::rounded<tenthMpaHalfEven>(var<Load> / loadedArea));
The quotient is calculated exactly, converted to megapascals, rounded to one place, and the rounded value is the result. A rounding inside a formula is a step of the calculation, unlike the rounding for reading in chapter 3, which only changes the text printed.
The specimen carried 675.4 kN:
auto const specimen = formula::environment(
formula::Measured<SideA> { 150 }, formula::Measured<SideB> { 150 }, formula::Measured<Load> { 675.4_r });
auto const result = formula::checked_evaluate(strength, specimen);
if (!result)
{
std::println("cannot calculate the strength: {}", result.error());
return 1;
}
std::println("675.4 kN, half away from zero: {} = {}", formula::symbol_of<Strength>(), *result);
675.4 kN over 22500 mm² is 30.0177… MPa, which rounds to 30.0. The result is
the exact number 30, and prints as 30 MPa: {} writes an exact value
without trailing zeros. A format spec that asks for one place in a named mode,
{:.1HalfAwayFromZero}, would print 30.0 MPa
(Displaying numbers).
The mode matters
A second specimen carried 676.125 kN. Its strength is 30.05 MPa exactly, halfway between 30.0 and 30.1, and the two rules decide it differently:
auto const halfway = formula::environment(
formula::Measured<SideA> { 150 }, formula::Measured<SideB> { 150 }, formula::Measured<Load> { 676.125_r });
auto const awayFromZero = formula::checked_evaluate(strength, halfway);
if (!awayFromZero)
{
std::println("cannot calculate the strength: {}", awayFromZero.error());
return 1;
}
std::println("676.125 kN, half away from zero: {} = {}", formula::symbol_of<Strength>(), *awayFromZero);
auto const toEven = formula::checked_evaluate(strengthHalfEven, halfway);
if (!toEven)
{
std::println("cannot calculate the strength: {}", toEven.error());
return 1;
}
std::println("676.125 kN, half to even: {} = {}", formula::symbol_of<Strength>(), *toEven);
Half away from zero rounds the half up to 30.1. Half to even rounds it to the neighbour whose last digit is even, 30.0. Only a value exactly halfway tells the two modes apart, which is why the mode a method prescribes belongs in its rounding.
Output
675.4 kN, half away from zero: f_c = 30 MPa
676.125 kN, half away from zero: f_c = 30.1 MPa
676.125 kN, half to even: f_c = 30 MPa
Summary
formula::DecimalRounding-- a rounding rule named once: a unit, a number of decimal places and a rounding mode.formula::DecimalPlaces-- how many decimal places of the unit to keep.formula::RoundingMode-- which way to round, including what to do with a value exactly halfway; name the one the method prescribes.formula::rounded<R>(operand)-- rounds the operand by the ruleR, at that position in the formula.