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

Add initRand() with seed based on time #16953

Merged
merged 3 commits into from
Feb 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
(instead of skipping them sometimes as it was before).
- Added optional `followSymlinks` argument to `setFilePermissions`.

- Added `random.initRand()` overload with no argument which uses the current time as a seed.

## Language changes

- `nimscript` now handles `except Exception as e`.
Expand Down
45 changes: 35 additions & 10 deletions lib/pure/random.nim
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ proc initRand*(seed: int64): Rand =
## generator's state.
##
## See also:
## * `initRand proc<#initRand>`_ that uses the current time
## * `randomize proc<#randomize,int64>`_ that accepts a seed for the default
## random number generator
## * `randomize proc<#randomize>`_ that initializes the default random
Expand All @@ -589,8 +590,11 @@ proc randomize*(seed: int64) {.benign.} =
## the same results for that seed each time.
##
## See also:
## * `initRand proc<#initRand,int64>`_
## * `initRand proc<#initRand,int64>`_ that initializes a Rand state
## with a given seed
## * `randomize proc<#randomize>`_ that uses the current time instead
## * `initRand proc<#initRand>`_ that initializes a Rand state using
## the current time
runnableExamples:
from times import getTime, toUnix, nanosecond

Expand Down Expand Up @@ -635,25 +639,46 @@ proc shuffle*[T](x: var openArray[T]) =

when not defined(nimscript) and not defined(standalone):
import times

proc initRand(): Rand =
## Initializes a new Rand state with a seed based on the current time.
##
## The resulting state is independent of the default random number generator's state.
##
## **Note:** Does not work for NimScript or the compile-time VM.
Copy link
Member

Choose a reason for hiding this comment

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

how about instead honor experimental:vmops:
if experimental:vmops is passed, it would use it, else would use a fixed seed (ie reproducible builds)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well you wouldn't use the random module if you cared about predictability. Current compilation isn't pure either, IOEffect procs already exist in VM (though not tagged as such), this would just use a TimeEffect proc. There's no way to check for that experimental, compileOption doesn't work for experimentals, compiles(getTime()) is true under when nimvm even if it doesn't work. Maybe it should be a compile option like --pureVM or --impureVM, but even then the entire random module wouldn't make sense as being pure, other languages have things like RandomEffect (Idris and I believe some Haskell libraries).

Copy link
Member

Choose a reason for hiding this comment

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

There's no way to check for that experimental

refs #8644 which is very fixable

Copy link
Member

@timotheecour timotheecour Feb 6, 2021

Choose a reason for hiding this comment

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

anyways, this can be fixed in future PR, just leave this comment as un-resolved

##
## See also:
## * `initRand proc<#initRand,int64>`_ that accepts a seed for a new Rand state
## * `randomize proc<#randomize>`_ that initializes the default random
## number generator using the current time
## * `randomize proc<#randomize,int64>`_ that accepts a seed for the default
## random number generator
timotheecour marked this conversation as resolved.
Show resolved Hide resolved
when defined(js):
let time = int64(times.epochTime() * 1000) and 0x7fff_ffff
result = initRand(time)
else:
let now = times.getTime()
result = initRand(convert(Seconds, Nanoseconds, now.toUnix) + now.nanosecond)

since (1, 5, 1):
export initRand
timotheecour marked this conversation as resolved.
Show resolved Hide resolved

proc randomize*() {.benign.} =
## Initializes the default random number generator with a value based on
## Initializes the default random number generator with a seed based on
## the current time.
##
## This proc only needs to be called once, and it should be called before
## the first usage of procs from this module that use the default random
## number generator.
##
## **Note:** Does not work for NimScript.
## **Note:** Does not work for NimScript or the compile-time VM.
##
## See also:
## * `randomize proc<#randomize,int64>`_ that accepts a seed
## * `initRand proc<#initRand,int64>`_
when defined(js):
let time = int64(times.epochTime() * 1000) and 0x7fff_ffff
randomize(time)
else:
let now = times.getTime()
randomize(convert(Seconds, Nanoseconds, now.toUnix) + now.nanosecond)
## * `initRand proc<#initRand>`_ that initializes a Rand state using
## the current time
## * `initRand proc<#initRand,int64>`_ that initializes a Rand state
## with a given seed
state = initRand()

{.pop.}