pragma Fast_Math
──というのがいつのまにか追加されてた。
http://gcc.gnu.org/onlinedocs/gnat_rm/Pragma-Fast_005fMath.html
規格上保たないといけない精度とか無視して突っ切るためのpragmaらしい。
紛らわしいですがきっと-ffast-mathとはなんの関係も無いです。そもそもCフロントエンドがintrinsic扱いしてるかどうかなんてのは他のフロントエンドには関係……いや展開してるとこがCフロントエンドの中にあるわけじゃないですし本来関係あるはずなんですが少なくともGNATフロントエンドだと関係ないです。
大体がAdaのべき乗って**ですし、ふつーに畳み込んでくれるよな、GNATフロントエンド……激しく信用できないな。
function a return integer is begin return 3 ** 4; end;
オプション無し-S
.file "a.adb" .text .globl __ada_a .def __ada_a; .scl 2; .type 32; .endef __ada_a: LFB3: pushl %ebp LCFI0: movl %esp, %ebp LCFI1: movl $81, %eax popl %ebp ret LFE3: .section .eh_frame,"dr" Lframe1: .long LECIE1-LSCIE1 LSCIE1: .long 0x0 .byte 0x1 .def ___gnat_eh_personality; .scl 2; .type 32; .endef .ascii "zP\0" .uleb128 0x1 .sleb128 -4 .byte 0x8 .uleb128 0x5 .byte 0x0 .long ___gnat_eh_personality .byte 0xc .uleb128 0x4 .uleb128 0x4 .byte 0x88 .uleb128 0x1 .align 4 LECIE1: LSFDE1: .long LEFDE1-LASFDE1 LASFDE1: .long LASFDE1-Lframe1 .long LFB3 .long LFE3-LFB3 .uleb128 0x0 .byte 0x4 .long LCFI0-LFB3 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long LCFI1-LCFI0 .byte 0xd .uleb128 0x5 .align 4 LEFDE1:
されてた。良かった。
これが畳み込まれてないと、1 shl n = 1 * 2 ** n, 1 shr n = 1 / 2 ** nで代用*1している箇所がえらいことになることろでした。良かった。
別に-ffast-math付けても変わりませんでした。
そうそう、4.3から遂にMinGWでもzcxですよ。system-mingw.adsのZCX_By_DefaultをTrueにしてやれば有効になります。
閑話休題してpragma Fast_Mathです。
関係ないですが連想されるのがDelphi.NET上の{$FINITEFLOAT OFF}。倍近く計算速度に影響していました。今となっては、.NETで速度が要求される計算なんてする方が間違ってると断言できますが、当時は衝撃でした。なにしろDelphi8時点ではUndocumented(ry
ところでDelphi2007のヘルプのUpdateが出てたのであてたのです。確かにあちこちで地味に言われているように品質は少しマシになっていたのですが、折角Delphiのみの版で、Delphi for Win32とWindows SDKだけの見通しの良い状態だったのに、C++Builderと.NET SDKのヘルプが登録されてorzなんですが……2007にはreghelp.exeが付いてないため外し方がわかりませんorz
閑話休題してpragma Fast_Mathです。
要するに、a-nucoty.adsと、それにpragma Fast_Math;を書き足したのとで、複素数の乗算を比べればいいらしいです。
しかし複素数の乗算って要するにa-ngcoty.adbの"*"が使われるだけでは?
function "*" (Left, Right : Complex) return Complex is X : R; Y : R; begin X := Left.Re * Right.Re - Left.Im * Right.Im; Y := Left.Re * Right.Im + Left.Im * Right.Re; -- If either component overflows, try to scale (skip in fast math mode) if not Standard'Fast_Math then if abs (X) > R'Last then X := R'(4.0) * (R'(Left.Re / 2.0) * R'(Right.Re / 2.0) - R'(Left.Im / 2.0) * R'(Right.Im / 2.0)); end if; if abs (Y) > R'Last then Y := R'(4.0) * (R'(Left.Re / 2.0) * R'(Right.Im / 2.0) - R'(Left.Im / 2.0) * R'(Right.Re / 2.0)); end if; end if; return (X, Y); end "*";
……わかりやすいですね。試すまでも無いです。
pragmaの他に属性Standard'Fast_Mathもいつのまにか追加されてて、これは単にpragma Fast_Mathの状態を返す、と……。汎用の条件コンパイル用のpragma入れたくないのだろうな、と勝手に想像した上で、それには賛成ですけれども……。こんなのAda.Numerics.Generic_Complex_Typesにデフォルト値付きのBoolean引数足したって一緒じゃないですか。あ、それだとpackage自体を仮引数宣言する時にothersが要るようになって互換性崩れるのかな。
むしろオーバーフローの判定式がabs (X) > R'Lastなのが驚きです。属性S'Machine_Overflowsってなんのためにあるのでしょうか……。あ、もしかしてS'Machine_Overflowsって例外発生中のみTrueになるのか……。全部Constraint_Errorになってしまう計算による例外の原因を分類するための属性なわけですね。使えねえ。
つかAdaCoreがresyncと称してgcc-patchesにもアナウンス無しで一度に大量のcommitを行うのは、gcc的にはどう思われているのか知りたいこの頃。--input-charsetや--exec-charsetを無視して独自にスイッチ設けるフロントエンドとかさ、他のフロントエンドは許していていいの?曲がりなりにも標準配布に含まれてる言語なのに?……なんて激しく思うのですが、きっとgccの中の人ですらAdaフロントエンドの惨状は誰も把握どころか単に見てないに違いないという容易な想像が。4.2になれど4.3になれどGNATはchanges.htmlすら書かれず、じっとFortranを見る。