メモの日々


2017年03月23日(木) [長年日記]

[hard] HPのプリンタ ENVY 4520 を買った

キヤノンのプリンタが使えなくなったので、新しいプリンタを買った。

買ったのはHPのENVY4520という複合機タイプのプリンタ。

HP プリンター インクジェット 複合機 ENVY 4520 F0V63#ABJ

ヒューレット・パッカード
¥ 8,255

Amazonが安かったのだけれど在庫が無かったのでヨドバシ.comで初めて買ってみた。9000円くらい。

HP製にしたのは、「カラーインクを外して黒インクだけで印刷」できることを公式に謳っているから。キヤノン製のプリンタなどでもカラーインクなしでの印刷はできるみたいなんだけれど、公式ウェブサイト上に説明がなく隠し機能みたいな扱いなので安心できなかった。

半月くらい使って、不満はない。初複合機なのだけれどコピーができるのは便利。インクの取り付け方法の説明が分かりにくくて手間取ったという問題はあった。


2017年03月15日(水) [長年日記]

[xrea][tdiary] またXREAのシステムが更新され日記が表示されなくなっていた

3/12にこのサーバがリニューアルされたようで、その後からこの日記がエラーで表示できなくなっていた模様。前回は2年前か。

FAQのQ8を参考に、tDiaryのCGIスクリプトのRubyのパスを /usr/local/bin/ruby2.2 に変更したら動くようになった。tDiary 4.1.3(古いバージョンです)にバンドルされているgemがRuby 2.2までに対してしか用意されていないからかな。

サーバが更新されたのはありがたい。


2017年03月07日(火) [長年日記]

[c][c++] open_memstream()

glibcなどにはopen_memstreamという関数がある。

FILE *open_memstream(char **ptr, size_t *sizeloc);

これは自動的に伸長するバッファをバックエンドに持つFILEポインタを返してくれる。データ長が分からない文字列構築をするときなどに便利。なお、sizelocにNULLを指定することはできない模様。サンプルコードと実行結果をメモ。

#include <stdio.h>
#include <stdlib.h>

int main() {
  char* p;
  size_t size;

  FILE* fp = open_memstream(&p, &size);
  if (!fp) return 1;

  fputs("hello", fp);
  fflush(fp);
  printf("%s %lu\n", p, size);

  fputs("world", fp);
  fflush(fp);
  printf("%s %lu\n", p, size);

  // バッファの先頭から書き込みなおす
  rewind(fp);

  fputs("hi", fp);
  fclose(fp);
  printf("%s %lu\n", p, size);

  free(p); // 要free
  return 0;
}
hello 5
helloworld 10
hi 2

[c++] std::ostringstreamは遅い

ostringstreamが遅いことは以前メモした。これはマルチスレッド動作時のことだったけど、シングルスレッドでもfprintfなどより遅い。

それでもostringstreamにはバッファサイズの管理をしなくてよいという便利なところがある。しかし、stdio.hにも上述のopen_memstreamがあるので、これを使えばostringstreamよりも速い出力文字列ストリームを作れるはず。

以下にopen_memstreamを使ったmy_ostringstreamとstd::ostringstreamの比較プログラムをメモ。my_ostringstreamの方が少しだけ速い。my_ostringstreamは標準ライブラリのストリームに似せているだけでstd::ostreamではないことに注意。

#include <chrono>
#include <iostream>
#include <sstream>
#include <stdexcept>

#include <stdio.h>
#include <stdlib.h>

class my_ostringstream {
public:
  my_ostringstream() : fp_{open_memstream(&buffer_, &buffer_size_)} {
    if (!fp_) throw std::runtime_error{"open_memstream failed"};
  }

  // copyやmoveは面倒
  my_ostringstream(const my_ostringstream&) = delete;
  my_ostringstream& operator=(const my_ostringstream&) = delete;
  my_ostringstream(my_ostringstream&&) = delete;
  my_ostringstream& operator=(my_ostringstream&&) = delete;

  ~my_ostringstream() {
    std::fclose(fp_);
    std::free(buffer_);
  }

  std::string str() {
    std::fflush(fp_);
    return {buffer_};
  }

  explicit operator bool() const { return !is_failed_; }

  my_ostringstream& operator<<(char c) {
    if (std::fputc(c, fp_) == EOF) is_failed_ = true;
    return *this;
  }

  my_ostringstream& operator<<(double d) {
    if (std::fprintf(fp_, "%g", d) < 0) is_failed_ = true;
    return *this;
  }

private:
  char* buffer_;
  std::size_t buffer_size_;
  FILE* fp_;
  bool is_failed_{false};
};

template<typename Out>
void call(const std::string& name, Out&& out) {
  using namespace std::chrono;
  constexpr int n = 1000000;

  const auto s = system_clock::now();
  for (double d = 0; d <= n; d += 0.1) {
    out << d << ' ';
  }
  const auto e = system_clock::now();

  std::cout
      << out.str().size()
      << ", " << duration_cast<milliseconds>(e - s).count() << " ms"
      << ", " << name
      << std::endl;
}

int main() {
  call("my_ostringstream", my_ostringstream{});
  call("std::ostringstream", std::ostringstream{});
}
70688902, 6103 ms, my_ostringstream
70688902, 7639 ms, std::ostringstream

2017年03月03日(金) [長年日記]

[c][c++] exp10()

glibcにexp10という関数があることを知った。pow10もある。

exp10はCやC++の今の標準ライブラリには入っていない。いずれ入るのかな。

手元の環境(CentOS 7, GCC 4.8.5)だと、<cmath>をincludeすればC++でexp10を使えた。Cの場合は_GNU_SOURCEをdefineしてから<math.h>をincludeしないと警告が出る。

[c++] exp10()とstd::pow()とstd::exp()

10のべき乗を計算するプログラムでstd::powを使っていたのだけれど、結構遅い。代わりにexp10を使ったら少し速くなった。exp10を標準化して欲しい。

ところで、10^x は

10^x = (e^log(10))^x = e^(log(10) * x)

と変換できるので、std::expを使っても計算できる。試すと、これが一番速かった。xの範囲によって計算の速度が変わるのかもしれないけれど。以下に、xが0の近辺で10^xを計算するプログラムとその実行結果を示す。

#include <chrono>
#include <cmath>
#include <iomanip>
#include <iostream>

template<typename F>
void call(const std::string& name, F f) {
  using namespace std::chrono;
  constexpr int n = 10000000;
  constexpr double d = 0.0001;

  const auto s = system_clock::now();
  double r = 1;
  for (int i = -n; i <= n; ++i) {
    r *= f(d * i / n);
  }
  const auto e = system_clock::now();

  std::cout
      << std::setprecision(20)
      << r
      << ", " << duration_cast<milliseconds>(e - s).count() << " ms"
      << ", " << name
      << std::endl;
}

int main() {
  call("std::pow", [](double x) {
    return std::pow(10.0, x);
  });
  call("exp10", [](double x) {
    return exp10(x);
  });
  call("std::exp", [](double x) {
    constexpr double log_10 = std::log(10);
    return std::exp(log_10 * x);
  });
}
1.0389215324922376205, 2650 ms, std::pow
1.0389215324948466446, 2371 ms, exp10
1.0389215324923555261, 1832 ms, std::exp

2017年02月26日(日) [長年日記]

[hard] プリンタが不調

13年前(!)に買ったPIXUS 560iをまだ使っているのだけれど、今日印刷できなくなってしまった。

電源ランプがオレンジ色に点滅しており、説明書で確認すると「プリントヘッドが装着されていない/プリントヘッドの不良」というエラーになっている模様。ヘッドを拭いてみたりしたけど直らない。

最近はカラーの印刷はできなくなっていて(インク詰まりのためか色が出ない)白黒印刷だけに使っていた。確定申告のためにプリンタが必要なので、新しいプリンタに買い替えようと思う。PIXUS 560i今までありがとう。文字を綺麗に出力してくれるプリンタでした。破棄は粗大ごみとして扱う必要があるので面倒だなあ。