Csswg-drafts: [css-values] Does tan(90deg) return +โˆž, โˆ’โˆž or NaN?

Created on 11 Jul 2019  ยท  10Comments  ยท  Source: w3c/csswg-drafts

From https://drafts.csswg.org/css-values/#funcdef-tan,

tan() can return any number between +โˆž and โˆ’โˆž.

But it's not clear to me what tan(90deg) is supposed to return. Mathematically, the limit from the left is +โˆž and the limit from the right is โˆ’โˆž, so the limit doesn't exist. Does this mean NaN? But this case is not covered in https://drafts.csswg.org/css-values/#trig-infinities, which only says

In sin(A), cos(A), or tan(A), if A is infinite, the result is NaN.

For the inverse functions:

In atan(A), if A is +โˆž, the result is 90deg; if A is -โˆž, the result is -90deg.

So I guess this should round-trip and tan(90deg) should be +โˆž and tan(-90deg) be -โˆž?

ECMAScript doesn't define this case either, but I guess it can be handwaved due to floating-point precision problems, e.g. Math.tan(Math.PI / 2) returns 16331239353195370 because ฯ€/2 can't be stored exactly. But in CSS, deg is the canonical unit for <angle>, and 90 is an integer, so I think there shouldn't be any precision problem.

css-values-4

Most helpful comment

So I guess this should round-trip and tan(90deg) should be +โˆž and tan(-90deg) be -โˆž?

I would argue strongly for a solution that supports round-tripping, so that atan(tan(90deg)) returns 90deg. If we can't do that, might as well give up on propagating the infinities through the nested functions at all.

And being approximately consistent with JS implementations is good, too. Even if the JS results are a side effect of numerical precision limits.

All 10 comments

So I guess this should round-trip and tan(90deg) should be +โˆž and tan(-90deg) be -โˆž?

I would argue strongly for a solution that supports round-tripping, so that atan(tan(90deg)) returns 90deg. If we can't do that, might as well give up on propagating the infinities through the nested functions at all.

And being approximately consistent with JS implementations is good, too. Even if the JS results are a side effect of numerical precision limits.

I think it's also good to preserve tan(x) = sin(x) / cos(x).

So assuming cos(90deg) = cos(-90deg) = +0 (not -0), then IEEE-754 says

tan(+90deg) = +1 / +0 = +โˆž
tan(โˆ’90deg) = โˆ’1 / +0 = โˆ’โˆž

I would argue strongly for a solution that supports round-tripping, so that atan(tan(90deg)) returns 90deg

IMO atan(tan(90deg)) = 90deg should just be a consequence, not what we want to enforce.

Note that atan โˆ˜ tan is not the identity, e.g. atan(tan(2ฯ€)) is not 2ฯ€ (given the usual definition of atan). The identity is tan โˆ˜ atan, so if we want to preserve this in CSS, what we actually need is tan(atan(+โˆž)) = +โˆž. And since atan(+โˆž) = 90deg, then tan(90deg) = +โˆž

what we actually need is tan(atan(+โˆž)) = +โˆž

Ah, good point. The input to tan() can be an arbitrary angle, but the output from atan will always be restricted to the base circle. But yes, once we reverse the nesting, we still want the consistent behavior.

Interesting question!

I agree that, at minimum, tan(90deg) should equal +inf. Since JS's Math.PI slightly undershoots the precise value, it happens to be true that Math.tan(Math.PI/2 * N) is always a very large (near infinite) positive value when N is a positive odd number, and a very large negative value when N is a negative odd. (But of course, adding a very tiny additional nudge will shift it over the threshold and swap the sign.)

So at least it's consistent with naive usage of JS to say that positive angles give +inf and negative give -inf. ^_^ And then yeah, that gives you roundtripping of either nesting (within the [-90deg, 90deg] range).

Um, I only mentioned 90deg and -90deg because I assumed we would preserve the 360deg periodicity.

Sure, saying tan(90deg) != tan(-90deg) already implies that we loose the 180deg periodicity, but the 360deg one is like very intrinsic to trigonometry. I'm not convinced that we should drop it just to match some floating-point precision problems.

This seems strange to me:

tan(-90deg) = -โˆž
tan(-90deg + 360deg) = +โˆž

Interesting. I had not realized that was a direction you might be wanting. That makes some sense, tho.

I had also assumed that keeping a consistent behavior for all equivalent angles (mod 360deg) was implied.

I know there are other places where we use a towards/away from zero rule, but for trigonometry having -90deg match 270deg (and so on) is more important.

@tabatkins There is some problem with your patch, ''tan(atan(1/0))'' and ''tan(atan(-1/0))'' are rendered as โ€˜0))โ€™. I guess you should escape the slash.

Ah, thanks, fixed. (It was the autolinker misfiring on the division sign, thinking it was a ''for/term'' autolink.)

Was this page helpful?
0 / 5 - 0 ratings