# HG changeset patch # User Gaƫl Bonithon # Date 1645384872 -3600 # Sun Feb 20 20:21:12 2022 +0100 # Node ID fcdae7946c7ad992bd3cc18978873532deb57454 # Parent 753e48aa488cd2efbaa0d07278ff6903052092db idivide.m: Avoid floating-point representation issues (bug #61319) * scripts/general/idivide.m: We start from `z = x ./ y` which corresponds to the classical rounding, and which we are sure is an integer value if `x` or `y` is an integer value. We then add or subtract `1` if necessary according to the rounding rule and the sign of `y`, keeping the starting integer type all along. diff -r 753e48aa488c -r fcdae7946c7a scripts/general/idivide.m --- a/scripts/general/idivide.m Sat Feb 19 13:14:44 2022 -0500 +++ b/scripts/general/idivide.m Sun Feb 20 20:21:12 2022 +0100 @@ -84,33 +84,28 @@ op = tolower (op); endif - if (isfloat (x)) - if (isinteger (y)) - typ = class (y); - else - error ("idivide: at least one input (X or Y) must be an integer type"); - endif - elseif (isfloat (y)) - if (isinteger (x)) - typ = class (x); - else - error ("idivide: at least one input (X or Y) must be an integer type"); - endif - else - typ = class (x); - if (! strcmp (typ, class (y))) - error ("idivide: integer type of X (%s) must match integer type of Y (%s)", typ, class (y)); - endif + if (! isinteger (x) && ! isinteger (y)) + error ("idivide: at least one input (X or Y) must be an integer type"); + elseif (isinteger (x) && isinteger (y) && ! strcmp (class (x), class (y))) + error ("idivide: integer type of X (%s) must match integer type of Y (%s)", + class (x), class (y)); endif + z = x ./ y; if (strcmp (op, "fix")) - z = cast (fix (double (x) ./ double (y)), typ); + z -= (z .* y > x) .* sign (y); elseif (strcmp (op, "round")) - z = x ./ y; + return; elseif (strcmp (op, "floor")) - z = cast (floor (double (x) ./ double (y)), typ); + y_sel = (y>0); + z(y_sel) -= (z(y_sel) .* y(y_sel) > x); + y_sel = ! ysel; + z(y_sel) -= (z(y_sel) .* y(y_sel) < x); elseif (strcmp (op, "ceil")) - z = cast (ceil (double (x) ./ double (y)), typ); + y_sel = (y>0); + z(y_sel) += (z(y_sel) .* y(y_sel) < x(y_sel)); + y_sel = ! ysel; + z(y_sel) += (z(y_sel) .* y(y_sel) > x(y_sel)); else error ('idivide: unrecognized rounding type "%s"', op); endif