| 1 | import * as Context from "../Context.ts" |
| 2 | import type { Random as RandomService } from "../Random.ts" |
| 3 | |
| 4 | /** @internal */ |
| 5 | export 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 */ |
| 18 | export 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 | } |