diff --git a/kernel/src/Api/BuildNo.hpp b/kernel/src/Api/BuildNo.hpp index 4adff58..b3a52e6 100644 --- a/kernel/src/Api/BuildNo.hpp +++ b/kernel/src/Api/BuildNo.hpp @@ -12,4 +12,4 @@ #pragma once -#define MONTAUK_BUILD_NUMBER 7 +#define MONTAUK_BUILD_NUMBER 8 diff --git a/programs/lib/libc/libc.c b/programs/lib/libc/libc.c index 0570e14..42476f6 100644 --- a/programs/lib/libc/libc.c +++ b/programs/lib/libc/libc.c @@ -1174,6 +1174,226 @@ static void _pf_putnum(struct _pf_state *st, unsigned long val, int base, int up _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) { struct _pf_state st; st.buf = buf; @@ -1188,12 +1408,16 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) { fmt++; char pad = ' '; - int left_align = 0; - while (*fmt == '0' || *fmt == '-' || *fmt == '+' || *fmt == ' ') { + int left_align = 0, plus = 0, space = 0, alt = 0; + while (*fmt == '0' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '#') { 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++; } + if (left_align) pad = ' '; int width = 0; if (*fmt == '*') { @@ -1299,6 +1523,14 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) { _pf_putc(&st, c); 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 '%': _pf_putc(&st, '%'); break; @@ -2386,9 +2618,6 @@ double cos(double x) { /* ---- 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) { if (x <= 0.0) return -HUGE_VAL; if (x == 1.0) return 0.0; diff --git a/programs/lib/libc/obj/libc.o b/programs/lib/libc/obj/libc.o index 866158a..ea40a3c 100644 Binary files a/programs/lib/libc/obj/libc.o and b/programs/lib/libc/obj/libc.o differ