- commit
- 3c6eb301934cb3c5e0498dfc91402d81a1cb3d15
- parent
- 70bd45978cf16804275ceedba32e8a6f50476c68
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2022-05-03 20:17
rm math module can be replaced by builtin math module https://sass-lang.com/documentation/modules/math
Diffstat
| D | sass/math.scss | 289 | ------------------------------------------------------------ |
| D | test/math.js | 237 | ------------------------------------------------------------ |
2 files changed, 0 insertions, 526 deletions
diff --git a/sass/math.scss b/sass/math.scss
@@ -1,289 +0,0 @@1 -1 ////2 -1 /// @group math3 -1 ///4 -1 /// This provides some common mathemetical functions implemented in pure sass.5 -1 ///6 -1 /// The implementations are based on taylor expansions. The `$steps` argument7 -1 /// defines how many steps of the series will be calculated. So a higher number8 -1 /// will result in higher precision.9 -1 ///10 -1 /// Taylor expansions converge quickly around their centers, so a decent11 -1 /// approximation can be calculated in constant time.12 -1 ///13 -1 /// If the input $x is too far off of the center, it is converted to a closer14 -1 /// value $y in a way that allows to calculate f($x) from f($y). This15 -1 /// conversion uses exact arithmetics and can be done in constant or16 -1 /// logarithmic time.17 -1 ///18 -1 /// This approach is havily inspired by19 -1 /// <http://www.sassmeister.com/gist/ad6e6771df050ff3727f>. However, the20 -1 /// implementations are much more efficient.21 -1 ////22 -123 -1 /// @type number24 -1 $planifolia-math-steps-default: 32 !default;25 -126 -1 /// @return {number}27 -1 @function pi() {28 -1 @return 3.141592653589793;29 -1 }30 -131 -1 @function _pf-angle-to-rad($x) {32 -1 @return (0rad + $x) / 1rad;33 -1 }34 -135 -1 @function _pf-exp-taylor-0($x, $steps) {36 -1 $item: 1;37 -1 $result: 1;38 -139 -1 @for $i from 1 to $steps {40 -1 $item: $item * $x / $i;41 -1 $result: $result + $item;42 -1 }43 -144 -1 @return $result;45 -1 }46 -147 -1 @function _pf-log-taylor-1($x, $steps) {48 -1 $z: ($x - 1) / ($x + 1);49 -150 -1 $power: $z;51 -1 $result: $z;52 -153 -1 @for $i from 1 to $steps {54 -1 $power: $power * $z * $z;55 -1 $result: $result + $power / (2 * $i + 1);56 -1 }57 -158 -1 @return 2 * $result;59 -1 }60 -161 -1 @function _pf-sin-taylor-0($x, $steps) {62 -1 $item: $x;63 -1 $result: $x;64 -165 -1 @for $i from 1 to $steps {66 -1 $item: -$item * $x * $x / (2 * $i) / (2 * $i + 1);67 -1 $result: $result + $item;68 -1 }69 -170 -1 @return $result;71 -1 }72 -173 -1 @function _pf-asin-taylor-0($x, $steps) {74 -1 $item: $x;75 -1 $result: $x;76 -177 -1 @for $i from 1 to $steps {78 -1 $item: $item * $x * $x * (2 * $i - 1) / (2 * $i);79 -1 $result: $result + $item / (2 * $i + 1);80 -1 }81 -182 -1 @return $result;83 -1 }84 -185 -1 @function _pf-pow-int($base, $exponent) {86 -1 @if $exponent < 0 {87 -1 @return 1 / _pf-pow-int($base, -$exponent);88 -1 } @else if $exponent == 0 {89 -1 @return 1;90 -1 } @else if $exponent == 1 {91 -1 @return $base;92 -1 } @else {93 -1 $exp: floor($exponent / 2);94 -1 $pow: _pf-pow-int($base, $exp);95 -1 @if $exp * 2 == $exponent {96 -1 @return $pow * $pow;97 -1 } @else {98 -1 @return $pow * $pow * $base;99 -1 }100 -1 }101 -1 }102 -1103 -1 @function _pf-log10-approx($x) {104 -1 @if $x <= 0 {105 -1 @error 'cannot calculate log of #{$x}';106 -1 } @else if $x >= 1 {107 -1 // choose the smaller option (-1) because it yields better108 -1 // results in log().109 -1 @return str-length(inspect(round($x))) - 1;110 -1 } @else {111 -1 @return -1 * str-length(inspect(round(1 / $x)));112 -1 }113 -1 }114 -1115 -1 /// @param {number} $x116 -1 /// @param {number} $steps [32] - steps of the taylor expansion117 -1 /// @return {number}118 -1 @function log($x, $steps: $planifolia-math-steps-default) {119 -1 $log10: 2.302585092994046;120 -1 $approx: _pf-log10-approx($x);121 -1 // $y is in range [1, 10]122 -1 $y: $x / _pf-pow-int(10, $approx);123 -1 @return $approx * $log10 + _pf-log-taylor-1($y, $steps);124 -1 }125 -1126 -1 /// @param {number} $x127 -1 /// @param {number} $steps [32] - steps of the taylor expansion128 -1 /// @return {number}129 -1 @function log10($x, $steps: $planifolia-math-steps-default) {130 -1 $log10: 2.302585092994046;131 -1 @return log($x, $steps) / $log10;132 -1 }133 -1134 -1 /// @param {number} $x135 -1 /// @param {number} $exponent136 -1 /// If $x is 0 or below, $exponent needs to be an integer.137 -1 /// @param {number} $steps [32] - steps of the taylor expansion138 -1 /// @return {number}139 -1 @function pow($x, $exponent, $steps: $planifolia-math-steps-default) {140 -1 $exp1: round($exponent);141 -1 $exp2: $exponent - $exp1;142 -1 $pow1: _pf-pow-int($x, $exp1);143 -1 @if $exp2 == 0 {144 -1 @return $pow1;145 -1 } @else if $x == 0 and $exponent > 0 {146 -1 @return 0;147 -1 } @else {148 -1 $y: log($x, $steps) * $exp2;149 -1 $pow2: _pf-exp-taylor-0($y, $steps);150 -1 @return $pow1 * $pow2;151 -1 }152 -1 }153 -1154 -1 /// @param {number} $x155 -1 /// @param {number} $exponent156 -1 /// @param {number} $steps [32] - steps of the taylor expansion157 -1 /// @return {number}158 -1 @function nth-root($x, $exponent, $steps: $planifolia-math-steps-default) {159 -1 @return pow($x, 1 / $exponent, $steps);160 -1 }161 -1162 -1 /// @param {number} $x163 -1 /// @param {number} $steps [32] - steps of the taylor expansion164 -1 /// @return {number}165 -1 @function sqrt($x, $steps: $planifolia-math-steps-default) {166 -1 @return nth-root($x, 2, $steps);167 -1 }168 -1169 -1 /// @param {number} $x170 -1 /// @param {number} $steps [32] - steps of the taylor expansion171 -1 /// @return {number}172 -1 @function sin($x, $steps: $planifolia-math-steps-default) {173 -1 $x: _pf-angle-to-rad($x);174 -1175 -1 @if $x > 2 * pi() {176 -1 $x: $x % (2 * pi());177 -1 }178 -1 @if $x > pi() {179 -1 @return -1 * sin($x - pi());180 -1 } @else if $x < 0 {181 -1 @return -1 * sin(-$x);182 -1 } @else {183 -1 @return _pf-sin-taylor-0($x, $steps);184 -1 }185 -1 }186 -1187 -1 /// @param {number} $x188 -1 /// @param {number} $steps [32] - steps of the taylor expansion189 -1 /// @return {number}190 -1 @function cos($x, $steps: $planifolia-math-steps-default) {191 -1 $x: _pf-angle-to-rad($x);192 -1 @return sin($x + pi() / 2, $steps);193 -1 }194 -1195 -1 /// @param {number} $x196 -1 /// @param {number} $steps [32] - steps of the taylor expansion197 -1 /// @return {number}198 -1 @function tan($x, $steps: $planifolia-math-steps-default) {199 -1 @return sin($x, $steps) / cos($x, $steps);200 -1 }201 -1202 -1 /// @param {number} $x203 -1 /// @param {number} $steps [32] - steps of the taylor expansion204 -1 /// @return {number}205 -1 @function asin($x, $steps: $planifolia-math-steps-default) {206 -1 @if $x < 0 {207 -1 @return -1 * asin(-$x, $steps);208 -1 } @else if $x * $x > 0.5 {209 -1 @return acos(sqrt(1 - $x * $x, $steps), $steps);210 -1 } @else {211 -1 @return _pf-asin-taylor-0($x, $steps);212 -1 }213 -1 }214 -1215 -1 /// @param {number} $x216 -1 /// @param {number} $steps [32] - steps of the taylor expansion217 -1 /// @return {number}218 -1 @function acos($x, $steps: $planifolia-math-steps-default) {219 -1 @return pi() / 2 - asin($x, $steps);220 -1 }221 -1222 -1 /// @param {number} $x223 -1 /// @param {number} $steps [32] - steps of the taylor expansion224 -1 /// @return {number}225 -1 @function atan($x, $steps: $planifolia-math-steps-default) {226 -1 @if $x == 0 {227 -1 @return 0;228 -1 } @else if $x < 0 {229 -1 @return -1 * atan(-$x, $steps);230 -1 } @else {231 -1 @return asin(1 / sqrt(1 + 1 / ($x * $x), $steps), $steps);232 -1 }233 -1 }234 -1235 -1 /// Computes the angle of the vector (x,y) with the x axis.236 -1 /// @param {number} $y237 -1 /// @param {number} $x238 -1 /// @param {number} $steps [32] - steps of the taylor expansion239 -1 /// @return {number}240 -1 @function atan2($y, $x, $steps: $planifolia-math-steps-default) {241 -1 @if $x > 0 {242 -1 @return atan($y / $x, $steps);243 -1 } @else if $x < 0 {244 -1 @if $y >= 0 {245 -1 @return atan($y / $x, $steps) + pi();246 -1 } @else {247 -1 @return atan($y / $x, $steps) - pi();248 -1 }249 -1 } @else {250 -1 @if $y > 0 {251 -1 @return pi() / 2;252 -1 } @else if $y < 0 {253 -1 @return pi() / -2;254 -1 } @else {255 -1 @return 0;256 -1 }257 -1 }258 -1 }259 -1260 -1 @function _pf-interpolate($a, $b, $t) {261 -1 $result: ();262 -1 @for $i from 1 through length($a) {263 -1 $value: nth($a, $i) * (1 - $t) + nth($b, $i) * $t;264 -1 $result: append($result, $value);265 -1 }266 -1 @return $result;267 -1 }268 -1269 -1 /// Generic bezier interpolation.270 -1 /// @param {P[]} $points271 -1 /// @param {number} $t position 0 .. 1272 -1 /// @param {function(P, P, number) => P} $interpolate [_pf-interpolate]273 -1 /// The default is a linear interpolation between lists of numbers.274 -1 /// You can specify a custom interpolation function, e.g. to interpolate275 -1 /// between colors.276 -1 /// @return {P} A single point.277 -1 @function bezier($points, $t, $interpolate: get-function(_pf-interpolate)) {278 -1 @if length($points) > 1 {279 -1 $tmp: ();280 -1 @for $i from 1 to length($points) {281 -1 $point1: nth($points, $i);282 -1 $point2: nth($points, $i + 1);283 -1 $tmp: append($tmp, call($interpolate, $point1, $point2, $t));284 -1 }285 -1 @return bezier($tmp, $t, $interpolate);286 -1 } @else {287 -1 @return nth($points, 1);288 -1 }289 -1 }
diff --git a/test/math.js b/test/math.js
@@ -1,237 +0,0 @@1 -1 var assert = require('assert');2 -1 var shared = require('./shared');3 -14 -1 describe('math', function() {5 -1 var renderer = new shared.Renderer('@import "math";');6 -17 -1 describe('pow', function() {8 -1 it('pow(3, 2) == 9', function() {9 -1 assert.strictEqual(renderer.value('pow(3, 2)'), '9')10 -1 });11 -1 it('pow(4, 3/2) == 8', function() {12 -1 assert.strictEqual(renderer.value('pow(4, 3/2)'), '8')13 -1 });14 -1 it('pow(144, 1/2) == 12', function() {15 -1 assert.strictEqual(renderer.value('pow(144, 1/2)'), '12')16 -1 });17 -1 it('pow(0, 1/2) == 0', function() {18 -1 assert.strictEqual(renderer.value('pow(0, 1/2)'), '0')19 -1 });20 -1 it('pow(-3, 2) == 9', function() {21 -1 assert.strictEqual(renderer.value('pow(-3, 2)'), '9')22 -1 });23 -1 it('pow(-3, 3) == -27', function() {24 -1 assert.strictEqual(renderer.value('pow(-3, 3)'), '-27')25 -1 });26 -1 it('pow(3, -2)', function() {27 -1 shared.similar(renderer.value('pow(3, -2)'), Math.pow(3, -2));28 -1 });29 -1 it('pow(64, -1/2) == 0.125', function() {30 -1 assert.strictEqual(renderer.value('pow(64, -1/2)'), '0.125')31 -1 });32 -1 it('pow(1200, 3.4)', function() {33 -1 shared.similar(renderer.value('pow(1200, 3.4)'), Math.pow(1200, 3.4), 0.1);34 -1 });35 -1 it('pow(1200.3, 3.4)', function() {36 -1 shared.similar(renderer.value('pow(1200.3, 3.4)'), Math.pow(1200.3, 3.4), 0.1);37 -1 });38 -1 it('pow(3px, 2.4) throws', function() {39 -1 assert.throws(function () {40 -1 renderer.value('pow(3px, 2)');41 -1 });42 -1 });43 -1 it('pow(3.5, 0) == 1', function() {44 -1 assert.strictEqual(renderer.value('pow(3.5, 0)'), '1')45 -1 });46 -1 it('pow(0, 3.5) == 0', function() {47 -1 assert.strictEqual(renderer.value('pow(0, 3.5)'), '0')48 -1 });49 -1 it('pow(0, 0) == 1', function() {50 -1 assert.strictEqual(renderer.value('pow(0, 0)'), '1')51 -1 });52 -1 });53 -154 -1 describe('log', function() {55 -1 it('log(1) == 0', function() {56 -1 assert.strictEqual(renderer.value('log(1)'), '0')57 -1 });58 -1 it('log(0.1)', function() {59 -1 shared.similar(renderer.value('log(0.1)'), Math.log(0.1));60 -1 });61 -1 it('log(123456789)', function() {62 -1 shared.similar(renderer.value('log(123456789)'), Math.log(123456789));63 -1 });64 -1 it('log(12345678.9)', function() {65 -1 shared.similar(renderer.value('log(12345678.9)'), Math.log(12345678.9));66 -1 });67 -1 });68 -169 -1 describe('sin', function() {70 -1 it('sin(0) == 0', function() {71 -1 assert.strictEqual(renderer.value('sin(0)'), '0')72 -1 });73 -1 it('sin(pi()) == 0', function() {74 -1 assert.strictEqual(renderer.value('sin(pi())'), '0');75 -1 });76 -1 it('sin(2 * pi()) == 0', function() {77 -1 assert.strictEqual(renderer.value('sin(2 * pi())'), '0');78 -1 });79 -1 it('sin(123456789 * pi()) ~= 0', function() {80 -1 shared.similar(renderer.value('sin(123456789 * pi())'), 0);81 -1 });82 -1 it('sin(-1 * pi()) == 0', function() {83 -1 assert.strictEqual(renderer.value('sin(-1 * pi())'), '0');84 -1 });85 -1 it('sin(1/2 * pi()) == 1', function() {86 -1 assert.strictEqual(renderer.value('sin(1/2 * pi())'), '1');87 -1 });88 -1 it('sin(3/2 * pi()) == -1', function() {89 -1 assert.strictEqual(renderer.value('sin(3/2 * pi())'), '-1');90 -1 });91 -1 it('sin(1)', function() {92 -1 shared.similar(renderer.value('sin(1)'), Math.sin(1));93 -1 });94 -1 it('sin(2)', function() {95 -1 shared.similar(renderer.value('sin(2)'), Math.sin(2));96 -1 });97 -1 it('sin(-1)', function() {98 -1 shared.similar(renderer.value('sin(-1)'), Math.sin(-1));99 -1 });100 -1 it('sin(270deg) == -1', function() {101 -1 assert.strictEqual(renderer.value('sin(270deg)'), '-1')102 -1 });103 -1 });104 -1105 -1 describe('cos', function() {106 -1 it('cos(0) == 1', function() {107 -1 assert.strictEqual(renderer.value('cos(0)'), '1')108 -1 });109 -1 it('cos(1)', function() {110 -1 shared.similar(renderer.value('cos(1)'), Math.cos(1));111 -1 });112 -1 it('cos(-2)', function() {113 -1 shared.similar(renderer.value('cos(-2)'), Math.cos(-2));114 -1 });115 -1 it('cos(270deg) == 0', function() {116 -1 assert.strictEqual(renderer.value('cos(270deg)'), '0')117 -1 });118 -1 });119 -1120 -1 describe('tan', function() {121 -1 it('tan(0) == 0', function() {122 -1 assert.strictEqual(renderer.value('tan(0)'), '0')123 -1 });124 -1 it('tan(1)', function() {125 -1 shared.similar(renderer.value('tan(1)'), Math.tan(1));126 -1 });127 -1 it('tan(-1)', function() {128 -1 shared.similar(renderer.value('tan(-1)'), Math.tan(-1));129 -1 });130 -1 it('tan(12345678.9)', function() {131 -1 shared.similar(renderer.value('tan(12345678.9)'), Math.tan(12345678.9));132 -1 });133 -1 it('tan(45deg) == tan(pi() / 4)', function() {134 -1 shared.similar(renderer.value('tan(45deg)'), Math.tan(Math.PI / 4));135 -1 });136 -1 });137 -1138 -1 describe('asin', function() {139 -1 it('asin(0) == 0', function() {140 -1 assert.strictEqual(renderer.value('asin(0)'), '0')141 -1 });142 -1 it('asin(0.1)', function() {143 -1 shared.similar(renderer.value('asin(0.1)'), Math.asin(0.1));144 -1 });145 -1 it('asin(0.5)', function() {146 -1 shared.similar(renderer.value('asin(0.5)'), Math.asin(0.5));147 -1 });148 -1 it('asin(0.9)', function() {149 -1 shared.similar(renderer.value('asin(0.9)'), Math.asin(0.9));150 -1 });151 -1 it('asin(1)', function() {152 -1 shared.similar(renderer.value('asin(1)'), Math.asin(1));153 -1 });154 -1 it('asin(-0.5)', function() {155 -1 shared.similar(renderer.value('asin(-0.5)'), Math.asin(-0.5));156 -1 });157 -1 it('asin(2) throws', function() {158 -1 assert.throws(function () {159 -1 renderer.value('asin(2)');160 -1 });161 -1 });162 -1 });163 -1164 -1 describe('acos', function() {165 -1 it('acos(1) == 0', function() {166 -1 assert.strictEqual(renderer.value('acos(1)'), '0')167 -1 });168 -1 it('acos(0.5)', function() {169 -1 shared.similar(renderer.value('acos(0.5)'), Math.acos(0.5));170 -1 });171 -1 it('acos(-0.5)', function() {172 -1 shared.similar(renderer.value('acos(-0.5)'), Math.acos(-0.5));173 -1 });174 -1 it('acos(2) throws', function() {175 -1 assert.throws(function () {176 -1 renderer.value('asin(2)');177 -1 });178 -1 });179 -1 });180 -1181 -1 describe('atan', function() {182 -1 it('atan(0) == 0', function() {183 -1 assert.strictEqual(renderer.value('atan(0)'), '0')184 -1 });185 -1 it('atan(0.5)', function() {186 -1 shared.similar(renderer.value('atan(0.5)'), Math.atan(0.5));187 -1 });188 -1 it('atan(-0.5)', function() {189 -1 shared.similar(renderer.value('atan(-0.5)'), Math.atan(-0.5));190 -1 });191 -1 it('atan(12345678.9)', function() {192 -1 shared.similar(renderer.value('atan(12345678.9)'), Math.atan(12345678.9));193 -1 });194 -1 });195 -1196 -1 describe('atan2', function() {197 -1 it('atan2(0, 1) == 0', function() {198 -1 assert.strictEqual(renderer.value('atan2(0, 1)'), '0')199 -1 });200 -1 it('atan2(1, 0)', function() {201 -1 shared.similar(renderer.value('atan2(1, 0)'), Math.atan2(1, 0));202 -1 });203 -1 it('atan2(0, -1)', function() {204 -1 shared.similar(renderer.value('atan2(0, -1)'), Math.atan2(0, -1));205 -1 });206 -1 it('atan2(-1, 0)', function() {207 -1 shared.similar(renderer.value('atan2(-1, 0)'), Math.atan2(-1, 0));208 -1 });209 -1 it('atan2(2, 0)', function() {210 -1 shared.similar(renderer.value('atan2(2, 0)'), Math.atan2(2, 0));211 -1 });212 -1 it('atan2(-1, -1)', function() {213 -1 shared.similar(renderer.value('atan2(-1, -1)'), Math.atan2(-1, -1));214 -1 });215 -1 });216 -1217 -1 describe('bezier', function() {218 -1 it('bezier((0 0, 1 1), 0.5) == 0.5 0.5', function() {219 -1 assert.strictEqual(renderer.value('bezier((0 0, 1 1), 0.5)'), '0.5 0.5');220 -1 });221 -1 it('bezier((0 0, 0.2 0.2, 1 1), 0.5) == 0.35 0.35', function() {222 -1 assert.strictEqual(renderer.value('bezier((0 0, 0.2 0.2, 1 1), 0.5)'), '0.35 0.35');223 -1 });224 -1 it('bezier((0 0, 0.5 0.2, 1 1), 0.5) == 0.5 0.35', function() {225 -1 assert.strictEqual(renderer.value('bezier((0 0, 0.5 0.2, 1 1), 0.5)'), '0.5 0.35');226 -1 });227 -1 it('bezier((0, 1), 0.5) == 0.5', function() {228 -1 assert.strictEqual(renderer.value('bezier((0, 1), 0.5)'), '0.5');229 -1 });230 -1 it('bezier((0, 2), 0.5) == 1', function() {231 -1 assert.strictEqual(renderer.value('bezier((0, 2), 0.5)'), '1');232 -1 });233 -1 it('bezier((0 0 0, 1 1 1), 0.5) == 0.5 0.5 0.5', function() {234 -1 assert.strictEqual(renderer.value('bezier((0 0 0, 1 1 1), 0.5)'), '0.5 0.5 0.5');235 -1 });236 -1 });237 -1 });