/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/struct/sched_param.h" #include "libc/dce.h" #include "libc/fmt/fmt.h" #include "libc/macros.internal.h" #include "libc/math.h" #include "libc/mem/gc.internal.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/vendor.internal.h" #include "libc/runtime/internal.h" #include "libc/runtime/stack.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/sched.h" #include "libc/testlib/testlib.h" #include "libc/thread/spawn.h" #include "libc/thread/wait0.internal.h" #include "libc/x/x.h" #define DUB(i) (union Dub){i}.x #define DUBBLE(a, b, c, d, e) \ { \ { 0x##e, 0x##d, 0x##c, 0x##b, 0x##a } \ } char buf[128]; union Dub { uint64_t i; double x; }; void SetUpOnce(void) { __enable_threads(); ASSERT_SYS(0, 0, pledge("stdio", 0)); } int Worker(void *p, int tid) { int i; char str[64]; for (i = 0; i < 256; ++i) { bzero(str, sizeof(str)); snprintf(str, sizeof(str), "%.15g", atan2(-1., -.5)); ASSERT_STREQ("-2.0344439357957", str); } return 0; } TEST(dtoa, locks) { int i, n = 32; struct spawn *t = gc(malloc(sizeof(struct spawn) * n)); for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, 0, t + i)); for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i)); } static const struct { uint64_t i; const char *f; const char *s; } Vd[] = { {0x3ff3ae147ae147ae, "%.8a", "0x1.3ae147aep+0"}, // {0x3ff3ae147ae147ae, "%.7a", "0x1.3ae147bp+0"}, // {0x3ff3ae147ae147ae, "%.2a", "0x1.3bp+0"}, // }; TEST(printf, double) { int i; for (i = 0; i < ARRAYLEN(Vd); ++i) { ++g_testlib_ran; snprintf(buf, sizeof(buf), Vd[i].f, DUB(Vd[i].i)); if (strcmp(Vd[i].s, buf)) { fprintf(stderr, "TEST FAILED\n" "EXPECT_STREQ(%`'s, FMT(%`'s, DUB(0x%016lx)))\n" " BUT GOT %`'s\n", Vd[i].s, Vd[i].f, Vd[i].i, buf); testlib_incrementfailed(); } } } #if LDBL_MANT_DIG == 64 static const struct { const char *s; const char *f; union { uint16_t i[5]; long double x; } u; } Vx[] = { {"1.23000000000000000002", "%.21Lg", DUBBLE(3fff, 9d70, a3d7, a3d, 70a4)}, {"123000000000000000000", "%.21Lg", DUBBLE(4041, d55e, f90a, 2da1, 8000)}, {"1.22999999999999999997e-20", "%.21Lg", DUBBLE(3fbc, e857, 267b, b3a9, 84f2)}, {"1.23456789000000000003", "%.21Lg", DUBBLE(3fff, 9e06, 5214, 1ef0, dbf6)}, {"123456589000000000000", "%.21Lg", DUBBLE(4041, d629, bd33, 5cc, ba00)}, {"1.22999999999999999999e+30", "%.21Lg", DUBBLE(4062, f865, 8274, 7dbc, 824a)}, {"1.22999999999999999999e-30", "%.21Lg", DUBBLE(3f9b, c794, 337a, 8085, 54eb)}, {"1.23456788999999999998e-20", "%.21Lg", DUBBLE(3fbc, e934, a38, f3d6, d352)}, {"1.23456788999999999999e-30", "%.21Lg", DUBBLE(3f9b, c851, f19d, decc, a8fc)}, {"1.23456789012345678899", "%.21Lg", DUBBLE(3fff, 9e06, 5214, 62cf, db8d)}, {"1.22999999999999999997e+306", "%.21Lg", DUBBLE(43f7, e033, b668, e30f, a6d5)}, {"1.23000000000000000002e-306", "%.21Lg", DUBBLE(3c06, dd1d, c2ed, 1cb7, 3f25)}, {"1.23000000000000000002e-320", "%.21Lg", DUBBLE(3bd8, 9b98, c371, 844c, 3f1a)}, {"0xap-3", "%.La", DUBBLE(3fff, 9d70, a3d7, a3d, 70a4)}, // cosmo prints 0x9.d70a3d70a3d70a400000p-3 // glibc prints 0x9.d70a3d70a3d70a400000p-3 // openbsd prints 0x9.d70a3d70a3d70a400000p-3 // apple prints 0x9.d70a3d70a3d70a400000p-3 // musl prints 0x1.3ae147ae147ae1480000p+0 // freebsd prints 0x1.3ae147ae147ae1480000p+0 {"0x9.d70a3d70a3d70a400000p-3", "%.20La", DUBBLE(3fff, 9d70, a3d7, 0a3d, 70a4)}, {"0x9.b18ab5df7180b6cp+88", "%La", DUBBLE(405a, 9b18, ab5d, f718, b6c)}, {"0xa.fc6a015291b4024p+87", "%La", DUBBLE(4059, afc6, a015, 291b, 4024)}, }; TEST(printf, longdouble) { if (IsGenuineBlink()) { return; // TODO(jart): long double precision in blink } int i; for (i = 0; i < ARRAYLEN(Vx); ++i) { ++g_testlib_ran; snprintf(buf, sizeof(buf), Vx[i].f, Vx[i].u.x); if (strcmp(Vx[i].s, buf)) { fprintf(stderr, "TEST FAILED\n" "\t{%`'s, %`'s, DUBBLE(%x, %x, %x, %x, %x)}\n" "\t→%`'s\n", Vx[i].s, Vx[i].f, Vx[i].u.i[4], Vx[i].u.i[3], Vx[i].u.i[2], Vx[i].u.i[1], Vx[i].u.i[0], buf); testlib_incrementfailed(); } } } #endif // LDBL_MANT_DIG == 64