Jest: toBeCloseTo() matcher does not handle large numbers as expected

Created on 3 Jan 2018  路  4Comments  路  Source: facebook/jest

Do you want to request a _feature_ or report a _bug_?

bug

What is the current behavior?

toBeCloseTo matcher does not behave as expected. This fails:
expect((0.1 + 0.2) * 1e20).toBeCloseTo(0.3e20)

If the current behavior is a bug, please provide the steps to reproduce and
either a repl.it demo through https://repl.it/languages/jest or a minimal
repository on GitHub that we can yarn install and yarn test.

https://repl.it/@hgossler/YouthfulVigilantMonoclonius

What is the expected behavior?

expect((0.1 + 0.2) * 1e20).toBeCloseTo(0.3e20) should pass. See the repl.it for a proposed solution

Please provide your exact Jest configuration and mention your Jest, node,
yarn/npm version and operating system.

Jest 20.0.4
node 8.9.1
yarn 1.3.2
macOS

Most helpful comment

The suggestion by @abhinavsingi will indeed work. The numDigits precision is used as the power of ten to determine the valid deviation.

This means that a precision of 0 creates a deviation radius of 10 ** 0 / 2 = 0.5 in each direction. Or, by example: expect(x).toBeCloseTo(y, 0) allows x to be anything from y - 0.5 to y + 0.5.

You can calculate the precision p you need for an allowed deviation of 卤d with the following formula:

p = -log_10(2 * d)

Or, as a JavaScript function:

function calculatePrecision(deviation) {
  return -Math.log10(2 * deviation)
}

We can verify this by reversing our example from above: Calling calculatePrecision(0.5) for a deviation of 卤0.5 actually yields a precision of 0.

All 4 comments

toBeCloseTo is created for decimal numbers, not large numbers. I'm not sure if it makes sense to use for huge numbers. What would "close to" mean in this setting?

One use case can be to compare timestamp. Say I have a function that is expected to give the current timestamp given certain input:

expect(getFooTime('input')).toBeCloseTo(Date.now());

Expected: 1551099111540
Received: 1551099111541

Just a millisecond difference, would be good to count as "close to".

You could pass numDigits as negative value.

Ex.

expect(getFooTime('input')).toBeCloseTo(Date.now(), -1);

It may work

The suggestion by @abhinavsingi will indeed work. The numDigits precision is used as the power of ten to determine the valid deviation.

This means that a precision of 0 creates a deviation radius of 10 ** 0 / 2 = 0.5 in each direction. Or, by example: expect(x).toBeCloseTo(y, 0) allows x to be anything from y - 0.5 to y + 0.5.

You can calculate the precision p you need for an allowed deviation of 卤d with the following formula:

p = -log_10(2 * d)

Or, as a JavaScript function:

function calculatePrecision(deviation) {
  return -Math.log10(2 * deviation)
}

We can verify this by reversing our example from above: Calling calculatePrecision(0.5) for a deviation of 卤0.5 actually yields a precision of 0.

Was this page helpful?
0 / 5 - 0 ratings