Skip to content

Commit

Permalink
Updated all calls for nearlyEqual
Browse files Browse the repository at this point in the history
  • Loading branch information
dvd101x committed Apr 6, 2024
1 parent 71cfe28 commit a761260
Show file tree
Hide file tree
Showing 15 changed files with 109 additions and 108 deletions.
7 changes: 4 additions & 3 deletions docs/datatypes/numbers.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,12 @@ false, as the addition `0.1 + 0.2` introduces a round-off error and does not
return exactly `0.3`.

To solve this problem, the relational functions of math.js check whether the
relative difference between the compared values is smaller than the configured
relative and absolute differences between the compared values is smaller than the configured
option `epsilon`. In pseudo code (without exceptions for 0, Infinity and NaN):

diff = abs(x - y)
nearlyEqual = (diff <= max(abs(x), abs(y)) * EPSILON) OR (diff < DBL_EPSILON)
relTol = epsilon
absTol = epsilon / 1000
abs(a-b) <= max(relTol * max(abs(a), abs(b)), absTol)

where:

Expand Down
8 changes: 4 additions & 4 deletions src/function/arithmetic/ceil.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ export const createCeilNumber = /* #__PURE__ */ factory(
name, ['typed', 'config', 'round'], ({ typed, config, round }) => {
return typed(name, {
number: function (x) {
if (nearlyEqual(x, round(x), config.epsilon)) {
if (nearlyEqual(x, round(x), config.epsilon, config.epsilon * 1e-3)) {
return round(x)
} else {
return Math.ceil(x)
}
},

'number, number': function (x, n) {
if (nearlyEqual(x, round(x, n), config.epsilon)) {
if (nearlyEqual(x, round(x, n), config.epsilon, config.epsilon * 1e-3)) {
return round(x, n)
} else {
let [number, exponent] = `${x}e`.split('e')
Expand Down Expand Up @@ -95,15 +95,15 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
},

BigNumber: function (x) {
if (bigNearlyEqual(x, round(x), config.epsilon)) {
if (bigNearlyEqual(x, round(x), config.epsilon, config.epsilon * 1e-3)) {
return round(x)
} else {
return x.ceil()
}
},

'BigNumber, BigNumber': function (x, n) {
if (bigNearlyEqual(x, round(x, n), config.epsilon)) {
if (bigNearlyEqual(x, round(x, n), config.epsilon, config.epsilon * 1e-3)) {
return round(x, n)
} else {
return x.toDecimalPlaces(n.toNumber(), Decimal.ROUND_CEIL)
Expand Down
8 changes: 4 additions & 4 deletions src/function/arithmetic/floor.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ export const createFloorNumber = /* #__PURE__ */ factory(
name, ['typed', 'config', 'round'], ({ typed, config, round }) => {
return typed(name, {
number: function (x) {
if (nearlyEqual(x, round(x), config.epsilon)) {
if (nearlyEqual(x, round(x), config.epsilon, config.epsilon * 1e-3)) {
return round(x)
} else {
return Math.floor(x)
}
},

'number, number': function (x, n) {
if (nearlyEqual(x, round(x, n), config.epsilon)) {
if (nearlyEqual(x, round(x, n), config.epsilon, config.epsilon * 1e-3)) {
return round(x, n)
} else {
let [number, exponent] = `${x}e`.split('e')
Expand Down Expand Up @@ -98,15 +98,15 @@ export const createFloor = /* #__PURE__ */ factory(name, dependencies, ({ typed,
},

BigNumber: function (x) {
if (bigNearlyEqual(x, round(x), config.epsilon)) {
if (bigNearlyEqual(x, round(x), config.epsilon, config.epsilon * 1e-3)) {
return round(x)
} else {
return x.floor()
}
},

'BigNumber, BigNumber': function (x, n) {
if (bigNearlyEqual(x, round(x, n), config.epsilon)) {
if (bigNearlyEqual(x, round(x, n), config.epsilon, config.epsilon * 1e-3)) {
return round(x, n)
} else {
return x.toDecimalPlaces(n.toNumber(), Decimal.ROUND_FLOOR)
Expand Down
8 changes: 4 additions & 4 deletions src/function/arithmetic/round.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export const createRound = /* #__PURE__ */ factory(name, dependencies, ({ typed,
number: function (x) {
// Handle round off errors by first rounding to epsilon precision
const xEpsilon = roundNumber(x, toExponent(config.epsilon))
const xSelected = nearlyEqual(x, xEpsilon, config.epsilon) ? xEpsilon : x
const xSelected = nearlyEqual(x, xEpsilon, config.epsilon, config.epsilon * 1e-3) ? xEpsilon : x
return roundNumber(xSelected)
},

Expand All @@ -87,7 +87,7 @@ export const createRound = /* #__PURE__ */ factory(name, dependencies, ({ typed,
if (n >= epsilonExponent) { return roundNumber(x, n) }

const xEpsilon = roundNumber(x, epsilonExponent)
const xSelected = nearlyEqual(x, xEpsilon, config.epsilon) ? xEpsilon : x
const xSelected = nearlyEqual(x, xEpsilon, config.epsilon, config.epsilon * 1e-3) ? xEpsilon : x
return roundNumber(xSelected, n)
},

Expand Down Expand Up @@ -117,7 +117,7 @@ export const createRound = /* #__PURE__ */ factory(name, dependencies, ({ typed,
BigNumber: function (x) {
// Handle round off errors by first rounding to epsilon precision
const xEpsilon = new BigNumber(x).toDecimalPlaces(toExponent(config.epsilon))
const xSelected = bigNearlyEqual(x, xEpsilon, config.epsilon) ? xEpsilon : x
const xSelected = bigNearlyEqual(x, xEpsilon, config.epsilon, config.epsilon * 1e-3) ? xEpsilon : x
return xSelected.toDecimalPlaces(0)
},

Expand All @@ -129,7 +129,7 @@ export const createRound = /* #__PURE__ */ factory(name, dependencies, ({ typed,
if (n >= epsilonExponent) { return x.toDecimalPlaces(n.toNumber()) }

const xEpsilon = x.toDecimalPlaces(epsilonExponent)
const xSelected = bigNearlyEqual(x, xEpsilon, config.epsilon) ? xEpsilon : x
const xSelected = bigNearlyEqual(x, xEpsilon, config.epsilon, config.epsilon * 1e-3) ? xEpsilon : x
return xSelected.toDecimalPlaces(n.toNumber())
},

Expand Down
4 changes: 2 additions & 2 deletions src/function/relational/compare.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const createCompare = /* #__PURE__ */ factory(name, dependencies, ({ type
},

'BigNumber, BigNumber': function (x, y) {
return bigNearlyEqual(x, y, config.epsilon)
return bigNearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
? new BigNumber(0)
: new BigNumber(x.cmp(y))
},
Expand All @@ -97,7 +97,7 @@ export const createCompare = /* #__PURE__ */ factory(name, dependencies, ({ type
export const createCompareNumber = /* #__PURE__ */ factory(name, ['typed', 'config'], ({ typed, config }) => {
return typed(name, {
'number, number': function (x, y) {
return nearlyEqual(x, y, config.epsilon)
return nearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
? 0
: (x > y ? 1 : -1)
}
Expand Down
6 changes: 3 additions & 3 deletions src/function/relational/equalScalar.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ export const createEqualScalar = /* #__PURE__ */ factory(name, dependencies, ({
},

'number, number': function (x, y) {
return nearlyEqual(x, y, config.epsilon)
return nearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
},

'BigNumber, BigNumber': function (x, y) {
return x.eq(y) || bigNearlyEqual(x, y, config.epsilon)
return x.eq(y) || bigNearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
},

'Fraction, Fraction': function (x, y) {
Expand All @@ -45,7 +45,7 @@ export const createEqualScalar = /* #__PURE__ */ factory(name, dependencies, ({
export const createEqualScalarNumber = factory(name, ['typed', 'config'], ({ typed, config }) => {
return typed(name, {
'number, number': function (x, y) {
return nearlyEqual(x, y, config.epsilon)
return nearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
}
})
})
4 changes: 2 additions & 2 deletions src/function/relational/larger.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed
'boolean, boolean': (x, y) => x > y,

'BigNumber, BigNumber': function (x, y) {
return x.gt(y) && !bigNearlyEqual(x, y, config.epsilon)
return x.gt(y) && !bigNearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
},

'Fraction, Fraction': (x, y) => (x.compare(y) === 1),
Expand All @@ -82,7 +82,7 @@ export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed
export const createLargerNumber = /* #__PURE__ */ factory(name, ['typed', 'config'], ({ typed, config }) => {
return typed(name, {
'number, number': function (x, y) {
return x > y && !nearlyEqual(x, y, config.epsilon)
return x > y && !nearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
}
})
})
4 changes: 2 additions & 2 deletions src/function/relational/largerEq.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const createLargerEq = /* #__PURE__ */ factory(name, dependencies, ({ typ
'boolean, boolean': (x, y) => x >= y,

'BigNumber, BigNumber': function (x, y) {
return x.gte(y) || bigNearlyEqual(x, y, config.epsilon)
return x.gte(y) || bigNearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
},

'Fraction, Fraction': (x, y) => (x.compare(y) !== -1),
Expand All @@ -78,7 +78,7 @@ export const createLargerEq = /* #__PURE__ */ factory(name, dependencies, ({ typ
export const createLargerEqNumber = /* #__PURE__ */ factory(name, ['typed', 'config'], ({ typed, config }) => {
return typed(name, {
'number, number': function (x, y) {
return x >= y || nearlyEqual(x, y, config.epsilon)
return x >= y || nearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
}
})
})
4 changes: 2 additions & 2 deletions src/function/relational/smaller.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ type
'boolean, boolean': (x, y) => x < y,

'BigNumber, BigNumber': function (x, y) {
return x.lt(y) && !bigNearlyEqual(x, y, config.epsilon)
return x.lt(y) && !bigNearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
},

'Fraction, Fraction': (x, y) => (x.compare(y) === -1),
Expand All @@ -82,7 +82,7 @@ export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ type
export const createSmallerNumber = /* #__PURE__ */ factory(name, ['typed', 'config'], ({ typed, config }) => {
return typed(name, {
'number, number': function (x, y) {
return x < y && !nearlyEqual(x, y, config.epsilon)
return x < y && !nearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
}
})
})
4 changes: 2 additions & 2 deletions src/function/relational/smallerEq.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const createSmallerEq = /* #__PURE__ */ factory(name, dependencies, ({ ty
'boolean, boolean': (x, y) => (x <= y),

'BigNumber, BigNumber': function (x, y) {
return x.lte(y) || bigNearlyEqual(x, y, config.epsilon)
return x.lte(y) || bigNearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
},

'Fraction, Fraction': (x, y) => (x.compare(y) !== 1),
Expand All @@ -78,7 +78,7 @@ export const createSmallerEq = /* #__PURE__ */ factory(name, dependencies, ({ ty
export const createSmallerEqNumber = /* #__PURE__ */ factory(name, ['typed', 'config'], ({ typed, config }) => {
return typed(name, {
'number, number': function (x, y) {
return x <= y || nearlyEqual(x, y, config.epsilon)
return x <= y || nearlyEqual(x, y, config.epsilon, config.epsilon * 1e-3)
}
})
})
4 changes: 2 additions & 2 deletions src/utils/bignumber/nearlyEqual.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* nearlyEqual(1.0, 1.009, undefined, 0.02); // true
* nearlyEqual(0.000000001, 0.0, undefined, 1e-8); // true
*/
export function nearlyEqual (a, b, relTol = Number.EPSILON, absTol = 1e-12) {
export function nearlyEqual (a, b, relTol = 1e-9, absTol = 0) {
if (relTol <= 0) {
throw new Error('Relative tolerance must be greater than 0')
}
Expand All @@ -34,6 +34,6 @@ export function nearlyEqual (a, b, relTol = Number.EPSILON, absTol = 1e-12) {
if (a.eq(b)) {
return true
}
// abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
// abs(a-b) <= max(relTol * max(abs(a), abs(b)), absTol)
return a.minus(b).abs().lte(a.constructor.max(a.constructor.max(a.abs(), b.abs()).mul(relTol), absTol))
}
2 changes: 1 addition & 1 deletion src/utils/complex.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import { nearlyEqual } from './number.js'
* @returns {boolean}
*/
export function complexEquals (x, y, epsilon) {
return nearlyEqual(x.re, y.re, epsilon) && nearlyEqual(x.im, y.im, epsilon)
return nearlyEqual(x.re, y.re, epsilon, epsilon * 1e-3) && nearlyEqual(x.im, y.im, epsilon, epsilon * 1e-3)
}
4 changes: 2 additions & 2 deletions src/utils/number.js
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ export const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-
* @param {number} a - First value to compare
* @param {number} b - Second value to compare
* @param {number} [relTol=1e-09] - The relative tolerance, indicating the maximum allowed difference relative to the larger absolute value. Must be greater than 0.
* @param {number} [absTol=0] - The minimum absolute tolerance, useful for comparisons near zero. Must be at least 0.
* @param {number} [absTol=1e-12] - The minimum absolute tolerance, useful for comparisons near zero. Must be at least 0.
* @return {boolean} whether the two numbers are nearly equal
*
* @throws {Error} If `relTol` is less than or equal to 0.
Expand All @@ -631,7 +631,7 @@ export const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-
* nearlyEqual(1.0, 1.009, undefined, 0.01); // true
* nearlyEqual(0.000000001, 0.0, undefined, 1e-8); // true
*/
export function nearlyEqual (a, b, relTol = Number.EPSILON, absTol = 1e-12) {
export function nearlyEqual (a, b, relTol = 1e-12, absTol = 1e-9) {
if (relTol <= 0) {
throw new Error('Relative tolerance must be greater than 0')
}
Expand Down

0 comments on commit a761260

Please sign in to comment.