たいしたことないネタでもちょいちょい記事を書いてみることにします。今日はホーナー法について。
多項式を計算する際、乗法の回数を削減することができます。上記リンク先によると、19世紀からある方法のようです。
やり方はとてもシンプルです。以下のような多項式があるとします。
これを、次のように変形するだけです。
JavaScriptで実装すると、以下のような感じになります。
var horner = (coeffs = [], x) => coeffs.reduce((a, b) => a * x + b, 0);
もしくは、簡潔さより高速さということであれば、以下のような感じでしょうか。
var horner = (coeffs = [], x) => { var r = coeffs[0]; for (let i = 1, l = coeffs.length; i < l; i++) r = r * x + coeffs[i]; return r; }
第一引数には、]の順に係数の配列を渡します。
実際のところ、べき乗の計算は効率的なアルゴリズムが知られているため、素直に展開形を実装するのに比べて、ホーナー法でそこまでの高速化は期待できません。 ただ、特に小数がある場合、計算精度の向上を望めます。
また、FMA (Fused Multiply-Add) をサポートしている環境では、更なる精度向上が期待できそうです。
例えばJuliaはfma()
関数を呼び出すことで、CPUが対応していればFMAを使うことができます。
function horner(coeffs, x) r = coeffs[1] for i in 1:length(coeffs) r = fma(r, x, coeffs[i]) end r end
FMAについては、以下のブログ記事が参考になりました。
ちなみに、JuliaについてはBase.Math
中に@horner(x, p...)
というマクロが予め定義されているようです。
以下のようにして呼び出すことができます。
julia> using Base.Math: @horner julia> a0, a1, a2 = 0.123, 0.234, 0.345 julia> x = 0.999 julia> @horner x a0 a1 a2 0.701076345
とても簡単に使えるアルゴリズムなので、ぜひ活用したいです。
以下の本を参考に書きました。
[改訂新版]C言語による標準アルゴリズム事典 (Software Technology)
- 作者: 奥村晴彦
- 出版社/メーカー: 技術評論社
- 発売日: 2018/04/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る