Here are some JavaScript functions to round one number to the “nearest” multiple of another. If the other number’s omitted from the call parameters (which JXA doesn’t seem to mind), the default used is 1, for “nearest integer”.
/* JXA script.
Round n in various ways to an adjacent multiple of q.
For 'nearest integer', the q parameter should be 1.
However, JXA doesn't mind if parameters are omitted from calls. If the q parameter's omitted, the functions adopt a default q of 1.
There's obviously no point in omitting the n parameter as well.
JXA returns whole-number values in integer form.
The functions below return 'NaN' when meaningful results aren't possible.
*/
// To nearest multiple, IEEE 754 style. (Midway values to nearest /even/ multiple.)
function round(n, q) {
if (q == undefined) {q = 1;}; // Default to 1 if q not given.
if (q == 0) {return q;}; // The only possible result if q's 0.
// If n is more than a quarter of the way (zerofugally) between two consecutive even multiples of q, round "as taught in school".
if ((n % (q * 2)) ** 2 > q * q / 4) {return n + n % q - (n * 2) % q;};
// Otherwise truncate.
return n - n % q;
};
// To nearest multiple, "as taught in school". (Midway values to nearest multiple away from zero.)
function roundAsTaughtInSchool(n, q) {
if (q == undefined) {q = 1;};
if (q == 0) {return q;};
return n + n % q - (n * 2) % q; // (Math.trunc(n * 2 / q) - Math.trunc(n / q)) * q ;
};
// To nearest multiple zerowards.
function truncate(n, q) {
if (q == undefined) {q = 1;};
if (q == 0) {return q;};
return n - n % q; // Math.trunc(n / q) * q;
};
// To nearest multiple away from zero.
function extend(n, q) {
if (q == undefined) {q = 1;};
if ((q == 0) && (n == 0)) {return q;};
if (n < 0) {return Math.floor(n / q) * q;};
return Math.ceil(n / q) * q;
};
// To nearest multiple below.
function floor(n, q) {
if (q == undefined) {q = 1;};
if ((q == 0) && (n >= 0)) {return q;};
return Math.floor(n / q) * q;
};
// To nearest multiple above.
function ceiling(n, q) {
if (q == undefined) {q = 1;};
if ((q == 0) && (n <= 0)) {return q;};
return Math.ceil(n / q) * q;
};
// Examples:
round(123456.5) // or round(123456.5, 1) // --> 123456 (nearest integer, IEEE 754 standard)
roundAsTaughtInSchool(123456.5) // or roundAsTaughtInSchool(123456.5, 1) // --> 123457 (ditto, "as taught in school")
round(123456.5, 100) // --> 123500 (nearest hundred)
round(1.234567, 0.001) // --> 1.235 (three decimal places)
truncate(123456.5, 1000) // --> 123000 (nearest thousand towards zero)
extend(123456.5, 1000) // --> 124000 (nearest thousand away from zero)
floor(123456.6, 1000) // --> 123000 (nearest thousand below)
floor(-123456.6, 1000) // --> -124000 (ditto)
And the AS equivalents. Both parameters have to be specified in these:
(* AppleScript script.
Round n in various ways to an adjacent multiple of q.
For 'nearest integer', the q parameter should be 1.
THE q PARAMETER ISN'T OPTIONAL HERE as it's less trouble to type ", 1" than to use AS's optional-parameter methods!
Some of the math is slightly different from that in the JXA script to ensure that the AS results are in the same number class as q.
The last three handlers below return 'missing value' when meaningful results aren't possible.
*)
-- To nearest multiple, IEEE 754 style. (Midway values to nearest /even/ multiple.)
on |round|(n, q)
if (q = 0) then return q -- The only possible result if q's 0.
-- If n is more than a quarter of the way (zerofugally) between two consecutive even multiples of q, round "as taught in school".
if ((n mod (q + q)) ^ 2 > q * q / 4) then return ((n + n) div q - n div q) * q
-- Otherwise truncate.
return n div q * q
end |round|
-- To nearest multiple, "as taught in school". (Midway values to nearest multiple away from zero.)
on roundAsTaughtInSchool(n, q)
if (q = 0) then return q
return ((n + n) div q - n div q) * q
end roundAsTaughtInSchool
-- To nearest multiple zerowards.
on truncate(n, q)
if (q = 0) then return q
return n div q * q
end truncate
-- To nearest multiple away from zero.
on extend(n, q)
if (q = 0) then
if (n = 0) then return q
return missing value
end if
set nTruncated to n div q * q
if (nTruncated = n) then return nTruncated
if (q < 0) then set q to -q
if (n < 0) then return nTruncated - q
return nTruncated + q
end extend
-- To nearest multiple below.
on floor(n, q)
if (q = 0) then
if (n < 0) then return missing value
return q
end if
set nTruncated to n div q * q
if (nTruncated > n) then
if (q < 0) then set q to -q
return nTruncated - q
end if
return nTruncated
end floor
-- To nearest multiple above.
on ceiling(n, q)
if (q = 0) then
if (n > 0) then return missing value
return q
end if
set nTruncated to n div q * q
if (nTruncated < n) then
if (q < 0) then set q to -q
return nTruncated + q
end if
return nTruncated
end ceiling
-- Examples:
|round|(1.234565E+5, 1) --> 1234356 (nearest integer, IEEE 754 standard)
roundAsTaughtInSchool(-1.234565E+5, 1) --> -123457 (ditto, "as taught in school")