-
Notifications
You must be signed in to change notification settings - Fork 131
Decimal powers and memoization #89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I’ve done a bit of testing with this a while back and performance is just bad, even in libsass. I may re-visit but until we get native At the moment, I’d rather push on Sass to include this much needed feature than to implement a sub-optimal work-around that may cause peoples projects to hang. |
Pushing this off to 3.1 or only enabling via external lib. Complexities of this feature are getting in the way of other important 3.0 work. |
Yup, you’ll be able to add this functionality easily in the next version by including a lib like mathsass, but not out of the box. |
...three years later ;-) If this is still on for a future version I found a super fast° pow function: ° fast of course is relative and depends on compiler. My tests on LibSass (CodeKit) If you want to limit the implementation to only include pow here is a stripped down version: $☠️--math-steps: 32 !default;
@function pow($x, $exponent, $steps: $☠️--math-steps) {
$exp1: round($exponent);
$exp2: $exponent - $exp1;
$pow1: ☠️--pow-int($x, $exp1);
@if $exp2 == 0 { @return $pow1; }
@else if $x == 0 and $exponent > 0 { @return 0; }
@else {
$y: ☠️--log($x, $steps) * $exp2;
$pow2: ☠️--exp-taylor-0($y, $steps);
@return $pow1 * $pow2;
}
}
// private helper functions
@function ☠️--log($x, $steps: $☠️--math-steps) {
$log10: 2.302585092994046;
$approx: ☠️--log10-approx($x);
// $y is in range [1, 10]
$y: $x / ☠️--pow-int(10, $approx);
@return $approx * $log10 + ☠️--log-taylor-1($y, $steps);
}
@function ☠️--pow-int($base, $exponent) {
@if $exponent < 0 { @return 1 / ☠️--pow-int($base, -$exponent); }
@else if $exponent == 0 { @return 1; }
@else if $exponent == 1 { @return $base; }
@else {
$exp: floor($exponent / 2);
$pow: ☠️--pow-int($base, $exp);
@if $exp * 2 == $exponent { @return $pow * $pow; }
@else { @return $pow * $pow * $base; }
}
}
@function ☠️--log10-approx($x) {
@if $x <= 0 { @error 'cannot calculate log of #{$x}'; }
// choose the smaller option (-1) because it yields better results in log().
@else if $x >= 1 { @return str-length(inspect(round($x))) - 1; }
@else { @return -1 * str-length(inspect(round(1 / $x))); }
}
@function ☠️--exp-taylor-0($x, $steps) {
$item: 1;
$result: 1;
@for $i from 1 to $steps {
$item: $item * $x / $i;
$result: $result + $item;
}
@return $result;
}
@function ☠️--log-taylor-1($x, $steps) {
$z: ($x - 1) / ($x + 1);
$power: $z;
$result: $z;
@for $i from 1 to $steps {
$power: $power * $z * $z;
$result: $result + $power / (2 * $i + 1);
}
@return 2 * $result;
}
Example (based on http://spencermortensen.com/articles/typographic-scale/) golden-scale {
$r: 1.61803398874989484820; // ratio: phi
$n: 2; // notes: number of notes
@for $i from -5 through 5 {
scale-#{$i+5}: pow($r, $i/$n);
}
} Output: golden-scale {
scale-0: 0.300283106;
scale-1: 0.3819660113;
scale-2: 0.4858682718;
scale-3: 0.6180339887;
scale-4: 0.7861513778;
scale-5: 1;
scale-6: 1.2720196495;
scale-7: 1.6180339887;
scale-8: 2.0581710273;
scale-9: 2.6180339887;
scale-10: 3.3301906768;
} |
Would it be possible to implement decimal powers to produce scales like these:
http://spencermortensen.com/articles/typographic-scale/
Maybe this could be done by switching to mathsass and perhaps considering memoization to speed things up a bit.
Tests:
memoization disabled
memoization enabled
Thanks and keep up the good work 👍
The text was updated successfully, but these errors were encountered: