Skip to content

Commit

Permalink
[css-values-4] Add the round() function.
Browse files Browse the repository at this point in the history
  • Loading branch information
tabatkins committed Jan 24, 2020
1 parent 2832430 commit 90ff717
Showing 1 changed file with 97 additions and 1 deletion.
98 changes: 97 additions & 1 deletion css-values-4/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -2573,6 +2573,101 @@ Comparison Functions: ''min()'', ''max()'', and ''clamp()''</h3>
</div>


<h3 id=round-func>
Rounding Values: ''round()''</h3>

The rounding function ''round()''
adjusts the value of a [=calculation=]
to a nearby multiple of a given precision [=calculation=],
giving several options for choosing which nearby multiple to use.

The <dfn lt="round()">round(<<rounding-strategy>>?, A, B)</dfn> function
contains an optional rounding strategy,
and two [=calculations=] A and B,
and returns the value of A,
rounded according to the rounding strategy,
to the nearest integer multiple of B either above or below A.
The argument [=calculations=] can resolve to any <<number>>, <<dimension>>, or <<percentage>>,
but must have the <em>same</em> [=determine the type of a calculation|type=],
or else the function is invalid;
the result will have the same [=CSSNumericValue/type=] as the arguments.

If A is exactly equal to an integer multiple of B,
''round()'' resolves to A exactly
(preserving whether A is 0⁻ or 0⁺, if relevant).
Otherwise, there are two integer multiples of B that are potentially "closest" to A,
|lower B| which is closer to −∞
and |upper B| which is closer to +∞.
The following <dfn><<rounding-strategy>></dfn>s dictate how to choose between them:

<dl dfn-type=value dfn-for="<rounding-strategy>">
: <dfn>nearest</dfn>
:: Choose whichever of |lower B| and |upper B|
that has the smallest absolute difference from A.
If both have an equal difference
(A is exactly between the two values),
choose |upper B|.
: <dfn>up</dfn>
:: Choose |upper B|.
: <dfn>down</dfn>
:: Choose |lower B|.
: <dfn>to-zero</dfn>
:: Choose whichever of |lower B| and |upper B|
that has the smallest absolute difference from 0.
</dl>

If |lower B| would be zero,
it is specifically equal to 0⁺;
if |upper B| would be zero,
it is specifically equal to 0⁻.

If <<rounding-strategy>> is omitted,
it defaults to ''nearest''.

<div class=example>
Unlike languages like JavaScript
which have a natural "precision" to round to
(integers),
CSS values have no such precision
because values can be written in many different compatible units.
As such, the precision has to be given exactly;
to round a width to the nearest ''50px'',
one can write ''round(var(--width), 50px)''.
</div>

Note: JavaScript and other programming languages
sometimes separate out the rounding strategies into separate rounding functions.
JS’s <code highlight=JS>Math.floor()</code>
is equivalent to CSS's ''round(down, ...)'';
JS’s <code highlight=JS>Math.ceil()</code>
is equivalent to CSS's ''round(up, ...)'';
JS’s <code highlight=JS>Math.trunc()</code>
is equivalent to CSS's ''round(to-zero, ...)'';
and JS’s <code highlight=JS>Math.round()</code>
is equivalent to CSS's ''round(nearest, ...)'',
or just ''round(...)''.


<h4 id=round-infinities>
Argument Ranges</h4>

In ''round(A, B)'',
if B is 0,
the result is NaN.

If A is +∞,
the result is +∞.
If A is −∞,
the result is −∞.

This comment has been minimized.

Copy link
@Loirooriol

Loirooriol Jan 24, 2020

Contributor

Even if B is infinite? If we consider A_n = n, B_n = 3*n, then lim_{n -> ∞} round(A_n, B_n) = 0, not ∞.
So I would have expected the result to be NaN if both are infinite.

This comment has been minimized.

Copy link
@tabatkins

tabatkins Jan 27, 2020

Author Member

Ah, reasonable point. I'll fix.


If A is finite
and B is infinite,
the result is 0⁺
if A is 0⁺ or positive finite,
and 0⁻ if A is 0⁻ or negative finite.



<h3 id=trig-funcs>
Trigonometric Functions: ''sin()'', ''cos()'', ''tan()'', ''asin()'', ''acos()'', ''atan()'', and ''atan2()''</h3>

Expand Down Expand Up @@ -3171,6 +3266,7 @@ Syntax</h3>
<<min()>> = min( <<calc-sum>># )
<<max()>> = max( <<calc-sum>># )
<<clamp()>> = clamp( <<calc-sum>>#{3} )
<<round()>> = round( <<rounding-strategy>>?, <<calc-sum>>, <<calc-sum>> )
<<sin()>> = sin( <<calc-sum>> )
<<cos()>> = cos( <<calc-sum>> )
<<tan()>> = tan( <<calc-sum>> )
Expand Down Expand Up @@ -3310,7 +3406,7 @@ Type Checking</h3>
is «[ "angle" → 1 ]».
* The [=CSSNumericValue/type=] of a ''pow()'', ''sqrt()'', ''log()'', or ''exp()'' expression
is «[ "number" → 1 ]».
* The [=CSSNumericValue/type=] of a ''hypot()'' expression
* The [=CSSNumericValue/type=] of a ''hypot()'' or ''round()'' expression
is the result of [=add two types|adding the types=]
of its comma-separated [=calculations=].

Expand Down

3 comments on commit 90ff717

@Crissov
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the cons after the rounding strategy really necessary?

Can we change to-zero to truncate to match JS slightly better? (If to infinity was added, it would then need to be called expand or some such.)

I think there is merit in adding nearest-even (as suggested by IEEE 754) and perhaps also nearest-odd.

@tabatkins
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the cons after the rounding strategy really necessary?

What do you mean by "cons"? If you mean comma, while not strictly necessary, as a rule I've been avoiding concatenating <calc-sum> with anything else, since it's a relatively complex grammar.

Can we change to-zero to truncate to match JS slightly better?

I considered that, but it's not actually truncating anything. I think it would cause more confusion than it would avoid.

I think there is merit in adding nearest-even (as suggested by IEEE 754) and perhaps also nearest-odd.

The point of nearest-even is to help reduce bias in estimates. I don't think there's currently a call for that in CSS.

(That said, if we do want to dictate the behavior of ties, the plan is to let you combine nearest with another keyword, so the default behavior is nearest up, and we'd indeed add at least nearest even as a possibility at that point.

@Crissov
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant comma indeed.

Please sign in to comment.