Skip to content

Rewrite TimeSpanSource, stop DoubleSource returning infinity - #11

Merged
holonsoftFounder merged 1 commit into
mainfrom
feature/timespan-and-floating-sources
Sep 11, 2026
Merged

Rewrite TimeSpanSource, stop DoubleSource returning infinity#11
holonsoftFounder merged 1 commit into
mainfrom
feature/timespan-and-floating-sources

Conversation

@holonsoftFounder

Copy link
Copy Markdown
Member

The last correctness sweep before the v6.0.0 tag. Both fixes change generated sequences, so they have to land inside the break 6.0 already takes.

TimeSpanSource did not work

Measured against the built library, not read from the code:

new TimeSpanSource()        ->  -10675199.02:48:05.4775808   (every draw, constant)
new TimeSpanSource(1h, 2h)  ->  00:33:31 | 00:53:19 | 00:23:35 | ...
new TimeSpanSource(2h, 1h)  ->  endless loop (killed at 30s, exit 124)

Three separate defects: maxTicks - minTicks overflows long over the default range, the two while loops pull the result out of the range that was asked for, and a reversed range keeps doing ticks *= Random.Next(1, 3) forever. Asking for one to two hours and getting 22 to 58 minutes is the most natural way anyone would use the type.

It picks uniformly from the inclusive tick range now, the same way DateTimeSource does, and throws ArgumentOutOfRangeException on a reversed range. Only ranges symmetric around zero worked before, which is exactly what the old stable-sequence test used, so nothing caught it.

DoubleSource returned infinity

new DoubleSource() gave on every draw: the default range is the whole range of double and the code computed max - min. DoubleSource, FloatSource and DecimalSource now share the overflow-safe interpolation min * (1 - sample) + max * sample that NumberSource<T> already used. DecimalSource does it in decimal arithmetic instead of the detour through double, so it keeps its full precision:

before: 27879346472004300000000000000
after:  27879346472004256951386422019

RandomIntegerExtensions becomes RandomNumberExtensions and holds both the inclusive integer pick and the continuous one, so NumberSource<T> and the four older sources cannot drift apart again.

Verification

dotnet build -c Release zero warnings, 868 tests per framework on net8/9/10, 2604 total, all green. The stable sequences of TimeSpanSource and FloatSource changed and were regenerated; twelve new tests pin the fixed behaviour, including the three cases above.

🤖 Generated with Claude Code

TimeSpanSource did not work. Measured against the built library:

  new TimeSpanSource()        -> -10675199.02:48:05.4775808 on every draw
  new TimeSpanSource(1h, 2h)  -> 00:33:31 | 00:53:19 | 00:23:35 | ...
  new TimeSpanSource(2h, 1h)  -> endless loop

The default range overflowed long in maxTicks - minTicks, the two while loops
pulled the result out of the requested range, and a reversed range kept
multiplying ticks by Random.Next(1, 3). It picks uniformly from the inclusive
tick range now, like DateTimeSource, and throws ArgumentOutOfRangeException on
a reversed range. Only ranges symmetric around zero worked before, which is
what the old test happened to use.

new DoubleSource() returned infinity on every draw, because its default range
is the whole range of double and the code computed max - min. DoubleSource,
FloatSource and DecimalSource share the overflow safe interpolation of
NumberSource now, min * (1 - sample) + max * sample. DecimalSource does it in
decimal arithmetic instead of going through double and keeps its full
precision: 27879346472004256951386422019 instead of 27879346472004300000000000000.

RandomIntegerExtensions becomes RandomNumberExtensions and carries both the
inclusive integer pick and the continuous one, so NumberSource and the four
older sources cannot drift apart.

868 tests per framework.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@holonsoftFounder
holonsoftFounder merged commit d5f0e9d into main Sep 11, 2026
2 checks passed
@holonsoftFounder
holonsoftFounder deleted the feature/timespan-and-floating-sources branch September 11, 2026 14:56
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.

1 participant