1import * as Context from "../Context.ts"
2import type { Random as RandomService } from "../Random.ts"
3
4/** @internal */
5export const Random: Context.Reference<RandomService> = Context.Reference<RandomService>("effect/Random", {
6 defaultValue: () => ({
7 nextIntUnsafe() {
8 return Math.floor(Math.random() * (Number.MAX_SAFE_INTEGER - Number.MIN_SAFE_INTEGER + 1)) +
9 Number.MIN_SAFE_INTEGER
10 },
11 nextDoubleUnsafe() {
12 return Math.random()
13 }
14 })
15})
16
17/** @internal */
18export const nextBetween = (min: number, max: number, draw: number): number => {
19 const value = draw * (max - min) + min
20 if (value !== max || min >= max || !Number.isFinite(max)) {
21 return value
22 }
23 // Rounding can reach the excluded endpoint even for a draw below 1.
24 // Return its immediate predecessor, which is at least min for finite min < max.
25 if (max === 0) {
26 return -Number.MIN_VALUE
27 }
28 const view = new DataView(new ArrayBuffer(8))
29 view.setFloat64(0, max)
30 const bits = view.getBigUint64(0)
31 view.setBigUint64(0, max > 0 ? bits - BigInt(1) : bits + BigInt(1))
32 return view.getFloat64(0)
33}