Re: [css-values] Concrete proposal for unit algebra in calc()

On Thu, Apr 10, 2014 at 12:43 PM, Zack Weinberg <zackw@panix.com> wrote:
> I brought up the question of being able to divide two <length>s in
> calc() earlier this week, along with min/max expressions.  I'm
> convinced min/max are Too Hard for right now, but I think it's not too
> hard to specify enough unit algebra to make <length> ratios feasible.
> Here is a concrete proposal relative to the current ED.
>
> In section 8.1.1 (calc() syntax):
>
> -  product : unit [ S* [ "*" S* unit | "/" S* NUMBER ] ]*;
> +  product : unit [ S* [ "*" S* unit | "/" S* unit ] ]*;
>
> In section 8.1.2 (type checking), replace the second two bullet points
> in the list with the following:
>
>  * At '*', apply these rules in order:
>
>    1. If both sides are <integer>, resolve to <integer>.
>    2. If one side is <number> and the other is <number> or <integer>,
>       resolve to <number>.
>    3. If one side is <number> or <integer> and the other is a
>       _dimension_, resolve to the type of the _dimension_.
>    4. If one side is <time> and the other is <frequency>, resolve to
>       <number>.
>    5. If one side is <length> and the other is <resolution>, resolve
>       to <number>.
>    6. All other combinations of units are invalid.
>
>  * At '/', apply these rules in order:
>
>    1. If both sides have the same type, resolve to <number>.
>    2. If the left side is a <number> or <integer> and the right side is
>       also a <number> or <integer>, resolve to <number>.
>    3. If the left side is a _dimension_ and the right side is <number>
>       or <integer>, resolve to the type of the _dimension_.
>    4. If the left side is a <number> or <integer> and the right side
>       is a <length>, resolve to <resolution>.
>    5. If the left side is a <number> or <integer> and the right side
>       is a <time>, resolve to <frequency>.
>    6. All other combinations of units are invalid.
>
> Also, replace from "Also, division by zero is invalid" through the end
> of that paragraph with:
>
>    ... The expression is also invalid if it contains a division by
>    zero which can be detected at parse time.  For example,
>    `calc(10px/0)` and `calc(10px/(1em - 1em))` are both invalid.
>    However, `calc(10px/1em)` and `calc(10px/5%)` are *not* invalid,
>    even though `1em` might evaluate to zero when the value is
>    computed, and `5%` might evaluate to zero when the value is used.
>
> In section 8.1.3 (computed value), delete the note about the
> representation of a computed calc(), and perhaps also add some more
> examples.
>
> In section 8.1.4 (range checking), add immediately after "...to the
> range allowed in the target context":
>
>     If a (sub-)expression contains a division by zero which was not
>     detected at parse time, the value of that (sub-)expression is
>     infinite.  The result of any further computation on infinite
>     values is also infinite, except that dividing any finite value
>     by an infinite value produces zero.
>
>     If the value resulting from a complete `calc()` expression is
>     infinite, it is clamped and becomes the most positive value
>     allowed in the target context.
>
> | NOTE: This deliberately differs from the behavior specified in IEEE
> | 754 in order to avoid introducing NaNs and negative zero into CSS,
> | However, implementations using IEEE 754-conformant floating point
> | arithmetic internally can produce the above semantics by treating
> | -Inf, +Inf, and NaN as "infinite", and -0 as equivalent to +0.
>
> That should be all that is required.

On the telcon today we accepted this proposal for V&U Level 4, but
with some changes:

* We should allow negative infinity; at minimum, it's produced by
subtraction with a finite LHS and infinite LHS, or the negation of an
infinite value.
* We'll discuss whether to accept full IEEE semantics; given that
impls are probably using them for the values of at least some types
anyway, it might be worthwhile.  (Lengths are generally fixed-width in
impls, but I dunno how most impls store other types like resolution or
time.)
* We'll allow unit powers other than 1/0/-1.
* We'll drop the rule that makes parse-time-detectable zero-division
invalid; instead, it'll trigger this infinity handling as well.

In addition, you suggest that every computation with an infinity
results in an infinity. Obviously the intent is to make infinities
infectious, but as suggested it means that invalid unit math doesn't
invalidate the calc().  I suspect that the infinity should still
participate in unit-checking?

~TJ

Received on Wednesday, 23 April 2014 23:56:53 UTC