Given that Math.ceil(1/3) yields 1, how do I get that 1 (or 1n) from BigInt input values of 1n and 3n? Obviously Math.ceil(Number(1n)/Number(3n)) would work but some bigints might be too big for that approach.
2 Answers
Create a simple function
Note: the .toString() is ONLY so the console output is shown here
const ceilN = (n, d) => n / d + (n % d ? 1n : 0n)
console.log(ceilN(120n, 3n).toString()); // 40
console.log(ceilN(121n, 3n).toString()); // 41
console.log(ceilN(122n, 3n).toString()); // 41
console.log(ceilN(123n, 3n).toString()); // 41
4 Comments
ceilN(121n, -3n), even though works for ceilN(-121n, 3n).(n, d) => (n + d - 1n) / d; that approach gets a bit messy though if it needs to handle negative inputs as well.The accepted answer does not handle negative bigints correctly.
We must handle each scenario correctly, plus it's easier to use a custom modulo operator rather than JavaScript's useless signed remainder operator (%).
Let's first patch the modulo operator:
const bigint_pos_mod = (a, b) => {
return ((a % b) + b) % b;
};
Now, observe that bigint division is truncated toward zero (and not, for example, floored):
For BigInt division, the result is the quotient of the two operands truncated towards zero, and the remainder is discarded.
In case the division was not smoothly done (there is a remainder), we aim to increase by one to achieve a ceiling. However, as truncation is towards zero, this already takes care of the increase in case of negative numbers, thus we are only interested in > 0n.
const bigint_ceil = (numerator, denominator) => {
const is_negative = (false
|| (numerator < 0n && denominator >= 0n)
|| (numerator >= 0n && denominator < 0n)
);
return (0n
+ numerator / denominator
+ (is_negative ? 0n : bigint_pos_mod(numerator, denominator) > 0n ? 1n : 0n)
);
};
Note that if you wanted to floor, you would decrease by one, and if you wanted to round or truncate toward zero you would take a slightly different approach by paying attention to the sign.
The following test cases pass like flying colors:
const bigint_pos_mod = (a, b) => {
return ((a % b) + b) % b;
};
const bigint_ceil = (numerator, denominator) => {
const is_negative = (false
|| (numerator < 0n && denominator >= 0n)
|| (numerator >= 0n && denominator < 0n)
);
return (0n
+ numerator / denominator
+ (is_negative ? 0n : bigint_pos_mod(numerator, denominator) > 0n ? 1n : 0n)
);
};
console.log("Both numerator and denominator positive.");
console.log(bigint_ceil(120n, 3n).toString()); // 40
console.log(bigint_ceil(121n, 3n).toString()); // 41
console.log(bigint_ceil(122n, 3n).toString()); // 41
console.log(bigint_ceil(123n, 3n).toString()); // 41
console.log("Numerator negative.");
console.log(bigint_ceil(-120n, 3n).toString()); // -40
console.log(bigint_ceil(-121n, 3n).toString()); // -40
console.log(bigint_ceil(-122n, 3n).toString()); // -40
console.log(bigint_ceil(-123n, 3n).toString()); // -41
console.log("Denominator negative.");
console.log(bigint_ceil(120n, -3n).toString()); // -40
console.log(bigint_ceil(121n, -3n).toString()); // -40
console.log(bigint_ceil(122n, -3n).toString()); // -40
console.log(bigint_ceil(123n, -3n).toString()); // -41
BigIntonly deals with integers. There are no fractions, so no need for theceil()function.