feat: add floating-point support to format functions in libc
This commit is contained in:
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MONTAUK_BUILD_NUMBER 7
|
#define MONTAUK_BUILD_NUMBER 8
|
||||||
|
|||||||
+235
-6
@@ -1174,6 +1174,226 @@ static void _pf_putnum(struct _pf_state *st, unsigned long val, int base, int up
|
|||||||
_pf_putc(st, tmp[--i]);
|
_pf_putc(st, tmp[--i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Union for double bit manipulation (used by float formatting and math). */
|
||||||
|
typedef union { double d; uint64_t u; } _dbl_bits;
|
||||||
|
|
||||||
|
/* Base-10 exponent of the leading digit of a positive finite value, i.e. the
|
||||||
|
E such that value = m * 10^E with m in [1, 10). No rounding is applied. */
|
||||||
|
static int _pf_exp10(double v) {
|
||||||
|
int E = (int)floor(log10(v));
|
||||||
|
double s = v / pow(10.0, (double)E);
|
||||||
|
if (s >= 10.0) E++;
|
||||||
|
else if (s < 1.0) E--;
|
||||||
|
return E;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate `nsig` significant decimal digits of a positive finite value into
|
||||||
|
`out` (ASCII, no terminator). Returns the base-10 exponent of the leading
|
||||||
|
digit, i.e. value ~= (out[0].out[1..]) * 10^E. Rounding is half-up and may
|
||||||
|
carry into a new leading digit, bumping the returned exponent. */
|
||||||
|
static int _pf_gendigits(double v, int nsig, char *out) {
|
||||||
|
int E = (int)floor(log10(v));
|
||||||
|
double scale = v / pow(10.0, (double)E);
|
||||||
|
/* Correct estimate errors so scale lands in [1, 10). */
|
||||||
|
if (scale >= 10.0) { scale /= 10.0; E++; }
|
||||||
|
else if (scale < 1.0) { scale *= 10.0; E--; }
|
||||||
|
|
||||||
|
for (int i = 0; i < nsig; i++) {
|
||||||
|
int d = (int)scale;
|
||||||
|
if (d < 0) d = 0; else if (d > 9) d = 9;
|
||||||
|
out[i] = (char)('0' + d);
|
||||||
|
scale = (scale - d) * 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale >= 5.0) { /* round up based on the next digit */
|
||||||
|
int i = nsig - 1;
|
||||||
|
while (i >= 0) {
|
||||||
|
if (out[i] == '9') { out[i] = '0'; i--; }
|
||||||
|
else { out[i]++; break; }
|
||||||
|
}
|
||||||
|
if (i < 0) { out[0] = '1'; E++; } /* all nines carried out */
|
||||||
|
}
|
||||||
|
return E;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append the two-or-more-digit exponent field of %e/%g ("e+NN"). */
|
||||||
|
static void _pf_put_exp(char *mbuf, int *mlen, int E, int upper) {
|
||||||
|
int m = *mlen;
|
||||||
|
mbuf[m++] = upper ? 'E' : 'e';
|
||||||
|
int ex = E; char es = '+';
|
||||||
|
if (ex < 0) { es = '-'; ex = -ex; }
|
||||||
|
mbuf[m++] = es;
|
||||||
|
char eb[8]; int el = 0;
|
||||||
|
if (ex == 0) eb[el++] = '0';
|
||||||
|
while (ex > 0) { eb[el++] = (char)('0' + ex % 10); ex /= 10; }
|
||||||
|
while (el < 2) eb[el++] = '0';
|
||||||
|
while (el > 0) mbuf[m++] = eb[--el];
|
||||||
|
*mlen = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format a floating-point value for the %e/%f/%g conversions (and uppercase
|
||||||
|
variants), honoring precision, width, padding and sign flags. */
|
||||||
|
static void _pf_putfloat(struct _pf_state *st, double v, char conv,
|
||||||
|
int precision, int width, char pad,
|
||||||
|
int left_align, int plus, int space, int alt) {
|
||||||
|
int upper = (conv >= 'A' && conv <= 'Z');
|
||||||
|
char lc = upper ? (char)(conv - 'A' + 'a') : conv;
|
||||||
|
|
||||||
|
_dbl_bits bits; bits.d = v;
|
||||||
|
int neg = (int)(bits.u >> 63);
|
||||||
|
uint64_t expo = (bits.u >> 52) & 0x7FF;
|
||||||
|
uint64_t mant = bits.u & 0x000FFFFFFFFFFFFFULL;
|
||||||
|
|
||||||
|
char sign = 0;
|
||||||
|
if (neg) sign = '-';
|
||||||
|
else if (plus) sign = '+';
|
||||||
|
else if (space) sign = ' ';
|
||||||
|
|
||||||
|
/* Infinity / NaN: never zero-padded. */
|
||||||
|
if (expo == 0x7FF) {
|
||||||
|
const char *word = mant ? (upper ? "NAN" : "nan") : (upper ? "INF" : "inf");
|
||||||
|
if (mant) sign = 0;
|
||||||
|
char tmp[8]; int tl = 0;
|
||||||
|
if (sign) tmp[tl++] = sign;
|
||||||
|
for (const char *p = word; *p; p++) tmp[tl++] = *p;
|
||||||
|
if (!left_align) for (int w = tl; w < width; w++) _pf_putc(st, ' ');
|
||||||
|
for (int i = 0; i < tl; i++) _pf_putc(st, tmp[i]);
|
||||||
|
if (left_align) for (int w = tl; w < width; w++) _pf_putc(st, ' ');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (precision < 0) precision = 6;
|
||||||
|
if (precision > 340) precision = 340;
|
||||||
|
|
||||||
|
double av = neg ? -v : v;
|
||||||
|
|
||||||
|
char mbuf[800];
|
||||||
|
int mlen = 0;
|
||||||
|
|
||||||
|
if (lc == 'e') {
|
||||||
|
int nsig = precision + 1;
|
||||||
|
char dig[400];
|
||||||
|
int E;
|
||||||
|
if (av == 0.0) { for (int i = 0; i < nsig; i++) dig[i] = '0'; E = 0; }
|
||||||
|
else E = _pf_gendigits(av, nsig, dig);
|
||||||
|
mbuf[mlen++] = dig[0];
|
||||||
|
if (precision > 0 || alt) {
|
||||||
|
mbuf[mlen++] = '.';
|
||||||
|
for (int i = 1; i <= precision; i++) mbuf[mlen++] = dig[i];
|
||||||
|
}
|
||||||
|
_pf_put_exp(mbuf, &mlen, E, upper);
|
||||||
|
}
|
||||||
|
else if (lc == 'f') {
|
||||||
|
if (av == 0.0) {
|
||||||
|
mbuf[mlen++] = '0';
|
||||||
|
if (precision > 0 || alt) {
|
||||||
|
mbuf[mlen++] = '.';
|
||||||
|
for (int i = 0; i < precision; i++) mbuf[mlen++] = '0';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int Ef = _pf_exp10(av);
|
||||||
|
int keep = Ef + 1 + precision;
|
||||||
|
if (keep <= 0) {
|
||||||
|
char d1[4];
|
||||||
|
_pf_gendigits(av, 1, d1);
|
||||||
|
int roundUp = (keep == 0 && d1[0] >= '5');
|
||||||
|
mbuf[mlen++] = '0';
|
||||||
|
if (precision > 0 || alt) {
|
||||||
|
mbuf[mlen++] = '.';
|
||||||
|
for (int i = 0; i < precision; i++) mbuf[mlen++] = '0';
|
||||||
|
}
|
||||||
|
if (roundUp) mbuf[mlen - 1] = '1';
|
||||||
|
} else {
|
||||||
|
if (keep > 380) keep = 380;
|
||||||
|
char dig[400];
|
||||||
|
int E = _pf_gendigits(av, keep, dig);
|
||||||
|
int len = keep;
|
||||||
|
int intlen = (E >= 0) ? (E + 1) : 0;
|
||||||
|
if (intlen == 0) mbuf[mlen++] = '0';
|
||||||
|
else for (int i = 0; i < intlen; i++) mbuf[mlen++] = (i < len ? dig[i] : '0');
|
||||||
|
if (precision > 0 || alt) {
|
||||||
|
mbuf[mlen++] = '.';
|
||||||
|
if (E < 0) {
|
||||||
|
int lead = -E - 1;
|
||||||
|
for (int k = 0; k < precision; k++) {
|
||||||
|
if (k < lead) mbuf[mlen++] = '0';
|
||||||
|
else { int idx = k - lead; mbuf[mlen++] = (idx < len ? dig[idx] : '0'); }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int k = 0; k < precision; k++) {
|
||||||
|
int idx = intlen + k;
|
||||||
|
mbuf[mlen++] = (idx < len ? dig[idx] : '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { /* 'g' / 'G' */
|
||||||
|
int P = precision; if (P == 0) P = 1;
|
||||||
|
char dig[400];
|
||||||
|
int E;
|
||||||
|
if (av == 0.0) { E = 0; for (int i = 0; i < P; i++) dig[i] = '0'; }
|
||||||
|
else E = _pf_gendigits(av, P, dig);
|
||||||
|
int len = P;
|
||||||
|
int useExp = (E < -4 || E >= P);
|
||||||
|
int hasDot = 0;
|
||||||
|
if (useExp) {
|
||||||
|
int fp = P - 1;
|
||||||
|
mbuf[mlen++] = dig[0];
|
||||||
|
if (fp > 0 || alt) {
|
||||||
|
mbuf[mlen++] = '.'; hasDot = 1;
|
||||||
|
for (int i = 1; i <= fp; i++) mbuf[mlen++] = dig[i];
|
||||||
|
}
|
||||||
|
if (!alt && hasDot) {
|
||||||
|
while (mbuf[mlen - 1] == '0') mlen--;
|
||||||
|
if (mbuf[mlen - 1] == '.') mlen--;
|
||||||
|
}
|
||||||
|
_pf_put_exp(mbuf, &mlen, E, upper);
|
||||||
|
} else {
|
||||||
|
int fp = P - 1 - E;
|
||||||
|
if (fp < 0) fp = 0;
|
||||||
|
int intlen = (E >= 0) ? (E + 1) : 0;
|
||||||
|
if (intlen == 0) mbuf[mlen++] = '0';
|
||||||
|
else for (int i = 0; i < intlen; i++) mbuf[mlen++] = (i < len ? dig[i] : '0');
|
||||||
|
if (fp > 0 || alt) {
|
||||||
|
mbuf[mlen++] = '.'; hasDot = 1;
|
||||||
|
if (E < 0) {
|
||||||
|
int lead = -E - 1;
|
||||||
|
for (int k = 0; k < fp; k++) {
|
||||||
|
if (k < lead) mbuf[mlen++] = '0';
|
||||||
|
else { int idx = k - lead; mbuf[mlen++] = (idx < len ? dig[idx] : '0'); }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int k = 0; k < fp; k++) {
|
||||||
|
int idx = intlen + k;
|
||||||
|
mbuf[mlen++] = (idx < len ? dig[idx] : '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!alt && hasDot) {
|
||||||
|
while (mbuf[mlen - 1] == '0') mlen--;
|
||||||
|
if (mbuf[mlen - 1] == '.') mlen--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int total = (sign ? 1 : 0) + mlen;
|
||||||
|
if (!left_align && pad == '0') {
|
||||||
|
if (sign) _pf_putc(st, sign);
|
||||||
|
for (int w = total; w < width; w++) _pf_putc(st, '0');
|
||||||
|
for (int i = 0; i < mlen; i++) _pf_putc(st, mbuf[i]);
|
||||||
|
} else if (!left_align) {
|
||||||
|
for (int w = total; w < width; w++) _pf_putc(st, ' ');
|
||||||
|
if (sign) _pf_putc(st, sign);
|
||||||
|
for (int i = 0; i < mlen; i++) _pf_putc(st, mbuf[i]);
|
||||||
|
} else {
|
||||||
|
if (sign) _pf_putc(st, sign);
|
||||||
|
for (int i = 0; i < mlen; i++) _pf_putc(st, mbuf[i]);
|
||||||
|
for (int w = total; w < width; w++) _pf_putc(st, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) {
|
int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) {
|
||||||
struct _pf_state st;
|
struct _pf_state st;
|
||||||
st.buf = buf;
|
st.buf = buf;
|
||||||
@@ -1188,12 +1408,16 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) {
|
|||||||
fmt++;
|
fmt++;
|
||||||
|
|
||||||
char pad = ' ';
|
char pad = ' ';
|
||||||
int left_align = 0;
|
int left_align = 0, plus = 0, space = 0, alt = 0;
|
||||||
while (*fmt == '0' || *fmt == '-' || *fmt == '+' || *fmt == ' ') {
|
while (*fmt == '0' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '#') {
|
||||||
if (*fmt == '0') pad = '0';
|
if (*fmt == '0') pad = '0';
|
||||||
if (*fmt == '-') { left_align = 1; pad = ' '; }
|
else if (*fmt == '-') left_align = 1;
|
||||||
|
else if (*fmt == '+') plus = 1;
|
||||||
|
else if (*fmt == ' ') space = 1;
|
||||||
|
else if (*fmt == '#') alt = 1;
|
||||||
fmt++;
|
fmt++;
|
||||||
}
|
}
|
||||||
|
if (left_align) pad = ' ';
|
||||||
|
|
||||||
int width = 0;
|
int width = 0;
|
||||||
if (*fmt == '*') {
|
if (*fmt == '*') {
|
||||||
@@ -1299,6 +1523,14 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) {
|
|||||||
_pf_putc(&st, c);
|
_pf_putc(&st, c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'f': case 'F':
|
||||||
|
case 'e': case 'E':
|
||||||
|
case 'g': case 'G': {
|
||||||
|
double dv = va_arg(ap, double);
|
||||||
|
_pf_putfloat(&st, dv, *fmt, precision, width, pad,
|
||||||
|
left_align, plus, space, alt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case '%':
|
case '%':
|
||||||
_pf_putc(&st, '%');
|
_pf_putc(&st, '%');
|
||||||
break;
|
break;
|
||||||
@@ -2386,9 +2618,6 @@ double cos(double x) {
|
|||||||
|
|
||||||
/* ---- log via exponent extraction + polynomial on [1, 2) ---- */
|
/* ---- log via exponent extraction + polynomial on [1, 2) ---- */
|
||||||
|
|
||||||
/* Union for double bit manipulation */
|
|
||||||
typedef union { double d; uint64_t u; } _dbl_bits;
|
|
||||||
|
|
||||||
double log(double x) {
|
double log(double x) {
|
||||||
if (x <= 0.0) return -HUGE_VAL;
|
if (x <= 0.0) return -HUGE_VAL;
|
||||||
if (x == 1.0) return 0.0;
|
if (x == 1.0) return 0.0;
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user