|
|
1.1 ! root 1: <?php ! 2: // ! 3: // XM6i ! 4: // Copyright (C) 2016 [email protected] ! 5: // ! 6: // XEiJ の fputest.x の結果ファイルを都合よく調整する。 ! 7: // FMOVECR は実機の ROM に合わせる。 ! 8: // 超越関数系の照合精度を実機並みに下げる。 ! 9: // ! 10: ! 11: // 丸め文字列のソート順を決めるテーブル。 ! 12: // XXX single/double と extended がどっちの順かはよく知らない。 ! 13: $round_table = array( ! 14: 0 => "single RN", ! 15: 1 => "single RZ", ! 16: 2 => "single RP", ! 17: 3 => "single RM", ! 18: 4 => "double RN", ! 19: 5 => "double RZ", ! 20: 6 => "double RP", ! 21: 7 => "double RM", ! 22: 8 => "extended RN", ! 23: 9 => "extended RZ", ! 24: 10 => "extended RP", ! 25: 11 => "extended RM", ! 26: ); ! 27: ! 28: if ($argc < 3) { ! 29: fprintf(STDERR, "usage: real.log fputest.log\n"); ! 30: exit(1); ! 31: } ! 32: ! 33: // 実機での結果読み込み ! 34: $real = read_log($argv[1]); ! 35: ! 36: // ターゲット結果読み込み ! 37: $target = read_log($argv[2]); ! 38: ! 39: // セクションごとに比較方法が違う ! 40: adj_fmovecr(); ! 41: pass("FMOVE"); ! 42: pass("FINT"); ! 43: adjs("FSINH"); ! 44: pass("FINTRZ"); ! 45: pass("FSQRT"); ! 46: adjs("FLOGNP1"); ! 47: adjs("FETOXM1"); ! 48: adjs("FTANH"); ! 49: adjs("FATAN"); ! 50: adjs("FASIN"); ! 51: adjs("FATANH"); ! 52: adjs("FSIN"); ! 53: adjs("FTAN"); ! 54: adjs("FETOX"); ! 55: adjs("FTWOTOX"); ! 56: adjs("FTENTOX"); ! 57: adjs("FLOGN"); ! 58: adjs("FLOG10"); ! 59: adjs("FLOG2"); ! 60: pass("FABS"); ! 61: adjs("FCOSH"); ! 62: pass("FNEG"); ! 63: adjs("FACOS"); ! 64: adjs("FCOS"); ! 65: pass("FGETEXP"); ! 66: pass("FGETMAN"); ! 67: pass("FDIV"); ! 68: pass("FMOD"); ! 69: pass("FADD"); ! 70: pass("FMUL"); ! 71: adjr("FSGLDIV (MC68882)"); ! 72: pass("FREM"); ! 73: pass("FSCALE"); ! 74: adjr("FSGLMUL (MC68882)"); ! 75: pass("FSUB"); ! 76: adj2("FSINCOS"); ! 77: pass("FCMP"); ! 78: pass("FTST"); ! 79: adj_fbcc(); ! 80: print_total_result(); ! 81: ?> ! 82: <?php ! 83: class fmp ! 84: { ! 85: public $sign; // 符号。0なら正、1なら負 ! 86: public $exp; // 指数。ゲタなし(0 なら 2^0) ! 87: public $mant; // 仮数。GMP ! 88: ! 89: function __construct($w1, $w2, $w3) ! 90: { ! 91: $this->sign = 0; ! 92: $this->exp = 0; ! 93: $this->mant = 0; ! 94: ! 95: $w1 = hexdec(substr($w1, 0, 4)); ! 96: if ($w1 & 0x8000) ! 97: $this->sign = 1; ! 98: $this->exp = ($w1 & 0x7fff) - 16383; ! 99: $this->mant = gmp_init("0x{$w2}{$w3}"); ! 100: } ! 101: } ! 102: ! 103: // ログファイルを読み込んでオンメモリデータベースを作成。 ! 104: // SQLite3 ハンドルを返す。 ! 105: function read_log($filename) ! 106: { ! 107: global $round_table; ! 108: ! 109: $fp = fopen($filename, "r"); ! 110: $db = new SQLite3(":memory:"); ! 111: ! 112: $db->exec("create table t_summary (" ! 113: . "op string," ! 114: . "summary string)"); ! 115: $db->exec("create table t_result (" ! 116: . "op string," ! 117: . "num int," ! 118: . "name string," ! 119: . "round int," ! 120: . "text string)"); ! 121: ! 122: $state = ""; ! 123: while (($buf = fgets($fp)) !== false) { ! 124: $buf = rtrim($buf) . "\n"; ! 125: switch ($state) { ! 126: case "": ! 127: if (preg_match("/^Testing (.*)/", $buf, $m)) { ! 128: $op = $m[1]; ! 129: if ($op == "FBcc") { ! 130: $state = "fbcc"; ! 131: // ここしか初期化のタイミングがない ! 132: $body = ""; ! 133: } else { ! 134: $state = "testing"; ! 135: } ! 136: } ! 137: break; ! 138: ! 139: case "testing": ! 140: if (preg_match("/^tested:/", $buf)) { ! 141: $state = ""; ! 142: $buf = rtrim($buf); ! 143: $db->exec("insert into t_summary values " ! 144: . "('{$op}', '{$buf}');"); ! 145: } else if (preg_match("/^#(\d+) (.*)/", $buf, $m)) { ! 146: $num = $m[1]; ! 147: $testname = "#{$num} {$m[2]}"; ! 148: } else if (preg_match("/expected result/", $buf)) { ! 149: $body .= $buf; ! 150: } else if (preg_match("/actual result/", $buf)) { ! 151: // テキストの最後の改行は取り除いておく ! 152: $body .= rtrim($buf); ! 153: $db->exec("insert into t_result values " ! 154: . "('{$op}', {$num}, '{$testname}', '${round}', '$body')"); ! 155: } else if (preg_match("/^\t.dc.l.*;(.*)/", $buf, $m)) { ! 156: $round = array_search($m[1], $round_table); ! 157: $body = $buf; ! 158: } ! 159: break; ! 160: ! 161: case "fbcc": ! 162: // FBcc だけ形式が異なる。 ! 163: if (preg_match("/^tested:/", $buf)) { ! 164: ! 165: // ここで body を追加。 ! 166: $body = rtrim($body); ! 167: $db->exec("insert into t_result values " ! 168: . "('{$op}', 0, '', '', '{$body}')"); ! 169: ! 170: // 続いてサマリ。 ! 171: $buf = rtrim($buf); ! 172: $db->exec("insert into t_summary values " ! 173: . "('{$op}', '{$buf}');"); ! 174: ! 175: $state = ""; ! 176: } else if (preg_match("/expected result/", $buf)) { ! 177: $body .= $buf; ! 178: } else if (preg_match("/actual result/", $buf)) { ! 179: $body .= $buf; ! 180: } ! 181: } ! 182: } ! 183: fclose($fp); ! 184: ! 185: return $db; ! 186: } ! 187: ! 188: // NG なテスト結果を出力する。 ! 189: // 大域変数 $failed をインクリメントする。(リセットするのは呼び出し側の責任) ! 190: function print_data($data) ! 191: { ! 192: global $failed; ! 193: global $prev_name; ! 194: ! 195: // テスト名ヘッダを表示 ! 196: if ($data['name'] != $prev_name) { ! 197: $prev_name = $data['name']; ! 198: print "{$data['name']}\n"; ! 199: } ! 200: ! 201: // 本文表示 ! 202: print "{$data['text']}\n"; ! 203: ! 204: $failed++; ! 205: } ! 206: ! 207: // 小計を出力する。 ! 208: // $op はテスト関数名。 ! 209: // adj_failed は調整後の失敗数、調整自体を行ってなければ false。 ! 210: function print_result($op, $adj_failed) ! 211: { ! 212: global $target; ! 213: global $total_tested; ! 214: global $total_passed; ! 215: global $total_adj_passed; ! 216: ! 217: // サマリ行取得 ! 218: $res = $target->query("select * from t_summary where op = '{$op}'"); ! 219: $data = $res->fetchArray(SQLITE3_ASSOC); ! 220: print "{$data['summary']}\n"; ! 221: ! 222: // 計算 ! 223: preg_match("/tested:(\d+)(, passed:(\d+))?(, failed.*)?/", ! 224: $data['summary'], $m); ! 225: if ($m === false) { ! 226: print "summary cannot be parsed\n"; ! 227: print "\n"; ! 228: return; ! 229: } ! 230: ! 231: $tested = $m[1]; ! 232: $passed = intval($m[3]); ! 233: $adj_passed = $passed; ! 234: ! 235: if ($adj_failed !== false) { ! 236: $adj_passed = $tested - $adj_failed; ! 237: printf("adjusted -> passed:%d(%4.1f%%)", ! 238: $adj_passed, $adj_passed * 100 / $tested); ! 239: if ($tested != $adj_passed) { ! 240: printf(", failed:%d(%4.1f%%)", ! 241: $adj_failed, $adj_failed * 100 / $tested); ! 242: } ! 243: print "\n"; ! 244: } ! 245: ! 246: // 一行空ける ! 247: print "\n"; ! 248: ! 249: // 大域変数に積算 ! 250: $total_tested += $tested; ! 251: $total_passed += $passed; ! 252: $total_adj_passed += $adj_passed; ! 253: } ! 254: ! 255: // トータルの合計を出力する。 ! 256: function print_total_result() ! 257: { ! 258: global $total_tested; ! 259: global $total_passed; ! 260: global $total_adj_passed; ! 261: ! 262: print "Total\n"; ! 263: printf("tested:%d, passed:%d(%4.1f%%)", ! 264: $total_tested, $total_passed, $total_passed * 100 / $total_tested); ! 265: if ($total_tested != $total_passed) { ! 266: $total_failed = $total_tested - $total_passed; ! 267: printf(", failed:%d(%4.1f%%)", ! 268: $total_failed, $total_failed * 100 / $total_tested); ! 269: } ! 270: print "\n"; ! 271: ! 272: printf("adjusted -> passed:%d(%4.1f%%)", ! 273: $total_adj_passed, $total_adj_passed * 100 / $total_tested); ! 274: if ($total_tested != $total_adj_passed) { ! 275: $total_adj_failed = $total_tested - $total_adj_passed; ! 276: printf(", failed:%d(%4.1f%%)", ! 277: $total_adj_failed, $total_adj_failed * 100 / $total_tested); ! 278: } ! 279: print "\n"; ! 280: } ! 281: ! 282: // FMOVECR の結果を比較する。 ! 283: // ROM と数学的真値とが異なっているところは ROM を正解とする。 ! 284: // 予約オフセット部分については比較しない。 ! 285: function adj_fmovecr() ! 286: { ! 287: global $real; ! 288: global $target; ! 289: global $failed; ! 290: ! 291: $op = "FMOVECR"; ! 292: $failed = 0; ! 293: ! 294: print "Testing {$op}\n"; ! 295: for ($i = 0; $i <= 0x3f; $i++) { ! 296: switch ($i) { ! 297: case 0: ! 298: case 13: ! 299: case 15: ! 300: // 公開オフセット。ROM と真値が一致している。 ! 301: // つまり差分が出てればそのまま誤りとして表示。 ! 302: $tres = $target->query("select * from t_result " ! 303: . " where op = '{$op}' and num = {$i} order by round"); ! 304: while (($data = $tres->fetchArray(SQLITE3_ASSOC)) !== false) { ! 305: print_data($data); ! 306: } ! 307: break; ! 308: ! 309: case 11: ! 310: case 12: ! 311: case 14: ! 312: // 公開オフセット。ROM と真値が一致しないケースがある。 ! 313: // 実機の結果と完全一致してれば一致とみなす。 ! 314: $tres = $target->query("select * from t_result " ! 315: . "where op = '{$op}' and num = {$i} order by round"); ! 316: while (($data = $tres->fetchArray(SQLITE3_ASSOC)) !== false) { ! 317: // 実機データの同じところ ! 318: $rres = $real->query("select * from t_result " ! 319: . "where op = '{$op}' and num = {$i} and " ! 320: . "round = {$data['round']}"); ! 321: $rdata = $rres->fetchArray(SQLITE3_ASSOC); ! 322: ! 323: $tlines = explode("\n", $data['text']); ! 324: $input = $tlines[0]; ! 325: $tactual = $tlines[2]; ! 326: ! 327: if ($rdata === false) { ! 328: $ractual = $tlines[1]; ! 329: } else { ! 330: $rlines = explode("\n", $rdata['text']); ! 331: $ractual = $rlines[2]; ! 332: } ! 333: // 違ってれば、表示 ! 334: if ($tactual != $ractual) { ! 335: // 表示用に expected を差し替える ! 336: $newlines = "{$input}\n" ! 337: . "{$ractual}\n" // expected は real actual ! 338: . "{$tactual}"; // actual は target actual ! 339: $data['text'] = $newlines; ! 340: print_data($data); ! 341: } ! 342: } ! 343: break; ! 344: ! 345: case 1: ! 346: case 2: ! 347: case 3: ! 348: case 4: ! 349: case 5: ! 350: case 6: ! 351: case 7: ! 352: case 8: ! 353: case 9: ! 354: case 10: ! 355: break; ! 356: } ! 357: } ! 358: ! 359: print_result($op, $failed); ! 360: } ! 361: ! 362: // FBcc の結果を比較する。 ! 363: // これだけ出力フォーマットが全く異なる。 ! 364: function adj_fbcc() ! 365: { ! 366: global $real; ! 367: global $target; ! 368: global $failed; ! 369: ! 370: $op = "FBcc"; ! 371: $failed = 0; ! 372: ! 373: print "Testing {$op}\n"; ! 374: // テスト名ヘッダはないので改行だけ表示されるのを防ぐ。 ! 375: $prev_name = ""; ! 376: ! 377: $tres = $target->query("select * from t_result where op = '{$op}'"); ! 378: $data = $tres->fetchArray(SQLITE3_ASSOC); ! 379: if ($data !== false) { ! 380: print_data($data); ! 381: } ! 382: ! 383: print_result($op, false); ! 384: } ! 385: ! 386: ! 387: // XEiJ の期待値と比較する。つまりここでは何もしない。 ! 388: function pass($op) ! 389: { ! 390: global $real; ! 391: global $target; ! 392: global $failed; ! 393: ! 394: $failed = 0; ! 395: ! 396: print "Testing {$op}\n"; ! 397: $tres = $target->query("select * from t_result " ! 398: . "where op = '{$op}' order by num, round"); ! 399: while (($data = $tres->fetchArray(SQLITE3_ASSOC)) !== false) { ! 400: print_data($data); ! 401: } ! 402: ! 403: print_result($op, false); ! 404: } ! 405: ! 406: // 超越関数とか用の比較。 ! 407: // 実機値より誤差が小さければよしとするか。 ! 408: function adjs($op) ! 409: { ! 410: global $real; ! 411: global $target; ! 412: global $failed; ! 413: ! 414: $failed = 0; ! 415: ! 416: print "Testing {$op}\n"; ! 417: $tres = $target->query("select * from t_result " ! 418: . "where op = '{$op}' order by num, round"); ! 419: while (($data = $tres->fetchArray(SQLITE3_ASSOC)) !== false) { ! 420: // 実機データの同じところ ! 421: $rres = $real->query("select * from t_result " ! 422: . "where op = '{$op}' and num = {$data['num']} " ! 423: . "and round = {$data['round']}"); ! 424: $rdata = $rres->fetchArray(SQLITE3_ASSOC); ! 425: ! 426: // expected: XEiJ の期待値 ! 427: // tactual: ターゲットログの actual ! 428: // ractual: 実機の actual ! 429: $tlines = explode("\n", $data['text']); ! 430: $xeij_expected = $tlines[1]; ! 431: $actual = $tlines[2]; ! 432: if ($rdata === false) { ! 433: // 実機データ側にエントリがないということは ! 434: // 実機の結果が XEiJ 期待と同じだったということ。 ! 435: $real_expected = $xeij_expected; ! 436: } else { ! 437: // 実機データ側にエントリがあれば、 ! 438: // それの actual が実機期待値。 ! 439: $rlines = explode("\n", $rdata['text']); ! 440: $real_expected = $rlines[2]; ! 441: } ! 442: ! 443: list($xm, $xeij_flag) = split_ext_flag($xeij_expected); ! 444: list($rm, $real_flag) = split_ext_flag($real_expected); ! 445: list($am, $act_flag) = split_ext_flag($actual); ! 446: // 判定 ! 447: if ($xeij_flag == $real_flag && // フラグが一致 ! 448: $xeij_flag == $act_flag && ! 449: fmp_judge($xm, $rm, $am)) // 値が一致 ! 450: { ! 451: continue; ! 452: } ! 453: ! 454: // 違っていたので、表示 ! 455: ! 456: // 表示用に加工 ! 457: // input, XEiJ expected, real expected, actual の4行にしてみる ! 458: $line1 = preg_replace("/expected/", "XEiJ expected", ! 459: $xeij_expected); ! 460: $line2 = preg_replace("/(expected|actual)/", "Real expected", ! 461: $real_expected); ! 462: $newlines = "{$tlines[0]}\n" // input ! 463: . "{$line1}\n" // XEiJ expected ! 464: . "{$line2}\n" // Real expected ! 465: . "{$actual}"; ! 466: $data['text'] = $newlines; ! 467: print_data($data); ! 468: } ! 469: ! 470: print_result($op, $failed); ! 471: } ! 472: ! 473: // FSINCOS など、戻り値が2つある関数の比較。 ! 474: // それぞれ実機値より誤差が小さければよしとするか。 ! 475: function adj2($op) ! 476: { ! 477: global $real; ! 478: global $target; ! 479: global $failed; ! 480: ! 481: $failed = 0; ! 482: ! 483: print "Testing {$op}\n"; ! 484: $tres = $target->query("select * from t_result " ! 485: . "where op = '{$op}' order by num, round"); ! 486: while (($data = $tres->fetchArray(SQLITE3_ASSOC)) !== false) { ! 487: // 実機データの同じところ ! 488: $rres = $real->query("select * from t_result " ! 489: . "where op = '{$op}' and num = {$data['num']} " ! 490: . "and round = {$data['round']}"); ! 491: $rdata = $rres->fetchArray(SQLITE3_ASSOC); ! 492: ! 493: // expected: XEiJ の期待値 ! 494: // tactual: ターゲットログの actual ! 495: // ractual: 実機の actual ! 496: $tlines = explode("\n", $data['text']); ! 497: $xeij_expected = $tlines[1]; ! 498: $actual = $tlines[2]; ! 499: if ($rdata === false) { ! 500: // 実機データ側にエントリがないということは ! 501: // 実機の結果が XEiJ 期待と同じだったということ。 ! 502: $real_expected = $xeij_expected; ! 503: } else { ! 504: // 実機データ側にエントリがあれば、 ! 505: // それの actual が実機期待値。 ! 506: $rlines = explode("\n", $rdata['text']); ! 507: $real_expected = $rlines[2]; ! 508: } ! 509: ! 510: list($xm1, $xm2, $xeij_flag) = split_ext2_flag($xeij_expected); ! 511: list($rm1, $rm2, $real_flag) = split_ext2_flag($real_expected); ! 512: list($am1, $am2, $act_flag) = split_ext2_flag($actual); ! 513: // 判定 ! 514: if ($xeij_flag == $real_flag && // フラグが一致 ! 515: $xeij_flag == $act_flag && ! 516: fmp_judge($xm1, $rm1, $am1) && // 1つ目の値が一致 ! 517: fmp_judge($xm2, $rm2, $am2)) // 2つ目の値が一致 ! 518: { ! 519: continue; ! 520: } ! 521: ! 522: // 違っていたので、表示 ! 523: ! 524: // 表示用に加工 ! 525: // input, XEiJ expected, real expected, actual の4行にしてみる ! 526: $line1 = preg_replace("/expected/", "XEiJ expected", ! 527: $xeij_expected); ! 528: $line2 = preg_replace("/(expected|actual)/", "Real expected", ! 529: $real_expected); ! 530: $newlines = "{$tlines[0]}\n" // input ! 531: . "{$line1}\n" // XEiJ expected ! 532: . "{$line2}\n" // Real expected ! 533: . "{$actual}"; ! 534: $data['text'] = $newlines; ! 535: print_data($data); ! 536: } ! 537: ! 538: print_result($op, $failed); ! 539: } ! 540: ! 541: // FSGLDIV など、実機値との完全一致をテストするもの。 ! 542: function adjr($op) ! 543: { ! 544: global $real; ! 545: global $target; ! 546: global $failed; ! 547: ! 548: $failed = 0; ! 549: ! 550: print "Testing {$op}\n"; ! 551: $tres = $target->query("select * from t_result " ! 552: . "where op = '{$op}' order by num, round"); ! 553: while (($data = $tres->fetchArray(SQLITE3_ASSOC)) !== false) { ! 554: // 実機データの同じところ ! 555: $rres = $real->query("select * from t_result " ! 556: . "where op = '{$op}' and num = {$data['num']} " ! 557: . "and round = {$data['round']}"); ! 558: $rdata = $rres->fetchArray(SQLITE3_ASSOC); ! 559: ! 560: $tlines = explode("\n", $data['text']); ! 561: $actual = $tlines[2]; ! 562: if ($rdata == false) { ! 563: // 実機データ側にエントリがないということは ! 564: // 実機の結果が XEiJ 期待と同じだったということ。 ! 565: $expected = $tlines[1]; ! 566: } else { ! 567: // 実機データ側にエントリがあれば、 ! 568: // それの actual が実機期待値。 ! 569: $rlines = explode("\n", $rdata['text']); ! 570: $expected = $rlines[2]; ! 571: } ! 572: ! 573: list($rm, $real_flag) = split_ext_flag($expected); ! 574: list($am, $act_flag) = split_ext_flag($actual); ! 575: // 判定 (完全一致) ! 576: if ($real_flag == $act_flag && ! 577: fmp_equ($rm, $am)) ! 578: { ! 579: continue; ! 580: } ! 581: ! 582: // 違っていたので、表示 ! 583: ! 584: // 表示用に加工 ! 585: // 期待値が XEiJ と実機で同じなら expected のまま、 ! 586: // 実機由来のものなら Real expected にしてみる。 ! 587: $line2 = preg_replace("/actual/", "Real expected", ! 588: $expected); ! 589: $newlines = "{$tlines[0]}\n" // input ! 590: . "{$line2}\n" // Real expected ! 591: . "{$actual}"; ! 592: $data['text'] = $newlines; ! 593: print_data($data); ! 594: } ! 595: ! 596: print_result($op, $failed); ! 597: } ! 598: ! 599: // 値が正しいかどうかを判定する。 ! 600: // 判定条件は、真値と実機値との中間値を中心として、真値と実機値の距離を ! 601: // 半径とする直径の中に測定値が入っていること。 ! 602: function fmp_judge($xm, $rm, $am) ! 603: { ! 604: // 3者で符号が一致してないと、false ! 605: if ($xm->sign != $rm->sign || $xm->sign != $am->sign) { ! 606: return false; ! 607: } ! 608: ! 609: // 3つとも指数を揃える ! 610: // どれか1つでも指数が64以上差がある場合は false ! 611: $max_exp = max($xm->exp, $rm->exp, $am->exp); ! 612: if (fmp_shr($xm, $max_exp - $xm->exp) === false) ! 613: return false; ! 614: if (fmp_shr($rm, $max_exp - $rm->exp) === false) ! 615: return false; ! 616: if (fmp_shr($am, $max_exp - $am->exp) === false) ! 617: return false; ! 618: ! 619: // 真値と実機値の距離 d ! 620: $d = gmp_sub($rm->mant, $xm->mant); ! 621: // 大小を揃える ! 622: if (gmp_sign($d) >= 0) { ! 623: $h = $rm->mant; ! 624: $l = $xm->mant; ! 625: } else { ! 626: $h = $xm->mant; ! 627: $l = $rm->mant; ! 628: $d = gmp_neg($d); ! 629: } ! 630: ! 631: // 距離 d の半分を上と下に広げたのが正答範囲 ! 632: // ただしなんとなく距離 3 以下なら半分にせず適用 ! 633: if (gmp_cmp($d, 3) <= 0) { ! 634: $d2 = $d; ! 635: } else { ! 636: $d2 = gmp_div($d, 2); ! 637: } ! 638: $low = gmp_sub($l, $d2); ! 639: $high = gmp_add($h, $d2); ! 640: ! 641: // 測定値がこの中に入っているか ! 642: // am >= low && am <= high ! 643: if (gmp_cmp($am->mant, $low) >= 0 && gmp_cmp($am->mant, $high) <= 0) { ! 644: // 一致とみなす ! 645: return true; ! 646: } ! 647: ! 648: return false; ! 649: } ! 650: ! 651: // 値が一致するか調べる。 ! 652: function fmp_equ($f1, $f2) ! 653: { ! 654: if ($f1->sign == $f2->sign && ! 655: $f1->exp == $f2->exp && ! 656: gmp_cmp($f1->mant, $f2->mant) == 0) ! 657: { ! 658: return true; ! 659: } ! 660: return false; ! 661: } ! 662: ! 663: // $fmp->mant を $shift ビット右シフトして、 ! 664: // $fmp->exp に $shift を加算する。(要は桁合わせ) ! 665: // $shift が 1 未満なら何もしない。 ! 666: // $shift が 64 以上の場合は false を返す。 ! 667: function fmp_shr(&$fmp, $shift) ! 668: { ! 669: if ($shift < 1) ! 670: return true; ! 671: ! 672: if ($shift > 63) ! 673: return false; ! 674: ! 675: $fmp->exp += $shift; ! 676: $two = gmp_init("2"); ! 677: for (; $shift > 0; $shift--) { ! 678: $fmp->mant = gmp_div($fmp->mant, $two); ! 679: } ! 680: return true; ! 681: } ! 682: ! 683: // 拡張精度1つとフラグがある行を分解して返す。 ! 684: function split_ext_flag($text) ! 685: { ! 686: preg_match("/\\$(.{8}),\\$(.{8}),\\$(.{8}),(\S*)\s+;/", $text, $m); ! 687: $fmp = new fmp($m[1], $m[2], $m[3]); ! 688: return array($fmp, $m[4]); ! 689: } ! 690: ! 691: // 拡張精度2つとフラグがある行を分解して返す。 ! 692: function split_ext2_flag($text) ! 693: { ! 694: preg_match( ! 695: "/\\$(.{8}),\\$(.{8}),\\$(.{8}),\\$(.{8}),\\$(.{8}),\\$(.{8}),(\S*)\s+;/", ! 696: $text, $m); ! 697: $fm1 = new fmp($m[1], $m[2], $m[3]); ! 698: $fm2 = new fmp($m[4], $m[5], $m[6]); ! 699: return array($fm1, $fm2, $m[7]); ! 700: } ! 701: ?>
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.