-
Notifications
You must be signed in to change notification settings - Fork 654
feat(math/unstable): add math
package with basic math utilities
#6823
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
5b9bc11
to
98eb5e1
Compare
98eb5e1
to
da04151
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6823 +/- ##
=======================================
Coverage 94.16% 94.17%
=======================================
Files 573 577 +4
Lines 42400 42430 +30
Branches 6732 6741 +9
=======================================
+ Hits 39928 39958 +30
Misses 2422 2422
Partials 50 50 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
dac2f0f
to
132a0be
Compare
132a0be
to
004dee2
Compare
export function modulo(num: number, modulus: number): number { | ||
if (!Number.isFinite(num) || Number.isNaN(modulus) || modulus === 0) { | ||
return NaN; | ||
} | ||
if (num === 0) return modulus < 0 ? -0 : 0; | ||
if (modulus === Infinity) return num < 0 ? Infinity : num; | ||
if (modulus === -Infinity) return num > 0 ? -Infinity : num; | ||
|
||
return (num % modulus + modulus) % modulus; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's an alternative implementation for modulo
.
export function modulo(num: number, modulus: number): number {
num %= modulus;
if (num === 0) {
num = modulus < 0 ? -0 : 0;
} else if ((num < 0) !== (modulus < 0)) {
num += modulus;
}
return num;
}
In my benchmarks (code below), it was faster than the current implementation in the common case where both inputs are finite and nonzero, although slower when either input is infinite, NaN or 0. All tests still pass.
// `baseline` and `modulo` are different implementations.
// `cases` is taken from the python parity test.
const sink = new Set<number>();
for (const [a, b] of cases) {
const group = Deno.inspect([a, b]);
Deno.bench("baseline", { group }, () => {
sink.add(baseline(a, b));
});
Deno.bench("modulo", { group }, () => {
sink.add(modulo(a, b));
});
}
export function clamp(num: number, limits: [min: number, max: number]): number { | ||
const [min, max] = limits; | ||
if (min > max) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Passing limits
as an array means that this array needs to be allocated prior to passing it to this function. Given that math functions are often used in high performance scenarios it might be more desirable to avoid the need to allocate at all for determining whether a value is in-between two others.
Closes #6803
clamp
: Clamp a number within a range. Based onMath.clamp
proposal, with notable differences being:TypeError
s forNaN
inputs, whereas my version returnsNaN
s, because throwingTypeError
s seems rather unexpected given the corresponding behavior ofMath.min
andMath.max
.[min, max]
as a tuple rather than two separate arguments. I think this way works better for@std
(to keep number of args within the style guide) and TypeScript (friendly tuple handling), plus it makes it visually apparent which arg is the input number and which are the limits.modulo
: Floor modulo operation, in contrast with JS's%
remainder operator. Based on Python's%
(floor modulo) operator and modulus math proposal.round-to
: Round a number to a specified number of decimal places using various rounding strategies. BasicallyNumber#toFixed
but returning a number instead of a string.Probably worth kicking the wheels for things like floating-point rounding issues, in cases where those are avoidable or optimizable.