Skip to content

Commit 0479e36

Browse files
committed
[css-values-5][editorial] More tweaking of how I talk about randomness and limits. Actually refer to the subsections for evaluation.
1 parent d4cdeb7 commit 0479e36

File tree

1 file changed

+78
-48
lines changed

1 file changed

+78
-48
lines changed

css-values-5/Overview.bs

Lines changed: 78 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,6 +1997,8 @@ Generating a Random Numeric Value: the ''random()'' function</h3>
19971997
| <<number [0,1]>>
19981998
</pre>
19991999

2000+
See [[#random-evaluation]] and [[#random-caching]]
2001+
for details on how the function is evaluated.
20002002
Its arguments are:
20012003

20022004
<dl>
@@ -2036,39 +2038,25 @@ Generating a Random Numeric Value: the ''random()'' function</h3>
20362038
chosen uniformly randomly from the possible values
20372039
that result in an in-range value.
20382040

2039-
To avoid issues with numeric precision,
2040-
if the max value is <em>very close</em> to equalling a stepped value
2041-
(above or below it),
2042-
the max value is used as the final stepped value instead.
2043-
See [[#random-evaluation]] for precise details.
2044-
20452041
<div class=example>
20462042
For example, ''random(100px, 300px, 50px)''
20472043
can only resolve to ''100px'', ''150px'', ''200px'', ''250px'', or ''300px'';
20482044
it will never return a value like ''120px''.
20492045

2050-
While the minimum value is always a possible result,
2051-
the maximum value isn't always,
2052-
if it's not also a multiple of the step from the minimum.
2053-
For example, in ''random(100px, 200px, 30px)'',
2054-
the largest possible value it can resolve to is ''190px'',
2055-
3 steps from the minimum value.
2056-
2057-
Numeric precision issues can be avoided by using exact formula
2058-
for step values that would be repeating decimals.
2059-
For example, in ''random(100px, 200px, 33.3px)'',
2060-
the largest possible value is ''199.9px'' (not ''200px''),
2061-
and in ''random(100px, 200px, 33.4px)'',
2062-
the largest possible value is <strong>''166.8px''</strong>,
2063-
because 3 steps from the min would give ''200.1px''
2064-
which is outside the allowed range.
2065-
But in ''random(100px, 200px, 100px / 3)'',
2066-
the largest value is guaranteed to be exactly ''200px''
2067-
because 3 steps from the min is
2068-
(to within the allowed error)
2069-
exactly equal to the max.
2046+
Note that the max value might not actually show up as a possible value;
2047+
for example, in ''random(100px, 200px, 30px)'',
2048+
the possible values are ''100px'', ''130px'', ''160px'', and ''190px''.
20702049
</div>
20712050

2051+
Note: Even if it's <em>intended</em> that <code>min</code> and <code>max</code>
2052+
are exactly some integer multiple of <code>step</code> apart,
2053+
numeric precision issues can prevent that from being true.
2054+
To avoid these issues,
2055+
if the max value is <em>very close</em> to equalling a stepped value
2056+
(above or below it),
2057+
the max value is used as the final stepped value instead.
2058+
See [[#random-evaluation]] for precise details.
2059+
20722060
<div class=example>
20732061
As explained in the definition of ''round()'',
20742062
CSS has no "natural" precision for values,
@@ -2365,19 +2353,19 @@ Picking a Random Item From a List: the ''random-item()'' function</h3>
23652353
&lt;random-item()> = random-item( <<random-value-sharing>> , [ <<declaration-value>>? ]# )
23662354
</pre>
23672355

2356+
See [[#random-evaluation]] and [[#random-caching]]
2357+
for details on how the function is evaluated.
2358+
23682359
The <em>required</em> <<random-value-sharing>>
23692360
is interpreted identically to ''random()''.
23702361
(See [[#random-caching]] for details.)
23712362

23722363
Note: The <<random-value-sharing>> argument is required in ''random-item()'',
23732364
but optional in ''random()'',
2374-
both for parsing reasons
2365+
for parsing reasons
23752366
(it's impossible to tell whether ''random-item(--foo, --bar, --baz)''
23762367
has three <<declaration-value>> arguments
2377-
or two and a <<random-value-sharing>> argument),
2378-
and because accidentally associating the random generation of ''random-item()'' functions together
2379-
is much easier to do accidentally,
2380-
since only the number of arguments is used to distinguish instances.
2368+
or two and a <<random-value-sharing>> argument).
23812369

23822370
The remaining arguments are arbitrary sequences of CSS values.
23832371
The ''random-item()'' function is substituted with one of these sequences,
@@ -2412,26 +2400,68 @@ Evaluating Random Values</h3>
24122400

24132401
: for a ''random()'' function with |min|, |max|, and |step|
24142402
::
2415-
* Let |threshold| be <code>|step| / 1000</code>,
2416-
or the smallest representable value in the numeric type being used
2417-
if |threshold| would round to zero.
2418-
* Let |values| be a list containing all values of the form <code>|min| + |N| * |step|</code>,
2419-
where |N| is a non-negative integer
2420-
and the result is less than or equal to |max|.
2421-
2422-
If the largest |N| produces a value that is not within |threshold| of |max|,
2423-
but |N|+1 would be within |threshold| of |max|,
2424-
include the |N|+1 value as well.
2425-
* If the largest value in |values| is within |threshold| of |max|,
2426-
replace it with |max|.
2427-
* Let |length| be the length of |values|.
2428-
* Let |random int| be <css>round(down, |R| * |length|, 1)</css>.
2429-
* Return the |random int|'th item of |values| (0-indexed).
2403+
* Let |epsilon| be <code>|step| / 1000</code>,
2404+
or the smallest representable value greater than zero
2405+
in the numeric type being used
2406+
if |epsilon| would round to zero.
2407+
* Let |N| be the largest integer
2408+
such that <code>|min| + |N| * |step|</code> is less than or equal to |max|.
2409+
2410+
If |N| produces a value that is not within |epsilon| of |max|,
2411+
but |N|+1 would produce a value within |epsilon| of |max|,
2412+
set |N| to |N|+1.
2413+
* Let |step index| be a [=random integer=] less than |N|+1, given |R|.
2414+
* Let |value| be <code>|min| + |step index| * |step|</code>.
2415+
* If |step index| is |N| and |value| is within |epsilon| of |max|, return |max|.
2416+
* Otherwise, return |value|.
2417+
2418+
<details class=note>
2419+
<summary>Epsilon/max Details</summary>
2420+
2421+
|epsilon| was chosen to be <code>|step| / 1000</code>
2422+
as a useful "middle ground" value:
2423+
small enough that it's very unlikely to accidentally trigger
2424+
when the author didn't intend it,
2425+
but large enough that it's guaranteed to catch floating-point precision errors.
2426+
2427+
It's size is also within the realm for authors to exploit themselves;
2428+
if their |max| is meant to be an integer multiple of their |step|,
2429+
but the |step| is not a terminating decimal,
2430+
as long as they write the |step| with 5 or 6 digits of precision
2431+
then the largest value should land within |epsilon| of |max|.
2432+
2433+
For example, while ''random(0px, 100px, 33.3px)'' will not generate a ''100px'' value
2434+
(the epsilon is ''.0333px'',
2435+
but 3 steps yields ''99.9px'',
2436+
which is ''.1px'' from |max|, more than the epsilon),
2437+
''random(0px, 100px, 33.333px)'' will
2438+
(the epsilon is ''.033333px'',
2439+
similar to the previous example,
2440+
but 3 steps yields ''99.999px'',
2441+
which is ''.001px'' from |max|, much less than the epsilon).
2442+
(A sufficiently large number of steps
2443+
could still cause enough divergence to defeat this,
2444+
but it works for any remotely reasonable use-case.)
2445+
2446+
Using a [=calculation=] to "exactly" represent non-terminating decimals
2447+
will also work, of course:
2448+
''random(0px, 100px, 100px / 3)''
2449+
is guaranteed to be able to generate a ''100px'' value,
2450+
as the step value will only be subject to floating-point precision errors
2451+
far smaller than the epsilon.
2452+
</details>
24302453

24312454
: for a ''random-item()'' function with |N| <<declaration-value>>? arguments:
24322455
::
2433-
* Let |random int| be <css>round(down, |R| * |N|, 1)</css>.
2434-
* Return the |random int|'th argument (0-indexed).
2456+
* Let |index| be a [=random integer=] less than |N|, given |R|.
2457+
* Return the |index|'th argument (0-indexed).
2458+
2459+
<div algorithm>
2460+
To <dfn local-lt="random integer">generate a random integer</dfn>
2461+
less than some integer |limit|
2462+
given a [=random base value=] |R|,
2463+
return <css>round(down, |R| * |limit|, 1)</css>
2464+
</div>
24352465

24362466

24372467

0 commit comments

Comments
 (0)