Annotation of nono/exp/fputestadj.php, revision 1.1.1.2

1.1       root        1: <?php
                      2:        //
                      3:        // XM6i
1.1.1.2 ! root        4:        // Copyright (C) 2016 Tetsuya Isaki
1.1       root        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: ?>

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.