カテゴリー別

お絵描き、デザイン

写真、動画関連ソフト

アメーバピグ専用ソフト

ホームページ関連

画像処理

スキャナー用

SEO 関連

お楽しみ

その他

過去ログ

2017年06月13日(火)

簡単なループアニメーションを生成するソフト、デバッグ中

ドロー系のお絵描きソフト、 ストローク で作成した 2 枚の画像から
アニメーションを生成するソフトのテスト、デバッグ中です。

今日は、指定のサイズよりも 1 ピクセル大きな画像
が出力される場合がある不具合を修正しました。

浮動小数点の誤差で、拡大後のサイズ / 元のサイズ
で計算した拡大率を、元のサイズにかけると、
拡大後のサイズよりも大きくなる場合があるのが原因でした。

int とかの整数型で、両方とも正の数だと、
小数点以下は、切り捨てになるので、こういうこと
は起こらないのですが、浮動小数点はちょっと違うみたいですね。

そんなわけで整数の演算のように、
切り捨てっぽい割り算の結果を返す
関数を作って対応してみました。

r = a / b をやってみて、
r * b > a の間、
r をちょっとだけ小さくしていく
っていうプログラムです。

まぁ、最初の r は一番近い値を返している
はずだから、r をちょっとだけ小さくするループは
1 回しか回らないはずですけど、一応ループにしてみました。

負については、まだ考えたくないので
assert でごまかしてます。

inline double floor_div(double a, double b)
{
  ATLASSERT(a >= 0);
  ATLASSERT(b >= 0);
  
  double r = a / b;
  while (r * b > a)
  {
    if (!float_dec_abs(r))
      break;
  }
  
  return r;
}

float_dec_abs も自作の関数で、
引数の r の絶対値をちょっとだけ小さくしますが、
できない場合は、false を返します。

typedef unsigned _int64 DInt;
const DInt D_NUM_MASK   = 0x000FFFFFFFFFFFFF;
const DInt D_S_EXP_MASK = 0xFFF0000000000000;
const DInt D_EXP_MASK   = 0x7FF0000000000000;
const DInt D_EXP_1      = 0x0010000000000000;

inline bool float_dec_abs(double& x)
{
  // 絶対値を 1 単位減らす //
  
  DInt* p = (DInt*)&x;
  if ((*p & D_NUM_MASK) > 0)
  {
    *p -= 1;
    return true;
  }

  if ((*p & D_EXP_MASK) > 0)
  {
    *p |= D_NUM_MASK;
    *p -= D_EXP_1;
    return true;
  }

  ATLASSERT(FALSE); // あんまりこないだろう
  return false;
}

なかなかトリッキーな関数で、
double の内部表現によっては
正しく動かないかもしれませんが、
自分の環境では正しく動いてるみたいです。
(簡単なテストしかしてませんけど)

やってることは、double の仮数部が
0 より大きければ、仮数部を 1 減らし、
0 なら、指数部を 1 減らして、仮数部を最大値にします。
ただし、指数部も 0 な場合は、false で失敗です。

・・・

ま、気になる方は、とりあえず
ストロークでもお試しください。

ストロークループアニメーターのアイコン作成にも使用したので、
実用は可能なはずですよ。

最新版は、こちらのページからダウンロードできます

c の frexp とかでやる方法もありそうですが、
かえってやっかいそうなので、断念しました。

ストローク
ストローク ダウンロード
ストローク サンプル画像
ストローク 更新履歴
ご意見・ご要望連絡窓口


コメント
コメントする