1116969Sdas/*- 2142843Sdas * Copyright (C) 2003, 2005 David Schultz <das@FreeBSD.org> 3116969Sdas * All rights reserved. 4116969Sdas * 5116969Sdas * Redistribution and use in source and binary forms, with or without 6116969Sdas * modification, are permitted provided that the following conditions 7116969Sdas * are met: 8116969Sdas * 1. Redistributions of source code must retain the above copyright 9116969Sdas * notice, this list of conditions and the following disclaimer. 10116969Sdas * 2. Redistributions in binary form must reproduce the above copyright 11116969Sdas * notice, this list of conditions and the following disclaimer in the 12116969Sdas * documentation and/or other materials provided with the distribution. 13116969Sdas * 14116969Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15116969Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16116969Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17116969Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18116969Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19116969Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20116969Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21116969Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22116969Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23116969Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24116969Sdas * SUCH DAMAGE. 25116969Sdas */ 26116969Sdas 27116969Sdas/* 28116969Sdas * Test for scanf() floating point formats. 29116969Sdas */ 30116969Sdas 31116969Sdas#include <sys/cdefs.h> 32116969Sdas__FBSDID("$FreeBSD$"); 33116969Sdas 34142843Sdas#include <fenv.h> 35116969Sdas#include <float.h> 36116969Sdas#include <locale.h> 37116969Sdas#include <math.h> 38116969Sdas#include <stdio.h> 39182711Sdas#include <stdlib.h> 40116969Sdas#include <string.h> 41116969Sdas 42290537Sngie#include <atf-c.h> 43290537Sngie 44116969Sdas#define eq(type, a, b) _eq(type##_EPSILON, (a), (b)) 45290537Sngiestatic int 46290537Sngie_eq(long double epsilon, long double a, long double b) 47290537Sngie{ 48290537Sngie long double delta; 49116969Sdas 50290537Sngie delta = fabsl(a - b); 51290537Sngie return (delta <= epsilon); 52290537Sngie} 53290537Sngie 54290537SngieATF_TC_WITHOUT_HEAD(normalized_numbers); 55290537SngieATF_TC_BODY(normalized_numbers, tc) 56116969Sdas{ 57116969Sdas char buf[128]; 58116969Sdas long double ld = 0.0; 59116969Sdas double d = 0.0; 60116969Sdas float f = 0.0; 61116969Sdas 62116969Sdas buf[0] = '\0'; 63290537Sngie ATF_REQUIRE(setlocale(LC_NUMERIC, "")); 64116969Sdas 65116969Sdas sscanf("3.141592", "%e", &f); 66290537Sngie ATF_REQUIRE(eq(FLT, f, 3.141592)); 67116969Sdas 68116969Sdas sscanf("3.141592653589793", "%lf", &d); 69290537Sngie ATF_REQUIRE(eq(DBL, d, 3.141592653589793)); 70116969Sdas 71116969Sdas sscanf("1.234568e+06", "%E", &f); 72290537Sngie ATF_REQUIRE(eq(FLT, f, 1.234568e+06)); 73116969Sdas 74116969Sdas sscanf("-1.234568e6", "%lF", &d); 75290537Sngie ATF_REQUIRE(eq(DBL, d, -1.234568e6)); 76116969Sdas 77116969Sdas sscanf("+1.234568e-52", "%LG", &ld); 78290537Sngie ATF_REQUIRE(eq(LDBL, ld, 1.234568e-52L)); 79116969Sdas 80116969Sdas sscanf("0.1", "%la", &d); 81290537Sngie ATF_REQUIRE(eq(DBL, d, 0.1)); 82116969Sdas 83116969Sdas sscanf("00.2", "%lA", &d); 84290537Sngie ATF_REQUIRE(eq(DBL, d, 0.2)); 85116969Sdas 86116969Sdas sscanf("123456", "%5le%s", &d, buf); 87290537Sngie ATF_REQUIRE(eq(DBL, d, 12345.)); 88290537Sngie ATF_REQUIRE(strcmp(buf, "6") == 0); 89116969Sdas 90116969Sdas sscanf("1.0Q", "%*5le%s", buf); 91290537Sngie ATF_REQUIRE(strcmp(buf, "Q") == 0); 92116969Sdas 93116969Sdas sscanf("-1.23e", "%e%s", &f, buf); 94290537Sngie ATF_REQUIRE(eq(FLT, f, -1.23)); 95290537Sngie ATF_REQUIRE(strcmp(buf, "e") == 0); 96116969Sdas 97116969Sdas sscanf("1.25e+", "%le%s", &d, buf); 98290537Sngie ATF_REQUIRE(eq(DBL, d, 1.25)); 99290537Sngie ATF_REQUIRE(strcmp(buf, "e+") == 0); 100116969Sdas 101116969Sdas sscanf("1.23E4E5", "%le%s", &d, buf); 102290537Sngie ATF_REQUIRE(eq(DBL, d, 1.23e4)); 103290537Sngie ATF_REQUIRE(strcmp(buf, "E5") == 0); 104116969Sdas 105116969Sdas sscanf("12e6", "%le", &d); 106290537Sngie ATF_REQUIRE(eq(DBL, d, 12e6)); 107116969Sdas 108116969Sdas sscanf("1.a", "%le%s", &d, buf); 109290537Sngie ATF_REQUIRE(eq(DBL, d, 1.0)); 110290537Sngie ATF_REQUIRE(strcmp(buf, "a") == 0); 111116969Sdas 112116969Sdas sscanf(".0p4", "%le%s", &d, buf); 113290537Sngie ATF_REQUIRE(eq(DBL, d, 0.0)); 114290537Sngie ATF_REQUIRE(strcmp(buf, "p4") == 0); 115116969Sdas 116116969Sdas d = 0.25; 117290537Sngie ATF_REQUIRE(sscanf(".", "%le", &d) == 0); 118290537Sngie ATF_REQUIRE(d == 0.25); 119116969Sdas 120116969Sdas sscanf("0x08", "%le", &d); 121290537Sngie ATF_REQUIRE(d == 0x8p0); 122116969Sdas 123116969Sdas sscanf("0x90a.bcdefP+09a", "%le%s", &d, buf); 124290537Sngie ATF_REQUIRE(d == 0x90a.bcdefp+09); 125290537Sngie ATF_REQUIRE(strcmp(buf, "a") == 0); 126116969Sdas 127124707Sdas#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__) 128124707Sdas sscanf("3.14159265358979323846", "%Lg", &ld); 129290537Sngie ATF_REQUIRE(eq(LDBL, ld, 3.14159265358979323846L)); 130124707Sdas 131116969Sdas sscanf(" 0X.0123456789abcdefffp-3g", "%Le%s", &ld, buf); 132290537Sngie ATF_REQUIRE(ld == 0x0.0123456789abcdefffp-3L); 133290537Sngie ATF_REQUIRE(strcmp(buf, "g") == 0); 134116969Sdas#endif 135116969Sdas 136116969Sdas sscanf("0xg", "%le%s", &d, buf); 137290537Sngie ATF_REQUIRE(d == 0.0); 138290537Sngie ATF_REQUIRE(strcmp(buf, "xg") == 0); 139116969Sdas 140290537Sngie ATF_REQUIRE(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */ 141116969Sdas 142116969Sdas sscanf("1.23", "%le%s", &d, buf); 143290537Sngie ATF_REQUIRE(d == 1.0); 144290537Sngie ATF_REQUIRE(strcmp(buf, ".23") == 0); 145116969Sdas 146116969Sdas sscanf("1,23", "%le", &d); 147290537Sngie ATF_REQUIRE(d == 1.23); 148142843Sdas 149290537Sngie ATF_REQUIRE(setlocale(LC_NUMERIC, "")); 150290537Sngie} 151116969Sdas 152290537SngieATF_TC_WITHOUT_HEAD(infinities_and_nans); 153290537SngieATF_TC_BODY(infinities_and_nans, tc) 154290537Sngie{ 155290537Sngie char buf[128]; 156290537Sngie long double ld = 0.0; 157290537Sngie double d = 0.0; 158290537Sngie float f = 0.0; 159142843Sdas 160290537Sngie ATF_REQUIRE(setlocale(LC_NUMERIC, "C")); 161290537Sngie 162116969Sdas sscanf("-Inf", "%le", &d); 163290537Sngie ATF_REQUIRE(d < 0.0 && isinf(d)); 164116969Sdas 165116969Sdas sscanf("iNfInItY and beyond", "%le%s", &d, buf); 166290537Sngie ATF_REQUIRE(d > 0.0 && isinf(d)); 167290537Sngie ATF_REQUIRE(strcmp(buf, " and beyond")); 168116969Sdas 169116969Sdas sscanf("NaN", "%le", &d); 170290537Sngie ATF_REQUIRE(isnan(d)); 171116969Sdas 172116969Sdas sscanf("NAN(123Y", "%le%s", &d, buf); 173290537Sngie ATF_REQUIRE(isnan(d)); 174290537Sngie ATF_REQUIRE(strcmp(buf, "(123Y") == 0); 175116969Sdas 176116969Sdas sscanf("nan(f00f)plugh", "%le%s", &d, buf); 177290537Sngie ATF_REQUIRE(isnan(d)); 178290537Sngie ATF_REQUIRE(strcmp(buf, "plugh") == 0); 179116969Sdas 180116969Sdas sscanf("-nan", "%le", &d); 181290537Sngie ATF_REQUIRE(isnan(d)); 182116969Sdas 183142843Sdas /* Only quiet NaNs should be returned. */ 184142843Sdas sscanf("NaN", "%e", &f); 185142843Sdas sscanf("nan", "%le", &d); 186142843Sdas sscanf("nan", "%Le", &ld); 187142843Sdas feclearexcept(FE_ALL_EXCEPT); 188290537Sngie ATF_REQUIRE(f != f); 189290537Sngie ATF_REQUIRE(d != d); 190290537Sngie ATF_REQUIRE(ld != ld); 191290537Sngie ATF_REQUIRE(fetestexcept(FE_INVALID) == 0); 192142843Sdas sscanf("nan(1234)", "%e", &f); 193142843Sdas sscanf("nan(1234)", "%le", &d); 194142843Sdas sscanf("nan(1234)", "%Le", &ld); 195142843Sdas feclearexcept(FE_ALL_EXCEPT); 196290537Sngie ATF_REQUIRE(f != f); 197290537Sngie ATF_REQUIRE(d != d); 198290537Sngie ATF_REQUIRE(ld != ld); 199182711Sdas /* POSIX says we should only generate quiet NaNs. */ 200290537Sngie ATF_REQUIRE(fetestexcept(FE_INVALID) == 0); 201290537Sngie} 202124707Sdas 203290537SngieATF_TC_WITHOUT_HEAD(rounding_tests); 204290537SngieATF_TC_BODY(rounding_tests, tc) 205290537Sngie{ 206290537Sngie long double ld = 0.0; 207290537Sngie double d = 0.0; 208142843Sdas 209290537Sngie ATF_REQUIRE(setlocale(LC_NUMERIC, "C")); 210142843Sdas 211142843Sdas fesetround(FE_DOWNWARD); 212142843Sdas 213142843Sdas sscanf("1.999999999999999999999999999999999", "%le", &d); 214290537Sngie ATF_REQUIRE(d < 2.0); 215142843Sdas sscanf("0x1.ffffffffffffffp0", "%le", &d); 216290537Sngie ATF_REQUIRE(d < 2.0); 217142843Sdas sscanf("1.999999999999999999999999999999999", "%Le", &ld); 218290537Sngie ATF_REQUIRE(ld < 2.0); 219142843Sdas 220142843Sdas sscanf("1.0571892669084007", "%le", &d); 221290537Sngie ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0); 222142843Sdas sscanf("-1.0571892669084007", "%le", &d); 223290537Sngie ATF_REQUIRE(d == -0x1.0ea3f4af0dc5ap0); 224142843Sdas sscanf("1.0571892669084010", "%le", &d); 225290537Sngie ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0); 226142843Sdas 227142843Sdas sscanf("0x1.23p-5000", "%le", &d); 228290537Sngie ATF_REQUIRE(d == 0.0); 229142843Sdas 230142843Sdas sscanf("0x1.2345678p-1050", "%le", &d); 231290537Sngie ATF_REQUIRE(d == 0x1.234567p-1050); 232142843Sdas 233142843Sdas fesetround(FE_UPWARD); 234142843Sdas 235142843Sdas sscanf("1.0571892669084007", "%le", &d); 236290537Sngie ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0); 237142843Sdas sscanf("-1.0571892669084007", "%le", &d); 238290537Sngie ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0); 239142843Sdas sscanf("1.0571892669084010", "%le", &d); 240290537Sngie ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0); 241142843Sdas 242142843Sdas sscanf("0x1.23p-5000", "%le", &d); 243290537Sngie ATF_REQUIRE(d == 0x1p-1074); 244142843Sdas 245142843Sdas sscanf("0x1.2345678p-1050", "%le", &d); 246290537Sngie ATF_REQUIRE(d == 0x1.234568p-1050); 247142843Sdas 248142843Sdas fesetround(FE_TOWARDZERO); 249142843Sdas 250142843Sdas sscanf("1.0571892669084007", "%le", &d); 251290537Sngie ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0); 252142843Sdas sscanf("-1.0571892669084007", "%le", &d); 253290537Sngie ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0); 254142843Sdas sscanf("1.0571892669084010", "%le", &d); 255290537Sngie ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0); 256142843Sdas 257142843Sdas sscanf("0x1.23p-5000", "%le", &d); 258290537Sngie ATF_REQUIRE(d == 0.0); 259142843Sdas 260142843Sdas sscanf("0x1.2345678p-1050", "%le", &d); 261290537Sngie ATF_REQUIRE(d == 0x1.234567p-1050); 262142843Sdas 263142843Sdas fesetround(FE_TONEAREST); 264142843Sdas 265142843Sdas /* 1.0571892669084007 is slightly closer to 0x1.0ea3f4af0dc59p0 */ 266142843Sdas sscanf("1.0571892669084007", "%le", &d); 267290537Sngie ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0); 268142843Sdas sscanf("-1.0571892669084007", "%le", &d); 269290537Sngie ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0); 270142843Sdas sscanf("1.0571892669084010", "%le", &d); 271290537Sngie ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0); 272142843Sdas 273124707Sdas /* strtod() should round small numbers to 0. */ 274124707Sdas sscanf("0x1.23p-5000", "%le", &d); 275290537Sngie ATF_REQUIRE(d == 0.0); 276124707Sdas 277124707Sdas /* Extra digits in a denormal shouldn't break anything. */ 278124707Sdas sscanf("0x1.2345678p-1050", "%le", &d); 279290537Sngie ATF_REQUIRE(d == 0x1.234568p-1050); 280290537Sngie} 281124707Sdas 282290537SngieATF_TC_WITHOUT_HEAD(strtod); 283290537SngieATF_TC_BODY(strtod, tc) 284290537Sngie{ 285290537Sngie char *endp; 286116969Sdas 287290537Sngie ATF_REQUIRE(setlocale(LC_NUMERIC, "C")); 288179919Sdas 289290537Sngie ATF_REQUIRE(strtod("0xy", &endp) == 0); 290290537Sngie ATF_REQUIRE(strcmp("xy", endp) == 0); 291179919Sdas 292182711Sdas /* This used to cause an infinite loop and round the wrong way. */ 293182711Sdas fesetround(FE_DOWNWARD); 294290537Sngie ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX); 295290537Sngie ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX); 296182711Sdas fesetround(FE_UPWARD); 297290537Sngie ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY); 298290537Sngie ATF_REQUIRE(strtod("2e308", &endp) == INFINITY); 299182711Sdas fesetround(FE_TOWARDZERO); 300290537Sngie ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX); 301290537Sngie ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX); 302182711Sdas fesetround(FE_TONEAREST); 303290537Sngie ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY); 304290537Sngie ATF_REQUIRE(strtod("2e308", &endp) == INFINITY); 305116969Sdas} 306116969Sdas 307290537SngieATF_TP_ADD_TCS(tp) 308116969Sdas{ 309116969Sdas 310290537Sngie ATF_TP_ADD_TC(tp, normalized_numbers); 311290537Sngie ATF_TP_ADD_TC(tp, infinities_and_nans); 312290537Sngie ATF_TP_ADD_TC(tp, rounding_tests); 313290537Sngie ATF_TP_ADD_TC(tp, strtod); 314290537Sngie 315290537Sngie return (atf_no_error()); 316116969Sdas} 317