目次: ベンチマーク
浮動小数点数の演算ではIEEE 754という規格があり、x86系のプロセッサはこの規格に基づいた演算を行っています。規格のなかに非正規化数(Denormal NumberもしくはSubnormal Numberとも)という、極めて小さい特殊な数のカテゴリがあります(参考: IEEE 754 - Wikipedia)。
通常はDenormal数も正確に演算しますが、Denormal数の演算は遅いです。計算精度より計算速度が重要な場面ではMXCSRレジスタに特殊なフラグを設定することで、Denormal数の扱いを変更し、高速に演算することができます(参考: FTZフラグとDAZフラグの設定 - インテルC++ コンパイラー18.0デベロッパー・ガイドおよびリファレンス)。
基本的にはDenormal数を無視して0として扱うようにしますが、Intelのプロセッサでは入力側と出力側を別々に扱えるようです。設定可能なフラグは2つあります。デノーマルフラッシュって必殺技の名前っぽいよね。どうでもいいけど。
うーん。わかるような、わからないような。こういうときは実際に動かしてどんな結果になるか試すのが一番良いでしょう。FTZとDAZを有効にする方法はIntelコンパイラの説明から抜粋したものですが、GCCでも全く同じ方法で利用可能です。
#include <stdint.h>
#include <stdio.h>
#include <pmmintrin.h>
double zero = 0.0f;
union {
double f;
long long n;
} a, b, c, d, ab, ac, ca, dc;
void test()
{
a.n = 0x0008000000000000ULL;
b.n = 0x0004000000000000ULL;
c.n = 0x0010000000000000ULL;
d.n = 0x0014000000000000ULL;
ab.f = a.f + b.f;
ac.f = a.f + c.f;
ca.f = c.f - a.f;
dc.f = d.f - c.f;
printf(" a : %e(0x%08llx)\n"
" b : %e(0x%08llx)\n"
" c : %e(0x%08llx)\n"
" d : %e(0x%08llx)\n"
" a+b : %e(0x%08llx)\n"
" a+c : %e(0x%08llx)\n"
" c-a : %e(0x%08llx)\n"
" d-c : %e(0x%08llx)\n"
" a==0: %d\n\n",
a.f, a.n, b.f, b.n, c.f, c.n, d.f, d.n,
ab.f, ab.n, ac.f, ac.n, ca.f, ca.n, dc.f, dc.n,
a.f == zero);
}
int main(int argc, char *argv[])
{
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
printf("FTZ:OFF, DAZ:OFF\n");
test();
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
printf("FTZ:OFF, DAZ:ON\n");
test();
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
printf("FTZ:ON, DAZ:OFF\n");
test();
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
printf("FTZ:ON, DAZ:ON\n");
test();
return 0;
}
変数aとbはDenormal数です(doubleのexponent部分が0)。変数cは非常に小さいですが通常の数です。最後のa.f == zeroはDenormal数と0を比較したときに、等しければ1、等しくなければ0が出力されます。実行結果とともに説明したほうが良いと思うので、実行結果を示します。
$ gcc a.c && ./a.out FTZ:OFF, DAZ:OFF a : 1.112537e-308(0x8000000000000) b : 5.562685e-309(0x4000000000000) c : 2.225074e-308(0x10000000000000) d : 2.781342e-308(0x14000000000000) a+b : 1.668805e-308(0xc000000000000) ★Denorm1 + Denorm2 = Denorm3 a+c : 3.337611e-308(0x18000000000000) ★Denorm1 + Normal1 = Normal1+α c-a : 1.112537e-308(0x8000000000000) ★Normal1 - Denorm1 = Denorm4 d-c : 5.562685e-309(0x4000000000000) ★Normal2 - Normal1 = Denorm5 a==0: 0 ★Denorm1 == 0 ? いいえ FTZ:OFF, DAZ:ON a : 1.112537e-308(0x8000000000000) b : 5.562685e-309(0x4000000000000) c : 2.225074e-308(0x10000000000000) d : 2.781342e-308(0x14000000000000) a+b : 0.000000e+00(0x00000000) ★Denorm1 + Denorm2 = 0(※1) a+c : 2.225074e-308(0x10000000000000) ★Denorm1 + Normal1 = Normal1 → 入力のDenormalが0扱い = DAZ c-a : 2.225074e-308(0x10000000000000) ★Normal1 - Denorm1 = Normal1 → 入力のDenormalが0扱い = DAZ d-c : 5.562685e-309(0x4000000000000) ★Normal2 - Normal1 = Denorm5 a==0: 1 ★Denorm1 == 0 ? はい → 入力のDenormalが0扱い = DAZ FTZ:ON, DAZ:OFF a : 1.112537e-308(0x8000000000000) b : 5.562685e-309(0x4000000000000) c : 2.225074e-308(0x10000000000000) d : 2.781342e-308(0x14000000000000) a+b : 0.000000e+00(0x00000000) ★Denorm1 + Denorm2 = 0(※1) a+c : 3.337611e-308(0x18000000000000) ★Denorm1 + Normal1 = Normal1+α c-a : 0.000000e+00(0x00000000) ★Normal1 - Denorm1 = 0 → 演算結果のDenormalが0扱い = FTZ d-c : 0.000000e+00(0x00000000) ★Normal2 - Normal1 = 0 → 演算結果のDenormalが0扱い = FTZ a==0: 0 ★Denorm1 == 0 ? いいえ FTZ:ON, DAZ:ON a : 1.112537e-308(0x8000000000000) b : 5.562685e-309(0x4000000000000) c : 2.225074e-308(0x10000000000000) d : 2.781342e-308(0x14000000000000) a+b : 0.000000e+00(0x00000000) ★Denorm1 + Denorm2 = 0(※1) a+c : 2.225074e-308(0x10000000000000) ★Denorm1 + Normal1 = Normal1 → 入力のDenormalが0扱い = DAZ c-a : 2.225074e-308(0x10000000000000) ★Normal1 - Denorm1 = Normal1 → 入力のDenormalが0扱い = DAZ d-c : 0.000000e+00(0x00000000) ★Normal2 - Normal1 = 0 → 演算結果のDenormalが0扱い = FTZ a==0: 1 ★Denorm1 == 0 ? はい → 入力のDenormalが0扱い = DAZ (※1)演算結果だけでは、入力のDenormal数が両方0扱いなのか、結果のDenormal数が0扱いなのか、判別できない。
FTZとDAZが発生する例を示したつもりです。できるだけ頑張って説明してみたんですが、良くわからなかったらごめんなさい。
< | 2021 | > | ||||
<< | < | 02 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | - | - | - | - | - | - |
合計:
本日:
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2023.
Powered by PHP 8.2.15.
using GD bundled (2.1.0 compatible)(png support.)