Annotation of nono/lib/exttostr.cpp, revision 1.1.1.1

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2024 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // MC68881 の Extended フォーマットを文字列にする
                      9: //
                     10: 
                     11: #include "exttostr.h"
                     12: #include "mystring.h"
                     13: 
                     14: #define BCD_N (3)
                     15: #define BCD_M (1'000'000'000)
                     16: 
                     17: // 5 の n 乗を返す。n は 0..13。
                     18: static uint32
                     19: pow5(int n)
                     20: {
                     21:        static const uint32 table[] = {
                     22:                1,
                     23:                5,
                     24:                25,
                     25:                125,
                     26:                625,
                     27:                3125,
                     28:                15625,
                     29:                78125,
                     30:                390625,
                     31:                1953125,
                     32:                9765625,
                     33:                48828125,
                     34:                244140625,
                     35:                1220703125,
                     36:        };
                     37:        return table[n];
                     38: }
                     39: 
                     40: // 10進右シフト (というか 10 ずつの除算)。
                     41: // n には桁数ではなく 10のべき数のみ渡すこと。
                     42: static void
                     43: bcdshr(uint32 *digit, uint32 n)
                     44: {
                     45:        uint64 t;
                     46:        t = 0;
                     47:        for (int i = BCD_N - 1; i >= 0; i--) {
                     48:                t += (uint64)digit[i];
                     49:                digit[i] = t / n;
                     50:                t = (t % n) * (BCD_M);
                     51:        }
                     52: }
                     53: 
                     54: // digit に v を乗算する。
                     55: // 戻り値は 10進で右シフトした桁数。
                     56: static uint32
                     57: bcdmul(uint32 *digit, uint32 v)
                     58: {
                     59:        uint64 cy = 0;
                     60:        uint64 t;
                     61:        for (int i = 0; i < BCD_N; i++) {
                     62:                t = (uint64)digit[i] * v + cy;
                     63:                digit[i] = (uint32)(t % BCD_M);
                     64:                cy = t / BCD_M;
                     65:        }
                     66: 
                     67:        uint32 d = 0;
                     68:        while (cy != 0) {
                     69:                bcdshr(digit, 10);
                     70:                digit[BCD_N - 1] += (cy % 10) * (BCD_M / 10);
                     71:                cy /= 10;
                     72:                d++;
                     73:        }
                     74: 
                     75:        return d;
                     76: }
                     77: 
                     78: // digit に v を加算する。
                     79: static uint32
                     80: bcdadd(uint32 *digit, uint32 v)
                     81: {
                     82:        uint64 cy = v;
                     83:        uint64 t;
                     84:        for (int i = 0; i < BCD_N; i++) {
                     85:                t = (uint64)digit[i] + cy;
                     86:                digit[i] = (uint32)(t % BCD_M);
                     87:                cy = t / BCD_M;
                     88:        }
                     89:        return cy;
                     90: }
                     91: 
                     92: // MC68881 の Extended 形式を 10進数文字列に変換する。
                     93: std::string
                     94: ExtToStr(const uint32 *data)
                     95: {
                     96:        std::string rv;
                     97: 
                     98:        int s = data[0] >> 31;
                     99:        int32 e = (int32)((data[0] >> 16) & 0x7fff);
                    100:        uint64 m = ((uint64)data[1] << 32) | data[2];
                    101: 
                    102:        if (e == 0x7fff) {
                    103:                if (m != 0) {
                    104:                        if (m & (1ULL << 62)) {
                    105:                                return "QNAN";
                    106:                        } else {
                    107:                                return "SNAN";
                    108:                        }
                    109:                } else {
                    110:                        if (s == 0) {
                    111:                                return "+INF";
                    112:                        } else {
                    113:                                return "-INF";
                    114:                        }
                    115:                }
                    116:        }
                    117: 
                    118:        if (s == 0) {
                    119:                rv = '+';
                    120:        } else {
                    121:                rv = '-';
                    122:        }
                    123: 
                    124:        if (e == 0 && (m & (1ULL << 63)) == 0) {
                    125:                // denormal
                    126:                e = -16383;
                    127:        } else {
                    128:                e -= 0x3fff;
                    129:        }
                    130: 
                    131:        // unnormal zero も 0 として返す。
                    132:        if (m == 0) {
                    133:                rv += '0';
                    134:                return rv;
                    135:        }
                    136: 
                    137:        // BCD に変換。
                    138:        uint32 a[BCD_N];
                    139:        for (int i = 0; i < BCD_N; i++) {
                    140:                a[i] = m % BCD_M;
                    141:                m /= BCD_M;
                    142:        }
                    143:        e -= 63;
                    144: 
                    145:        int d = 0;
                    146:        uint32 x;
                    147: 
                    148:        // 2進指数を 10進指数化する。
                    149:        if (e > 0) {
                    150:                // 2**e を 2**31 以下単位で掛けていく。
                    151:                while (e > 0) {
                    152:                        x = e;
                    153:                        if (x >= 31) {
                    154:                                x = 31;
                    155:                        }
                    156:                        e -= x;
                    157:                        d += bcdmul(a, 1U << x);
                    158:                }
                    159:        } else {
                    160:                // 2**abs(e) で割らないといけないが、10以外での除算は大変なので、
                    161:                // m / 10**abs(e) * 5**abs(e) する。
                    162:                d = e;
                    163:                e = -e;
                    164:                while (e > 0) {
                    165:                        x = e;
                    166:                        if (x >= 13) {
                    167:                                x = 13;
                    168:                        }
                    169:                        e -= x;
                    170:                        d += bcdmul(a, pow5(x));
                    171:                }
                    172:        }
                    173: 
                    174:        // 上詰めにする。
                    175:        while (a[BCD_N - 1] < BCD_M / 10) {
                    176:                bcdmul(a, 10);
                    177:                d--;
                    178:        }
                    179:        d += BCD_N * 9 - 1;
                    180: 
                    181:        // 四捨五入。ここは 10進変換の丸めで、FPU の丸めモードとは関係ない。
                    182: #define BCD_ROUNDER    (500'000)
                    183:        bcdadd(a, BCD_ROUNDER);
                    184: 
                    185:        // E形式、小数点以下20桁を返す。
                    186:        rv += string_format("%u.%08u%09u%03u",
                    187:                a[BCD_N - 1] / (BCD_M / 10),
                    188:                a[BCD_N - 1] % (BCD_M / 10),
                    189:                a[BCD_N - 2],
                    190:                a[BCD_N - 3] / (BCD_ROUNDER * 2));
                    191: 
                    192:        if (d != 0) {
                    193:                rv += string_format("E%d", d);
                    194:        }
                    195:        return rv;
                    196: }
                    197: 
                    198: #if defined(TEST)
                    199: //
                    200: // How to use:
                    201: //  % make test_exttostr
                    202: //  % ./test_exttostr
                    203: //
                    204: #include <stdio.h>
                    205: 
                    206: int
                    207: main(int ac, char *av[])
                    208: {
                    209: #define E(M1,M2,M3) { 0x##M1, 0x##M2, 0x##M3 }
                    210:        struct {
                    211:                uint32 inp[3];
                    212:                const char *exp;
                    213:        } table[] = {
                    214:                { E(00000000, 00000000, 00000000), "+0" },
                    215:                { E(80000000, 00000000, 00000000), "-0" },
                    216:                { E(7fff0000, 00000000, 00000000), "+INF" },
                    217:                { E(ffff0000, 00000000, 00000000), "-INF" },
                    218:                { E(7fff0000, ffffffff, ffffffff), "QNAN" },
                    219:                { E(ffff0000, ffffffff, ffffffff), "QNAN" },
                    220:                { E(7fff0000, bfffffff, ffffffff), "SNAN" },
                    221:                { E(ffff0000, bfffffff, ffffffff), "SNAN" },
                    222:                { E(3fff0000, 80000000, 00000000), "+1.00000000000000000000" },
                    223:                { E(bfff0000, 80000000, 00000000), "-1.00000000000000000000" },
                    224:                { E(40050000, c8000000, 00000000), "+1.00000000000000000000E2" },
                    225:                { E(400e0000, ffff0000, 00000000), "+6.55350000000000000000E4" },
                    226: 
                    227:                // 1 より大きい最小の区別可能な数
                    228:                { E(3fff0000, 80000000, 00000001), "+1.00000000000000000011" },
                    229: 
                    230:                // From XEiJ/EFPBox.java
                    231:                // 正規化数の最大値
                    232:                { E(7ffe0000, ffffffff, ffffffff), "+1.18973149535723176502E4932" },
                    233:                // 正規化数の最小値
                    234:                { E(00000000, 80000000, 00000000), "+1.68105157155604675313E-4932" },
                    235:                // 非正規化数の最大値
                    236:                { E(00000000, 7fffffff, ffffffff), "+1.68105157155604675295E-4932" },
                    237:                // 非正規化数の最小値
                    238:                { E(00000000, 00000000, 00000001), "+1.82259976594123730126E-4951" },
                    239:        };
                    240: 
                    241:        int total = countof(table);
                    242:        int failed = 0;
                    243:        for (int i = 0; i < total; i++) {
                    244:                const uint32 *inp = table[i].inp;
                    245:                const char *exp = table[i].exp;
                    246: 
                    247:                std::string act = ExtToStr(inp);
                    248:                if (act != exp) {
                    249:                        printf("[%u] %08x_%08x_%08x expects \"%s\" but \"%s\"\n",
                    250:                                i, inp[0], inp[1], inp[2], exp, act.c_str());
                    251:                        failed++;
                    252:                }
                    253:        }
                    254:        if (failed > 0) {
                    255:                printf("%u tests, %u failed.\n", total, failed);
                    256:        } else {
                    257:                printf("%u tests, all passed.\n", total);
                    258:        }
                    259:        return 0;
                    260: }
                    261: #endif

unix.superglobalmegacorp.com

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