Add exponential math functions. (#909)

This commit is contained in:
Awjin Ahn 2020-01-06 17:47:43 -08:00 committed by awjin
parent d487d761bd
commit 3cbaec11b2
2 changed files with 87 additions and 2 deletions

View File

@ -5,6 +5,11 @@
in between `$min` and `$max`.
* `hypot()`: given *n* numbers, outputs the length of the *n*-dimensional
vector that has components equal to each of the inputs.
* Exponential (all inputs must be unitless):
* `log($number)` or `log($number, $base)`. If no base is provided, `log()`
performs a natural log.
* `pow($base, $exponent)`
* `sqrt($number)`
* Add the variables `$pi` and `$e` to the built-in "sass:math" module.

View File

@ -23,8 +23,8 @@ final global = UnmodifiableListView([
/// The Sass math module.
final module = BuiltInModule("math", functions: [
_abs, _ceil, _clamp, _compatible, _floor, _hypot, _isUnitless, _max, _min, //
_percentage, _randomFunction, _round, _unit,
_abs, _ceil, _clamp, _compatible, _floor, _hypot, _isUnitless, _log, _max, //
_min, _pow, _percentage, _randomFunction, _round, _sqrt, _unit,
], variables: {
"e": SassNumber(math.e),
"pi": SassNumber(math.pi),
@ -133,6 +133,86 @@ final _hypot = BuiltInCallable("hypot", r"$numbers...", (arguments) {
numeratorUnits: numeratorUnits, denominatorUnits: denominatorUnits);
});
///
/// Exponential functions
///
final _log = BuiltInCallable("log", r"$number, $base: null", (arguments) {
var number = arguments[0].assertNumber("number");
if (number.hasUnits) {
throw SassScriptException("\$number: Expected $number to have no units.");
}
var numberValue = fuzzyEquals(number.value, 0) ? 0 : number.value;
if (arguments[1] == sassNull) return SassNumber(math.log(numberValue));
var base = arguments[1].assertNumber("base");
if (base.hasUnits) {
throw SassScriptException("\$base: Expected $base to have no units.");
}
var baseValue = fuzzyEquals(base.value, 0) || fuzzyEquals(base.value, 1)
? fuzzyRound(base.value)
: base.value;
return SassNumber(math.log(numberValue) / math.log(baseValue));
});
final _pow = BuiltInCallable("pow", r"$base, $exponent", (arguments) {
var base = arguments[0].assertNumber("base");
var exponent = arguments[1].assertNumber("exponent");
if (base.hasUnits) {
throw SassScriptException("\$base: Expected $base to have no units.");
} else if (exponent.hasUnits) {
throw SassScriptException(
"\$exponent: Expected $exponent to have no units.");
}
var baseValue = base.value;
var exponentValue = exponent.value;
if (fuzzyEquals(baseValue.abs(), 1) && exponentValue.isInfinite) {
return SassNumber(double.nan);
}
// Exponentiating certain real numbers leads to special behaviors. Ensure that
// these behaviors are consistent for numbers within the precision limit.
if (fuzzyEquals(exponentValue, 0)) {
exponentValue = 0;
} else if (fuzzyEquals(baseValue, 0)) {
baseValue = baseValue.isNegative ? -0.0 : 0;
if (exponentValue.isFinite &&
fuzzyIsInt(exponentValue) &&
fuzzyAsInt(exponentValue) % 2 == 1) {
exponentValue = fuzzyRound(exponentValue);
}
} else if (baseValue.isFinite &&
fuzzyLessThan(baseValue, 0) &&
exponentValue.isFinite &&
fuzzyIsInt(exponentValue)) {
exponentValue = fuzzyRound(exponentValue);
} else if (baseValue.isInfinite &&
fuzzyLessThan(baseValue, 0) &&
exponentValue.isFinite &&
fuzzyIsInt(exponentValue) &&
fuzzyAsInt(exponentValue) % 2 == 1) {
exponentValue = fuzzyRound(exponentValue);
}
return SassNumber(math.pow(baseValue, exponentValue));
});
final _sqrt = BuiltInCallable("sqrt", r"$number", (arguments) {
var number = arguments[0].assertNumber("number");
if (number.hasUnits) {
throw SassScriptException("\$number: Expected $number to have no units.");
}
return SassNumber(math.sqrt(number.value));
});
///
/// Unit functions
///