diff --git a/newlib/libc/tinystdio/conv_flt.c b/newlib/libc/tinystdio/conv_flt.c index deef747a7c..512f30470f 100644 --- a/newlib/libc/tinystdio/conv_flt.c +++ b/newlib/libc/tinystdio/conv_flt.c @@ -431,8 +431,12 @@ conv_flt (FLT_STREAM *stream, FLT_CONTEXT *context, width_t width, void *addr, u if (!isdigit (edig)) { scanf_ungetc(edig, stream, context); - if (esign != EOF) - scanf_ungetc(esign, stream, context); + if (esign != EOF) { + esign = scanf_getc (stream, context); + if(!isdigit (esign)) + return 0; + scanf_ungetc(edig, stream, context); + } goto no_exp; } diff --git a/newlib/libc/tinystdio/stdio.h b/newlib/libc/tinystdio/stdio.h index 9356c3ed98..7fda4fa433 100644 --- a/newlib/libc/tinystdio/stdio.h +++ b/newlib/libc/tinystdio/stdio.h @@ -89,6 +89,9 @@ typedef __uint16_t __ungetc_t; struct __file { __ungetc_t unget; /* ungetc() buffer */ __uint8_t flags; /* flags, see below */ +#ifdef __IO_PERCENT_N + size_t buflimit; /* buffer limit size */ +#endif #define __SRD 0x0001 /* OK to read */ #define __SWR 0x0002 /* OK to write */ #define __SERR 0x0004 /* found error */ diff --git a/newlib/libc/tinystdio/stdio_private.h b/newlib/libc/tinystdio/stdio_private.h index e8256cacf1..b4898417a1 100644 --- a/newlib/libc/tinystdio/stdio_private.h +++ b/newlib/libc/tinystdio/stdio_private.h @@ -49,6 +49,13 @@ #include #include +#ifdef __IO_PERCENT_N +#define PRINTF_BUF_LIMIT(_s, _end) \ + .buflimit = (size_t)((_end) ? ((char *)(_end) - (char *)(_s)) : (INT_MAX)), +#else +#define PRINTF_BUF_LIMIT(_s, _end) +#endif + struct __file_str { struct __file file; /* main file struct */ char *pos; /* current buffer position */ @@ -111,6 +118,7 @@ bool __matchcaseprefix(const char *input, const char *pattern); #define FDEV_SETUP_STRING_WRITE(_s, _end) { \ .file = { \ .flags = __SWR, \ + PRINTF_BUF_LIMIT(_s, _end) \ .put = __file_str_put, \ __LOCK_INIT_NONE \ }, \ diff --git a/newlib/libc/tinystdio/vfprintf.c b/newlib/libc/tinystdio/vfprintf.c index 0e697109ab..920075dc42 100644 --- a/newlib/libc/tinystdio/vfprintf.c +++ b/newlib/libc/tinystdio/vfprintf.c @@ -245,6 +245,15 @@ typedef long ultoa_signed_t; #define arg_to_unsigned(ap, flags, result_var) arg_to_t(ap, flags, unsigned, result_var) #define arg_to_signed(ap, flags, result_var) arg_to_t(ap, flags, signed, result_var) +#define ASSIGN_STREAM_LEN(stream_len, buflimit, flags, type) \ + if (flags & __SBUF) { \ + *va_arg(ap, type *) = stream_len; \ + } else { \ + *va_arg(ap, type *) = ((size_t)stream_len >= buflimit) ? \ + (type)buflimit : \ + (type)stream_len; \ + } + #include "ultoa_invert.c" /* Order is relevant here and matches order in format string */ @@ -1192,17 +1201,25 @@ int vfprintf (FILE * stream, const CHAR *fmt, va_list ap_orig) goto handle_error; #else if (flags & FL_LONG) { - if (flags & FL_REPD_TYPE) - *va_arg(ap, long long *) = stream_len; - else - *va_arg(ap, long *) = stream_len; + if ((flags)&FL_REPD_TYPE) { + ASSIGN_STREAM_LEN(stream_len, stream->buflimit, + stream->flags, long long); + } else { + ASSIGN_STREAM_LEN(stream_len, stream->buflimit, + stream->flags, long); + } } else if (flags & FL_SHORT) { - if (flags & FL_REPD_TYPE) - *va_arg(ap, char *) = stream_len; - else - *va_arg(ap, short *) = stream_len; + if ((flags)&FL_REPD_TYPE) { + ASSIGN_STREAM_LEN(stream_len, stream->buflimit, + stream->flags, char); + } else { + ASSIGN_STREAM_LEN(stream_len, stream->buflimit, + stream->flags, short); + } } else { - *va_arg(ap, int *) = stream_len; + ASSIGN_STREAM_LEN(stream_len, stream->buflimit, + stream->flags, int); + } #endif #endif @@ -1249,7 +1266,9 @@ int vfprintf (FILE * stream, const CHAR *fmt, va_list ap_orig) base = 2; #endif } else { - my_putc('%', stream); + while (--width > 0) { + my_putc(' ', stream); + } my_putc(c, stream); continue; } diff --git a/newlib/libc/tinystdio/vfscanf.c b/newlib/libc/tinystdio/vfscanf.c index 6d4b6dcd1c..1fc39c42f4 100644 --- a/newlib/libc/tinystdio/vfscanf.c +++ b/newlib/libc/tinystdio/vfscanf.c @@ -297,6 +297,8 @@ conv_int (FILE *stream, scanf_context_t *context, width_t width, void *addr, uin base = 16; if (!--width || IS_EOF(i = scanf_getc (stream, context))) goto putval; + if(!isxdigit(i)) + goto err; #ifdef _NEED_IO_PERCENT_B } else if (i == 'b' && base <= 2) { base = 2; diff --git a/newlib/libm/complex/cacoshf.c b/newlib/libm/complex/cacoshf.c index 41a557ad76..df2ae5c59f 100644 --- a/newlib/libm/complex/cacoshf.c +++ b/newlib/libm/complex/cacoshf.c @@ -33,11 +33,19 @@ */ #include +#include float complex cacoshf(float complex z) { float complex w; + float x = crealf(z); + float y = cimagf(z); + + if (y == 0.0f && x >= 1.0f) { + float w = acoshf(x); + return CMPLXF(w, 0.0f); + } #if 0 /* does not give the principal value */ w = I * cacosf(z); diff --git a/newlib/libm/complex/casin.c b/newlib/libm/complex/casin.c index a1e3a07344..8f6f250897 100644 --- a/newlib/libm/complex/casin.c +++ b/newlib/libm/complex/casin.c @@ -85,81 +85,22 @@ __weak_alias(casin, _casin) double complex casin(double complex z) { - double complex w; - double complex ca, ct, zz, z2; - double x, y; - - x = creal(z); - y = cimag(z); - -#if 0 /* MD: test is incorrect, casin(>1) is defined */ - if (y == 0.0) { - if (fabs(x) > 1.0) { - w = M_PI_2 + 0.0 * (double complex) I; -#if 0 - mtherr ("casin", DOMAIN); -#endif - } else { - w = asin(x) + 0.0 * (double complex) I; - } - return w; - } -#endif - -/* Power series expansion */ -/* -b = cabs(z); -if( b < 0.125 ) -{ -z2.r = (x - y) * (x + y); -z2.i = 2.0 * x * y; - -cn = 1.0; -n = 1.0; -ca.r = x; -ca.i = y; -sum.r = x; -sum.i = y; -do - { - ct.r = z2.r * ca.r - z2.i * ca.i; - ct.i = z2.r * ca.i + z2.i * ca.r; - ca.r = ct.r; - ca.i = ct.i; - - cn *= n; - n += 1.0; - cn /= n; - n += 1.0; - b = cn/n; - - ct.r *= b; - ct.i *= b; - sum.r += ct.r; - sum.i += ct.i; - b = fabs(ct.r) + fabs(ct.i); - } -while( b > MACHEP ); -w->r = sum.r; -w->i = sum.i; -return; -} -*/ + double x = creal(z); + double y = cimag(z); + double complex res; + if (x == 0.0 && y == 0.0) return z; - ca = x + y * (double complex) I; - ct = ca * (double complex) I; - /* sqrt( 1 - z*z) */ - /* cmul( &ca, &ca, &zz ) */ - /*x * x - y * y */ - zz = (x - y) * (x + y) + (2.0 * x * y) * (double complex) I; + if (isnan(x) || isnan(y)) { + if (isinf(x) || isinf(y)) { + return CMPLX(NAN, copysign((double) INFINITY, y)); + } + return CMPLX((double) NAN, (double) NAN); + } - zz = 1.0 - creal(zz) - cimag(zz) * (double complex) I; - z2 = csqrt(zz); + double complex iz = CMPLX(-y,x); + double complex w = casinh(iz); + res = CMPLX(cimag(w), - creal(w)); - zz = ct + z2; - zz = clog(zz); - /* multiply by 1/i = -i */ - w = zz * (-1.0 * (double complex) I); - return w; + return res; } diff --git a/newlib/libm/complex/casinf.c b/newlib/libm/complex/casinf.c index 9a9f759ef3..2ab64817ab 100644 --- a/newlib/libm/complex/casinf.c +++ b/newlib/libm/complex/casinf.c @@ -42,81 +42,22 @@ __weak_alias(casinf, _casinf) float complex casinf(float complex z) { - float complex w; - float complex ca, ct, zz, z2; - float x, y; + float x = crealf(z); + float y = cimagf(z); + float complex res; - x = crealf(z); - y = cimagf(z); + if (x == 0.0f && y == 0.0f) return z; -#if 0 /* MD: test is incorrect, casin(>1) is defined */ - if (y == 0.0f) { - if (fabsf(x) > 1.0) { - w = M_PI_2 + 0.0f * I; -#if 0 - mtherr ("casin", DOMAIN); -#endif - } else { - w = asinf(x) + 0.0f * I; - } - return w; - } -#endif - -/* Power series expansion */ -/* -b = cabsf(z); -if( b < 0.125 ) -{ -z2.r = (x - y) * (x + y); -z2.i = 2.0 * x * y; - -cn = 1.0; -n = 1.0; -ca.r = x; -ca.i = y; -sum.r = x; -sum.i = y; -do - { - ct.r = z2.r * ca.r - z2.i * ca.i; - ct.i = z2.r * ca.i + z2.i * ca.r; - ca.r = ct.r; - ca.i = ct.i; - - cn *= n; - n += 1.0; - cn /= n; - n += 1.0; - b = cn/n; - - ct.r *= b; - ct.i *= b; - sum.r += ct.r; - sum.i += ct.i; - b = fabsf(ct.r) + fabsf(ct.i); - } -while( b > MACHEP ); -w->r = sum.r; -w->i = sum.i; -return; -} -*/ - - - ca = x + y * I; - ct = ca * I; - /* sqrt( 1 - z*z) */ - /* cmul( &ca, &ca, &zz ) */ - /*x * x - y * y */ - zz = (x - y) * (x + y) + (2.0f * x * y) * I; + if (isnanf(x) || isnanf(y)) { + if (isinff(x) || isinff(y)) { + return CMPLXF(NAN, copysignf(INFINITY, y)); + } + return CMPLXF(NAN, NAN); + } - zz = 1.0f - crealf(zz) - cimagf(zz) * I; - z2 = csqrtf(zz); + float complex iz = CMPLXF(-y,x); + float complex w = casinhf(iz); + res = CMPLXF(cimagf(w), - crealf(w)); - zz = ct + z2; - zz = clogf(zz); - /* multiply by 1/i = -i */ - w = zz * (-1.0f * I); - return w; + return res; } diff --git a/newlib/libm/complex/casinh.c b/newlib/libm/complex/casinh.c index 6573be64e4..16da2e2a57 100644 --- a/newlib/libm/complex/casinh.c +++ b/newlib/libm/complex/casinh.c @@ -86,12 +86,60 @@ QUICKREF #include +#include +#include double complex casinh(double complex z) { - double complex w; + double x = fabs(creal(z)); + double y = fabs(cimag(z)); + double complex res; + double complex w; - w = -1.0 * (double complex) I * casin(z * (double complex) I); - return w; + const double eps = DBL_EPSILON; + + if (y == 0.0) { + if (isnan(x)) { + res = CMPLX((double) NAN, copysign(0.0, cimag(z))); + } + else if (isinf(x)) { + res = CMPLX(x, copysign(0.0, cimag(z))); + } + else { + res = CMPLX(asinh(x), copysign(0.0, cimag(z))); + } + } + /* Handle large values */ + else if (x >= 1.0/eps || y >= 1.0/eps) { + res = clog(CMPLX(x, y)); + res = CMPLX(creal(res) + (double) _M_LN2, cimag(res)); + } + + /* Case where real part >= 0.5 and imag part very samll */ + else if (x >= 0.5 && y < eps/8.0) { + double s = hypot(1.0, x); + res = CMPLX(log(x + s), atan2(y, s)); + } + + /* Case Where real part very small and imag part >= 1.5 */ + else if (x < eps/8.0 && y >= 1.5) { + double s = sqrt((y + 1.0) * (y - 1.0)); + res = CMPLX(log(y + s), atan2(s, x)); + } + + else { + /* General case */ + w = CMPLX((x - y) * (x + y) + 1.0, 2.0 * x * y); + w = csqrt(w); + + w = CMPLX(x + creal(w), y + cimag(w)); + res = clog(w); + } + + /* Apply correct signs */ + res = CMPLX(copysign(creal(res), creal(z)), + copysign(cimag(res), cimag(z))); + + return res; } diff --git a/newlib/libm/complex/casinhf.c b/newlib/libm/complex/casinhf.c index 0db55a0ade..5c2d75d21b 100644 --- a/newlib/libm/complex/casinhf.c +++ b/newlib/libm/complex/casinhf.c @@ -33,12 +33,60 @@ */ #include +#include +#include float complex casinhf(float complex z) { - float complex w; + float x = fabsf(crealf(z)); + float y = fabsf(cimagf(z)); + float complex res; + float complex w; - w = -1.0f * I * casinf(z * I); - return w; + const float eps = FLT_EPSILON; + + if (y == 0.0f) { + if (isnanf(x)) { + res = CMPLXF(NAN, copysignf(0.0, cimagf(z))); + } + else if (isinff(x)) { + res = CMPLXF(x, copysignf(0.0, cimagf(z))); + } + else { + res = CMPLXF(asinhf(x), copysignf(0.0, cimagf(z))); + } + } + /* Handle large values */ + else if (x >= 1.0f/eps || y >= 1.0f/eps) { + res = clogf(CMPLXF(x, y)); + res = CMPLXF(crealf(res) + (float) _M_LN2, cimagf(res)); + } + + /* Case where real part >= 0.5 and imag part very samll */ + else if (x >= 0.5f && y < eps/8.0f) { + float s = hypotf(1.0f, x); + res = CMPLXF(logf(x + s), atan2f(y, s)); + } + + /* Case Where real part very small and imag part >= 1.5 */ + else if (x < eps/8.0f && y >= 1.5f) { + float s = sqrtf((y + 1.0f) * (y - 1.0f)); + res = CMPLXF(logf(y + s), atan2f(s, x)); + } + + else { + /* General case */ + w = CMPLXF((x - y) * (x + y) + 1.0f, 2.0f * x * y); + w = csqrtf(w); + + w = CMPLXF(x + crealf(w), y + cimagf(w)); + res = clogf(w); + } + + /* Apply correct signs */ + res = CMPLXF(copysignf(crealf(res), crealf(z)), + copysignf(cimagf(res), cimagf(z))); + + return res; } diff --git a/newlib/libm/complex/casinhl.c b/newlib/libm/complex/casinhl.c index 2f1c7f4dc6..827654c8f2 100644 --- a/newlib/libm/complex/casinhl.c +++ b/newlib/libm/complex/casinhl.c @@ -30,16 +30,72 @@ */ #include +#include +#include #ifdef __HAVE_LONG_DOUBLE_MATH +#ifdef __GNUCLIKE_PRAGMA_DIAGNOSTIC +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +/* GCC analyzer gets confused about the use of 'res' here */ +#pragma GCC diagnostic ignored "-Wanalyzer-use-of-uninitialized-value" +#endif + long double complex casinhl(long double complex z) { - long double complex w; + long double x = fabsl(creall(z)); + long double y = fabsl(cimagl(z)); + long double complex res; + long double complex w; + + const long double eps = LDBL_EPSILON; + + if (y == 0.0L) { + if (isnan(x)) { + res = CMPLXL(NAN, copysignl(0.0L, cimagl(z))); + } + else if (isinf(x)) { + res = CMPLXL(x, copysignl(0.0L, cimagl(z))); + } + else { + res = CMPLXL(asinhl(x), copysignl(0.0L, cimagl(z))); + } + } + /* Handle large values */ + else if (x >= 1.0L/eps || y >= 1.0L/eps) { + res = clogl(CMPLXL(x, y)); + res = CMPLXL(creall(res) + _M_LN2_LD, cimagl(res)); + } + + /* Case where real part >= 0.5 and imag part very samll */ + else if (x >= 0.5L && y < eps/8.0L) { + long double s = hypotl(1.0L, x); + res = CMPLXL(logl(x + s), atan2l(y, s)); + } + + /* Case Where real part very small and imag part >= 1.5 */ + else if (x < eps/8.0L && y >= 1.5L) { + long double s = sqrtl((y + 1.0L) * (y - 1.0L)); + res = CMPLXL(logl(y + s), atan2l(s, x)); + } + + else { + /* General case */ + w = CMPLXL((x - y) * (x + y) + 1.0L, (2.0L * x * y)); + w = csqrtl(w); + + w = CMPLXL(x + creall(w), y + cimagl(w)); + res = clogl(w); + } + + /* Apply correct signs */ + res = CMPLXL(copysignl(creall(res), creall(z)), + copysignl(cimagl(res), cimagl(z))); - w = -1.0L * (long double complex) I * casinl(z * (long double complex) I); - return w; + return res; } #endif diff --git a/newlib/libm/complex/casinl.c b/newlib/libm/complex/casinl.c index 04cccd481a..922c294f12 100644 --- a/newlib/libm/complex/casinl.c +++ b/newlib/libm/complex/casinl.c @@ -30,6 +30,7 @@ */ #include +#include #ifdef __HAVE_LONG_DOUBLE_MATH @@ -40,83 +41,21 @@ __weak_alias(casinl, _casinl) long double complex casinl(long double complex z) { - long double complex w; - long double complex ca, ct, zz, z2; - long double x, y; + long double x = creall(z); + long double y = cimagl(z); - x = creall(z); - y = cimagl(z); + if (x == 0.0L && y == 0.0L) return z; -#if 0 /* MD: test is incorrect, casin(>1) is defined */ - if (y == 0.0L) { - if (fabsl(x) > 1.0L) { - w = M_PI_2L + 0.0L * (double complex) I; -#if 0 - mtherr ("casinl", DOMAIN); -#endif - } else { - w = asinl(x) + 0.0L * (double complex) I; - } - return w; - } -#endif - -/* Power series expansion */ -/* -b = cabsl(z); -if( b < 0.125L ) -{ -z2.r = (x - y) * (x + y); -z2.i = 2.0L * x * y; - -cn = 1.0L; -n = 1.0L; -ca.r = x; -ca.i = y; -sum.r = x; -sum.i = y; -do - { - ct.r = z2.r * ca.r - z2.i * ca.i; - ct.i = z2.r * ca.i + z2.i * ca.r; - ca.r = ct.r; - ca.i = ct.i; - - cn *= n; - n += 1.0; - cn /= n; - n += 1.0; - b = cn/n; - - ct.r *= b; - ct.i *= b; - sum.r += ct.r; - sum.i += ct.i; - b = fabsl(ct.r) + fabsl(ct.i); - } -while( b > MACHEPL ); -w->r = sum.r; -w->i = sum.i; -return; -} -*/ - - - ca = x + y * (long double complex) I; - ct = ca * (long double complex) I; - /* sqrtl( 1 - z*z) */ - /* cmull( &ca, &ca, &zz ) */ - /*x * x - y * y */ - zz = (x - y) * (x + y) + (2.0L * x * y) * (long double complex) I; - - zz = 1.0L - creall(zz) - cimagl(zz) * (long double complex) I; - z2 = csqrtl(zz); + if (isnanl(x) || isnanl(y)) { + if (isinfl(x) || isinfl(y)) { + return CMPLXL(NAN, copysignl((long double) INFINITY, y)); + } + return CMPLXL(NAN, NAN); + } - zz = ct + z2; - zz = clogl(zz); - /* multiply by 1/i = -i */ - w = zz * (-1.0L * (long double complex) I); - return w; + long double complex iz = CMPLXL(-y,x); + long double complex w = casinhl(iz); + return CMPLXL(cimagl(w), -creall(w)); } #endif diff --git a/newlib/libm/complex/catan.c b/newlib/libm/complex/catan.c index d3fb8f9d00..ce8bcc72e9 100644 --- a/newlib/libm/complex/catan.c +++ b/newlib/libm/complex/catan.c @@ -34,12 +34,12 @@ /* FUNCTION - <>, <>---complex arc tangent + <>, <>---complex arc tangent INDEX - catan + catan INDEX - catanf + catanf SYNOPSIS #include @@ -48,37 +48,37 @@ SYNOPSIS DESCRIPTION - @ifnottex - These functions compute the complex arc tangent of <[z]>, - with branch cuts outside the interval [-i, +i] along the - imaginary axis. - @end ifnottex - @tex - These functions compute the complex arc tangent of <[z]>, - with branch cuts outside the interval [$-i$, $+i$] along the - imaginary axis. - @end tex - - <> is identical to <>, except that it performs - its calculations on <>. + @ifnottex + These functions compute the complex arc tangent of <[z]>, + with branch cuts outside the interval [-i, +i] along the + imaginary axis. + @end ifnottex + @tex + These functions compute the complex arc tangent of <[z]>, + with branch cuts outside the interval [$-i$, $+i$] along the + imaginary axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. RETURNS - @ifnottex - These functions return the complex arc tangent value, in the range - of a strip mathematically unbounded along the imaginary axis - and in the interval [-pi/2, +pi/2] along the real axis. - @end ifnottex - @tex - These functions return the complex arc tangent, in the range - of a strip mathematically unbounded along the imaginary axis - and in the interval [$-\pi/2$, $+\pi/2$] along the real axis. - @end tex + @ifnottex + These functions return the complex arc tangent value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [-pi/2, +pi/2] along the real axis. + @end ifnottex + @tex + These functions return the complex arc tangent, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [$-\pi/2$, $+\pi/2$] along the real axis. + @end tex PORTABILITY - <> and <> are ISO C99 + <> and <> are ISO C99 QUICKREF - <> and <> are ISO C99 + <> and <> are ISO C99 */ @@ -100,8 +100,17 @@ catan(double complex z) x = creal(z); y = cimag(z); - if ((x == 0.0) && (y > 1.0)) - goto ovrf; + if (x == 0.0) { + if (y > 1.0) { + return CMPLX(M_PI_2, 0.5 * log((1.0 + y)/(y - 1.0))); + } + if (y < -1.0) { + return CMPLX(-M_PI_2, 0.5 * log((1.0 - y)/(-y - 1.0))); + } + if (fabs(y) <= 1.0) { + return CMPLX(0.0, atanh(y)); + } + } x2 = x * x; a = 1.0 - x2 - (y * y); diff --git a/newlib/libm/complex/catanf.c b/newlib/libm/complex/catanf.c index 9dc2fb23f1..12dccb7963 100644 --- a/newlib/libm/complex/catanf.c +++ b/newlib/libm/complex/catanf.c @@ -49,8 +49,17 @@ catanf(float complex z) x = crealf(z); y = cimagf(z); - if ((x == 0.0f) && (y > 1.0f)) - goto ovrf; + if (x == 0.0f) { + if (y > 1.0f) { + return CMPLXF((float)M_PI_2, 0.5f * logf((1.0f + y)/(y - 1.0f))); + } + if (y < -1.0) { + return CMPLXF((float)-M_PI_2, 0.5f * logf((1.0f - y)/(-y - 1.0f))); + } + if (fabsf(y) <= 1.0f) { + return CMPLXF(0.0f, atanhf(y)); + } + } x2 = x * x; a = 1.0f - x2 - (y * y); diff --git a/newlib/libm/complex/catanl.c b/newlib/libm/complex/catanl.c index 506889c65e..c83f6efc32 100644 --- a/newlib/libm/complex/catanl.c +++ b/newlib/libm/complex/catanl.c @@ -48,8 +48,17 @@ catanl(long double complex z) x = creall(z); y = cimagl(z); - if ((x == 0.0L) && (y > 1.0L)) - goto ovrf; + if (x == 0.0L) { + if (y > 1.0L) { + return CMPLXL(_M_PI_2L, 0.5L * logl((1.0L + y)/(y - 1.0L))); + } + if (y < -1.0L) { + return CMPLXL(-_M_PI_2L, 0.5L * logl((1.0L - y)/(-y - 1.0L))); + } + if (fabsl(y) <= 1.0L) { + return CMPLXL(0.0L, atanhl(y)); + } + } x2 = x * x; a = 1.0L - x2 - (y * y); diff --git a/newlib/libm/complex/clog.c b/newlib/libm/complex/clog.c index 5eec3ddc45..062e6b795b 100644 --- a/newlib/libm/complex/clog.c +++ b/newlib/libm/complex/clog.c @@ -81,9 +81,20 @@ double complex clog(double complex z) { double p, rr; + double x = creal(z); + double y = cimag(z); rr = cabs(z); - p = log(rr); - rr = atan2(cimag(z), creal(z)); + + /* use log1p and compute x^2 + y^2 -1 more accuratly when rr ~= 1.0 */ + if (0.5 < rr && rr < 2.0) { + double d = (x - 1.0) * (x + 1.0) + y * y; + p = 0.5 * log1p(d); + } + else { + p = log(rr); + } + + rr = atan2(y, x); return (double complex) p + rr * (double complex) I; } diff --git a/newlib/libm/complex/clogl.c b/newlib/libm/complex/clogl.c index 3275445abc..3ea97415da 100644 --- a/newlib/libm/complex/clogl.c +++ b/newlib/libm/complex/clogl.c @@ -39,9 +39,21 @@ clogl(long double complex z) { long double p, rr; + long double x = creall(z); + long double y = cimagl(z); + rr = cabsl(z); - p = logl(rr); - rr = atan2l(cimagl(z), creall(z)); + + /* use log1pl and compute x^2 + y^2 -1 more accuratly when rr ~= 1.0 */ + if (0.5 < rr && rr < 2.0) { + long double d = (x - 1.0) * (x + 1.0) + y * y; + p = 0.5 * log1pl(d); + } + else { + p = logl(rr); + } + + rr = atan2l(y, x); return (long double complex) p + rr * (long double complex) I; } diff --git a/semihost/mapstdio.c b/semihost/mapstdio.c index fcd1e23f3e..62beccd020 100644 --- a/semihost/mapstdio.c +++ b/semihost/mapstdio.c @@ -42,7 +42,7 @@ #include #include -static int fd_stdout, fd_stderr; +static int fd_stdin, fd_stdout, fd_stderr; static bool _check_done; int @@ -50,12 +50,13 @@ _map_stdio(int fd) { if (!_check_done) { _check_done = true; + fd_stdin = sys_semihost_open(":tt", 0); fd_stdout = sys_semihost_open(":tt", 4); fd_stderr = sys_semihost_open(":tt", 8); } switch (fd) { case 0: - return -1; + return fd_stdin; case 1: return fd_stdout; case 2: diff --git a/semihost/open.c b/semihost/open.c index dbd3eb6ede..6825d07bb7 100644 --- a/semihost/open.c +++ b/semihost/open.c @@ -69,8 +69,10 @@ open(const char *pathname, int flags, ...) default: if (flags & O_TRUNC) semiflags = SH_OPEN_W_PLUS_B; /* 'wb+' */ - else + else if (flags & O_APPEND) semiflags = SH_OPEN_A_PLUS_B; /* 'ab+' */ + else + semiflags = SH_OPEN_R_PLUS_B; /* 'rb+' */ break; } diff --git a/semihost/read.c b/semihost/read.c index 1a24f3418e..772c331500 100644 --- a/semihost/read.c +++ b/semihost/read.c @@ -44,11 +44,6 @@ ssize_t read(int fd, void *buf, size_t count) { - if (fd == 0) { - int ch = sys_semihost_getc((FILE *) 0); - *(char *) buf = ch; - return 1; - } fd = _map_stdio(fd); uintptr_t ret = sys_semihost_read(fd, buf, count);