Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Large bounds are not required to cause rounding #35933

Closed
per-reimers-profcon opened this issue Sep 18, 2024 · 4 comments · Fixed by #35957
Closed

Large bounds are not required to cause rounding #35933

per-reimers-profcon opened this issue Sep 18, 2024 · 4 comments · Fixed by #35957
Labels
Content:JS JavaScript docs

Comments

@per-reimers-profcon
Copy link

MDN URL

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random

What specific section or headline is this issue about?

Examples

What information was incorrect, unhelpful, or incomplete?

"If extremely large bounds are chosen (2**53 or higher), it's possible in extremely rare cases to reach the usually-excluded upper bound."

What did you expect to see?

"It's possible in extremely rare cases to reach the usually-excluded upper bound, especially if large bounds are chosen."

Do you have any supporting links, references, or citations?

No response

Do you have anything more you want to share?

const almost_1 = 0.9999999999999999;
Math.random = () => almost_1;

// Example from page, supposedly always returns numbers less than max
function getRandomArbitrary(min, max) {
  return Math.random() * (max - min) + min;
}

console.log(getRandomArbitrary(1, 3)); // Logs 3

MDN metadata

Page report details
@per-reimers-profcon per-reimers-profcon added the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Sep 18, 2024
@github-actions github-actions bot added the Content:JS JavaScript docs label Sep 18, 2024
@Josh-Cena Josh-Cena removed the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Sep 18, 2024
@OnkarRuikar
Copy link
Contributor

OnkarRuikar commented Sep 19, 2024

This is because 0.9999999999999999 is possible in JS, but 1.9999999999999999 is not. The later rounds to 2.

console.log(0.9999999999999999); // 0.9999999999999999
console.log(1.9999999999999999); // 2
console.log(1.9999999999999998); // 1.9999999999999998

The large bounds have nothing to do with it. So the statement could be, "It's possible in extremely rare cases(when Math.random() returns 0.9999999999999999) the returned random number to reach the usually excluded upper bound."

Or the function could be written as:

const almost_1 = 0.9999999999999999;
Math.random = () => almost_1;

// Example from page, supposedly always returns numbers less than max
function getRandomArbitrary(min, max) {
  return (Math.random() - 0.0000000000000001) * (max - min) + min;
}

console.log(getRandomArbitrary(1, 3)); // Logs 2.9999999999999996

@per-reimers-profcon
Copy link
Author

The large bounds have nothing to do with it. So the statement could be, "It's possible in extremely rare cases(when Math.random() returns 0.9999999999999999) the returned random number to reach the usually excluded upper bound."

Well, not quite. As the bounds get larger, the more common it becomes for a rounding error to cause the upper bound to be reached. I'd guess the probability doubles as the bounds doubles.

Or the function could be written as:

const almost_1 = 0.9999999999999999;
Math.random = () => almost_1;

// Example from page, supposedly always returns numbers less than max
function getRandomArbitrary(min, max) {
  return (Math.random() - 0.0000000000000001) * (max - min) + min;
}

console.log(getRandomArbitrary(1, 3)); // Logs 2.9999999999999996

No, that won't work if Math.random returns 0:

Math.random = () => 0;

// Adjusted example, I disagree with
function getRandomArbitrary(min, max) {
  return (Math.random() - 0.0000000000000001) * (max - min) + min;
}

console.log(getRandomArbitrary(1, 3)); // Logs 0.9999999999999998

This might be better:

Math.random = () => 0.9999999999999999;

// Adjusted example, with special check
function getRandomArbitrary(min, max) {
  const result = Math.random() * (max - min) + min;
  if (result >= max) return min; // Handle floating point rounding error
  return result;
}

console.log(getRandomArbitrary(1, 3)); // Logs 1 now.

@OnkarRuikar
Copy link
Contributor

OnkarRuikar commented Sep 19, 2024

As the bounds get larger, the more common it becomes for a rounding error to cause the upper bound to be reached.

You are right. My point is that the possibility exists across the range, not just with larger bounds.

if (result >= max) return min; // Handle floating point rounding error

Returning min is the best tradeoff 🙂. But the probability of returning min would increase with bigger bounds.

How about the following?

function getRandomArbitrary(min, max) {
  let result = max;
  while(result >= max) {
     result = Math.random() * (max - min) + min;
  }
  return result;
}

Fixing the code blocks would be better than explaining the rounding error cases.

@per-reimers-profcon
Copy link
Author

As the bounds get larger, the more common it becomes for a rounding error to cause the upper bound to be reached.

You are right. My point is that the possibility exists across the range, not just with larger bounds.

That's true. We probably shouldn't be too specific since I don't think we really know.

if (result >= max) return min; // Handle floating point rounding error

Returning min is the best tradeoff 🙂. But the probability of returning min would increase with bigger bounds.

That might be true.

How about the following?

function getRandomArbitrary(min, max) {
  let result = max;
  while(result >= max) {
     result = Math.random() * (max - min) + min;
  }
  return result;
}

Good in theory, but it would be nicer if it would handle min >= max gracefully. If a beginner tries the wrong way around they would get an infinite loop.

Fixing the code blocks would be better than explaining the rounding error cases.

Hmm, I disagree. I think accurate documentation is more important. Example code is nice and useful, but not required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:JS JavaScript docs
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants