Loading...
--- Libc/Libc-1725.40.4/tests/strtod.c
+++ /dev/null
@@ -1,622 +0,0 @@
-#include <fenv.h>
-#include <float.h>
-#include <locale.h>
-#include <math.h>
-#include <stdlib.h>
-#include <xlocale.h>
-
-#include <darwintest.h>
-
-#pragma STDC FENV_ACCESS ON
-
-static void strtod_verify_with_rounding_mode(const char *src, int mode, double e, int expected_errno, const char *expected_end, const char *detail) {
- union {
- uint64_t raw;
- double d;
- } actual, expected;
- errno = 0;
- expected.d = e;
-
- fesetround(mode);
- const char *mode_name =
- (mode == FE_TONEAREST) ? "TONEAREST" :
- (mode == FE_DOWNWARD) ? "DOWNWARD" :
- (mode == FE_UPWARD) ? "UPWARD" :
- (mode == FE_TOWARDZERO) ? "TOWARDZERO" :
- "<UNKNOWN MODE>";
-
- char *base_end = NULL;
- actual.d = strtod(src, &base_end);
- int actual_errno = errno;
- int failed = 0;
-
- // Note: Verify the bits, not the FP value!
- // In particular, this correctly validates NaNs and signed zeros
- if (actual.raw != expected.raw) {
- T_FAIL("Parsed value mismatch: "
- "Input \"%s\", mode = %s, "
- "actual = %.25g %a (0x%016llx), "
- "expected = %.25g %a (0x%016llx) %s",
- src, mode_name,
- actual.d, actual.d, actual.raw,
- expected.d, expected.d, expected.raw,
- detail);
- failed = 1;
- }
-
- if (actual_errno != expected_errno) {
- T_FAIL("Errno mismatch: "
- "input \"%s\", mode = %s, "
- "result = %.25g %a (0x%016llx), "
- "actual errno = %d, expected errno = %d %s",
- src, mode_name,
- actual.d, actual.d, actual.raw,
- actual_errno, expected_errno,
- detail);
- failed = 1;
- }
-
- if ((expected_end != NULL) && (base_end != expected_end)) {
- T_FAIL("End did not match: "
- "input \"%s\", mode = %s, "
- "end = \"%s\", expected end = \"%s\" %s",
- src, mode_name, base_end, expected_end, detail);
- failed = 1;
- }
-
- {
- // "errno should never be set to zero by any library function"
- errno = 999;
- (void)strtod(src, NULL);
- if (errno == 0) {
- T_FAIL("Errno forced to zero for input \"%s\", mode = %s %s", src, mode_name, detail);
- failed = 1;
- }
- }
-
- // Adding non-relevant characters to the end should not affect how it got parsed.
- // In particular, the updated `end` should point to the same offset.
- char *buff = malloc(strlen(src) + 10);
- // Redundant '.' should be ignored if there's already a '.'
- const char *extras = strchr(src, '.') != NULL ? "Q+%-&!x.," : "Q+%-&!x," ;
- for (size_t i = 0; i < strlen(extras); i++) {
- strcpy(buff, src);
- size_t s = strlen(src);
- buff[s] = extras[i];
- buff[s + 1] = '\0';
- expected.d = actual.d; // We expect the same value as before
- char *end = NULL;
- actual.d = strtod(buff, &end);
- if (actual.raw != expected.raw) {
- T_FAIL("Adding %c to end of \"%s\" changed result from %.25g %a (0x%016llx) to %.25g %a (0x%016llx)",
- extras[i], buff, expected.d, expected.d, expected.raw, actual.d, actual.d, actual.raw);
- failed = 1;
- }
- if (end != buff + (base_end - src)) {
- T_FAIL("End did not update correctly for input \"%s\", end = \"%s\" (buff + %d) %s",
- buff, end, (int)(end - buff), detail);
- failed = 1;
- }
- }
- free(buff);
-
- if (!failed) {
- T_PASS("%s: %s %s", mode_name, src, detail);
- }
-}
-
-// This is the general verifier used for anything that
-// isn't covered by a special case below.
-
-// It expects ERANGE to be set whenever the result is not
-// a normal value. This includes both overflow and
-// underflow cases:
-
-// OVERFLOW: For inputs between max_value and max_value + 1 ULP,
-// this expect ERANGE if the result rounds to infinity.
-// (Inputs larger than max_value + 1 ULP are handled by
-// strtod_verify_overflow below.)
-// Rationale:
-// 1. Rounding to ∞ seems like "extreme rounding". ;-)
-// 2. Normally, NEAREST rounds by at most 1/2 ULP and
-// UP/DOWN/TOZERO by at most 1 ULP. This verifier
-// is used for inputs < max_value + 1 ULP, which
-// rounds down in exactly those cases.
-
-// UNDERFLOW: For inputs that are > 0.0 and less than
-// min_normal, we expect ERANGE if the result rounds to
-// a subnormal or zero.
-// Rationale:
-// * If a non-zero input rounds to zero, that's
-// something that people want to detect.
-// * If an input rounds to normal, then it's
-// within 1/2 ULP, which means this is ordinary
-// rounding.
-// Some implementations try to set ERANGE for inexact
-// conversions. Since exact subnormals are quite long in
-// decimal, we wouldn't gain much by trying to enforce
-// this. (We do enforce it for hex subnormals, though.)
-static void strtod_verify(const char *src, double expected_nearest, double expected_down, double expected_up) {
- // Literal infinities get tested with strtod_verify_infinity below, so any infinity here is really an overflow
- int expected_errno = isnormal(expected_nearest) ? 0 : ERANGE;
- strtod_verify_with_rounding_mode(src, FE_TONEAREST, expected_nearest, expected_errno, src + strlen(src), "");
- expected_errno = isnormal(expected_down) ? 0 : ERANGE;
- strtod_verify_with_rounding_mode(src, FE_DOWNWARD, expected_down, expected_errno, src + strlen(src), "");
- expected_errno = isnormal(expected_up) ? 0 : ERANGE;
- strtod_verify_with_rounding_mode(src, FE_UPWARD, expected_up, expected_errno, src + strlen(src), "");
- double expected = signbit(expected_up) ? expected_up : expected_down;
- expected_errno = isnormal(expected) ? 0 : ERANGE;
- strtod_verify_with_rounding_mode(src, FE_TOWARDZERO, expected, expected_errno, src + strlen(src), "");
-}
-
-// I consider inputs larger than max_value + 1 ULP to be
-// unconditional overflows and require that we set ERANGE,
-// regardless of whether it rounds to infinity or not.
-// rdar://123637060 - Correctly round overflow values toward zero
-static void strtod_verify_overflow(const char *src, double expected_nearest, double expected_down, double expected_up) {
- int expected_errno = ERANGE;
- strtod_verify_with_rounding_mode(src, FE_TONEAREST, expected_nearest, expected_errno, src + strlen(src), "");
- strtod_verify_with_rounding_mode(src, FE_DOWNWARD, expected_down, expected_errno, src + strlen(src), "");
- strtod_verify_with_rounding_mode(src, FE_UPWARD, expected_up, expected_errno, src + strlen(src), "");
- double expected = signbit(expected_up) ? expected_up : expected_down;
- strtod_verify_with_rounding_mode(src, FE_TOWARDZERO, expected, expected_errno, src + strlen(src), "");
-}
-
-// rdar://108539918 - Don't set ERANGE for exact subnormal hexfloats
-static void strtod_verify_exact_subnormal(const char *src, double expected_nearest, double expected_down, double expected_up) {
- int expected_errno = 0;
- strtod_verify_with_rounding_mode(src, FE_TONEAREST, expected_nearest, expected_errno, src + strlen(src), "");
- strtod_verify_with_rounding_mode(src, FE_DOWNWARD, expected_down, expected_errno, src + strlen(src), "");
- strtod_verify_with_rounding_mode(src, FE_UPWARD, expected_up, expected_errno, src + strlen(src), "");
- double expected = signbit(expected_up) ? expected_up : expected_down;
- strtod_verify_with_rounding_mode(src, FE_TOWARDZERO, expected, expected_errno, src + strlen(src), "");
-}
-
-// Explicit zero, infinity, or Nan inputs never trigger ERANGE...
-static void strtod_verify_no_overunder(const char *src, double expected) {
- strtod_verify_with_rounding_mode(src, FE_TONEAREST, expected, 0, src + strlen(src), "");
- strtod_verify_with_rounding_mode(src, FE_DOWNWARD, expected, 0, src + strlen(src), "");
- strtod_verify_with_rounding_mode(src, FE_UPWARD, expected, 0, src + strlen(src), "");
- strtod_verify_with_rounding_mode(src, FE_TOWARDZERO, expected, 0, src + strlen(src), "");
-}
-static void strtod_verify_infinity(const char *src, double expected) {
- strtod_verify_no_overunder(src, expected);
-}
-static void strtod_verify_zero(const char *src, double expected) {
- strtod_verify_no_overunder(src, expected);
-}
-static void strtod_verify_nan(const char *src, double expected) {
- strtod_verify_no_overunder(src, expected);
-}
-
-// TODO: test hexfloat parsing of large integers
-
-T_DECL(strtod, "strtod(3)")
-{
- static const double min_subnormal = 0x1p-1074;
- static const double min_subnormal_succ = 0x2p-1074;
- static const double max_subnormal = 0x0.fffffffffffffp-1022;
- static const double min_normal = 0x1p-1022;
- static const double max_normal_pred = 0x1.ffffffffffffep+1023;
- static const double max_normal = 0x1.fffffffffffffp+1023;
- static const double infinity = HUGE_VAL;
-
- static const double pi_pred = 0x1.921fb54442d17p+1;
- static const double pi = 0x1.921fb54442d18p+1;
- static const double pi_succ = 0x1.921fb54442d19p+1;
-
- // Sanity-test the environment
- T_EXPECT_FALSE(isnormal(max_subnormal), "isnormal(max_subnormal) should be false");
- T_EXPECT_TRUE(isnormal(min_normal), "isnormal(min_normal) should be true");
- T_EXPECT_TRUE(isnormal(max_normal), "isnormal(max_normal) should be true");
- T_EXPECT_TRUE(isinf(infinity), "isinf(infinity) should be true");
- T_EXPECT_FALSE(isinf(min_normal), "isinf(min_normal) should be false");
-
- strtod_verify("1.0", 1.0, 1.0, 1.0);
- strtod_verify(" 1.0", 1.0, 1.0, 1.0);
- strtod_verify(" 1.0", 1.0, 1.0, 1.0);
- strtod_verify("\t1.0", 1.0, 1.0, 1.0);
- strtod_verify("\n1.0", 1.0, 1.0, 1.0);
- strtod_verify("\v1.0", 1.0, 1.0, 1.0);
- strtod_verify("\f1.0", 1.0, 1.0, 1.0);
- strtod_verify("\r1.0", 1.0, 1.0, 1.0);
- strtod_verify(" \t\n\v\f\r1.0", 1.0, 1.0, 1.0);
- strtod_verify("5e-324", min_subnormal, min_subnormal, min_subnormal_succ);
- strtod_verify("-5e-324", -min_subnormal, -min_subnormal_succ, -min_subnormal);
- strtod_verify("1.11253692925360069154511635866620203211e-308", min_normal / 2, min_normal / 2, 0x1.0000000000002p-1023);
- strtod_verify("2225073858507201e-323", max_subnormal, max_subnormal, min_normal);
- strtod_verify("2.225073858507201e-308", max_subnormal, max_subnormal, min_normal);
- strtod_verify("2.225073858507201137e-308", min_normal, max_subnormal, min_normal);
- strtod_verify("2.22507385850720114e-308", min_normal, max_subnormal, min_normal);
- strtod_verify("2.2250738585072012e-308", min_normal, max_subnormal, min_normal);
- strtod_verify("2.2250738585072013e-308", min_normal, max_subnormal, min_normal);
- strtod_verify("2.2250738585072014e-308", min_normal, min_normal, 0x1.0000000000001p-1022);
- strtod_verify("17976931348623157e292", max_normal, max_normal_pred, max_normal);
- // Tiny bit less than max normal
- strtod_verify("1.7976931348623157e308", max_normal, max_normal_pred, max_normal);
- // Tiny bit larger than max normal
- strtod_verify("1.7976931348623158e308", max_normal, max_normal, infinity);
- // Larger than midpoint between max normal and max normal + 1 ULP
- strtod_verify("1.7976931348623159e308", infinity, max_normal, infinity);
- // Larger than max normal + 1 ULP
- strtod_verify_overflow("1.797693134862316e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.79769313486232e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.7976931348624e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.797693134863e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.79769313487e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.7976931349e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.797693135e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.79769314e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.7976932e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.797694e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.7977e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.798e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.8e308", infinity, max_normal, infinity);
- strtod_verify_overflow("1.9e308", infinity, max_normal, infinity);
- strtod_verify_overflow("2e308", infinity, max_normal, infinity);
-
- strtod_verify("3.141592653589793", pi, pi_pred, pi);
- strtod_verify("3.141592653589793238462643383279502884197169399"
- "375105820974944592307816406286208998628034825342117",
- pi, pi, pi_succ);
- strtod_verify("0x1.921fb54442d18p+1", pi, pi, pi);
- strtod_verify("0x1.921fb54442d188p+1", pi, pi, pi_succ);
- strtod_verify("0x1.921fb54442d1800000000000000000000000p+1", pi, pi, pi);
- strtod_verify("0x1.921fb54442d1800000000000000000000001p+1", pi, pi, pi_succ);
- strtod_verify("-0x1.921fb54442d18p+1", -pi, -pi, -pi);
- strtod_verify("-0x1.921fb54442d1800000000000000000000001p+1", -pi, -pi_succ, -pi);
-
- strtod_verify("2.47032822920623272088284396434110686182529901307162382212792841"
- "2503377536351043759326499181808179961898982823477228588654633283"
- "5517796989819938739800539093906315035659515570226392290858392449"
- "1051844359318028499365361525003193704576782492193656236698636584"
- "8075700158576926990370631192827955855133292783433840935197801553"
- "1246597263579574622766465272827220056374006485499977096599470454"
- "0208281662262378573934507363390079677619305775067401763246736009"
- "6895134053553745851666113422376667860416215968046191446729184030"
- "0530057530849048765391711386591646239524912623653881879636239373"
- "2804238910186723484976682350898633885879256283027559956575244555"
- "0725518931369083625477918694866799496832404970582102851318545139"
- "6213837722826145437693412532098591327667236328125e-324",
- 0.0, 0.0, min_subnormal);
- strtod_verify("2.47032822920623272088284396434110686182529901307162382212792841"
- "2503377536351043759326499181808179961898982823477228588654633283"
- "5517796989819938739800539093906315035659515570226392290858392449"
- "1051844359318028499365361525003193704576782492193656236698636584"
- "8075700158576926990370631192827955855133292783433840935197801553"
- "1246597263579574622766465272827220056374006485499977096599470454"
- "0208281662262378573934507363390079677619305775067401763246736009"
- "6895134053553745851666113422376667860416215968046191446729184030"
- "0530057530849048765391711386591646239524912623653881879636239373"
- "2804238910186723484976682350898633885879256283027559956575244555"
- "0725518931369083625477918694866799496832404970582102851318545139"
- "6213837722826145437693412532098591327667236328125000000000000000"
- "0000000000000000000000000000000000000000000000000000000000000000"
- "0000000000000000000000000000000000000000000000000000000000000000"
- "00000000000000000000000000000000000000000000000000000000000e-324",
- 0.0, 0.0, min_subnormal);
- strtod_verify("2.47032822920623272088284396434110686182529901307162382212792841"
- "2503377536351043759326499181808179961898982823477228588654633283"
- "5517796989819938739800539093906315035659515570226392290858392449"
- "1051844359318028499365361525003193704576782492193656236698636584"
- "8075700158576926990370631192827955855133292783433840935197801553"
- "1246597263579574622766465272827220056374006485499977096599470454"
- "0208281662262378573934507363390079677619305775067401763246736009"
- "6895134053553745851666113422376667860416215968046191446729184030"
- "0530057530849048765391711386591646239524912623653881879636239373"
- "2804238910186723484976682350898633885879256283027559956575244555"
- "0725518931369083625477918694866799496832404970582102851318545139"
- "6213837722826145437693412532098591327667236328125000000000000000"
- "0000000000000000000000000000000000000000000000000000000000000000"
- "0000000000000000000000000000000000000000000000000000000000000000"
- "00000000000000000000000000000000000000000000000000000000001e-324",
- min_subnormal, 0.0, min_subnormal);
- strtod_verify("2.47032822920623272088284396434110686182529901307162382212792841"
- "2503377536351043759326499181808179961898982823477228588654633283"
- "5517796989819938739800539093906315035659515570226392290858392449"
- "1051844359318028499365361525003193704576782492193656236698636584"
- "8075700158576926990370631192827955855133292783433840935197801553"
- "1246597263579574622766465272827220056374006485499977096599470454"
- "0208281662262378573934507363390079677619305775067401763246736009"
- "6895134053553745851666113422376667860416215968046191446729184030"
- "0530057530849048765391711386591646239524912623653881879636239373"
- "2804238910186723484976682350898633885879256283027559956575244555"
- "0725518931369083625477918694866799496832404970582102851318545139"
- "6213837722826145437693412532098591327667236328124999999999999999"
- "99999999999999999999999999999999999999999999999999999999999e-324",
- 0.0, 0.0, min_subnormal);
- strtod_verify("7.41098468761869816264853189302332058547589703921487146638378523"
- "7510132609053131277979497545424539885696948470431685765963899850"
- "6553390969459816219401617281718945106978546710679176872575177347"
- "3155533077954085498096084575009581113730347476580968710095909754"
- "4227100475730780971111893578483867565399878350301522805593404659"
- "3739791790738723868299395818481660169122019456499931289798411362"
- "0624844986787135721803522090170239032857917325202205289740208029"
- "0685402160661237554998340267130003581248647904138574340187552090"
- "1590172592547146296175134159774938718574737870961645638908718119"
- "8412716730560170454930047052695901657637768849082679869725733665"
- "2176556794107250876433756084600398490497214911746308553955635418"
- "8641513168478436313080237596295773983001708984375e-324",
- min_subnormal_succ, min_subnormal, min_subnormal_succ);
- strtod_verify("7.41098468761869816264853189302332058547589703921487146638378523"
- "7510132609053131277979497545424539885696948470431685765963899850"
- "6553390969459816219401617281718945106978546710679176872575177347"
- "3155533077954085498096084575009581113730347476580968710095909754"
- "4227100475730780971111893578483867565399878350301522805593404659"
- "3739791790738723868299395818481660169122019456499931289798411362"
- "0624844986787135721803522090170239032857917325202205289740208029"
- "0685402160661237554998340267130003581248647904138574340187552090"
- "1590172592547146296175134159774938718574737870961645638908718119"
- "8412716730560170454930047052695901657637768849082679869725733665"
- "2176556794107250876433756084600398490497214911746308553955635418"
- "8641513168478436313080237596295773983001708984374999999999999999"
- "99999999999999999999999999999999999999999999999999999999999e-324",
- min_subnormal, min_subnormal, min_subnormal_succ);
- strtod_verify("7.41098468761869816264853189302332058547589703921487146638378523"
- "7510132609053131277979497545424539885696948470431685765963899850"
- "6553390969459816219401617281718945106978546710679176872575177347"
- "3155533077954085498096084575009581113730347476580968710095909754"
- "4227100475730780971111893578483867565399878350301522805593404659"
- "3739791790738723868299395818481660169122019456499931289798411362"
- "0624844986787135721803522090170239032857917325202205289740208029"
- "0685402160661237554998340267130003581248647904138574340187552090"
- "1590172592547146296175134159774938718574737870961645638908718119"
- "8412716730560170454930047052695901657637768849082679869725733665"
- "2176556794107250876433756084600398490497214911746308553955635418"
- "8641513168478436313080237596295773983001708984375000000000000000"
- "00000000000000000000000000000000000000000000000000000000001e-324",
- min_subnormal_succ, min_subnormal, min_subnormal_succ);
-
- // Subnormal hexfloats
- // rdar://108539918 - Only set erange for inexact subnormal hexfloats
- strtod_verify_exact_subnormal("0x0.8p-1022", 0x0.8p-1022, 0x0.8p-1022, 0x0.8p-1022);
- strtod_verify_exact_subnormal("0x0.5555555555555p-1022",
- 0x0.5555555555555p-1022, 0x0.5555555555555p-1022, 0x0.5555555555555p-1022);
- strtod_verify_exact_subnormal("0x0.fffffffffffffp-1022", max_subnormal, max_subnormal, max_subnormal);
- // This is inexact, so should set ERANGE
- strtod_verify("0x0.555555555555555555p-1022",
- 0x1.5555555555554p-1024, 0x1.5555555555554p-1024, 0x1.5555555555558p-1024);
- // Rounds up to min normal (no error), down to max subnormal (erange)
- static const char *hexfloat1 = "0x0.fffffffffffff8p-1022";
- strtod_verify_with_rounding_mode(hexfloat1, FE_TONEAREST, min_normal, 0, hexfloat1 + strlen(hexfloat1), "");
- strtod_verify_with_rounding_mode(hexfloat1, FE_UPWARD, min_normal, 0, hexfloat1 + strlen(hexfloat1), "");
- strtod_verify_with_rounding_mode(hexfloat1, FE_DOWNWARD, max_subnormal, ERANGE, hexfloat1 + strlen(hexfloat1), "");
-
- strtod_verify("123456.7890123e-4789", 0.0, 0.0, min_subnormal);
- strtod_verify("-8e-9999999999999999999999999999999999", -0.0, -min_subnormal, -0.0);
- strtod_verify("0xfp-999999999999999999999999999999999", 0.0, 0.0, min_subnormal);
- strtod_verify("-0xfedcba987654321p-987654", -0.0, -min_subnormal, -0.0);
-
- // Obvious overflows
- strtod_verify_overflow("123456.7890123e+4789", infinity, max_normal, infinity);
- strtod_verify_overflow("1e309", infinity, max_normal, infinity);
- strtod_verify_overflow("-1e+99999999999999999999999999999999", -infinity, -infinity, -max_normal);
- strtod_verify_overflow("-1e309", -infinity, -infinity, -max_normal);
- strtod_verify_overflow("0x123456789abcdefp9999999999999999999999999999", infinity, max_normal, infinity);
- strtod_verify_overflow("0x123456789abcdefp123456789", infinity, max_normal, infinity);
- // Borderline overflows
- // Exact 2^1024 is the max normal double + 1 ULP. This requires
- // rounding by >= 1 ULP, so is considered overflow always.
- strtod_verify_overflow("1797693134862315907729305190789024733617976978942306572734300811"
- "5773267580550096313270847732240753602112011387987139335765878976"
- "8814416622492847430639474124377767893424865485276302219601246094"
- "1194530829520850057688381506823424628814739131105408272371633505"
- "10684586298239947245938479716304835356329624224137216",
- infinity, max_normal, infinity);
- // 1 less than 2^1024 is within 1 ULP of the max normal double. We count this
- // as overflow when it rounds to infinity.
- strtod_verify("1797693134862315907729305190789024733617976978942306572734300811"
- "5773267580550096313270847732240753602112011387987139335765878976"
- "8814416622492847430639474124377767893424865485276302219601246094"
- "1194530829520850057688381506823424628814739131105408272371633505"
- "10684586298239947245938479716304835356329624224137215",
- infinity, max_normal, infinity);
- // Exact midpoint between max_normal and (max normal + 1 ULP)
- strtod_verify("1797693134862315807937289714053034150799341327100378269361737789"
- "8044496829276475094664901797758720709633028641669288791094655554"
- "7851940402630657488671505820681908902000708383676273854845817711"
- "5317644757302700698555713669596228429148198608349364752927190741"
- "68444365510704342711559699508093042880177904174497792",
- infinity, max_normal, infinity);
- // 1 more than the above
- strtod_verify("1797693134862315807937289714053034150799341327100378269361737789"
- "8044496829276475094664901797758720709633028641669288791094655554"
- "7851940402630657488671505820681908902000708383676273854845817711"
- "5317644757302700698555713669596228429148198608349364752927190741"
- "68444365510704342711559699508093042880177904174497793",
- infinity, max_normal, infinity);
- // 1 less than the above
- strtod_verify("1797693134862315807937289714053034150799341327100378269361737789"
- "8044496829276475094664901797758720709633028641669288791094655554"
- "7851940402630657488671505820681908902000708383676273854845817711"
- "5317644757302700698555713669596228429148198608349364752927190741"
- "68444365510704342711559699508093042880177904174497791",
- max_normal, max_normal, infinity);
-
- // Nan parsing
- strtod_verify_nan("NaN", nan(""));
- strtod_verify_nan("-NaN", -nan(""));
- strtod_verify_nan("nan", nan(""));
- strtod_verify_nan("+NAN", nan(""));
- strtod_verify_nan("nAn", nan(""));
- strtod_verify_nan("NaN()", nan(""));
- strtod_verify_nan("nan(1)", nan("1"));
- strtod_verify_nan("NaN(011)", nan("9"));
- strtod_verify_nan("NaN(0x11)", nan("0x11"));
- strtod_verify_nan("NaN(11)", nan("0xb"));
- strtod_verify_nan("nan(0xffffffffffffffffffffff9)", nan("0x7fffffffffff9"));
-
- // Spellings of explicit infinity
- strtod_verify_infinity("inf", infinity);
- strtod_verify_infinity("InF", infinity);
- strtod_verify_infinity("iNf", infinity);
- strtod_verify_infinity("+inf", infinity);
- strtod_verify_infinity("-InF", -infinity);
-
- strtod_verify_infinity("InFiNiTy", infinity);
- strtod_verify_infinity("iNfInItY", infinity);
- strtod_verify_infinity("-infinity", -infinity);
- strtod_verify_infinity("+infinity", infinity);
- const char *infinite_string = "infinite";
- strtod_verify_with_rounding_mode(infinite_string, FE_TONEAREST, infinity, 0, infinite_string + 3, "");
-
- // Spellings of zero
- strtod_verify_zero("0", 0.0);
- strtod_verify_zero("+0", 0.0);
- strtod_verify_zero("+0000000.0000000e0000000", 0.0);
- strtod_verify_zero("0e99999999999999999999999999", 0.0);
- strtod_verify_zero("-0.0e0", -0.0);
- strtod_verify_zero("-0", -0.0);
- strtod_verify_zero("-.0", -0.0);
- strtod_verify_zero("-.0e+0", -0.0);
- strtod_verify_zero("-.0e-0", -0.0);
-}
-
-T_DECL(strtod_locale, "strtod(3) locale support")
-{
- // Literals that we'll test against:
- // Include values with a decimal point in the beginning, middle, and end.
- // Include values for C/en_US, fr_FR, and a synthesized locale that uses a multi-byte decimal point
- // Include values with a malformed multi-byte decimal point
- const char *us_123_456 = "123.456";
- const char *fr_123_456 = "123,456";
- const char *syn_123_456 = "123%$456";
- const char *syn_trunc_123_456 = "123%456";
- const char *us__279 = ".279";
- const char *fr__279 = ",279";
- const char *syn__279 = "%$279";
- const char *syn_trunc__279 = "%279";
- const char *us_843_ = "843.";
- const char *fr_843_ = "843,";
- const char *syn_843_ = "843%$";
- const char *syn_trunc_843_ = "843%";
-
- (void)setlocale(LC_ALL, "C");
- struct lconv *lc = localeconv();
- T_EXPECT_EQ_STR(lc->decimal_point, ".", "Expected C locale to have '.' as decimal point");
- strtod_verify_with_rounding_mode(us_123_456, FE_TONEAREST, 123.456, 0, us_123_456 + 7, "C locale");
- strtod_verify_with_rounding_mode(fr_123_456, FE_TONEAREST, 123.0, 0, fr_123_456 + 3, "C locale");
- strtod_verify_with_rounding_mode(syn_123_456, FE_TONEAREST, 123.0, 0, syn_123_456 + 3, "C locale");
- strtod_verify_with_rounding_mode(syn_trunc_123_456, FE_TONEAREST, 123.0, 0, syn_trunc_123_456 + 3, "C locale");
- strtod_verify_with_rounding_mode(us__279, FE_TONEAREST, 0.279, 0, us__279 + 4, "C locale");
- strtod_verify_with_rounding_mode(fr__279, FE_TONEAREST, 0.0, 0, fr__279, "C locale");
- strtod_verify_with_rounding_mode(syn__279, FE_TONEAREST, 0.0, 0, syn__279, "C locale");
- strtod_verify_with_rounding_mode(syn_trunc__279, FE_TONEAREST, 0.0, 0, syn_trunc__279, "C locale");
- strtod_verify_with_rounding_mode(us_843_, FE_TONEAREST, 843.0, 0, us_843_ + 4, "C locale");
- strtod_verify_with_rounding_mode(fr_843_, FE_TONEAREST, 843.0, 0, fr_843_ + 3, "C locale");
- strtod_verify_with_rounding_mode(syn_843_, FE_TONEAREST, 843.0, 0, syn_843_ + 3, "C locale");
- strtod_verify_with_rounding_mode(syn_trunc_843_, FE_TONEAREST, 843.0, 0, syn_trunc_843_ + 3, "C locale");
-
- if (setlocale(LC_ALL, "en_US") != NULL || setlocale(LC_ALL, "en_US.UTF-8") != NULL) {
- // Skip this if "en_US" locale can't be found
- lc = localeconv();
- T_EXPECT_EQ_STR(lc->decimal_point, ".", "Expected en_US locale to have '.' as decimal point");
- strtod_verify_with_rounding_mode(us_123_456, FE_TONEAREST, 123.456, 0, us_123_456 + 7, "en_US locale");
- strtod_verify_with_rounding_mode(fr_123_456, FE_TONEAREST, 123.0, 0, fr_123_456 + 3, "en_US locale");
- strtod_verify_with_rounding_mode(syn_123_456, FE_TONEAREST, 123.0, 0, syn_123_456 + 3, "en_US locale");
- strtod_verify_with_rounding_mode(syn_trunc_123_456, FE_TONEAREST, 123.0, 0, syn_trunc_123_456 + 3, "en_US locale");
- strtod_verify_with_rounding_mode(us__279, FE_TONEAREST, 0.279, 0, us__279 + 4, "en_US locale");
- strtod_verify_with_rounding_mode(fr__279, FE_TONEAREST, 0.0, 0, fr__279, "en_US locale");
- strtod_verify_with_rounding_mode(syn__279, FE_TONEAREST, 0.0, 0, syn__279, "en_US locale");
- strtod_verify_with_rounding_mode(syn_trunc__279, FE_TONEAREST, 0.0, 0, syn_trunc__279, "en_US locale");
- strtod_verify_with_rounding_mode(us_843_, FE_TONEAREST, 843.0, 0, us_843_ + 4, "en_US locale");
- strtod_verify_with_rounding_mode(fr_843_, FE_TONEAREST, 843.0, 0, fr_843_ + 3, "en_US locale");
- strtod_verify_with_rounding_mode(syn_843_, FE_TONEAREST, 843.0, 0, syn_843_ + 3, "en_US locale");
- strtod_verify_with_rounding_mode(syn_trunc_843_, FE_TONEAREST, 843.0, 0, syn_trunc_843_ + 3, "en_US locale");
- }
-
- if (setlocale(LC_ALL, "fr_FR") != NULL || setlocale(LC_ALL, "fr_FR.UTF-8") != NULL) {
- // Skip this if "fr_FR" locale can't be found
- lc = localeconv();
- T_EXPECT_EQ_STR(lc->decimal_point, ",", "Expected fr_FR locale to have ',' as decimal point");
- strtod_verify_with_rounding_mode(us_123_456, FE_TONEAREST, 123.0, 0, us_123_456 + 3, "fr_FR locale");
- strtod_verify_with_rounding_mode(fr_123_456, FE_TONEAREST, 123.456, 0, fr_123_456 + 7, "fr_FR locale");
- strtod_verify_with_rounding_mode(syn_123_456, FE_TONEAREST, 123.0, 0, syn_123_456 + 3, "fr_FR locale");
- strtod_verify_with_rounding_mode(syn_trunc_123_456, FE_TONEAREST, 123.0, 0, syn_trunc_123_456 + 3, "fr_FR locale");
- strtod_verify_with_rounding_mode(us__279, FE_TONEAREST, 0.0, 0, us__279, "fr_FR locale");
- strtod_verify_with_rounding_mode(fr__279, FE_TONEAREST, 0.279, 0, fr__279 + 4, "fr_FR locale");
- strtod_verify_with_rounding_mode(syn__279, FE_TONEAREST, 0.0, 0, syn__279, "fr_FR locale");
- strtod_verify_with_rounding_mode(syn_trunc__279, FE_TONEAREST, 0.0, 0, syn_trunc__279, "fr_FR locale");
- strtod_verify_with_rounding_mode(us_843_, FE_TONEAREST, 843.0, 0, us_843_ + 3, "fr_FR locale");
- strtod_verify_with_rounding_mode(fr_843_, FE_TONEAREST, 843.0, 0, fr_843_ + 4, "fr_FR locale");
- strtod_verify_with_rounding_mode(syn_843_, FE_TONEAREST, 843.0, 0, syn_843_ + 3, "fr_FR locale");
- strtod_verify_with_rounding_mode(syn_trunc_843_, FE_TONEAREST, 843.0, 0, syn_trunc_843_ + 3, "fr_FR locale");
- }
-
- if (setlocale(LC_ALL, "en_US") != NULL || setlocale(LC_ALL, "en_US.UTF-8") != NULL) {
- lc = localeconv();
- lc->decimal_point = "%$";
- lc = localeconv();
- T_EXPECT_EQ_STR(lc->decimal_point, "%$", "Expected to be able to configure locale with '%%$' as decimal point");
- strtod_verify_with_rounding_mode(us_123_456, FE_TONEAREST, 123.0, 0, us_123_456 + 3, "Synthetic locale");
- strtod_verify_with_rounding_mode(fr_123_456, FE_TONEAREST, 123.0, 0, fr_123_456 + 3, "Synthetic locale");
- strtod_verify_with_rounding_mode(syn_123_456, FE_TONEAREST, 123.456, 0, syn_123_456 + 8, "Synthetic locale");
- strtod_verify_with_rounding_mode(syn_trunc_123_456, FE_TONEAREST, 123.0, 0, syn_trunc_123_456 + 3, "Synthetic locale");
- strtod_verify_with_rounding_mode(us__279, FE_TONEAREST, 0.0, 0, us__279, "Synthetic locale");
- strtod_verify_with_rounding_mode(fr__279, FE_TONEAREST, 0.0, 0, fr__279, "Synthetic locale");
- strtod_verify_with_rounding_mode(syn__279, FE_TONEAREST, 0.279, 0, syn__279 + 5, "Synthetic locale");
- strtod_verify_with_rounding_mode(syn_trunc__279, FE_TONEAREST, 0.0, 0, syn_trunc__279, "Synthetic locale");
- strtod_verify_with_rounding_mode(us_843_, FE_TONEAREST, 843.0, 0, us_843_ + 3, "Synthetic locale");
- strtod_verify_with_rounding_mode(fr_843_, FE_TONEAREST, 843.0, 0, fr_843_ + 3, "Synthetic locale");
- strtod_verify_with_rounding_mode(syn_843_, FE_TONEAREST, 843.0, 0, syn_843_ + 5, "Synthetic locale");
- strtod_verify_with_rounding_mode(syn_trunc_843_, FE_TONEAREST, 843.0, 0, syn_trunc_843_ + 3, "Synthetic locale");
- lc->decimal_point = ".";
- }
-
- // Try hard to restore a sane default locale after the above
- (void)setlocale(LC_ALL, "");
- (void)setlocale(LC_ALL, "POSIX");
- (void)setlocale(LC_ALL, "C");
- (void)uselocale(LC_GLOBAL_LOCALE);
-}
-
-// Based on bug report from
-// https://stackoverflow.com/questions/76133503/strtod-does-not-respect-locale-on-macos-13-3-1
-// also see rdar://111449210 (SEED: Web: strtod() function does not respect locale in macOS 13)
-T_DECL(strtod_thread_locale, "strtod(3) thread-local locale support")
-{
- if (setlocale(LC_ALL, "fr_FR") != NULL || setlocale(LC_ALL, "fr_FR.UTF-8") != NULL) {
- // Skip these tests if "fr_FR" locale can't be found
- double d1 = strtod("123.25", NULL);
- if (d1 != 123.0) {
- T_FAIL("\"123.25\" in fr_FR locale should parse to 123.0, not %g", d1);
- } else {
- T_PASS("fr_FR global locale ignores '.'");
- }
-
- double d2 = strtod("123,25", NULL);
- if (d2 != 123.25) {
- T_FAIL("\"123,25\" in fr_FR locale should parse to 123.25, not %g", d2);
- } else {
- T_PASS("fr_FR global locale recognizes ','");
- }
- }
-
- locale_t c_locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
- if (c_locale != NULL) {
- // Now set the thread-specific locale to use '.' and verify that works correctly
- // Caveat: These are less interesting if selecting the global "fr_FR" locale
- // above failed, but they should still pass in that case.
- uselocale(c_locale);
- double d3 = strtod("123.25", NULL);
- if (d3 != 123.25) {
- T_FAIL("\"123.25\" in fr_FR global locale with C thread locale should parse to 123.25, not %g", d3);
- } else {
- T_PASS("fr_FR global locale with C thread locale recognizes '.'");
- }
- double d4 = strtod("123,25", NULL);
- if (d4 != 123.0) {
- T_FAIL("\"123,25\" in fr_FR global locale with C thread locale should parse to 123.0, not %g", d4);
- } else {
- T_PASS("fr_FR global locale with C thread locale ignores ','");
- }
- uselocale(LC_GLOBAL_LOCALE);
- freelocale(c_locale);
- }
-
- // Try hard to restore a sane default locale after the above
- (void)setlocale(LC_ALL, "");
- (void)setlocale(LC_ALL, "POSIX");
- (void)setlocale(LC_ALL, "C");
- (void)uselocale(LC_GLOBAL_LOCALE);
-}