@@ -2465,6 +2465,247 @@ Comparison Functions: ''min()'', ''max()'', and ''clamp()''</h3>
24652465 </div>
24662466
24672467
2468+ <h3 id=trig-funcs>
2469+ Trigonometric Functions: ''sin()'', ''cos()'', ''tan()'', ''asin()'', ''acos()'', ''atan()'', and ''atan2()''</h3>
2470+
2471+ The trigonometric functions--
2472+ ''sin()'' , ''cos()'' , ''tan()'' , ''asin()'' , ''acos()'' , ''atan()'' , and ''atan2()'' --
2473+ compute the various basic trigonometric relationships.
2474+
2475+ The <dfn lt="sin()">sin(A)</dfn> , <dfn lt="cos(A)">cos()</dfn> , and <dfn lt="tan()">tan(A)</dfn> functions
2476+ all contain a single [=calculation=]
2477+ which must resolve to either a <<number>>
2478+ or an <<angle>> ,
2479+ and compute their corresponding function
2480+ by interpreting the result of their argument as radians.
2481+ (That is, ''sin(45deg)'' , ''sin(.125)'' , and ''sin(3.14159 / 4 * 1rad)''
2482+ all represent the same value,
2483+ approximately ''.707'' .)
2484+ They all represent a <<number>> ;
2485+ ''sin()'' and ''cos()'' will always return a number between 0 and 1,
2486+ while ''tan()'' can return any number between +∞ and −∞.
2487+ (See [[#calc-type-checking]] for details on how [=math functions=] handle ∞.)
2488+
2489+ The <dfn lt="asin()">asin(A)</dfn> , <dfn lt="acos()">acos(A)</dfn> , and <dfn lt="atan()">atan(A)</dfn> functions
2490+ are the "arc" or "inverse" trigonometric functions,
2491+ representing the inverse function to their corresponding "normal" trig functions.
2492+ All of them contain a single [=calculation=]
2493+ which must resolve to a <<number>> ,
2494+ and compute their corresponding function,
2495+ interpreting their result as a number of radians,
2496+ representing an <<angle>> .
2497+ The angle returned by ''asin()'' must be normalized to the range [''-90deg'', ''90deg''] ;
2498+ the angle returned by ''acos()'' to the range [''0deg'', ''180deg''] ;
2499+ and the angle returned by ''atan()'' to the range [''-90deg'', ''90deg''] .
2500+
2501+ The <dfn lt="atan2()">atan2(A, B)</dfn> function
2502+ contains two comma-separated [=calculations=] A and B
2503+ that must resolve to <<number>> s,
2504+ and returns the <<angle>>
2505+ between the positive X-axis and the point (B,A).
2506+ The returned angle must be normalized to the interval (''-180deg'' , ''180deg'' ]
2507+ (that is, greater than ''-180deg'' , and less than or equal to ''180deg'' ).
2508+
2509+ Note: ''atan2(Y, X)'' is <em> generally</em> equivalent to ''atan(Y / X)'' ,
2510+ but it gives a better answer when the point in question is in the second (NW) or third (SW) quadrants of the plane.
2511+ ''atan2(1, -1)'' , corresponding to the point (-1, 1) in the NW of the plane,
2512+ returns ''135deg'' ,
2513+ distinct from ''atan2(-1, 1)'' , corresponding to the point (1, -1) in the SE of the plane,
2514+ which returns ''-45deg'' .
2515+ However, as ''1 / -1'' and ''-1 / 1'' both resolve to ''-1'' ,
2516+ ''atan()'' returns the same ''-45deg'' for both points.
2517+
2518+
2519+ <h4 id="trig-infinities">
2520+ Argument Ranges</h4>
2521+
2522+ In ''sin(A)'' , ''cos(A)'' , or ''tan(A)'' ,
2523+ if A is infinite,
2524+ the result is NaN.
2525+ (See [[#calc-type-checking]] for details on how [=math functions=] handle NaN.)
2526+
2527+ In ''asin(A)'' or ''acos(A)'' ,
2528+ if A is less than -1 or greater than 1,
2529+ the result is NaN.
2530+
2531+ In ''atan(A)'' ,
2532+ if A is +∞,
2533+ the result is ''90deg'' ;
2534+ if A is -∞,
2535+ the result is ''-90deg'' .
2536+
2537+ In ''atan2(A, B)'' ,
2538+ if A and B are both zero,
2539+ the result is ''0deg'' .
2540+ If either or both [=calculations=] are infinite,
2541+ the function must return an angle
2542+ as if the infinite value was replaced by ''1'' (for +∞) or ''-1'' (for -∞)
2543+ and the finite value was replaced by ''0'' :
2544+ ''atan2(finite, ∞)'' must return ''0deg'' , as if it were ''atan2(0, 1)'' ;
2545+ ''atan2(∞, ∞)'' must return ''45deg'' , as if it were ''atan2(1, 1)'' ;
2546+ and so on around the circle.
2547+
2548+ Note: All of these behaviors are intended to match the "standard" definitions of these functions
2549+ as implemented by most programming languages,
2550+ in particular as implemented in JS.
2551+
2552+
2553+ <h3 id=exponent-funcs>
2554+ Exponential Functions: ''pow()'', ''sqrt()'', ''hypot()''</h3>
2555+
2556+ The exponential functions--
2557+ ''pow()'' , ''sqrt()'' , and ''hypot()'' --
2558+ compute various exponential functions with their arguments.
2559+
2560+ The <dfn lt="pow()">pow(A, B)</dfn> function
2561+ contains two comma-separated [=calculations=] A and B,
2562+ both of which must resolve to <<number>> s,
2563+ and returns the result of raising A to the power of B,
2564+ returning the value as a <<number>> .
2565+
2566+ The <dfn lt="sqrt()">sqrt(A)</dfn> function
2567+ contains a single [=calculation=]
2568+ which must resolve to a <<number>> ,
2569+ and returns the square root of the value
2570+ as a <<number>> .
2571+ (''sqrt(X)'' and ''pow(X, .5)'' are equivalent;
2572+ ''sqrt()'' is a common enough function
2573+ that it is provided as a convenience.)
2574+
2575+ The <dfn lt="hypot()">hypot(A,B)</dfn> function
2576+ contains two comma-separated [=calculations=] A and B,
2577+ and returns the length of the hypotenuse of a right-angled triangle
2578+ with legs equal to A and B.
2579+ A and B can resolve to any <<number>> , <<dimension>> , or <<percentage>> ,
2580+ but must have the <em> same</em> [=determine the type of a calculation|type=] ,
2581+ or else the function is invalid;
2582+ the result will have the same [=CSSNumericValue/type=] as the arguments.
2583+
2584+ <details class=note>
2585+ <summary> Why does ''hypot()'' allow dimensions (values with units), but ''pow()'' and ''sqrt()'' only work on numbers?</summary>
2586+
2587+ You are allowed to write expressions like ''hypot(30px, 40px)'' ,
2588+ which resolves to ''50px'' ,
2589+ but you aren't allowed to write the expression
2590+ ''sqrt(pow(30px, 2) + pow(40px, 2))'' ,
2591+ despite the two being equivalent in most mathematical systems.
2592+
2593+ There are two reasons for this:
2594+ numeric precision in the exponents,
2595+ and clashing expectations from authors.
2596+
2597+ First, numerical precision.
2598+ For a [=CSSNumericValue/type=] to [=CSSNumericValue/match=] a CSS production like <<length>> ,
2599+ it needs to have a single unit with its exponent set to exactly 1.
2600+ Theoretically, expressions like ''pow(pow(30px, 3), 1/3)'' should result in exactly that:
2601+ the inner ''pow(30px, 3)'' would resolve to a value of 27000 with a [=CSSNumericValue/type=] of «[ "length" → 3 ] »
2602+ (aka <<length>> ³),
2603+ and then the ''pow(X, 1/3)'' would cube-root the value back down to 30 and multiply the exponent by 1/3,
2604+ giving «[ "length" → 1 ] »,
2605+ which [=CSSNumericValue/matches=] <<length>> .
2606+ In the realm of pure mathematics, that's guaranteed to work out;
2607+ in the real-world of computers using binary floating-point arithmetic,
2608+ in some cases the powers might not exactly cancel out,
2609+ leaving you with an invalid [=math function=]
2610+ for confusing, hard-to-track-down reasons.
2611+ (For a JS example,
2612+ evaluate <code> Math.pow(Math.pow(30, 10/3), .1+.1+.1)</code> ;
2613+ the result is not exactly 30,
2614+ because <code> .1+.1+.1</code> is not exactly 3/10.
2615+ Instead, <code> (10/3) * (.1 + .1 + .1)</code> is <em> slightly greater</em> than 1.)
2616+
2617+ Requiring authors to cast their value down into a number,
2618+ do all the math on the raw number,
2619+ then finally send it back to the desired unit,
2620+ while inconvenient,
2621+ ensures that numerical precision won't bite anyone:
2622+ ''calc(pow(pow(30px / 1px, 3), 1/3) * 1px)'' is guaranteed to resolve to a <<length>> ,
2623+ with a value that, if not exactly 30, is at least very close to 30,
2624+ even if numerical precision actually prevents the powers from exactly canceling.
2625+
2626+ Second, clashing expectations.
2627+ It's not uncommon for authors to expect ''pow(30px, 2)''
2628+ to result in ''900px''
2629+ (such as in <a href="https://github.com/sass/sass/issues/684">this Sass issue</a> );
2630+ that is,
2631+ just squaring the numerical value
2632+ and leaving the unit alone.
2633+ This, however, means the result is dependent on what unit you're expressing the argument in;
2634+ if ''1em'' is ''16px'' ,
2635+ then ''pow(1em, 2)'' would give ''1em'' ,
2636+ while ''pow(16px, 2)'' would give ''256px'' , or ''16em'' ,
2637+ which are very different values for what should otherwise be identical input arguments!
2638+ This sort of input dependency is troublesome for CSS,
2639+ which generally allows values to be [=canonical unit|canonicalized=] freely;
2640+ it also makes more complex expressions like ''pow(2em + 10px, 2)'' difficult to interpret.
2641+
2642+ Again, requiring authors to cast their value down into a number
2643+ and then back up again into the desired unit
2644+ sidesteps these issues;
2645+ ''pow(30, 2)'' is indeed ''900'' ,
2646+ and the author can interpret that however they wish.
2647+
2648+ <hr>
2649+
2650+ On the other hand, ''hypot()'' doesn't suffer from these problems.
2651+ Numerical precision in units isn't a concern,
2652+ as the inputs and output all have the same type.
2653+ The result isn't unit-dependent, either,
2654+ due to the nature of the operation;
2655+ ''hypot(3em, 4em)'' and ''hypot(48px, 64px)'' give the same result in both cases:
2656+ ''5em'' or ''80px'' .
2657+ Thus it's fine to let author use dimensions directly in ''hypot()'' .
2658+ </details>
2659+
2660+ <h4 id="exponent-infinities">
2661+ Argument Ranges</h4>
2662+
2663+ In ''pow(A, B)'' :
2664+
2665+ <dl class=switch>
2666+ : if A is ±∞ and B is 0
2667+ :: the result is 1
2668+ : if A is +∞ and B is greater than 0
2669+ :: the result is +∞
2670+ : if A is +∞ and B is less than 0
2671+ :: the result is 0
2672+ : if A is -∞ and B is greater than 0
2673+ :: the result is -∞ if B is an odd integer, +∞ otherwise
2674+ : if A is -∞ and B is less than 0
2675+ :: the result is 0⁻ if B is an odd integer, 0⁺ otherwise
2676+
2677+ : if A is in the (exclusive) range (-1, 1) and B is +∞
2678+ :: the result is 0⁺
2679+ : if A is 1 or -1 and B is +∞
2680+ :: the result is NaN
2681+ : if A is less than -1 or greater than 1, and B is +∞
2682+ :: the result is +∞
2683+
2684+ : if A is in the (exclusive) range (-1, 1) and B is -∞
2685+ :: the result is +∞
2686+ : if A is 1 or -1 and B is -∞
2687+ :: the result is NaN
2688+ : if A is less than -1 or greater than 1, and B is -∞
2689+ :: the result is 0⁺
2690+ </dl>
2691+
2692+ In ''sqrt(A)'' ,
2693+ if A is +∞,
2694+ the result is +∞.
2695+ If A is less than 0,
2696+ the result is NaN.
2697+
2698+ In ''hypot(A, B)'' ,
2699+ if either or both values are infinite,
2700+ the result is +∞.
2701+
2702+ (See [[#calc-type-checking]] for details on how [=math functions=] handle NaN and infinities.)
2703+
2704+ Note: All of these behaviors are intended to match the "standard" definitions of these functions
2705+ as implemented by most programming languages,
2706+ in particular as implemented in JS.
2707+
2708+
24682709<h3 id='calc-syntax'>
24692710Syntax</h3>
24702711
0 commit comments