DTPab

印刷やデザイン、アドビ製アプリやスクリプトなど、雑多な技術ブログ

微小な誤差にハマった

テキストフレームの座標を比較して順序をソートするメソッドを仕込んでおいたのに、どうしても順序が正しく並び替えられない…という事態に遭遇して解決したのでメモ。
改めて勉強になりました…。

オチ

UI上、絶対に目視では確認できない微小な誤差(-5.6843418860808e-14)が発生していた。
どういうことかというと下図のとおり。

それぞれ163という値だが、差が0にならない

e-14とはなんぞや

指数表記です。
5e-14は 5 * 10-14 になります。

回避するには

要するに、VS Codeのデバッガー上もそこまで小さな値は端折って表示されていた(当然InDesignのUI上もそんな小さな値まで表示されない)。

Array.sort()メソッドの中で、取得する値をある程度の概数にするほかないんだけど、方法論としては2つ考えた。

  1. 値を取得するタイミングで概数にして変数に渡す(その変数の差を取る)
  2. 値はそのまま取得して差を取得したものを概数にする

JavaScriptの浮動小数点にまつわる問題は計算のタイミングで起きるよな、と思って、前者で対応することにした。具体的には小数点以下3桁が有効になるように四捨五入。

found.sort(function (a, b) {
    var digits = 3;
    var roundA = Math.round(a * Math.pow(10, digits)) / Math.pow(10, digits);
    var roundB = Math.round(b * Math.pow(10, digits)) / Math.pow(10, digits);
    return roundA - roundB;
});

みたいな感じ。
実際にはgeometricBounds相手だったのでもうちょっと複雑でした。

参考文献