【Dart Sass対応】scssによる三角関数(cos,sin等)の取扱う方法 〜 基礎から応用まで


※ 当ページには【広告/PR】を含む場合があります。
2020/03/29
2021/06/07
【CSS/Sass】box-shadowプロパティでパーティクルを生成してみる
蛸壺の技術ブログ|scssによる三角関数(cos,sin等)の取扱う方法 〜 基礎から応用まで

Sass/scssは、使いこなすと何かと便利なcss言語プリプロセッサです。

nodejsでSassを扱いたい方向けには、
node-sassという選択肢があります。

node-sassを使えば、以下のコマンドでお手元の環境にsassを直ぐにでも構築できます。

            
            $ npm install node-sass
#OR
$ yarn add node-sass
        
以前以下のリンクでも特集しましたが、既にnode-sass(libsass)はSass公式から推奨されないライブラリ扱いになってしました。

合同会社タコスキングダム|蛸壺の技術ブログ
[LibSass非推奨化] node-sassとのお別れ ~ Dart Sassへ移行する

LibSassからdart-sassをサクッと移行する方法を解説します。

既にnodejsユーザーでDart Sassへお引越しした方は、このブログの首題でもあった三角関数(sin/cos/tan等)が自作せずとも組込み関数として利用できるようになりましたが、袂を分かれたとはいえnode-sassも独自の実装とメンテナンスが今も継続しています。

node-sassユーザー向けとして以下で三角関数の実装方法を説明していきます。

またDart SassユーザーにとってもSassを用いた数学関数の実装方法の何かしらの参考になると思います。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】CSS/Sassをこれから学びたい人のためのオススメ書籍&教材特集

Scssで独自関数を扱うための基本

まずはsassを用いた三角関数を実装して行く前に、基礎的な知識をざっとおさらいしておきます。

ローカル変数 ($)

独自の変数を定義したい場合、
$記号の後に変数名を記述して用います。

            
            $str: 'a strong guy';
$val: 1;
        
という用法で、:によって変数に紐つけされることに慣れましょう。変数は入れ子にもできて、上のソースコードをに続けて、

            
            $str: 'I am ' + $str; // I am a strong guy
$val: $val * 2; // 2
        
というかんじに利用します。

@function (関数)

何らかの値を返したい場合は、独自の@functionを定義する必要があります。例えば、円周率を返す関数を定義すると、

            
            @function pi() {
    @return 3.14159265359;
}
        
と定義できます。引数をとる関数を定義する場合は、

            
            @function add_one($num) {
    @return $num + 1;
}
        
sassでは、引数に明示に型を記述することはできないので、注意が必要です。実際には、変数の型(number, string, list, ...)など気を付けないと、演算時に思わぬ落とし穴にハマることがあります。

なお、
ビルドイン関数`comparable`で、演算可能かどうか判定できるので、デバック時に活用できます。

関数を使うときの呼び出し

上の関数を呼び出してみます。

            
            $init_val: 1;
$init_val: add_one($init_val); // 2
$init_val: add_one($init_val); // 3
$init_val: add_one($init_val); // 4

$init_val: $init_val / $init_val; // 1

$init_val: $init_val * pi(); // 3.14159265359

$init_val: $init_val - pi(); // 0

$init_val: $init_val + pi(); // 3.14159265359

$init_val: $init_val % 3; // 0.14159265359
        
上の用に、関数を定義した後に呼び出して使うことが可能です。四則演算の詳細に関しては割愛します。

配列 (list)

sassでは配列ライクな
Listというものを使うことができます。釘カッコ[]でなく、丸カッコ()で取り扱うので、配列というよりタプルっぽく感じる…ので何だか抵抗感ありますが、これが配列として扱うことができます。

基本的な用法を以下に示します。

            
            $hoge_list: (0, 1, 2, 3, 4);

$len: length($hoge_list); // 5

$val: nth($hoge_list, 1); // 0
$val: nth($hoge_list, 2); // 1
$val: nth($hoge_list, 3); // 2
$val: nth($hoge_list, 4); // 3
$val: nth($hoge_list, 5); // 4
        
このコードでは$hoge_listに対して、リストの全要素数をビルドイン関数lengthで取り出しています。

また、先頭からの要素順で値を取得するビルドイン関数
nthもよく使うと思います。ただし、要素番号の指定は、先頭を1から初めることに注意してください。

@for

上の配列を
@forを使って、イテレーションしてます。

            
            $hoge_list: (0, 1, 2, 3, 4);

$val: 0;
@for $i from 1 through length($hoge_list) {
    $val: nth($hoge_list, $i);
}
        
によって、繰り返し処理ができました。なお、ループ内(波括弧{}の中)で、便宜上用いている変数$valは、変数スコープの関係上、ループより手前に記述しておかないと、'Undefined variable'として警告されてしまいますので気を付けましょう。

@if

sassでは、if文も備わっているので、以下の様に条件分岐を記述できます。

            
            $result: '';

$mode: 1;
@if $mode == 0 {
    $result: 'Good';
} @else if $mode == 1 {
    $result: 'Not bad';
} @else {
    $result: 'Worst';
}
        
上のソースでは、$resultに'Not bad'が格納されて処理されます。

@debug

sassを開発して行く場合、せめてjsいうところの
console.logっぽい機能が最低限度欲しくなります。

そんな時に使うのが、ビルドイン
@debugです。

こいつはどこにでもおけますので、デバック中に気になった箇所に挿入しましょう。すると、ビルドの際にターミナル上に出力される仕様です。

            
            $misterous_val: 'Unknown';

// ...

@debug $misterous_val; // Unknown
        

合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】CSS/Sassをこれから学びたい人のためのオススメ書籍&教材特集

実装編その1 〜 テイラー展開法による三角関数を作る

前節までは、sassでの基本構文・テクニックをおさらいしました。それではそれらを用いてSassコードに三角関数を実装して行きます。

最初に三角関数の計算アルゴリズムで、パッと思い浮かぶのはテイラー展開による求解です。

とりあえず、
ココのサイトを参考に自分で噛み砕き、独自関数として実装していきます。

テイラー展開式とは

数学使うのなんて久しぶりな方にざっとテイラー展開がどんなのだったかおさらいです。

sinx\sin x, cosx\cos xは以下の数式で求めることができます。

sinx=n=0(1)n(2n+1)!x2n+1=xx33!+x55!\sin x = \displaystyle\sum_{n=0}^{\infty} \frac{(-1)^n}{(2n+1)!} x^{2n+1} = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \dotsEq. (1)

cosx=n=0(1)n(2n)!x2n=1x22!+x44!\cos x = \displaystyle\sum_{n=0}^{\infty} \frac{(-1)^n}{(2n)!} x^{2n} = 1 - \frac{x^2}{2!} + \frac{x^4}{4!} - \dotsEq. (2)

ということで、これら式(1)、式(2)とも、計算を実行するには、指数計算のパート(
x2n+1x^{2n+1}など)と、階乗計算のパート((2n)!(2n)!など)を計算できるように補助的な関数を定義しておきましょう。

指数計算するための関数

この関数は整数をとる指数計算なので、悩む必要はないでしょう。以下のようにズバッと関数を書きます。

            
            @function pow($bs, $exp) {
    $val: $bs;
    @if $exp > 1 {
        @for $i from 2 through $exp {
            $val: $val * $bs;
        }
    } @else if $exp < 1 {
        @for $i from 0 through -$exp {
            $val: $val / $bs;
        }
    }
    @return $val;
}
        
なおx1=xx^1 = xですので、指数が1の場合には分岐処理されることなくそのまま素通りで値が返ります。

階乗の計算

こちらも上と同じように特に留意する点もなく以下のように書き下させます。

            
            @function fact($num) {
    $val: 1;
    @if $num > 0 {
        @for $i from 1 through $num {
        $val: $val * $i;
        }
    }
    @return $val;
}
        

角度からラジアンへの変換

上記の式(1)、式(2)とも変数はラジアンをとりますが、独自関数として呼び出す際には、角度表示で使う方が感覚的な面で利便性が良いのが確かです。そんな時は、sassのビルドイン関数
unit()で単位を取得させることで、角度(deg)か、ラジアン(rad)かを判別し、後続の関数に渡す橋渡しを作成しておくと良いようです。

            
            @function pi() {
    @return 3.14159265359;
}

@function rad($angle) {
    $unit: unit($angle);
    $val: $angle / (1 + 0 * $angle);
    // 変数に角度(deg)が渡されていると、ラジアンに変換
    // それ以外は、問答無用でラジアン
    @if $unit == "deg" {
        $val: $val / 180 * pi();
    }
    @return $val;
}
        

三角関数の計算

以上をもとに三角関数のテイラー展開式を実装しようと思います。

            
            $accuracy: 10; // 計算精度

@function sin($angle) {
    $theta: rad($angle);
    $sin: $theta;
    @for $n from 1 through $accuracy {
      $sin: $sin + pow(-1, $n) / fact(2 * $n + 1) * pow($a, 2 * $n + 1);
    }
    @return $sin;
}

@function cos($angle) {
    $a: rad($angle);
    $cos: 1;
    @for $n from 1 through $accuracy {
        $cos: $cos + pow(-1, $n) / fact(2 * $n) * pow($a, 2 * $n);
    }
    @return $cos;
}
        
それでは関数の検証のため、0°から90°の範囲で10°ずつずらして計算値の方を出してみましょう。

            
            // ...
@for $s1 from 0 through 9 {
    $angle: 10deg * $s1;
    @debug $angle, sin($angle), cos($angle);
    }
// ...
        
出力結果は…

            
            DEBUG: 0deg, 0, 1
DEBUG: 10deg, 0.1736481777, 0.984807753
DEBUG: 20deg, 0.3420201433, 0.9396926208
DEBUG: 30deg, 0.5, 0.8660254038
DEBUG: 40deg, 0.6427876097, 0.7660444431
DEBUG: 50deg, 0.7660444431, 0.6427876097
DEBUG: 60deg, 0.8660254038, 0.5
DEBUG: 70deg, 0.9396926208, 0.3420201433
DEBUG: 80deg, 0.984807753, 0.1736481777
DEBUG: 90deg, 1, 0
        
と、それらしい値がテーラー展開法で得られました。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】CSS/Sassをこれから学びたい人のためのオススメ書籍&教材特集

実装編その2 〜 CORDICアルゴリズムで三角関数を作る

一通りは上記までの内容で三角関数が実装できたのですが、個人的な感想では、sassでゴリゴリとテイラー展開やらせるのは思うほど実用性がないんではないか…とプログラムを走らせながら感じました。

当初は、Sassはプリプロセッサなのでどんなに前処理が重くても、最終生成物のcssにきちんと計算した座標が書き込めてれば問題ないんではないか、と思っておりました。でも、cssなどでパーティクルなど描画座標を計算させればさせるほど、何かビルド中に問題があるようで…生成されたcssコードが壊れていて描画できないブラウザでエラーを吐いてしまうことも...。

深くプリプロセッサ側の問題を追求しませんでしたが、このテイラー展開法をそのまま使うのは厳しいそうだなぁと判断し、また別の方法を模索します。

という訳で、もっと実用的で軽量な別の計算アルゴリズムとして、
CORDICアルゴリズムでのscssコード実装方法を考えてみました。

ちょっとだけCORDICアルゴリズムの解説

いきなり話は逸れますが、私が高校生の頃なんて行列が数学の必修としてあったので、
まさか2012年度以降は'行列'が必修分野から外れていた…なんてのをここ最近知りました。

さて、CORDICアルゴリズムを理解する上で、個人的に行列論には昔からかなりのこだわりがありやはり'行列'を使って厳密に…といきたいですが、
複素数で丁寧にCORDICの説明を解説されている方の記事がありまして、本ブログの拙い内容で説明させていただくこともないだろうな、という結論に至りました。CORDICの導出方法は是非そちらの内容をご参照下さい。

なお、
'複素数'もわからんという方向けに、初等幾何の知識でCORDICのアルゴリズムの説明をされておられる猛者もいらっしゃいます。サインコサインぐらいは分かるよー、という方は是非こちらの内容をみて理解されて下さい。

いきなりですが、複素平面上で得られる結論の式だけ、書き出させていただきます。

複素平面上のある点
p+qip+qiθc=tan1(1/2n)\theta_c = \tan^{-1} (1/2^n)だけ反時計回りに回す操作は次のようになります。ただし、n=0,1,2,n = 0, 1, 2, \dotsをとる非負の整数です。nnは増やせば増やすほど計算精度が上がります。

(p+qi)(1+12ni)=pq(1/2n)+{p(1/2n)+q}iSc(p+qi) \cdot (1 + \frac{1}{2^n}i) = \frac{p - q(1/2^n) + \{p(1/2^n) + q \}i}{S_c}Eq. (3)

一方で、時計回りの回転が次の式で求めることができます。

(p+qi)(112ni)=p+q(1/2n)+{p(1/2n)+q}iSc(p+qi) \cdot (1 - \frac{1}{2^n}i) = \frac{p + q(1/2^n) + \{ - p(1/2^n) + q \}i}{S_c}Eq. (4)

ここでの
ScS_cは式左辺の実部を規格化する正の実数で、Sc=1/cosθcS_c = 1/\cos \theta_c を満たします。

θc=tan1(1/2n)\theta_c = \tan^{-1} (1/2^n)の部分に着目すると、何故2で割れるような数値を繰り返し計算の部分に採用しているかというと、CORDICアルゴリズムは誕生から60年以上も立っている古き良きで当時としては、四則演算も計算リソースへの負荷が高く、軽量なビット演算で÷2\div 2を利用できるようにとのようです。

Sassでビット演算できるのか?

現在のところ、Sass標準で残念ながらビット演算はサポートされていません。

少し古いプロジェクトで
Bitwise operators in Sassっぽいものはあったのですが、お遊び程度に使ってね、とのことですので、Sass単独でのビット演算を実装するには(私個人の能力として)現実的ではなさそう…と思います。

ということは、ビット演算を使わずもうただの数値の割り算をするのと変わらないのなら、
'2で割る'計算に拘る必要もないので、'自分の好みの数で割って'も良い、と言えます。

改良CORDICの方法は後述します。

CORDICアルゴリズムの実装

それでは、奇を衒う前に、オーソドックスなCORDICアルゴリズムをsassで実装していきましょう。まずは、既知として利用できる数値を連想配列で準備しておきます。

要素のキーの名前を
nnのインデックスに合わせておきます。各値は、配列形式で与え、1番目の要素にはθc\theta_cと、2番目に2n2^nをあらかじめ計算値としてセットしておきます。

            
            $cordic_dataset: (
    0: (45, 1),
    1: (26.56505118, 2),
    2: (14.03624347, 4),
    3: (7.125016349, 8),
    4: (3.576334375, 16),
    5: (1.789910608, 32),
    6: (0.8951737102, 64),
    7: (0.4476141709, 128),
    8: (0.2238105004, 256),
    9: (0.1119056771, 512),
    10: (0.05595289189, 1024),
    11: (0.02797645262, 2048),
    12: (0.01398822714, 4096),
    13: (0.006994113675, 8192),
    14: (0.003497056851, 16384),
    15: (0.001748528427, 32768),
    16: (0.0008742642137, 65536),
    17: (0.0004371321069, 131072),
    18: (0.0002185660534, 262144),
);

$s_all: 1.646760258;
        
また、今回の計算コード例で言えば、データセット$cordic_datasetの総要素数の19回分だけ、式(3)と式(4)のどちらか計算されます。結局、式の性質上ScS_cは独立して掛け算の累積値を保持しておけば、計算の最後に補正値として掛けこむだけで良いので、

Sall=n=018θc=1.646760258S_\mathrm{all} = \displaystyle\prod_{n = 0}^{18} \theta_c = 1.646760258Eq. (5)

とできるので、これを定数として与えておきます。

範囲制限を考慮した補正

CORDICアルゴリズムの弱点として、0°から90°の間での三角関数の値を返すことになります(表の
θc\theta_cを試しに全部足していただいたらわかります)。ですので、あらゆる角度に対応させるためには、関数対称性を使った一工夫が必要です。

            
            @function check_domain($angle) {
    $reduced_angle: $angle % 360;
    $result: (0, 0, 0);
    $constraint_angle: $reduced_angle % 90;

    @if ($reduced_angle >= 0) and ($reduced_angle < 90) {
        $result: ($constraint_angle, 1, 1);
    } @else if ($reduced_angle >= 90) and ($reduced_angle < 180) {
        $result: (90 - $constraint_angle, -1, 1);
    } @else if ($reduced_angle >= 180) and ($reduced_angle < 270) {
        $result: ($constraint_angle, -1, -1);
    } @else {
        $result: (90 - $constraint_angle, 1, -1);
    }
    @return $result;
}
        
上記の関数を用いれば、任意の角度を、1番目の要素で0°から90°の範囲におとし込めた値、2,3番目の要素に各象限を表す2つの極性を割り当てた配列を返します。

CORDICコード

それでは、CORDICアルゴリズムを実装してみます。

            
            @function cossintan($angle, $mode) {
    $modifier: check_domain($angle);
    $p_c: 1 / $sum_all;
    $q_c: 0;
    $theta: 0;
    $p_next: 0;
    $q_next: 0;
    $result: 0;

    @for $n from 1 through length($cordic_dataset) {
        $coeffecient: nth(nth($cordic_dataset, $n), 2);
        @if nth($modifier, 1) > $theta {
            $p_next: $p_c - ($q_c / nth($coeffecient, 2));
            $q_next: $q_c + ($p_c / nth($coeffecient, 2));
            $theta: $theta + nth($coeffecient, 1);
        } @else {
            $p_next: $p_c + ($q_c / nth($coeffecient, 2));
            $q_next: $q_c - ($p_c / nth($coeffecient, 2));
            $theta: $theta - nth($coeffecient, 1);
        }
        $p_c: $p_next;
        $q_c: $q_next;
    }

    @if $mode == 0 {
        $result: $p_c * nth($modifier, 2); // cos
    } @else if $mode == 1 {
        $result: $q_c * nth($modifier, 3); // sin
    } @else {
        $result: $q_c / $p_c * nth($modifier, 2) * nth($modifier, 3); // tan
    }
    @return $result;
}
        
ちなみに、この関数の第2引数で、0指定でcos、1指定でsin、2指定でtanが計算できるようにしましたが、使い勝手に応じてお好みで変更してください。

検証

どこかの要素のスタイルにでも、以下のテストを貼り付けます。

            
            @for $t from 0 through 18 {
    $angle: 10 * $t;
    @debug unquote('angle:') $angle, unquote('cos:') cossintan($angle, 0), unquote('sin:') cossintan($angle, 1);
}
        
ビルドすると、コンソールに計算結果が出力されます。

            
            DEBUG: angle: 0, cos: 1.0000000001, sin: -0.0000014786
DEBUG: angle: 10, cos: 0.9848072373, sin: 0.1736511027
DEBUG: angle: 20, cos: 0.9396914558, sin: 0.3420233442
DEBUG: angle: 30, cos: 0.8660238404, sin: 0.500002708
DEBUG: angle: 40, cos: 0.7660461494, sin: 0.6427855763
DEBUG: angle: 50, cos: 0.6427855763, sin: 0.7660461494
DEBUG: angle: 60, cos: 0.500002708, sin: 0.8660238404
DEBUG: angle: 70, cos: 0.3420233442, sin: 0.9396914558
DEBUG: angle: 80, cos: 0.1736511027, sin: 0.9848072373
DEBUG: angle: 90, cos: -0.0000014786, sin: 1.0000000001
DEBUG: angle: 100, cos: -0.1736511027, sin: 0.9848072373
DEBUG: angle: 110, cos: -0.3420233442, sin: 0.9396914558
DEBUG: angle: 120, cos: -0.500002708, sin: 0.8660238404
DEBUG: angle: 130, cos: -0.6427855763, sin: 0.7660461494
DEBUG: angle: 140, cos: -0.7660461494, sin: 0.6427855763
DEBUG: angle: 150, cos: -0.8660238404, sin: 0.500002708
DEBUG: angle: 160, cos: -0.9396914558, sin: 0.3420233442
DEBUG: angle: 170, cos: -0.9848072373, sin: 0.1736511027
DEBUG: angle: 180, cos: -1.0000000001, sin: 0.0000014786
        
...テイラー展開の解法と比べて、計算精度のほどはお察しですが、計算負荷も少なく軽量になった分実用的かと思います。cssはhtmlデザインの為の言語ですので、0.000001ピクセルの違いが気にならない限りは、さほどの厳密性は見過ごしてあげても良いと思います。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】CSS/Sassをこれから学びたい人のためのオススメ書籍&教材特集

実装編その3 〜 改良版!CORDICアルゴリズムで三角関数を作る

ここまでで、CORDICアルゴリズムで三角関数の解を求められるようなプログラムをsassで実装しましたが、更にやりながら個人的に気になった点を改良したCORDICコードもご説明しましょう。なお、改良CORDICアルゴリズムでちょっとだけ計算ステップが早くなることが期待されます。

式をちょっと修正

繰り返しになりますが、Sassではビット演算が標準で利用できません。なのでそのままだと、従来のCORDICアルゴリズムでの
θc=tan1(1/2n)\theta_c = \tan^{-1} (1/2^n)としていた部分が特に意味をなさなくなります。逆にいうと、sassで計算させる上では、自分で好きなように弄くって良いと言えます。

ここでは、試しに
n=0,1,n = 0, 1, \dotsの計算ステップが大きくなるのと連動して、θc\theta_cが細かくなるように以下の式で表現してみましよう。

θc=tan1{1(n+1)n}\theta_c = \tan^{-1} \bigl\{ \frac{1}{(n+1)^n} \bigr\}Eq. (6)

これにより、従来のCORDICアルゴリズムよりも細かい刻みの回転子が得られました。この式をベースにコーディングをしていきます。

Sassの@while文を利用する

実は、sassでもwhileループが存在します。

この
@whileを利用することで、@forよりも複雑な処理を記述できます。

先ずはあらかじめ保持すべきデータセットを以下のような連想配列で用意していきます。今回の改良コードでは
@whileループ内で自由度の高い演算をする為、従来の単縦な累積値であったSallS_\mathrm{all}が利用できません。

よって、データセット内に規格化定数
Sc=1/cosθcS_c = 1/\cos \theta_cを第3引数に保持させています。

            
            $cordic_dataset: (
    0:  (            45,            1, 1.414213562),
    1:  (   26.56505118,            2, 1.118033989),
    2:  (   6.340191746,            9, 1.006153904),
    3:  (  0.8951737102,           64, 1.000122063),
    4:  ( 0.09167316899,          625,  1.00000128),
    5:  (7.368284362e-3,         7776, 1.000000008),
    6:  (4.870060902e-4,       117649,           1),
    7:  (2.732075668e-5,      2097152,           1),
    8:  (1.331013796e-6,     43046721,           1),
    9:  (5.729577951e-8,          1e9,           1),
    10: (      2.209e-9, 2.5937425e10,           1)
);
        
このデータをみると、n=10n=10程度のステップでも、かなりθc\theta_cの値が細かく取れていることがわかります。

それでは前回のCORDICメソッドを改良するかたちで、各ステップの
θc\theta_cの差分が10810^{-8}以下を満たすまで三角関数の値を求めるプログラムの例を以下に示します。

            
            @function cordic_2($angle, $mode) {
    $modifier: check_domain($angle);
    $p_c: 1;
    $q_c: 0;
    $p_next: $p_c;
    $q_next: $q_c;

    $result: 0;

    $delta: nth($modifier, 1);
    $stage_index: 1;
    $upper_limit: length($cordic_dataset);
    $resolution: 1e-8;

    @while $delta > $resolution {
        $coefficient: nth(nth($cordic_dataset, $stage_index), 2);
        @if $delta >= nth($coefficient, 1) {
            $p_next: ($p_c - $q_c / nth($coefficient, 2)) / nth($coefficient, 3);
            $q_next: ($q_c + $p_c / nth($coefficient, 2)) / nth($coefficient, 3);
            $delta: $delta - nth($coefficient, 1);
        } @else {
            $stage_index: $stage_index + 1;
            @if $stage_index > $upper_limit {
                $delta: $resolution;
            }
        }
        $p_c: $p_next;
        $q_c: $q_next;
    }

    @if $mode == 0 {
        $result: $p_c * nth($modifier, 2); // cos
    } @else if $mode == 1 {
        $result: $q_c * nth($modifier, 3); // sin
    } @else {
        $result: $q_c / $p_c * nth($modifier, 2) * nth($modifier, 3); // tan
    }
    @return $result;
}
        
ちなみにさらなる精度を求められる場合には、データセットのステップ毎の値を増やす必要がありますのでその点はご留意ください。

この関数を実行してみますと、

            
            @for $s1 from 0 through 9 {
    $angle: 10 * $s1;
    @debug unquote('angle:') $angle, unquote('cos:') cordic_2($angle, 0), unquote('sin:') cordic_2($angle, 1);
}
        
実行結果は

            
            DEBUG: angle: 0, cos: 1, sin: 0
DEBUG: angle: 10, cos: 0.9848077558, sin: 0.173648178
DEBUG: angle: 20, cos: 0.9396926244, sin: 0.3420201445
DEBUG: angle: 30, cos: 0.8660254039, sin: 0.4999999998
DEBUG: angle: 40, cos: 0.7660444442, sin: 0.6427876103
DEBUG: angle: 50, cos: 0.6427876113, sin: 0.7660444447
DEBUG: angle: 60, cos: 0.5000000017, sin: 0.8660254065
DEBUG: angle: 70, cos: 0.3420201443, sin: 0.9396926231
DEBUG: angle: 80, cos: 0.1736481781, sin: 0.9848077543
DEBUG: angle: 90, cos: 0, sin: 1.0000000005
        
と、従来のCORDICよりも、少ないステップ数で精度もグッと良くなって出力されます。計算は少し重くなっておりますが精度とのトレードオフです。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】CSS/Sassをこれから学びたい人のためのオススメ書籍&教材特集

まとめ

以上、テーラー展開法による三角関数の求解アルゴリズムと、CORDICアルゴリズムでの求解法を2つに関してSassで実装する方法をご紹介しました。

何はともあれ、LibSass単独で三角関数を使えるようになったので、色々とデザイン的な応用に重宝できると思います。

また、
sin/cos/tan関数がカスタマイズできるので、他のマニアックな数学関数も自分で設計・構築できるはずです。
記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。

合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】CSS/Sassをこれから学びたい人のためのオススメ書籍&教材特集