accepted/more-math-functions.md
This proposal adds the following members to the built-in sass:math module.
This section is non-normative.
Sass recently implemented a module system with a new built-in sass:math
module. The demand for built-in math functions can now be fulfilled safely by
implementing them inside this module. None of these new functions will be made
available on the global namespace.
This section is non-normative.
This proposal defines Sassified versions of all the mathematical functions in
the CSS Values and Units 4 Draft, as well as logarithms and the constants
e and pi. Each function is basically equivalent to its mathematical form,
with stricter unit handling. Proper unit handling prevents these functions from
creating meaningless units. For instance, consider (1px)^(1/3)—what does
the unit px^(1/3) mean?
To avoid issues like this, the exponential functions—log(), pow(), sqrt()—
accept only a unitless number as input, and output a unitless number.
The trig functions—cos(), sin(), tan()—accept a SassScript number with a
unit, as long as that unit is an angle type. If the input is a unitless
number, it is treated as though it were in rad. These functions output a
unitless number.
The inverse trig functions—acos(), asin(), atan()—accept a unitless number
and output a SassScript number in deg. atan2() is similar, but it accepts
two unitless numbers.
clamp() accepts three SassScript numbers with compatible units: the
minimum value, preferred value, and maximum value. This function "clamps" the
preferred value in between the minimum and maximum values, while preserving
their units appropriately. For example, clamp(1in, 15cm, 12in) outputs 15cm,
whereas clamp(1in, 1cm, 12in) outputs 1in.
hypot() accepts n SassScript numbers with compatible units, and outputs the
length of the n-dimensional vector that has components equal to each of the
inputs. Since the inputs' units may all be different, the output takes the unit
of the first input.
Variables defined in built-in modules are not modifiable. As such, this proposal modifies the semantics of Executing a Variable Declaration within the Variables spec to read as follows:
To execute a VariableDeclaration declaration:
Let value be the result of evaluating declaration's Expression.
Let name be declaration's Variable.
Let resolved be the result of resolving a variable named name.
If name is a NamespacedVariable and declaration has a !global flag,
throw an error.
Otherwise, if resolved is a variable from a built-in module, throw an
error.
Otherwise, if declaration is outside of any block of statements, or
declaration has a !global flag, or name is a NamespacedVariable:
resolved be the result of resolving a variable named name using
file, uses, and import.(...)
Otherwise, if declaration is within one or more blocks associated with
@if, @each, @for, and/or @while rules and no other blocks:
resolved be the result of resolving a variable named name.(...)
Otherwise, if no block containing declaration has a scope with a
variable named name, set the innermost block's scope's variable name to
value.
Otherwise, if resolved is null, get the innermost block containing
declaration and set its scope's variable name to value.
Otherwise, let scope be the scope of the innermost block such that scope
already has a variable named name.
Otherwise, set resolved's value to value.
$eEqual to the value of the mathematical constant e with a precision of 10
digits after the decimal point: 2.7182818285.
$piEqual to the value of the mathematical constant pi with a precision of 10
digits after the decimal point: 3.1415926536.
clamp()clamp($min, $number, $max)
$min, $number, and $max are not compatible with each
other, throw an error.$min >= $max, return $min.$number <= $min, return $min.$number >= $max, return $max.$number.hypot()hypot($numbers...)
Infinity or -Infinity, return Infinity.log()log($number, $base: null)
$number has units, throw an error.$base is null:
$number < 0, return NaN as a unitless number.$number == 0, return -Infinity as a unitless number.$number == Infinity, return Infinity as a unitless number.$number, as a unitless number.$number divided by the natural log of
$base, as a unitless number.pow()pow($base, $exponent)
If $base or $exponent has units, throw an error.
If $exponent == 0, return 1 as a unitless number.
Otherwise, if $exponent == Infinity or $exponent == -Infinity:
$base == 1 or $base == -1, return NaN as a unitless number.$base < -1 or $base > 1 and if $exponent > 0, or if $base > -1
and $base < 1 and $exponent < 0, return Infinity as a
unitless number.0 as a unitless number.Otherwise:
If $base < 0 and $exponent is not an integer, return NaN as a unitless
number.
If $base == 0 and $exponent < 0, or if $base == Infinity and
$exponent > 0, return Infinity as a unitless number.
If $base == -0 and $exponent < 0, or if $base == -Infinity and
$exponent > 0:
$exponent is an odd integer, return -Infinity as a unitless number.Infinity as a unitless number.If $base == 0 and $exponent > 0, or if $base == Infinity and
$exponent < 0, return 0 as a unitless number.
If $base == -0 and $exponent > 0, or if $base == -Infinity and
$exponent < 0:
$exponent is an odd integer, return -0 as a unitless number.0 as a unitless number.Return $base raised to the power of $exponent, as a unitless number.
sqrt()sqrt($number)
$number has units, throw an error.$number < 0, return NaN as a unitless number.$number == -0, return -0 as a unitless number.$number == 0, return 0 as a unitless number.$number == Infinity, return Infinity as a unitless number.$number, as a unitless number.cos()cos($number)
$number has units but is not an angle, throw an error.$number is unitless, treat it as though its unit were rad.$number == Infinity or $number == -Infinity, return NaN as a unitless
number.$number, as a unitless number.sin()sin($number)
$number has units but is not an angle, throw an error.$number is unitless, treat it as though its unit were rad.$number == Infinity or $number == -Infinity, return NaN as a unitless
number.$number == -0, return -0 as a unitless number.$number == 0, return 0 as a unitless number.$number, as a unitless number.tan()tan($number)
$number has units but is not an angle, throw an error.$number is unitless, treat it as though its unit were rad.$number == Infinity or $number == -Infinity, return NaN as a unitless
number.$number == -0, return -0 as a unitless number.$number == 0, return 0 as a unitless number.$number is equivalent to 90deg +/- 360deg * n, where n is any
integer, return Infinity as a unitless number.$number is equivalent to -90deg +/- 360deg * n, where n is any
integer, return -Infinity as a unitless number.$number, as a unitless number.acos()acos($number)
$number has units, throw an error.$number < -1 or $number > 1, return NaN as a number in deg.$number == 1, return 0deg.$number, as a number in deg.asin()asin($number)
$number has units, throw an error.$number < -1 or $number > 1, return NaN as a number in deg.$number == -0, return -0deg.$number == 0, return 0deg.$number, as a number in deg.atan()atan($number)
$number has units, throw an error.$number == -0, return -0deg.$number == 0, return 0deg.$number == -Infinity, return -90deg.$number == Infinity, return 90deg.$number, as a number in deg.atan2()
atan2($y, $x)is distinct fromatan($y / $x)because it preserves the quadrant of the point in question. For example,atan2(1, -1)corresponds to the point(-1, 1)and returns135deg. In contrast,atan(1 / -1)andatan(-1 / 1)resolve first toatan(-1), so both return-45deg.
atan2($y, $x)
$y and $x are not compatible, throw an error.$y has units and $x does not, or vice-versa, throw an error.$y and $x, as a
number in deg.