Annotation of nono/fpe/fpu_bcd.c, revision 1.1.1.1

1.1       root        1: //
                      2: // XM6i
                      3: // Copyright (c) 2013 Y.Sugahara
                      4: //
                      5: // [ fpn → BCD 変換 ]
                      6: //
                      7: 
                      8: #include "fpu_emulate.h"
                      9: #include "fpu_bcd.h"
                     10: #include <string.h>
                     11: #include <stdint.h>
                     12: #include <stdio.h>
                     13: #include <math.h>
                     14: #include <stdlib.h>
                     15: 
                     16: //#define FPU_BCD_DEBUG
                     17: 
                     18: #if defined(FPU_BCD_DEBUG)
                     19: #define DPRINTF(msg, ...)      printf(msg, ## __VA_ARGS__)
                     20: #define dump(s, a)     debug_dump(s, a)
                     21: #else
                     22: #define DPRINTF(msg, ...)      /**/
                     23: #define dump(s, a)     /**/
                     24: #endif
                     25: 
                     26: static int fpu_bcd_iszero(const BCD *a);
                     27: static uint8_t fpu_bcd_shr(BCD *a);
                     28: static uint8_t fpu_bcd_shr_n(BCD *a, int n);
                     29:        uint8_t fpu_bcd_shl(BCD *a);
                     30: static uint8_t fpu_bcd_shl_n(BCD *a, int n);
                     31: static uint8_t fpu_bcd_add_d(BCD *a, const BCD *b);
                     32: static void fpu_bcd_add_last_n(BCD *a, uint8_t n);
                     33: static void fpu_bcd_round_cy(BCD *a, uint8_t cy);
                     34: static void fpu_bcd_round(BCD *a);
                     35: static void fpu_bcd_add(BCD *a, const BCD *b);
                     36: static void fpu_bcd_mul(BCD *a, const BCD *b);
                     37: static void fpu_bcd_exp2(BCD *a, int n);
                     38: static int getbit(struct fpn *fp, int n);
                     39: static void fpu_itobcd(BCD *a, int x);
                     40: static void fpu_fpntobcd(BCD *res, struct fpn *fp);
                     41: 
                     42: #if defined(FPU_BCD_DEBUG)
                     43: static void __attribute__((__unused__))
                     44: debug_dump(const char *s, const BCD *a)
                     45: {
                     46:        int i;
                     47: 
                     48:        printf("%10s ", s);
                     49:        printf("e=%+5d ", a->e);
                     50:        printf("%d.", a->d[0]);
                     51:        for (i = 1; i < FPU_BCD_DIGIT; i++) {
                     52:                printf("%d", a->d[i]);
                     53:        }
                     54:        printf("\n");
                     55: }
                     56: #endif
                     57: 
                     58: /*
                     59:  * (a == 0)
                     60:  */
                     61: static int
                     62: fpu_bcd_iszero(const BCD *a)
                     63: {
                     64:        int i;
                     65:        for (i = 0; i < FPU_BCD_DIGIT; i++) {
                     66:                if (a->d[i]) return 0;
                     67:        }
                     68:        return 1;
                     69: }
                     70: 
                     71: /*
                     72:  * a >>= 1
                     73:  * return: carry digit
                     74:  */
                     75: static uint8_t
                     76: fpu_bcd_shr(BCD *a)
                     77: {
                     78:        int i;
                     79:        uint8_t cy;
                     80: 
                     81:        cy = a->d[FPU_BCD_DIGIT - 1];
                     82:        for (i = FPU_BCD_DIGIT - 1; i >= 1; i--) {
                     83:                a->d[i] = a->d[i - 1];
                     84:        }
                     85:        a->d[0] = 0;
                     86: dump("shr", a);
                     87:        return cy;
                     88: }
                     89: 
                     90: /*
                     91:  * a >>= n
                     92:  */
                     93: static uint8_t
                     94: fpu_bcd_shr_n(BCD *a, int n)
                     95: {
                     96:        uint8_t cy;
                     97:        int count;
                     98: 
                     99:        if (n <= 0) return 0;
                    100:        count = FPU_BCD_DIGIT - n;
                    101:        if (count < 0) {
                    102:                memset(a->d, 0, FPU_BCD_DIGIT * sizeof(a->d[0]));
                    103:                return 0;
                    104:        }
                    105:        cy = a->d[count];
                    106: 
                    107:        memmove(&a->d[n], &a->d[0], count * sizeof(a->d[0]));
                    108:        memset(&a->d[0], 0, n * sizeof(a->d[0]));
                    109:        return cy;
                    110: }
                    111: 
                    112: /*
                    113:  * a <<= 1
                    114:  * return: carry digit
                    115:  */
                    116: /* 使われてないけど対称性のため残してある。どうすべ */
                    117: uint8_t
                    118: fpu_bcd_shl(BCD *a)
                    119: {
                    120:        int i;
                    121:        uint8_t cy;
                    122: 
                    123:        cy = a->d[0];
                    124:        for (i = 0; i < FPU_BCD_DIGIT - 1; i++) {
                    125:                a->d[i] = a->d[i + 1];
                    126:        }
                    127:        a->d[FPU_BCD_DIGIT - 1] = 0;
                    128: dump("shl", a);
                    129:        return cy;
                    130: }
                    131: 
                    132: /*
                    133:  * a <<= n
                    134:  * return: carry digit
                    135:  */
                    136: static uint8_t
                    137: fpu_bcd_shl_n(BCD *a, int n)
                    138: {
                    139:        uint8_t cy;
                    140: 
                    141:        if (n <= 0)
                    142:                return 0;
                    143:        if (n >= FPU_BCD_DIGIT) {
                    144:                memset(a->d, 0, FPU_BCD_DIGIT * sizeof(a->d[0]));
                    145:                return 0;
                    146:        }
                    147:        cy = a->d[n - 1];
                    148: 
                    149:        memmove(&a->d[0], &a->d[n], (FPU_BCD_DIGIT - n) * sizeof(a->d[0]));
                    150:        memset(&a->d[FPU_BCD_DIGIT - n], 0, n * sizeof(a->d[0]));
                    151:        return cy;
                    152: }
                    153: 
                    154: /*
                    155:  * a = a + b
                    156:  * add digit only
                    157:  */
                    158: static uint8_t
                    159: fpu_bcd_add_d(BCD *a, const BCD *b)
                    160: {
                    161:        uint8_t cy = 0;
                    162:        int i;
                    163: 
                    164:        for (i = FPU_BCD_DIGIT - 1; i >= 0; i--) {
                    165:                a->d[i] = a->d[i] + b->d[i] + cy;
                    166:                if (a->d[i] >= 10) {
                    167:                        a->d[i] -= 10;
                    168:                        cy = 1;
                    169:                } else {
                    170:                        cy = 0;
                    171:                }
                    172:        }
                    173:        return cy;
                    174: }
                    175: 
                    176: /*
                    177:  * a = a[last digit] + n
                    178:  * for rounding
                    179:  */
                    180: static void
                    181: fpu_bcd_add_last_n(BCD *a, uint8_t n)
                    182: {
                    183:        uint8_t cy = n;
                    184:        int i;
                    185: 
                    186:        for (i = FPU_BCD_DIGIT - 1; i >= 0; i--) {
                    187:                a->d[i] += cy;
                    188:                if (a->d[i] >= 10) {
                    189:                        a->d[i] -= 10;
                    190:                        cy = 1;
                    191:                } else {
                    192:                        cy = 0;
                    193:                        /* breakable because no more carry */
                    194:                        break;
                    195:                }
                    196:        }
                    197: 
                    198:        if (cy) {
                    199:                cy = fpu_bcd_shr(a);
                    200:                a->d[0] = 1;
                    201:                a->e++;
                    202:                fpu_bcd_round_cy(a, cy);
                    203:        }
                    204: dump("add_last_n", a);
                    205: }
                    206: 
                    207: /*
                    208:  * banker's rounding by carry
                    209:  */
                    210: static void
                    211: fpu_bcd_round_cy(BCD *a, uint8_t cy)
                    212: {
                    213:        if (cy > 5
                    214:         || (cy == 5 && a->d[FPU_BCD_DIGIT - 1] % 2 != 0)) {
                    215:                fpu_bcd_add_last_n(a, 1);
                    216:        }
                    217: }
                    218: 
                    219: /*
                    220:  * rounding at last digit
                    221:  */
                    222: static void
                    223: fpu_bcd_round(BCD *a)
                    224: {
                    225:        if (a->d[FPU_BCD_DIGIT - 1] >= 5) {
                    226:                fpu_bcd_add_last_n(a, 10);
                    227:                a->d[FPU_BCD_DIGIT - 1] = 0;
                    228:        }
                    229: }
                    230: 
                    231: /*
                    232:  * a = a + b
                    233:  */
                    234: static void
                    235: fpu_bcd_add(BCD *a, const BCD *b)
                    236: {
                    237:        uint8_t cy = 0;
                    238:        BCD t0;
                    239:        BCD *t = &t0;
                    240: 
                    241:        if (fpu_bcd_iszero(a)) {
                    242:                *a = *b;
                    243:                return;
                    244:        }
                    245:        if (fpu_bcd_iszero(b)) {
                    246:                return;
                    247:        }
                    248: 
                    249:        *t = *b;
                    250: 
                    251:        while (a->e != t->e) {
                    252:                if (a->e > t->e) {
                    253:                        t->e++;
                    254:                        cy = fpu_bcd_shr(t);
                    255:                } else if (a->e < t->e) {
                    256:                        a->e++;
                    257:                        cy = fpu_bcd_shr(a);
                    258:                }
                    259:        }
                    260:        fpu_bcd_round_cy(a, cy);
                    261: 
                    262: dump("add:a", a);
                    263: dump("add:t", t);
                    264:        cy = fpu_bcd_add_d(a, t);
                    265: 
                    266:        if (cy) {
                    267:                // last digit rounding
                    268:                cy = fpu_bcd_shr(a);
                    269:                a->d[0] = 1;
                    270:                a->e++;
                    271:                fpu_bcd_round_cy(a, cy);
                    272:        }
                    273: dump("add", a);
                    274: }
                    275: 
                    276: /*
                    277:  * a = a * b
                    278:  */
                    279: static void
                    280: fpu_bcd_mul(BCD *a, const BCD *b)
                    281: {
                    282:        /* need DIGIT * 2 + 1 for mul + cy */
                    283:        uint8_t t0[FPU_BCD_DIGIT * 2 + 1 + 1];
                    284:        uint8_t *t = &t0[1];
                    285:        int i, j, k;
                    286: 
                    287: dump("mul:a", a);
                    288: dump("mul:b", b);
                    289:        memset(t0, 0, sizeof(t0));
                    290: 
                    291:        for (i = FPU_BCD_DIGIT - 1; i >= 0; i--) {
                    292:                for (j = FPU_BCD_DIGIT - 1; j >= 0; j--) {
                    293:                        t[i + j] += a->d[i] * b->d[j];
                    294:                        for (k = i + j; k >= 0; k--) {
                    295:                                if (t[k] >= 10) {
                    296:                                        /* t[-1] available */
                    297:                                        t[k - 1] += t[k] / 10;
                    298:                                        t[k] %= 10;
                    299:                                } else {
                    300:                                        break;
                    301:                                }
                    302:                        }
                    303:                }
                    304:        }
                    305: 
                    306:        a->e = a->e + b->e;
                    307:        if (t[-1]) {
                    308:                a->e++;
                    309:                /* copy 1 digit shifted */
                    310:                memcpy(a->d, &t[-1], sizeof(a->d));
                    311:                fpu_bcd_round_cy(a, t[FPU_BCD_DIGIT - 1]);
                    312:        } else {
                    313:                memcpy(a->d, t, sizeof(a->d));
                    314:                fpu_bcd_round_cy(a, t[FPU_BCD_DIGIT]);
                    315:        }
                    316: dump("mul", a);
                    317: }
                    318: 
                    319: /*
                    320:  * a = pow(2, n)
                    321:  */
                    322: static void
                    323: fpu_bcd_exp2(BCD *a, int n)
                    324: {
                    325:        BCD r0;
                    326:        BCD *r = &r0;
                    327:        int i;
                    328: #if defined(FPU_BCD_DEBUG)
                    329: int save_n = n;
                    330: #endif
                    331: DPRINTF("exp2 n=%d\n", n);
                    332:        memset(a, 0, sizeof(*a));
                    333:        a->d[0] = 1;
                    334: 
                    335:        if (n == 0) {
                    336:        } else {
                    337:                memset(r, 0, sizeof(*r));
                    338:                if (n > 0) {
                    339:                        /* r = 2 */
                    340:                        r->d[0] = 2;
                    341:                } else {
                    342:                        n = -n;
                    343:                        /* r = 0.5 */
                    344:                        r->e = -1;
                    345:                        r->d[0] = 5;
                    346:                }
                    347: 
                    348:                for (i = 0; i < 32; i++) {
                    349:                        if (n & (1 << i)) {
                    350:                                n ^= (1 << i);
                    351:                                fpu_bcd_mul(a, r);
                    352:                        }
                    353:                        if (n == 0) break;
                    354:                        fpu_bcd_mul(r, r);
                    355:                }
                    356:        }
                    357: dump("exp2", a);
                    358: #if defined(__NetBSD__)        /* とりあえず */
                    359: DPRINTF("%18s %.*e\n", "pow", FPU_BCD_DIGIT-1, pow(2, save_n));
                    360: #else
                    361: DPRINTF("%18s %.*Le\n", "powl", FPU_BCD_DIGIT-1, powl(2, save_n));
                    362: #endif
                    363: }
                    364: 
                    365: /* relative mantissa bit */
                    366: int
                    367: getbit(struct fpn *fp, int n)
                    368: {
                    369:        int t;
                    370:        uint32_t x;
                    371:        int b;
                    372: 
                    373:        t = n + (32 - FP_LG);
                    374:        x = fp->fp_mant[(t - 1) / 32];
                    375:        b = x & (1 << (31 - ((t - 1) % 32)));
                    376: DPRINTF("n=%d %d\n", n, b);
                    377:        return b;
                    378: }
                    379: 
                    380: static void
                    381: fpu_itobcd(BCD *a, int x)
                    382: {
                    383:        int i;
                    384:        BCD r0;
                    385:        BCD *r = &r0;
                    386: 
                    387:        memset(a, 0, sizeof(*a));
                    388: 
                    389:        x = abs(x);
                    390: 
                    391:        for (i = 0; i < 32; i++) {
                    392:                if (x == 0) break;
                    393:                if (x & (1 << i)) {
                    394:                        x ^= (1 << i);
                    395:                        fpu_bcd_exp2(r, i);
                    396:                        fpu_bcd_add(a, r);
                    397:                }
                    398:        }
                    399: }
                    400: 
                    401: /* Convert fpn to internal BCD structure */
                    402: static void
                    403: fpu_fpntobcd(BCD *res, struct fpn *fp)
                    404: {
                    405:        BCD bcd_r0;
                    406:        BCD *bcd_r = &bcd_r0;
                    407:        BCD bcd_a0;
                    408:        BCD *bcd_a = &bcd_a0;
                    409:        BCD bcd_b0;
                    410:        BCD *bcd_b = &bcd_b0;
                    411:        int i;
                    412: 
                    413:        memset(bcd_r, 0, sizeof(*bcd_r));
                    414:        memset(bcd_a, 0, sizeof(*bcd_a));
                    415:        memset(bcd_b, 0, sizeof(*bcd_b));
                    416: 
                    417:        for (i = FP_NMANT - 1; i >= 0; i--) {
                    418:                // 最下位ビットから取り出していく
                    419:                if (getbit(fp, i)) {
                    420: 
                    421:                        // 調べるビットの相当する 2^(exp-i) を計算する
                    422:                        fpu_bcd_exp2(bcd_r, fp->fp_exp - i);
                    423: dump("r", bcd_r);
                    424: 
                    425:                        fpu_bcd_add(bcd_b, bcd_r);
                    426: dump("b", bcd_b);
                    427:                }
                    428:        }
                    429: dump("b", bcd_b);
                    430: 
                    431:        fpu_bcd_round(bcd_b);
                    432: dump("b", bcd_b);
                    433: 
                    434:        /* とりあえず */
                    435:        *res = *bcd_b;
                    436:        return;
                    437: }
                    438: 
                    439: /*
                    440:  * fpn -> 96-bit packed BCD(space)
                    441:  */
                    442: void
                    443: fpu_ftop(struct fpemu *fe, struct fpn *fp, uint32_t *space, int kfactor)
                    444: {
                    445:        BCD b0, *b;
                    446:        BCD e0, *e;
                    447:        int i;
                    448:        int shift;
                    449: 
                    450:        b = &b0;
                    451:        e = &e0;
                    452: 
                    453:        space[0] = 0;
                    454:        space[1] = 0;
                    455:        space[2] = 0;
                    456: 
                    457:        if (fp->fp_sign) {
                    458:                space[0] |= 0x80000000;
                    459:        }
                    460: 
                    461:        if (ISINF(fp)) {
                    462:                space[0] |= 0x7fff0000;
                    463:                return;
                    464:        }
                    465: 
                    466:        /* fp をアンパックド BCD に変換 */
                    467:        fpu_fpntobcd(b, fp);
                    468: 
                    469:        /*
                    470:         * k-factor
                    471:         */
                    472: DPRINTF("kfactor=%d\n", kfactor);
                    473:        if (kfactor <= 0) {
                    474:                /*
                    475:                 * FORTRAN "F" format.
                    476:                 * 小数以下 -k 桁まで出力する。
                    477:                 */
                    478:                if (b->e >= 17) {
                    479:                        /* 10^17以上の値なら17桁で小数に到達しないので k=+17 と等価 */
                    480:                        kfactor = 17;
                    481:                } else {
                    482:                        shift = FPU_BCD_DIGIT - b->e + kfactor - 2;
                    483:                }
                    484:        }
                    485:        if (kfactor > 0) {
                    486:                if (kfactor > 17) {
                    487:                        fe->fe_fpsr |= FPSR_OPERR;
                    488:                        kfactor = 17;
                    489:                }
                    490:                /*
                    491:                 * FORTRAN "E" format.
                    492:                 * k は小数点位置に関わらず出力する桁数(文字数) を表す。
                    493:                 * 1 なら 1桁だけ(つまり整数部のみ)、17 で全桁となる。
                    494:                 */
                    495:                shift = FPU_BCD_DIGIT - kfactor - 1;
                    496:        }
                    497: dump("k:0", b);
                    498:        fpu_bcd_shr_n(b, shift);
                    499: dump("k:1", b);
                    500:        fpu_bcd_round(b);
                    501:        /* 四捨五入に使った最終桁はもう不要 */
                    502:        b->d[FPU_BCD_DIGIT - 1] = 0;
                    503: dump("k:2", b);
                    504:        fpu_bcd_shl_n(b, shift);
                    505: dump("k:3", b);
                    506: 
                    507:        /*
                    508:         * ここから 68881 の パックド BCD に変換していく
                    509:         */
                    510:        /* exp の変換 */
                    511:        /* P 形式の EXP フィールドは 10 基数 */
                    512:        if (b->e < 0) {
                    513:                space[0] |= 0x40000000;
                    514:        }
                    515: 
                    516:        fpu_itobcd(e, abs(b->e));
                    517:        fpu_bcd_shr_n(e, 3 - e->e);
                    518:        space[0] |= e->d[0] << 12;      /* EXP3 */
                    519:        space[0] |= e->d[1] << 24;      /* EXP2 */
                    520:        space[0] |= e->d[2] << 20;      /* EXP1 */
                    521:        space[0] |= e->d[3] << 16;      /* EXP0 */
                    522: 
                    523:        space[0] |= b->d[0];
                    524: DPRINTF("BCD[0]=%08x\n", space[0]);
                    525: 
                    526:        /* 小数部 */
                    527:        for (i = 1; i < 9; i++) {
                    528:                space[1] <<= 4;
                    529:                space[1] |= b->d[i];
                    530:        }
                    531: 
                    532:        for (i = 9; i < 17; i++) {
                    533:                space[2] <<= 4;
                    534:                space[2] |= b->d[i];
                    535:        }
                    536: }

unix.superglobalmegacorp.com

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