Skip to content

Commit 3cbaec1

Browse files
Awjin AhnAwjin
authored andcommitted
Add exponential math functions. (#909)
1 parent d487d76 commit 3cbaec1

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
in between `$min` and `$max`.
66
* `hypot()`: given *n* numbers, outputs the length of the *n*-dimensional
77
vector that has components equal to each of the inputs.
8+
* Exponential (all inputs must be unitless):
9+
* `log($number)` or `log($number, $base)`. If no base is provided, `log()`
10+
performs a natural log.
11+
* `pow($base, $exponent)`
12+
* `sqrt($number)`
813

914
* Add the variables `$pi` and `$e` to the built-in "sass:math" module.
1015

lib/src/functions/math.dart

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ final global = UnmodifiableListView([
2323

2424
/// The Sass math module.
2525
final module = BuiltInModule("math", functions: [
26-
_abs, _ceil, _clamp, _compatible, _floor, _hypot, _isUnitless, _max, _min, //
27-
_percentage, _randomFunction, _round, _unit,
26+
_abs, _ceil, _clamp, _compatible, _floor, _hypot, _isUnitless, _log, _max, //
27+
_min, _pow, _percentage, _randomFunction, _round, _sqrt, _unit,
2828
], variables: {
2929
"e": SassNumber(math.e),
3030
"pi": SassNumber(math.pi),
@@ -133,6 +133,86 @@ final _hypot = BuiltInCallable("hypot", r"$numbers...", (arguments) {
133133
numeratorUnits: numeratorUnits, denominatorUnits: denominatorUnits);
134134
});
135135

136+
///
137+
/// Exponential functions
138+
///
139+
140+
final _log = BuiltInCallable("log", r"$number, $base: null", (arguments) {
141+
var number = arguments[0].assertNumber("number");
142+
if (number.hasUnits) {
143+
throw SassScriptException("\$number: Expected $number to have no units.");
144+
}
145+
146+
var numberValue = fuzzyEquals(number.value, 0) ? 0 : number.value;
147+
148+
if (arguments[1] == sassNull) return SassNumber(math.log(numberValue));
149+
150+
var base = arguments[1].assertNumber("base");
151+
if (base.hasUnits) {
152+
throw SassScriptException("\$base: Expected $base to have no units.");
153+
}
154+
155+
var baseValue = fuzzyEquals(base.value, 0) || fuzzyEquals(base.value, 1)
156+
? fuzzyRound(base.value)
157+
: base.value;
158+
159+
return SassNumber(math.log(numberValue) / math.log(baseValue));
160+
});
161+
162+
final _pow = BuiltInCallable("pow", r"$base, $exponent", (arguments) {
163+
var base = arguments[0].assertNumber("base");
164+
var exponent = arguments[1].assertNumber("exponent");
165+
166+
if (base.hasUnits) {
167+
throw SassScriptException("\$base: Expected $base to have no units.");
168+
} else if (exponent.hasUnits) {
169+
throw SassScriptException(
170+
"\$exponent: Expected $exponent to have no units.");
171+
}
172+
173+
var baseValue = base.value;
174+
var exponentValue = exponent.value;
175+
176+
if (fuzzyEquals(baseValue.abs(), 1) && exponentValue.isInfinite) {
177+
return SassNumber(double.nan);
178+
}
179+
180+
// Exponentiating certain real numbers leads to special behaviors. Ensure that
181+
// these behaviors are consistent for numbers within the precision limit.
182+
if (fuzzyEquals(exponentValue, 0)) {
183+
exponentValue = 0;
184+
} else if (fuzzyEquals(baseValue, 0)) {
185+
baseValue = baseValue.isNegative ? -0.0 : 0;
186+
if (exponentValue.isFinite &&
187+
fuzzyIsInt(exponentValue) &&
188+
fuzzyAsInt(exponentValue) % 2 == 1) {
189+
exponentValue = fuzzyRound(exponentValue);
190+
}
191+
} else if (baseValue.isFinite &&
192+
fuzzyLessThan(baseValue, 0) &&
193+
exponentValue.isFinite &&
194+
fuzzyIsInt(exponentValue)) {
195+
exponentValue = fuzzyRound(exponentValue);
196+
} else if (baseValue.isInfinite &&
197+
fuzzyLessThan(baseValue, 0) &&
198+
exponentValue.isFinite &&
199+
fuzzyIsInt(exponentValue) &&
200+
fuzzyAsInt(exponentValue) % 2 == 1) {
201+
exponentValue = fuzzyRound(exponentValue);
202+
}
203+
204+
return SassNumber(math.pow(baseValue, exponentValue));
205+
});
206+
207+
final _sqrt = BuiltInCallable("sqrt", r"$number", (arguments) {
208+
var number = arguments[0].assertNumber("number");
209+
if (number.hasUnits) {
210+
throw SassScriptException("\$number: Expected $number to have no units.");
211+
}
212+
213+
return SassNumber(math.sqrt(number.value));
214+
});
215+
136216
///
137217
/// Unit functions
138218
///

0 commit comments

Comments
 (0)