[csswg-drafts] [css-values] round(A,B) with B negative (#4718)

Loirooriol has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-values] round(A,B) with B negative ==
When rounding a value A with a negative precision B, I think there are two reasonable approaches:

 1. Ignore the sign, so that

    ```
    round(nearest, A, -B) = round(nearest, A, B)
    round(up, A, -B) = round(up, A, B)
    round(down, A, -B) = round(down, A, B)
    round(to-zero, A, -B) = round(to-zero, A, B)
    ```

    We find the two integer multiples of B closest to A, "lower B" and "upper B", with "lower B" < "upper B". And then we choose between by applying the strategy to "lower B" and "upper B":

    - For `nearest`, choose whichever of "lower B" and "upper B" that is closer to A. In case of tie, choose "upper B".
    - For `up`, choose "upper B".
    - For `down`, choose "lower B".
    - For `to-zero`, choose whichever of "lower B" and "upper B" that is closer to 0.

    In JS, for finite B,
    ```
    round(nearest, A,B) = Math.round(A/Math.abs(B)) * Math.abs(B)
    round(up, A,B) = Math.ceil(A/Math.abs(B)) * Math.abs(B)
    round(down, A,B) = Math.floor(A/Math.abs(B)) * Math.abs(B)
    round(to-zero, A,B) = Math.trunc(A/Math.abs(B)) * Math.abs(B)
    ```
 2. Use the sign to reverse the strategy, so that

    ```
    round(nearest, A, -B) = -round(nearest, -A, B)
    round(up, A, -B) = round(down, A, B)
    round(down, A, -B) = round(up, A, B)
    round(to-zero, A, -B) = round(to-zero, A, B)
    ```

    We find the two integer multiples of B closest to A, `B*n` and `B*(n+1)`. And then we choose between them by applying the strategy to `n` and `n+1`:

    - For `nearest`, choose whichever of `B*n` and `B*(n+1)` that is closer to A. In case of tie, choose `B*(n+1)`.
    - For `up`, choose `B*(n+1)`.
    - For `down`, choose `B*n`.
    - For `to-zero`, choose `B*n` if `n` is closer to 0 than `n*1`, else `B*(n+1)`.

    In JS, for finite B,
    ```
    round(nearest, A,B) = Math.round(A/B) * B
    round(up, A,B) = Math.ceil(A/B) * B
    round(down, A,B) = Math.floor(A/B) * B
    round(to-zero, A,B) = Math.trunc(A/B) * B
    ```

Note there is no difference for `to-zero`. And for `nearest` it only matters in case of tie.

Currently the spec defines [`round()`](https://drafts.csswg.org/css-values-4/#round-func) with (1). However, later it seems to assume (2):

> `mod()` and `rem()` can also be defined directly in terms of other functions: `mod(A, B)` is equivalent to `calc(A - round(down, A, B))`, while `rem(A, B)` is equivalent to `calc(A - round(to-zero, A, B))`.

The former doesn't hold with (1), e.g. `mod(3, -2)` is supposed to be `-1`, but `3 - round(down, 3, -2)` is `3 - 2 = 1`. But it works with (2): `3 - 4 = -1`. With (1), I guess the quote should say `(A - round(down, A, B)) * sign(B)`

So either keep the definition of round() as-is and fix the quote, or change the definition of round() and keep the quote. And add a note.

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/4718 using your GitHub account

Received on Thursday, 30 January 2020 22:01:27 UTC