Skip to content

Fix random.randint() with negative numbers - #215

Merged
sspickle merged 1 commit into
vpython:masterfrom
greatsong:fix-randint-negative
Oct 31, 2026
Merged

sspickle merged 1 commit into
vpython:masterfrom
greatsong:fix-randint-negative

Conversation

@greatsong

Copy link
Copy Markdown
Contributor

On glowscript.org, randint(-2, 2) never returns -2 and returns 0 about twice as often as the other values. With both bounds negative it goes out of range: randint(-5, -1) can return 0. This is easy to hit in class, for example when picking a random velocity between -5 and 5.

The cause is in the RapydScript random module. randint() uses int(), which truncates toward zero. Bruce reported it upstream in November 2024 (kovidgoyal/rapydscript-ng#185), and the fix there is kovidgoyal/rapydscript-ng#193. GlowScript ships its own copy of the compiler, so it needs the same fix here.

This is the same kind of patch as 2debbe4 for randrange(). The one line changes to return a + randbelow(b - a + 1) in:

  • lib/rapydscript/compiler.js
  • package/RScompiler.3.2.min.js
  • GlowScriptOffline/glowscript_libraries/RScompiler.3.2.min.js
  • the build notes in lib/compiling/GScompiler.js, so the fix isn't lost on the next RapydScript update

Older package versions are left as they are.

I compiled test programs with the current and patched RScompiler.3.2.min.js and called each function 100,000 times.

Before:

randint(-2, 2)    -2:0      -1:20279  0:39758  1:20004  2:19959
randint(-5, -1)   -5:0      -4:19854  -3:19889  -2:20192  -1:20115  0:19950
randint(0, 10**10) returns negative numbers

After:

randint(-2, 2)    -2:19696  -1:20045  0:20145  1:20045  2:20069
randint(-5, -1)   -5:20056  -4:19995  -3:20144  -2:19972  -1:19833  0:0
randint(0, 10**10) stays in range

@BruceSherwood @sspickle glowscript.org will need a redeploy to pick this up.

randint(a, b) used int(random()*(b-a+1) + a). int() truncates toward
zero, so with a negative lower bound randint almost never returns a and
returns 0 twice as often as the other values. With both bounds negative
it goes out of range: randint(-5, -1) can return 0.

Use randbelow(), the same way randrange() already does. Same one-line
change as the randrange patch in 2debbe4, applied to the 3.2 files and
the build notes. Upstream report: kovidgoyal/rapydscript-ng#185
@sspickle

Copy link
Copy Markdown
Collaborator

Thanks, @greatsong. That's a clear write-up, and the before/after counts make the bug obvious. We're working on this: next we'll review the patch, check that randint() is right across negative, mixed-sign and large ranges in a local build, and then merge and redeploy glowscript.org.

🤖 Generated with Claude Code

@sspickle sspickle left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified, thanks. Each of the four files changes only the randint body. I ran randint through the GlowScriptOffline compile-and-run pipeline with the master build and with this PR's RScompiler.3.2.min.js:

master this PR
randint(-2, 2) never −2, 0 twice as often −2..2, even
randint(-5, -1) never −5, returns 0 −5..−1, even
randint(-5, 5) never −5, 0 doubled even
randint(3, 3) 3 3
randint(0, 10**10) 8,636 of 20,000 out of range 0 out of range

Upstream's follow-up (165020b) also makes randint raise TypeError and ValueError for non-integers and empty ranges. Keeping this to the one line is the right call for now, since raising could break existing student programs. We'll look at that change separately, together with a RapydScript refresh.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants