パスワードを忘れた? アカウント作成
331599 journal

TarZの日記: 【面白ネタ】デジタル計算機の「正確さ」のマージンを部分的に緩めることで消費電力を50~90%改善する 1

日記 by TarZ

 効果とか、省電力のアプローチとしての方向性の正しさについてはよく判らないが、純粋に面白い。

Code Green: Energy-Efficient Programming to Curb Computers' Power Use
EnerJ (PDF)

 デジタル回路では、ある閾値でぶった切って出力を解釈することで、デジタルで結果を得る。この動作にはマージンを見込んであるので、ある程度の熱や電圧変動、電荷のリークといった、素子自体あるいは外部からの擾乱があっても同じ結果を返す。

 しかし、そうしたハードウェア上で実行されるアプリケーションは、そこまで正確な結果を要求しないものもある。たとえば、MPEG2動画の伸長・表示処理を考えてみる。ほんの一瞬だけ表示される画像のどこか1ピクセルがおかしかったり、音声に少しノイズが乗ったところで視聴上の問題はほとんどない。

 つまり、分野によっては現在のデジタル回路の動作は過剰品質になっている。この正確性を維持するために多くの電力が必要になっているなら、多少のエラーは許容したうえでそのマージンを削ることで消費電力を下げられるのではないか、というアイディアが出てくる。

 たとえば、DRAMのリフレッシュレート。1秒あたり10^-9の確率でビット化けを許容できるなら、リフレッシュレートを下げて17%の消費電力低減になる。もし10^-3までビット化けの確率を上げていいなら、電力を24%低減できる。
 浮動小数点演算も同様で、仮数部のビットを少なくすることで劇的な省電力化が見込める。単精度で仮数部16ビットにすれば32%、4ビットでよいなら実に85%(推定値)にまで消費電力を低減できる。

 画像や音声のように多少の誤りは許容できる処理がある一方、プログラムのロジック部分などで曖昧な動作をされては困る。どんな処理やデータなら誤りを許容できるかは、ハード側で判断できる部分は少ない。それはソフト側しか知らない。
 そこで、部分的に誤差を許容するようなハードウェアの仕組みを用意するとともに、これに対応するソフトウェア側での工夫も必要になる。しかし、誤差を許容するような処理やデータを、プログラマが全て把握しなけれればならないとなると面倒くさいので(というより大規模なアプリケーションを作るのはほとんど不可能になるので)、言語なりライブラリなりでサポートするのが現実的な手段だろう。

 ここでは具体的に、Javaに対して近似的(誤差を許容する)データ approximate data type を追加する機能拡張を提案している。文法的にはアノテーションによって実現するので、Javaプログラマなら割とすんなり理解できる。
 PDFにサンプルが記載されているが、こんな感じ。

    int p;               // デフォルトでは、従来と同様に正確な値を保持する変数になる
    @Approx int a = ...; // 不正確でも構わない変数には、アノテーション @Approx を付ける
 
      :
 
    a = p;               // こういうのはOK
 
      :
 
    p = a;               // うっかりこうした代入をしようとすると、エラーとして弾いてくれる
    p = endorse(a);      // 近似的なデータを正確な変数に代入する必要がある場合は、明示的に変換する

 ここまではまあ、なんとなくわかる。

 さらに恐ろしいことに、単に扱うデータだけでなく、ロジックでも近似的な記述が許される。

  // 浮動小数点の配列を扱う近似的なクラス
  @Approximable class FloatSet {
    @Context float[] nums = ...;
 
    // 配列に入っているデータの平均値を返す
    float mean() {
      float total = 0.0f;
      for (int i = 0; i < nums.length; ++i) // 律儀に全てのデータを足す
        total += nums[i];
      return total / nums.length;           // 個数で割って平均値
    }
 
    // 配列に入っているデータの平均値を近似的に返す
    @Approx float mean_APPROX() {
      @Approx float total = 0.0f;
      for (int i = 0; i < nums.length; i += 2) // 一つ飛ばしに加算している(笑)
        total += nums[i];
      return 2 * total / nums.length;          // まー大体は半分になっているだろ、ってことで2倍にしてから個数で割る
    }
  }

 いや、コレ省電力がどうとか以前に面白すぎるんですけど!

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

にわかな奴ほど語りたがる -- あるハッカー

読み込み中...