Here is my version. If you care about performance you should benchmark. You didn't specify how to handle negative values so I assumed you "keep" the digit.
#include <concepts>
#include <cmath>
constexpr auto keep_msd(std::integral auto n)
{
decltype(n) ten_pow = 1;
while (n > 9 || n < -9)
{
n /= 10;
ten_pow *= 10;
}
return n * ten_pow;
}
template <class F>
requires std::floating_point<F>
constexpr F keep_msd(F f)
{
if (!std::isfinite(f))
return f;
if (f == 0.0)
return 0.0;
if (f >= 1 || f <= -1)
return static_cast<F>(keep_msd(static_cast<long long>(f)));
F sig = f < 0 ? -1.0 : 1.0;
f *= sig;
F ten_pow = 1.0;
while (f <= 1)
{
f *= static_cast<F>(10.0);
ten_pow /= static_cast<F>(10.0);
}
return sig * static_cast<int>(f) * ten_pow;
}
Keep in mind that floating point math is broken so with that out of the way here is the test suite:
template <class F>
requires std::floating_point<F>
constexpr bool are_almost_eq(F a, F b, F delta)
{
return std::abs(a - b) <= delta;
}
static_assert(keep_msd(0) == 0);
static_assert(keep_msd(5) == 5);
static_assert(keep_msd(10) == 10);
static_assert(keep_msd(12) == 10);
static_assert(keep_msd(1'234) == 1'000);
static_assert(keep_msd(1'004) == 1'000);
static_assert(keep_msd(1'000) == 1'000);
static_assert(keep_msd(-5) == -5);
static_assert(keep_msd(-10) == -10);
static_assert(keep_msd(-12) == -10);
static_assert(keep_msd(-1'234) == -1'000);
static_assert(keep_msd(-1'004) == -1'000);
static_assert(keep_msd(-1'000) == -1'000);
static_assert(keep_msd(0.0) == 0.0);
static_assert(keep_msd(std::numeric_limits<double>::infinity()) ==
std::numeric_limits<double>::infinity());
static_assert(keep_msd(-std::numeric_limits<double>::infinity()) ==
-std::numeric_limits<double>::infinity());
static_assert(keep_msd(1.2) == 1.0);
static_assert(keep_msd(1.2) == 1.0);
static_assert(keep_msd(1.002) == 1.0);
static_assert(keep_msd(1'000.0004) == 1'000.0);
static_assert(keep_msd(1'002.3004) == 1'000.0);
static_assert(keep_msd(-1.2) == -1.0);
static_assert(keep_msd(-1.2) == -1.0);
static_assert(keep_msd(-1.002) == -1.0);
static_assert(keep_msd(-1'000.0004) == -1'000.0);
static_assert(keep_msd(-1'002.3004) == -1'000.0);
static_assert(are_almost_eq(keep_msd(0.1), 0.1, 0.000'000'1));
static_assert(are_almost_eq(keep_msd(0.3), 0.3, 0.000'000'1));
static_assert(are_almost_eq(keep_msd(0.123456), 0.1, 0.000'000'1));
static_assert(are_almost_eq(keep_msd(0.000'001), 0.000'001, 0.000'000'001));
static_assert(are_almost_eq(keep_msd(-0.1), -0.1, 0.000'000'1));
static_assert(are_almost_eq(keep_msd(-0.3), -0.3, 0.000'000'1));
static_assert(are_almost_eq(keep_msd(-0.123456), -0.1, 0.000'000'1));
static_assert(are_almost_eq(keep_msd(-0.000'001), -0.000'001, 0.000'000'001));