static_inline void f64_bin_to_dec()

in include/yyjson/yyjson.c [7296:7354]


static_inline void f64_bin_to_dec(u64 sig_raw, u32 exp_raw,
                                  u64 sig_bin, i32 exp_bin,
                                  u64 *sig_dec, i32 *exp_dec) {
    
    bool is_even, regular_spacing, u_inside, w_inside, round_up;
    u64 s, sp, cb, cbl, cbr, vb, vbl, vbr, pow10hi, pow10lo, upper, lower, mid;
    i32 k, h, exp10;
    
    is_even = !(sig_bin & 1);
    regular_spacing = (sig_raw == 0 && exp_raw > 1);
    
    cbl = 4 * sig_bin - 2 + regular_spacing;
    cb  = 4 * sig_bin;
    cbr = 4 * sig_bin + 2;
    
    /* exp_bin: [-1074, 971]                                                  */
    /* k = regular_spacing ? floor(log10(pow(2, exp_bin)))                    */
    /*                     : floor(log10(pow(2, exp_bin) * 3.0 / 4.0))        */
    /*   = regular_spacing ? floor(exp_bin * log10(2))                        */
    /*                     : floor(exp_bin * log10(2) + log10(3.0 / 4.0))     */
    k = (i32)(exp_bin * 315653 - (regular_spacing ? 131237 : 0)) >> 20;
    
    /* k: [-324, 292]                                                         */
    /* h = exp_bin + floor(log2(pow(10, e)))                                  */
    /*   = exp_bin + floor(log2(10) * e)                                      */
    exp10 = -k;
    h = exp_bin + ((exp10 * 217707) >> 16) + 1;
    
    pow10_table_get_sig(exp10, &pow10hi, &pow10lo);
    pow10lo += (exp10 < POW10_SIG_TABLE_MIN_EXACT_EXP ||
                exp10 > POW10_SIG_TABLE_MAX_EXACT_EXP);
    vbl = round_to_odd(pow10hi, pow10lo, cbl << h);
    vb  = round_to_odd(pow10hi, pow10lo, cb  << h);
    vbr = round_to_odd(pow10hi, pow10lo, cbr << h);
    
    lower = vbl + !is_even;
    upper = vbr - !is_even;
    
    s = vb / 4;
    if (s >= 10) {
        sp = s / 10;
        u_inside = (lower <= 40 * sp);
        w_inside = (upper >= 40 * sp + 40);
        if (u_inside != w_inside) {
            *sig_dec = sp + w_inside;
            *exp_dec = k + 1;
            return;
        }
    }
    
    u_inside = (lower <= 4 * s);
    w_inside = (upper >= 4 * s + 4);
    
    mid = 4 * s + 2;
    round_up = (vb > mid) || (vb == mid && (s & 1) != 0);
    
    *sig_dec = s + ((u_inside != w_inside) ? w_inside : round_up);
    *exp_dec = k;
}