Skip to content

Commit

Permalink
Make max of Random methods inclusive rather than exclusive (#8768)
Browse files Browse the repository at this point in the history
* Make max inclusive rather than exclusive

* Update names to min max. Remove end_inclusive

* Indicies should remain exclusive

* Make the tests pass
  • Loading branch information
AdRiley authored Jan 24, 2024
1 parent 6eb00a7 commit 23d6fcd
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 40 deletions.
35 changes: 16 additions & 19 deletions distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,18 @@ type Random

## GROUP Random
Return a random `Integer` between `min` (inclusive) and `max`
(exclusive).
(inclusive).

Arguments:
- min: The minimum value of the range to pick from (inclusive).
- max: The maximum value of the range to pick from (exclusive).
- max: The maximum value of the range to pick from (inclusive).

> Example
Generate an integer between 1 and 10.

import Standard.Base.Random.Random

i = Random.integer 1 11
i = Random.integer 1 10
integer : Integer -> Integer -> Integer ! Illegal_Argument
integer (min:Integer) (max:Integer) = Random_Generator.global_random_generator.integer min max

Expand Down Expand Up @@ -146,8 +146,8 @@ type Random
Return a `Date` within the specified `Date_Range`.

Arguments:
- start_date: The lower bound of the range to pick from (inclusive).
- end_date: The upper bound of the range to pick from (exclusive).
- min: The lower bound of the range to pick from (inclusive).
- max: The upper bound of the range to pick from (inclusive).

> Example
Generate a random date.
Expand All @@ -156,22 +156,19 @@ type Random

d = Random.date (Date.new 2023 03 01) (Date.new 2023 10 15)
date : Date -> Date -> Boolean -> Date
date start_date:Date end_date:Date end_exclusive=True = Random_Generator.global_random_generator.date start_date end_date end_exclusive
date min:Date max:Date = Random_Generator.global_random_generator.date min max

## GROUP Random
Return a `Time_Of_Day` between `start_time` and `end_time` (inclusive).

Arguments:
- start_time: The lower bound of the range to pick from (inclusive).
- end_time: The upper bound of the range to pick from (inclusive).
- min: The lower bound of the range to pick from (inclusive).
- max: The upper bound of the range to pick from (inclusive).

The generated time is at a granularity of 1 second. Random values are
generated for hours, minutes and seconds. The `nanoseconds` field is
always 0.

Note: the time range end is inclusive because it is impossible to specify
an end time after the last second of the day.

> Example
Generate a random time.

Expand All @@ -181,8 +178,8 @@ type Random
end = Time_Of_Day.new 9 40 2
t = Random.time start end
time : Time_Of_Day -> Time_Of_Day -> Time_Of_Day
time (start_time:Time_Of_Day=(Time_Of_Day.new 0 0 0)) (end_time:Time_Of_Day=(Time_Of_Day.new 23 59 59)) =
Random_Generator.global_random_generator.time start_time end_time
time (min:Time_Of_Day=(Time_Of_Day.new 0 0 0)) (max:Time_Of_Day=(Time_Of_Day.new 23 59 59)) =
Random_Generator.global_random_generator.time min max

## GROUP Random
Return a new UUID.
Expand Down Expand Up @@ -273,7 +270,7 @@ type Random_Generator
## PRIVATE
integer : Integer -> Integer -> Integer ! Illegal_Argument
integer self (min:Integer) (max:Integer) =
range = max - min
range = max - min + 1
if range >= Java_Integer.MAX_VALUE then Error.throw (Illegal_Argument.Error "Currently only integer ranges of up to 2^31-1 are supported.") else
min + (self.java_random.nextInt range)

Expand Down Expand Up @@ -301,16 +298,16 @@ type Random_Generator

## PRIVATE
date : Date -> Date -> Boolean -> Date
date self start_date:Date end_date:Date end_exclusive=True =
date_range = start_date.up_to end_date include_end=end_exclusive.not
date_range.at (self.integer 0 date_range.length)
date self start_date:Date end_date:Date =
date_range = start_date.up_to end_date include_end=True
date_range.at (self.integer 0 (date_range.length - 1))

## PRIVATE
time : Time_Of_Day -> Time_Of_Day -> Time_Of_Day
time self (start_time:Time_Of_Day=(Time_Of_Day.new 0 0 0)) (end_time:Time_Of_Day=(Time_Of_Day.new 23 59 59)) =
## The time range end is inclusive because it is impossible to specify
an end time after the last second of the day.
seconds = self.integer 0 (end_time.to_seconds - start_time.to_seconds + 1)
seconds = self.integer 0 (end_time.to_seconds - start_time.to_seconds)
start_time.date_add seconds Time_Period.Second

## PRIVATE
Expand All @@ -323,7 +320,7 @@ type Random_Generator
case with_replacement of
True ->
len = v.length
0.up_to count . map _-> v.at (self.integer 0 len)
0.up_to count . map _-> v.at (self.integer 0 (len - 1))
False ->
if count > v.length then Error.throw (Illegal_Argument.Error "`count` cannot be greater than the size of the collection when `with_replacement` is false") else
new_array = Random_Utils.sample v count self.java_random
Expand Down
25 changes: 10 additions & 15 deletions test/Base_Tests/src/Random_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import Standard.Test.Extensions
spec = Test.group "Random" <|
Test.specify "should allow generating random integers" <|
Random.set_seed 12345
Random.integer 0 100 . should_equal 51
Random.integer 0 10000 . should_equal 9080
Random.integer 0 99 . should_equal 51
Random.integer 0 9999 . should_equal 9080

random_range = 0.up_to 1000 . map (_-> Random.integer 0 100) . compute_bulk [Statistic.Minimum, Statistic.Maximum]
random_range = 0.up_to 1000 . map (_-> Random.integer 0 99) . compute_bulk [Statistic.Minimum, Statistic.Maximum]
(random_range.at 0 >= 0) . should_equal True
(random_range.at 1 <= 100) . should_equal True
(random_range.at 1 <= 99) . should_equal True

Test.specify "should allow generating random floats" <|
Random.set_seed 12345
Expand Down Expand Up @@ -71,17 +71,12 @@ spec = Test.group "Random" <|

Test.specify "should allow generating random dates" <|
Random.set_seed 4000
Random.date (Date.new 2023 03 01) (Date.new 2023 10 15) . should_equal (Date.new 2023 6 9)
Random.date (Date.new 2023 03 01) (Date.new 2023 10 15) . should_equal (Date.new 2023 7 16)
Random.date (Date.new 2023 03 01) (Date.new 2023 10 15) . should_equal (Date.new 2023 10 12)
Random.date (Date.new 2023 03 01) (Date.new 2023 10 14) . should_equal (Date.new 2023 6 9)
Random.date (Date.new 2023 03 01) (Date.new 2023 10 14) . should_equal (Date.new 2023 7 16)
Random.date (Date.new 2023 03 01) (Date.new 2023 10 14) . should_equal (Date.new 2023 10 12)

all_from_small_range = [Date.new 2023 03 01, Date.new 2023 03 02, Date.new 2023 03 03]
dates = 0.up_to 100 . map (_-> Random.date (Date.new 2023 03 01) (Date.new 2023 03 04))
dates.should_contain_the_same_elements_as all_from_small_range

Test.specify "should allow generating random dates, with end_exclusive=False" <|
all_from_small_range = [Date.new 2023 03 01, Date.new 2023 03 02, Date.new 2023 03 03, Date.new 2023 03 04]
dates = 0.up_to 100 . map (_-> Random.date (Date.new 2023 03 01) (Date.new 2023 03 04) end_exclusive=False)
dates = 0.up_to 100 . map (_-> Random.date (Date.new 2023 03 01) (Date.new 2023 03 03))
dates.should_contain_the_same_elements_as all_from_small_range

Test.specify "should allow generating random times" <|
Expand Down Expand Up @@ -148,13 +143,13 @@ spec = Test.group "Random" <|
permutations_2 . should_contain_the_same_elements_as all_permutations

Test.specify "should not allow using a too-large integer range" <|
high = 9223372036854775807000
high = 9223372036854775806999
Random.integer 0 high . should_fail_with Illegal_Argument

Test.specify "Can call an instance directly" <|
Random.new_generator . should_be_a Random_Generator
Random.new_generator 12345 . should_be_a Random_Generator
Random.new_generator 12345 . integer 0 100 . should_equal 51
Random.new_generator 12345 . integer 0 99 . should_equal 51
Random.new_generator 12345 . float . should_equal 0.3618031071604718 epsilon=0.00000001
Random.new_generator 12345 . gaussian . should_equal -0.187808989658912 epsilon=0.00000001

Expand Down
2 changes: 1 addition & 1 deletion test/Benchmarks/src/Map/Hash_Map.enso
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Data
create n =
create_ints =
Vector.new n _->
Random.integer 0 (n.div 100)
Random.integer 0 ((n.div 100) - 1)
Data.Value create_ints

type Scenario
Expand Down
4 changes: 2 additions & 2 deletions test/Benchmarks/src/Table/Add_Row_Number.enso
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ options = Bench.options . set_warmup (Bench.phase_conf 2 2) . set_measure (Bench
create_table : Integer -> Table
create_table num_rows =
rng = Random.new_generator 42
x = Vector.new num_rows _-> rng.integer min=0 max=50
y = Vector.new num_rows _-> rng.integer min=0 max=10000
x = Vector.new num_rows _-> rng.integer min=0 max=49
y = Vector.new num_rows _-> rng.integer min=0 max=9999
t = Table.new [["X", x], ["Y", y]]

assert condition =
Expand Down
6 changes: 3 additions & 3 deletions test/Benchmarks/src/Table/Internal/Multi_Value_Key.enso
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ Comparable.from (_:My_Pair) = My_Pair_Comparator
create_table : Integer -> Table
create_table num_rows =
rng = Random.new_generator 42
x = Vector.new num_rows _-> rng.integer min=0 max=100
x = Vector.new num_rows _-> rng.integer min=0 max=99
y = Vector.new num_rows _-> rng.integer min=0 max=20 . to_text
z = Vector.new num_rows _->
a = Random.integer min=0 max=100
b = Random.integer min=0 max=100
a = Random.integer min=0 max=99
b = Random.integer min=0 max=99
My_Pair.Value a b
t = Table.new [["X", x], ["Y", y], ["Z", z]]

Expand Down

0 comments on commit 23d6fcd

Please sign in to comment.