0

I'm developing an online game that uses deterministic physics, and it seems that trigonometric / transcendental functions can be implemented differently on different browsers, and give slightly different results. I need the results to be the exact same on every browser.

From all the testing I've done (Chrome, Firefox, Safari), it seems their answers are basically identical. Math.sin and Math.cos seem to give identical results on the latest versions of Chrome, Firefox, and Safari. Math.atan2 on the other-hand seems to give identical results on Chrome and Firefox, but the last (16th) digit differs by one on Safari.

This being the case, rather than implement my own versions of sin, cos, atan2, would it be safe to do something like this?

function crossPlatformCos(x) {
  const precision = 100000;

  return Math.floor(Math.cos(x) * precision) / precision;
}

The logic being that it is extremely unlikely for a browser to differ by that many decimals. This approach basically rounds cos down to 6 or so decimal places, instead of 16. And honestly, even if this only works for 99.99% of users, I'm fine with that.

I suppose my question is, does this sound reasonable? And would this work to ensure deterministic behavior for all the transcendental functions that may have slightly differing implementations on different browsers / platforms? If I don't need 16 digits of precision and am fine with 6, would this sort of logic ensure maximal determinism? Or is it still recommended to create my own versions of everything? By using something like this:

const tp = 1 / (2 * Math.PI);

function cos(x) {
  const a = x * tp;
  const b = a - (0.25 + Math.floor(a + 0.25));
  const c = b * (16 * (Math.abs(b) - 0.5));

  return c + 0.225 * c * (Math.abs(c) - 1.0);
}
Ryan Peschel
  • 11,087
  • 19
  • 74
  • 136
  • No that kind of rounding is not safe as `double` value mantissa is shifted by its exponent while your `10000` is fixed so it would round differently small and big numbers. Its safer to round the mantissa directly (its just unsigned integer). Also why do you need goniometrics in physics? Once you start using vectors all the goniometrics will be gone (and even simplified) for most physics problems – Spektre Oct 22 '22 at 07:09
  • Is your comment accurate? I am only performing this operation on the the results of sin, cos, and atan2. All those results are somewhere in the range of -1 to 1. So not sure the relevance of it affecting small and large numbers differently. Also, in my tests this seems to safely eliminate the cross browser differences of these operations, so I'm not sure why you're saying this is not safe either. Can you give an example of how this could fail? – Ryan Peschel Oct 22 '22 at 12:34
  • Couple of Q&As that might assist you... https://stackoverflow.com/questions/588004/is-floating-point-math-broken and https://stackoverflow.com/questions/1458633/how-to-deal-with-floating-point-number-precision-in-javascript... – Trentium Oct 22 '22 at 12:59
  • yes `sin,cos` output is in range `<-1,+1>` but what if you do for example `sin(1e-20)` ... – Spektre Oct 23 '22 at 06:26

0 Answers0