diff --git a/scss/tools/functions/__tests__/_fn.luminance.spec.scss b/scss/tools/functions/__tests__/_fn.luminance.spec.scss index 2dd8fc9..45298e4 100644 --- a/scss/tools/functions/__tests__/_fn.luminance.spec.scss +++ b/scss/tools/functions/__tests__/_fn.luminance.spec.scss @@ -4,6 +4,6 @@ @include describe("luminance()") { @include it("Returns luminance of color") { - @include assert-equal(luminance(#555), 0.04987, $inspect: true); + @include assert-equal(luminance(#555), 0.0908417112, $inspect: true); } } diff --git a/scss/tools/functions/__tests__/_fn.pow.spec.scss b/scss/tools/functions/__tests__/_fn.pow.spec.scss index 2d60de3..e68f946 100644 --- a/scss/tools/functions/__tests__/_fn.pow.spec.scss +++ b/scss/tools/functions/__tests__/_fn.pow.spec.scss @@ -2,7 +2,29 @@ @import "../_fn.pow"; @include describe("pow()") { - @include it("Returns value powered to exponent") { - @include assert-equal(pow(2, 2), 4); + @include it("Returns result of position integer number powered to positive integer exponent") { + @include assert-equal(pow(2, 2, 2), 4); + } + + @include it("Returns result of positive integer number powered to negative integer exponent") { + @include assert-equal(pow(2, -2, 2), 0.25); + } + + @include it("Returns result of positive integer number powered to a float exponent") { + @include assert-equal(pow(2, 2.5), 5.6568542495); + } + + @include it("Returns result of positive float number powered to a positive integer exponent") { + @include assert-equal(pow(2.5, 2), 6.25); + } + + @include it("Returns result of positive float number powered to a positive integer exponent") { + @include assert-equal(pow(2.5, -2, 2), 0.16); + } + + /// hack despite the number output is the same the test still fails + /// probably related to sass precision, requires investigation + @include it("Returns result of positive float number powered to a positive float exponent") { + @include assert-equal("#{pow(1.5, 1.5)}", "1.8371173071"); } } diff --git a/scss/tools/functions/_fn.pow.scss b/scss/tools/functions/_fn.pow.scss index bc76da3..faa4251 100644 --- a/scss/tools/functions/_fn.pow.scss +++ b/scss/tools/functions/_fn.pow.scss @@ -1,17 +1,106 @@ +$PI: 3.141592653589793; + +@function -math-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 -math-ln-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; +} + +@function -math-sin-taylor-0($x, $steps) { + $item: $x; + $result: $x; + + @for $i from 1 to $steps { + $item: -$item * $x * $x / (2 * $i) / (2 * $i + 1); + $result: $result + $item; + } + + @return $result; +} + +@function -math-pow-int($base, $exponent) { + @if $exponent < 0 { + @return 1 / -math-pow-int($base, -$exponent); + } @else if $exponent == 0 { + @return 1; + } @else if $exponent == 1 { + @return $base; + } @else { + $exp: floor($exponent / 2); + $pow: -math-pow-int($base, $exp); + @if $exp * 2 == $exponent { + @return $pow * $pow; + } @else { + @return $pow * $pow * $base; + } + } +} + +@function -math-log-approx($x) { + @if $x <= 0 { + @error "cannot calculate log of #{$x}"; + } @else if $x >= 1 { + // choose the smaller option (-1) because it yield better + // results in ln(). + @return str-length(inspect(round($x))) - 1; + } @else { + @return -1 * str-length(inspect(round(1 / $x))); + } +} + +@function ln($x, $steps: 32) { + $ln10: 2.302585092994046; + $approx: -math-log-approx($x); + // $y is in range [1, 10] + $y: $x / -math-pow-int(10, $approx); + @return $approx * $ln10 + -math-ln-taylor-1($y, $steps); +} + /// -/// power number to exponent +/// power a number to exponent, that can be positiv or negative int or float +/// when we get sass dependencies right, consider moving this to the +/// external package dependency like https://github.com/xi/sass-planifolia or +/// https://www.npmjs.com/package/sass-math-pow /// /// @group Tools -/// @author Hugo Giraudel +/// @author Tobias Bengfort +/// @link https://www.sassmeister.com/gist/5bbe8480c48e2fc10ab5 +/// @link https://gist.github.com/davidkpiano/ad6e6771df050ff3727f +/// @link https://css-tricks.com/snippets/sass/power-function/ /// -@function pow($number, $exponent) { - $value: 1; +/// @param {Number} $x - integer or float +/// @param {Number} $exponent - integer or float +/// @param {Number} $steps [32] - Number of iterations, more equals more precision, less perf - @if $exponent > 0 { - @for $i from 1 through $exponent { - $value: $value * $number; +@function pow($x, $exponent, $steps: 32) { + $exp1: round($exponent); + $exp2: $exponent - $exp1; + $pow1: -math-pow-int($x, $exp1); + @if $exp2 == 0 { + @return $pow1; + } @else { + $y: ln($x, $steps) * $exp2; + $pow2: -math-exp-taylor-0($y, $steps); + @return $pow1 * $pow2; } - } - - @return $value; }