void calc 1long double a printflong double fn
双子もいるの? 区別つくかなぁ。。。 大丈夫!違う服を着ています。 void calc 1(long double a) { printf("long double %fn", a); } void calc 1(double a) { printf("double %fn", a); } int main() calc 1(0. 1 L); ⇒ long double 0. 100000 calc 1(0. 1); ⇒ double 0. 100000 } わんくま同盟 大阪勉強会 #20
かけっこしよっ! C = a + b; 【 float 】 fld dword ptr a fadd dword ptr b fstp dword ptr c ; aをST 0にpush ; ST 0にbを加算 ; ST 0をcに設定してpop 【double】 fld qword ptr a fadd qword ptr b fstp qword ptr c ; aをST 0にpush ; ST 0にbを加算 ; ST 0をcに設定してpop こんなコードならfloatもdoubleも同じ。 わんくま同盟 大阪勉強会 #20
かけっこしよっ! float f = 0; for (int i = 0; i < 10000; ++i) { f += 0. 1 f; } double d = 0; for (int i = 0; i < 10000; ++i) { d += 0. 1; } 最適化レベル:/O 2 float: 1056 ms double: 233 ms わんくま同盟 大阪勉強会 #20
かけっこしよっ! doubleは・・・ fldz ; st 0に 0をpush fld QWORD PTR __real@3 fb 999999 a ; st 0に 0. 1をpush mov eax, 10000000 $LN 6@main: sub eax, 1 fadd ST(1), ST(0) ; st 1にst 0を足す fadd ST(1), ST(0) : fadd ST(1), ST(0) jne SHORT $LN 6@main doubleは、レジスタのみで処理。 わんくま同盟 大阪勉強会 #20
かけっこしよっ! floatは・・・ fldz ; st 0に 0をpush mov eax, 10000000 fstp DWORD PTR [esp] ; st 0をメモリ(f)に設定してpop fld QWORD PTR __real@3 fb 99999 a 0000000 ; st 0に 0. 1をpush $LN 3@main: fld DWORD PTR [esp] ; st 0にfをpush fadd ST(0), ST(1) ; st 0にst 1を足す fstp DWORD PTR [esp] ; st 0をfに設定してpop : ; floatの精度に変換 fld DWORD PTR [esp] fadd ST(0), ST(1) fstp DWORD PTR [esp] jne SHORT $LN 3@main fstp ST(0) ; st 0をpop わんくま同盟 大阪勉強会 #20
かけっこしよっ! float f = 0; for (int i = 0; i < 1000; ++i) { f += 0. 1 f; } /fp: precise /fp: fast VC++ 6. 0 VC++. Net 2003 VC++ 2005 float f = 0; for (int i = 0; i < 1000; ++i) { f += 0. 1 f; printf("%. 7 f", f); } printfなし printfあり 99. 9990463 100. 0000015 99. 9990463 /O 2では/fp: fast相当 /Op(浮動小数点の整合性を改善する) /fp: precise わんくま同盟 大阪勉強会 #20
限界超えて遊ぶぞっ!朝までオール? オーバーフローさせてみよっ! float ff = FLT_MAX; for (int i = 0; i < 12; ++i) { ff *= 2. 0 f; } for (int i = 0; i < 12; ++i) { ff /= 2. 0 f; } printf("ff = %en", ff); double dd = DBL_MAX; for (int i = 0; i < 12; ++i) { dd *= 2. 0; } for (int i = 0; i < 12; ++i) { dd /= 2. 0; } printf(“dd = %en”, dd); FPUの演算精度: 53ビット /fp: precise ff = 1. #INF 00 e+000 dd = 1. 797693 e+308 わんくま同盟 大阪勉強会 #20
限界超えて遊ぶぞっ!朝までオール? オーバーフローさせてみよっ! fld DWORD PTR __real@7 f 7 fffff fstp DWORD PTR [esp] fld QWORD PTR __real@400000000 mov eax, 2 $LN 6@main: sub eax, 1 fld DWORD PTR [esp] fmul ST(0), ST(1) fstp DWORD PTR [esp] : ; st 0にFLT_MAXをpush ; st 0をメモリに設定してpop ; st 0に 2. 0をpush ; st 0にメモリのFLT_MAXをpush ; st 0にst 1を掛ける(FLT_MAX× 2. 0) ; st 0をメモリに設定してpop ; オーバーフロー! わんくま同盟 大阪勉強会 #20
限界超えて遊ぶぞっ!朝までオール? オーバーフローさせてみよっ! fld QWORD PTR __real@7 fefffffff fld QWORD PTR __real@400000000 mov eax, 2 $LN 12@main: sub eax, 1 fmul ST(1), ST(0) : jne SHORT $LN 12@main fstp ST(0) mov eax, 2 fld QWORD PTR __real@3 fe 0000000 $LN 9@main: sub eax, 1 fmul ST(1), ST(0) : jne SHORT $LN 9@main ; st 0にDBL_MAXをpush ; st 0に 2. 0をpush ; st 1にst 0を掛ける(DBL_MAX× 2. 0) ; st 0をpop ; st 0に 0. 5をpush ; st 1にst 0を掛ける わんくま同盟 大阪勉強会 #20
限界超えて遊ぶぞっ!朝までオール? オーバーフローさせてみよっ! double dd = DBL_MAX; for (int i = 0; i < 12; ++i) { dd *= 2. 0; } for (int i = 0; i < 12; ++i) { dd /= 2. 0; } printf("dd = %en", dd); double dd = DBL_MAX; for (int i = 0; i < 12; ++i) { dd *= 2. 0; } printf("dd = %en", dd); for (int i = 0; i < 12; ++i) { dd /= 2. 0; } printf("dd = %en", dd); dd = 1. 797693 e+308 dd = 1. #INF 00 e+000 /fp: precise ⇒ /fp: strict dd = 1. #INF 00 e+000 わんくま同盟 大阪勉強会 #20
違う公園も行こー! movsd xmm 1, QWORD PTR __real@7 fefffffff movsd xmm 0, QWORD PTR __real@400000000 add esp, 20 mov eax, 2 npad 3 $LL 12@main: sub eax, 1 mulsd xmm 1, xmm 0 : mulsd xmm 1, xmm 0 jne SHORT $LL 12@main : わんくま同盟 大阪勉強会 #20
さっきのかけっこでズルしたっしょ? float f = 0; for (int i = 0; i < 10000; ++i) { f += 0. 1 f; } double d = 0; for (int i = 0; i < 10000; ++i) { d += 0. 1; } f = 2097152. 0 d = 9999999. 9811294507 わんくま同盟 大阪勉強会 #20
さっきのかけっこでズルしたっしょ? 20971521回目のループ $LN 3@main: ST 0 = +1. 0000000149011611 e-0001 fld DWORD PTR [esp] ; st 0にfをpush ST 0 = +2. 09715200000 e+0006 ST 1 = +1. 0000000149011611 e-0001 fadd ST(0), ST(1) ; st 0にst 1を足す ST 0 = +2. 0971521000000014 e+0006 ST 1 = +1. 0000000149011611 e-0001 fstp DWORD PTR [esp] ; st 0をfに設定してpop ST 0 = +1. 0000000149011611 e-0001 fld DWORD PTR [esp] ; st 0にfをpush ST 0 = +2. 09715200000 e+0006 ST 1 = +1. 0000000149011611 e-0001 わんくま同盟 大阪勉強会 #20
さっきのかけっこでズルしたっしょ? fld QWORD PTR __real@4341 c 37937 e 08000 ST 0 = +1. 00000000 e+0016 fld QWORD PTR __real@3 fb 999999 a ST 0 = +1. 00000000 e-0001 ST 1 = +1. 00000000 e+0016 add esp, 12 mov eax, 10000000 $LN 3@main: sub eax, 1 fadd ST(1), ST(0) ST 0 = +1. 00000000 e-0001 ST 1 = +1. 00000000 e+0016 fadd ST(1), ST(0) : わんくま同盟 大阪勉強会 #20
遊び足りない? 浮動小数点数値を減算するときに発生する誤差:桁落ち double d 1 = 0. 1234567; double d 2 = 0. 1234566; double dd = d 1 - d 2; d 1 = 1. 234567016363144 e-001 d 2 = 1. 234565973281860 e-001 dd = 1. 043081283569336 e-007 ・・・有効桁数が小さくなる わんくま同盟 大阪勉強会 #20
- Slides: 34