メモの日々


2019年05月21日(火) [長年日記]

[math] 相対誤差

相対誤差の定義をメモ。

近似値xの真値Tに対する相対誤差は、

\Large | \frac{T - x}{T} |

で求める。Tが0の場合には計算できないことに注意。

[ruby] test-unitでの浮動小数点の比較

test-unitで浮動小数点の値を比較するためのアサーションをメモ。

test-unitで使えるアサーションの一覧は

を見るとわかる。この中で、浮動小数点比較用のアサーションは次の4つになると思われる。

_in_deltaは絶対誤差、_in_epsilonは相対誤差で誤差の許容範囲を指定する。


2019年05月08日(水) [長年日記]

[c++] reverse_iteratorが指す要素の削除

reverse_iteratorが指す要素の削除方法をメモしておく。Effective STLの第28項「reverse_iteratorの基底iteratorの使い方を理解しよう」に説明がある。

  • コンテナのerase()メソッドはreverse_iteratorを受け付けないので、reverse_iteratorのbase()メソッドによりiteratorオブジェクトを取得する必要がある。
  • base()が返すイテレータが指す要素はreverse_iteratorが指す要素からend()方向に1つずれているので、erase()に渡す際にはイテレータの位置を調整する必要がある。調整には (++rit).base() のようにreverse_iteratorを1つ進めてからbase()を呼ぶべしとEffective STLにある。
 rend()                         rit                         rbegin()
       +-------+-------+-----+-------+-------+-----+-------+-------+
       |   a   |   b   | ... |   h   |   i   | ... |   y   |   z   |
       +-------+-------+-----+-------+-------+-----+-------+-------+
         begin()                     rit.base()                      end()
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

int main()
{
  std::vector<int> v(10);
  std::iota(v.begin(), v.end(), 1);

  auto rit = std::find_if(
      v.rbegin(),
      v.rend(),
      [](int i) { return i % 3 == 0; });
  if (rit != v.rend()) {
    // reverse_iterator::base()が返すイテレータは指す要素が異なるので調整が必要
    // see Effective STL 第28項
    v.erase((++rit).base());
  }

  for (const auto& e : v) {
    std::cout << e << " ";
  }
  std::cout << std::endl;
}
1 2 3 4 5 6 7 8 10

2019年04月17日(水) [長年日記]

[web] テーブルにスクロールバーを付ける (2)

HTMLのtable要素で作るテーブルが縦に長い場合に、テーブルにスクロールバーを表示しかつスクロールしても行ヘッダが見えたままになるようにしたい。できればJavaScriptは使わずに。

14年前に同様のことをメモしたのだけれど、そのときの結果を今試しても想定通りには動かない。

CSSの「position: sticky」を使うと実現できるようなのでメモしておく。動作はFirefox 66とChrome 73で確認。

テーブルの高さが固定の例

テーブルの高さを固定にする場合はわりと簡単に実現できた。

スクロールバーはtable要素ではなくそれを囲むdiv要素が表示することに注意。HTMLとCSSを抜粋すると次のような感じ。

    <div class="table-wrapper">
        <table>
        ...
        </table>
    </div>
    .table-wrapper {
        display: inline-block;
        height: 300px;
        overflow: auto;
    }
    th {
        background-color: orange;
        position: sticky;
        top: 0;
    }
  • テーブルの高さを決める要素(上の例ではclassがtable-wrapperのdiv要素)にCSSでheightを設定し、table要素はこの要素の中に配置する。
  • th要素にCSSでstickyを設定する。
  • そのままだとスクロールした時にテーブルのヘッダとボディの文字が重なって表示されてしまうので、th要素には背景色を設定する。
  • table-wrapperクラスをinline-blockにしているのは、幅を内容(table要素)の幅に合わせるため。ただ、こうするとFirefox 66ではテーブルの幅が狭くなりすぎてしまう模様。

なお、Firefox 66ではヘッダのセル間に線を描画するためにtable要素のborder-collapseをseparateにする必要があった(上の抜粋には含めていない)。

テーブルの高さをブラウザのウィンドウの高さと連動させる例

テーブルの高さは、固定ではなくブラウザのウィンドウの高さと連動するようにしたいことが多いのでそのケースもメモ。

HTMLとCSSを抜粋する。HTMLは前の例と同じなのだけれど、table-wrapperを囲むdivにもスタイルを設定するのでその部分を含めて抜粋し直す。

    <div class="container">
        <h1>テーブルにスクロールバーを付ける</h1>
        <h2>テーブルの高さがウィンドウの高さに連動する例</h2>
        <div class="table-wrapper">
            <table>
            ...
            </table>
        </div>
    </div>
    .container {
        position: absolute;
        bottom: 10px;
        top: 10px;

        display: flex;
        align-items: start;
        flex-flow: column nowrap;
    }
    .table-wrapper {
        overflow: auto;
    }
    th {
        background-color: orange;
        position: sticky;
        top: 0;
    }
  • table-wrapperの親要素(上の例ではclassがcontainerのdiv要素)に「position: absolute」と「display: flex」を指定する。これにより、table-wrapperの高さがウィンドウの高さと連動するようになる。
  • table-wrapperにはinline-block指定やheightの指定は不要になる。

2019年04月05日(金) [長年日記]

[c++] 二分探索にはstd::partition_point()が使える

C++で二分探索を行いたいときはstd::lower_bound()を使っていたが、C++11で導入されたstd::partition_point()を使えばより柔軟に二分探索が行えることを知った。

lower_boundはpartition_pointの特殊なケースに過ぎない。

lower_boundは使えずpartition_pointなら使える例として、次を行うコードを示す。

  • 文字列長を基準にソートされた文字列配列から、特定の文字列長の文字列を二分探索で見つける
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

template<typename Langs>
std::string f(const Langs& langs, int length)
{
  const auto it = std::partition_point(
      std::cbegin(langs),
      std::cend(langs),
      [length](const auto& s) { return s.size() < length; });
  return it == std::end(langs) ? "" : *it;
}

int main()
{
  std::vector<std::string> langs = {
    "c", "c++", "go", "rust", "c#", "java", "swift", "python", "ruby", "javascript"
  };
  std::sort(
      std::begin(langs),
      std::end(langs),
      [](const auto& lhs, const auto& rhs) { return lhs.size() < rhs.size(); });
  std::cout << f(langs, 3) << std::endl;
  std::cout << f(langs, 7) << std::endl;
}
c++
javascript

2019年03月19日(火) [長年日記]

[ruby] test-unit-runner-junitxmlをリリースした

Rubyのtest-unitのテスト結果をJUnit XML形式で出力するためのライブラリをリリースした。

実際に作ったのは5年くらい前で、テスト結果をJenkinsに登録するために使っていたもの。現在において需要があるかは疑問だけれど、gemになっていた方が自分が便利なので公開した。

次のようにして使う。

# test.rb
require "test/unit/runner/junitxml"

class MyTest < Test::Unit::TestCase
  def test_1
    assert_equal(1, 2)
  end
end
$ ruby test.rb --runner=junitxml --junitxml-output-file=result.xml
$ cat result.xml
<?xml version="1.0" encoding="UTF-8" ?>
<testsuites>
  <testsuite name="MyTest"
             tests="1"
             errors="0"
             failures="1"
             skipped="0"
             time="0.0048183">
    <testcase classname="MyTest"
              name="test_1(MyTest)"
              time="0.0047834"
              assertions="1">
      <failure message="&lt;1&gt; expected but was
&lt;2&gt;.">
Failure:
test_1(MyTest) [test.rb:6]:
&lt;1&gt; expected but was
&lt;2&gt;.
      </failure>
    </testcase>
  </testsuite>
</testsuites>