eslint: Bug: `no-loss-of-precision` false positive

Environment

Node version: 16.3.1 npm version: 8.1.2 Local ESLint version: 8.12.0 Global ESLint version: none Operating System: Kubuntu 20

What parser are you using?

Default (Espree)

What did you do?

const test = 555.9771118164062

eslint demo

What did you expect to happen?

This value is actually fine from my testing in chrome, brave, firefox and node console. it shouldn’t be marked as an error

What actually happened?

eslint reported a problem with the no-loss-of-precision rule

Participation

  • I am willing to submit a pull request for this issue.

Additional comments

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 24 (19 by maintainers)

Commits related to this issue

Most upvoted comments

Okay, then let’s just remove “immediately” from the docs.

Can you share the tests that show that 555.9771118164062 literal doesn’t lose precision?

Please excuse my naivete in posting this without digging deeper into understanding precision in JS beyond reading the rule description and making assumptions. My “testing” was just to the simple extent of setting the value and making sure it was “preserved” in usage in dev consoles like below

2022-04-08_11-45

To me this showed an example in direct opposition to the part of the rule that states “number literals that immediately lose precision at runtime when converted to a JS Number”. I didn’t know about the toPrecision function or that that’s how the rule is handled under the surface. I did a little more testing (see below) and this number definitely has issues with precision at such a small scale. However I don’t think it’s correct to say it “immediately loses precision” as the value does seem to be preserved until you manipulate it in some way… This issue may just be a matter of updating the documentation to better match the behavior under the hood. Also possibly worth adding a link to some documentation discussing how JS handles precision and/or directly to the toPrecision MDN page so others who see this error and go to ESLint to check it can become more informed.

let test = 555.9771118164062;
console.log(test); // 555.9771118164062
console.log(test.toPrecision(16)); // 555.9771118164063
console.log(test === 555.9771118164062); // true  <-- this contradicts the "immediately lose..."
console.log(test + 0.0000000000001); // 555.9771118164064
console.log(test + 0.0000000000002); // 555.9771118164065
console.log(test + 0.0000000000003); // 555.9771118164066
console.log(test + 0.0000000000004); // 555.9771118164067
console.log(test + 0.0000000000005); // 555.9771118164067 <-- this is weird right? or is it a rounding issue?
console.log(test + 0.0000000000006); // 555.9771118164068
console.log(test + 0.0000000000007); // 555.9771118164069
console.log(test + 0.0000000000008); // 555.977111816407   
console.log(test + 0.0000000000009); // 555.9771118164072

// and just to prove that there are similar issues with a "valid" number by eslint's standards
test = 555.9771118164063; // <-- this does not trigger the eslint rule
console.log(test); // 555.9771118164062  // <-- but that's not the same value
console.log(test.toPrecision(16)); // 555.9771118164063 <-- but this is?
console.log(test === 555.9771118164063); // true
console.log(test + 0.0000000000001); // 555.9771118164064
console.log(test + 0.0000000000002); // 555.9771118164065
console.log(test + 0.0000000000003); // 555.9771118164066
console.log(test + 0.0000000000004); // 555.9771118164067
console.log(test + 0.0000000000005); // 555.9771118164067
console.log(test + 0.0000000000006); // 555.9771118164068
console.log(test + 0.0000000000007); // 555.9771118164069
console.log(test + 0.0000000000008); // 555.977111816407
console.log(test + 0.0000000000009); // 555.9771118164072