feat: config and approximate equality (#19)
All checks were successful
/ test (push) Successful in 17s
All checks were successful
/ test (push) Successful in 17s
Establishes a global config object for a TypeDispatcher instance, so far with just properties representing comparison tolerances. Begins a "relational" group of functions with basic approximate equality, and an initial primitive ordering comparison. Ensures that methods that depend on properties of `config` will be properly updated when those properties change. Reviewed-on: #19 Co-authored-by: Glen Whitney <glen@studioinfinity.org> Co-committed-by: Glen Whitney <glen@studioinfinity.org>
This commit is contained in:
parent
27fa4b0193
commit
70ce01d12b
27 changed files with 788 additions and 218 deletions
37
src/number/relational.js
Normal file
37
src/number/relational.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import {onType} from '#core/helpers.js'
|
||||
import {Returns} from '#core/Type.js'
|
||||
import {Optional} from '#core/TypePatterns.js'
|
||||
import {boolnum} from './helpers.js'
|
||||
import {NumberT} from './NumberT.js'
|
||||
|
||||
// In nanomath, we take the point of view that two comparators are primitive:
|
||||
// indistinguishable(a, b, relTol, absTol), and exceeds(a, b). All others
|
||||
// are defined generically in terms of these. They typically return BooleanT,
|
||||
// but in a numbers-only bundle, they return 1 or 0.
|
||||
|
||||
// Notice a feature of TypedDispatcher: if you specify one tolerance, you must
|
||||
// specify both.
|
||||
export const indistinguishable = onType(
|
||||
[NumberT, NumberT, Optional([NumberT, NumberT])],
|
||||
boolnum((a, b, [tolerances = [0, 0]]) => {
|
||||
const [relTol, absTol] = tolerances
|
||||
if (relTol < 0 || absTol < 0) {
|
||||
throw new RangeError(
|
||||
`Tolerances (relative: ${relTol}, absolute: ${absTol}) `
|
||||
+ 'must be nonnegative')
|
||||
}
|
||||
if (isNaN(a) || isNaN(b)) return false
|
||||
if (a === b) return true
|
||||
if (!isFinite(a) || !isFinite(b)) return false
|
||||
// |a-b| <= absTol or |a-b| <= relTol*max(|a|, |b|)
|
||||
const diff = Math.abs(a-b)
|
||||
if (diff <= absTol) return true
|
||||
const magnitude = Math.max(Math.abs(a), Math.abs(b))
|
||||
return diff <= relTol * magnitude
|
||||
})
|
||||
)
|
||||
|
||||
// Returns truthy if a (interpreted as completely precise) represents a
|
||||
// greater value than b (interpreted as completely precise). Note that even if
|
||||
// so, a and b might be indistinguishable() to some tolerances.
|
||||
export const exceeds = onType([NumberT, NumberT], boolnum((a, b) => a > b))
|
Loading…
Add table
Add a link
Reference in a new issue