Fix #128102: Integer Math division has only float precision

The additional division modes were implemented with float
division then rounding to match float > int conversion in
existing float to int node.

As pointed out in the bug report the precision here is limited.

This patch replaces the float division with integer math which
increases the precision to much higher numbers.
Divide Round by due to the way it is calculated has less precision
than Divide Floor and Divide Ceil.

Pull Request: https://projects.blender.org/blender/blender/pulls/128123
This commit is contained in:
Charlie Jolly
2024-09-26 14:44:09 +02:00
committed by Jacques Lucke
parent b96a7b7204
commit c0a864aaa3

View File

@@ -105,6 +105,14 @@ static void node_label(const bNodeTree * /*ntree*/, const bNode *node, char *lab
BLI_strncpy(label, IFACE_(name), maxlen);
}
/* Derived from `divide_round_i` but fixed to be safe and handle negative inputs. */
static int safe_divide_round_i(const int a, const int b)
{
const int c = math::abs(b);
return (a >= 0) ? math::safe_divide((2 * a + c), (2 * c)) * math::sign(b) :
-math::safe_divide((2 * -a + c), (2 * c)) * math::sign(b);
}
static const mf::MultiFunction *get_multi_function(const bNode &bnode)
{
NodeIntegerMathOperation operation = NodeIntegerMathOperation(bnode.custom1);
@@ -119,16 +127,14 @@ static const mf::MultiFunction *get_multi_function(const bNode &bnode)
"Divide", [](int a, int b) { return math::safe_divide(a, b); }, exec_preset);
static auto divide_floor_fn = mf::build::SI2_SO<int, int, int>(
"Divide Floor",
[](int a, int b) { return int(math::floor(math::safe_divide(float(a), float(b)))); },
[](int a, int b) { return (b != 0) ? divide_floor_i(a, b) : 0; },
exec_preset);
static auto divide_ceil_fn = mf::build::SI2_SO<int, int, int>(
"Divide Ceil",
[](int a, int b) { return int(math::ceil(math::safe_divide(float(a), float(b)))); },
[](int a, int b) { return (b != 0) ? -divide_floor_i(a, -b) : 0; },
exec_preset);
static auto divide_round_fn = mf::build::SI2_SO<int, int, int>(
"Divide Round",
[](int a, int b) { return int(math::round(math::safe_divide(float(a), float(b)))); },
exec_preset);
"Divide Round", [](int a, int b) { return safe_divide_round_i(a, b); }, exec_preset);
static auto pow_fn = mf::build::SI2_SO<int, int, int>(
"Power", [](int a, int b) { return math::pow(a, b); }, exec_preset);
static auto madd_fn = mf::build::SI3_SO<int, int, int, int>(