1113147Sdas/*- 2187963Sdas * Copyright (c) 2002-2009 David Schultz <das@FreeBSD.org> 3113147Sdas * All rights reserved. 4113147Sdas * 5113147Sdas * Redistribution and use in source and binary forms, with or without 6113147Sdas * modification, are permitted provided that the following conditions 7113147Sdas * are met: 8113147Sdas * 1. Redistributions of source code must retain the above copyright 9113147Sdas * notice, this list of conditions and the following disclaimer. 10113147Sdas * 2. Redistributions in binary form must reproduce the above copyright 11113147Sdas * notice, this list of conditions and the following disclaimer in the 12113147Sdas * documentation and/or other materials provided with the distribution. 13113147Sdas * 14113147Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15113147Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16113147Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17113147Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18113147Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19113147Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20113147Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21113147Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22113147Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23113147Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24113147Sdas * SUCH DAMAGE. 25113147Sdas */ 26113147Sdas 27113147Sdas/* 28113147Sdas * Test for printf() floating point formats. 29113147Sdas */ 30113147Sdas 31113147Sdas#include <sys/cdefs.h> 32113147Sdas__FBSDID("$FreeBSD$"); 33113147Sdas 34113147Sdas#include <assert.h> 35113147Sdas#include <err.h> 36142842Sdas#include <fenv.h> 37113147Sdas#include <float.h> 38113147Sdas#include <locale.h> 39113147Sdas#include <math.h> 40113147Sdas#include <stdio.h> 41113147Sdas#include <stdarg.h> 42113147Sdas#include <stdint.h> 43113147Sdas#include <stdlib.h> 44113147Sdas#include <string.h> 45187963Sdas#include <wchar.h> 46113147Sdas 47113147Sdas#define testfmt(result, fmt, ...) \ 48113147Sdas _testfmt((result), __LINE__, #__VA_ARGS__, fmt, __VA_ARGS__) 49113147Sdasvoid _testfmt(const char *, int, const char *, const char *, ...); 50113147Sdasvoid smash_stack(void); 51113147Sdas 52113147Sdasint 53113147Sdasmain(int argc, char *argv[]) 54113147Sdas{ 55113147Sdas 56142842Sdas printf("1..11\n"); 57174228Sdas assert(setlocale(LC_NUMERIC, "C")); 58113147Sdas 59142842Sdas /* 60142842Sdas * Basic tests of decimal output functionality. 61142842Sdas */ 62113147Sdas testfmt(" 1.000000E+00", "%13E", 1.0); 63113147Sdas testfmt(" 1.000000", "%13f", 1.0); 64113147Sdas testfmt(" 1", "%13G", 1.0); 65113147Sdas testfmt(" 1.000000E+00", "%13LE", 1.0L); 66113147Sdas testfmt(" 1.000000", "%13Lf", 1.0L); 67113147Sdas testfmt(" 1", "%13LG", 1.0L); 68113147Sdas 69113192Sdas testfmt("2.718282", "%.*f", -2, 2.7182818); 70113192Sdas 71113147Sdas testfmt("1.234568e+06", "%e", 1234567.8); 72113147Sdas testfmt("1234567.800000", "%f", 1234567.8); 73113147Sdas testfmt("1.23457E+06", "%G", 1234567.8); 74113147Sdas testfmt("1.234568e+06", "%Le", 1234567.8L); 75113147Sdas testfmt("1234567.800000", "%Lf", 1234567.8L); 76113147Sdas testfmt("1.23457E+06", "%LG", 1234567.8L); 77113147Sdas 78124708Sdas#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__) 79113147Sdas testfmt("123456789.864210", "%Lf", 123456789.8642097531L); 80113147Sdas testfmt("-1.23457E+08", "%LG", -123456789.8642097531L); 81113147Sdas testfmt("123456789.8642097531", "%.10Lf", 123456789.8642097531L); 82113147Sdas testfmt(" 3.141592653589793238e-4000", "%L27.18Le", 83113147Sdas 3.14159265358979323846e-4000L); 84113147Sdas#endif 85113147Sdas 86142842Sdas printf("ok 1 - printfloat\n"); 87142842Sdas 88142842Sdas /* 89142842Sdas * Infinities and NaNs 90142842Sdas */ 91113147Sdas testfmt("nan", "%e", NAN); 92113147Sdas testfmt("NAN", "%F", NAN); 93113147Sdas testfmt("nan", "%g", NAN); 94113147Sdas testfmt("NAN", "%LE", (long double)NAN); 95174205Sdas testfmt(" nan", "%05e", NAN); 96113147Sdas 97113147Sdas testfmt("INF", "%E", HUGE_VAL); 98113147Sdas testfmt("-inf", "%f", -HUGE_VAL); 99113147Sdas testfmt("+inf", "%+g", HUGE_VAL); 100113147Sdas testfmt(" inf", "%4.2Le", HUGE_VALL); 101113147Sdas testfmt("-inf", "%Lf", -HUGE_VALL); 102174205Sdas testfmt(" inf", "%05e", HUGE_VAL); 103174205Sdas testfmt(" -inf", "%05e", -HUGE_VAL); 104113147Sdas 105142842Sdas printf("ok 2 - printfloat\n"); 106142842Sdas 107142842Sdas /* 108142842Sdas * Padding 109142842Sdas */ 110113147Sdas testfmt("0.000000e+00", "%e", 0.0); 111113147Sdas testfmt("0.000000", "%F", (double)0.0); 112113147Sdas testfmt("0", "%G", 0.0); 113113147Sdas testfmt(" 0", "%3.0Lg", 0.0L); 114113469Sdas testfmt(" 0", "%5.0f", 0.001); 115142842Sdas printf("ok 3 - printfloat\n"); 116113469Sdas 117142842Sdas /* 118142842Sdas * Precision specifiers 119142842Sdas */ 120113147Sdas testfmt("1.0123e+00", "%.4e", 1.0123456789); 121113147Sdas testfmt("1.0123", "%.4f", 1.0123456789); 122113147Sdas testfmt("1.012", "%.4g", 1.0123456789); 123113147Sdas testfmt("1.2346e-02", "%.4e", 0.0123456789); 124113147Sdas testfmt("0.0123", "%.4f", 0.0123456789); 125113147Sdas testfmt("0.01235", "%.4g", 0.0123456789); 126142842Sdas printf("ok 4 - printfloat\n"); 127113147Sdas 128142842Sdas /* 129142842Sdas * Thousands' separators and other locale fun 130142842Sdas */ 131113147Sdas testfmt("12345678.0625", "%'.04f", 12345678.0625); 132113147Sdas testfmt("0012345678.0625", "%'015.4F", 12345678.0625); 133113147Sdas 134113147Sdas assert(setlocale(LC_NUMERIC, "hi_IN.ISCII-DEV")); /* grouping == 2;3 */ 135113147Sdas testfmt("123,456,78.0625", "%'.4f", 12345678.0625); 136113147Sdas testfmt("00123,456,78.0625", "%'017.4F", 12345678.0625); 137113192Sdas testfmt(" 90,00", "%'6.0f", 9000.0); 138113192Sdas testfmt("90,00.0", "%'.1f", 9000.0); 139136497Skeramida 140113147Sdas assert(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */ 141113147Sdas testfmt("3,1415", "%g", 3.1415); 142136497Skeramida 143136497Skeramida /* thousands=. decimalpoint=, grouping=3;3 */ 144136497Skeramida assert(setlocale(LC_NUMERIC, "el_GR.ISO8859-7")); /* decimalpoint==, */ 145136497Skeramida testfmt("1.234,00", "%'.2f", 1234.00); 146136497Skeramida testfmt("123.456,789", "%'.3f", 123456.789); 147136497Skeramida 148174228Sdas assert(setlocale(LC_NUMERIC, "C")); 149113192Sdas testfmt("12345678.062500", "%'f", 12345678.0625); 150113192Sdas testfmt("9000.000000", "%'f", 9000.0); 151113147Sdas 152142842Sdas printf("ok 5 - printfloat\n"); 153142842Sdas 154142842Sdas /* 155142842Sdas * Signed conversions 156142842Sdas */ 157113147Sdas testfmt("+2.500000e-01", "%+e", 0.25); 158113147Sdas testfmt("+0.000000", "%+F", 0.0); 159113147Sdas testfmt("-1", "%+g", -1.0); 160113147Sdas 161113147Sdas testfmt("-1.000000e+00", "% e", -1.0); 162113147Sdas testfmt("+1.000000", "% +f", 1.0); 163113147Sdas testfmt(" 1", "% g", 1.0); 164113147Sdas testfmt(" 0", "% g", 0.0); 165113147Sdas 166142842Sdas printf("ok 6 - printfloat\n"); 167142842Sdas 168142842Sdas /* 169142842Sdas * ``Alternate form'' 170142842Sdas */ 171113147Sdas testfmt("1.250e+00", "%#.3e", 1.25); 172113147Sdas testfmt("123.000000", "%#f", 123.0); 173113147Sdas testfmt(" 12345.", "%#7.5g", 12345.0); 174113147Sdas testfmt(" 1.00000", "%#8g", 1.0); 175113147Sdas testfmt("0.0", "%#.2g", 0.0); 176142842Sdas printf("ok 7 - printfloat\n"); 177113147Sdas 178142842Sdas /* 179142842Sdas * Padding and decimal point placement 180142842Sdas */ 181113147Sdas testfmt("03.2E+00", "%08.1E", 3.25); 182113147Sdas testfmt("003.25", "%06.2F", 3.25); 183113147Sdas testfmt("0003.25", "%07.4G", 3.25); 184113147Sdas 185113147Sdas testfmt("3.14159e-05", "%g", 3.14159e-5); 186113147Sdas testfmt("0.000314159", "%g", 3.14159e-4); 187113147Sdas testfmt("3.14159e+06", "%g", 3.14159e6); 188113147Sdas testfmt("314159", "%g", 3.14159e5); 189113147Sdas testfmt("314159.", "%#g", 3.14159e5); 190113147Sdas 191113724Sdas testfmt(" 9.000000e+03", "%13e", 9000.0); 192113724Sdas testfmt(" 9000.000000", "%12f", 9000.0); 193113724Sdas testfmt(" 9000", "%5g", 9000.0); 194113724Sdas testfmt(" 900000.", "%#8g", 900000.0); 195113724Sdas testfmt(" 9e+06", "%6g", 9000000.0); 196113724Sdas testfmt(" 9.000000e-04", "%13e", 0.0009); 197113724Sdas testfmt(" 0.000900", "%9f", 0.0009); 198113724Sdas testfmt(" 0.0009", "%7g", 0.0009); 199113724Sdas testfmt(" 9e-05", "%6g", 0.00009); 200113724Sdas testfmt(" 9.00000e-05", "%#12g", 0.00009); 201113724Sdas testfmt(" 9.e-05", "%#7.1g", 0.00009); 202113724Sdas 203113162Stjr testfmt(" 0.0", "%4.1f", 0.0); 204113192Sdas testfmt("90.0", "%4.1f", 90.0); 205113162Stjr testfmt(" 100", "%4.0f", 100.0); 206113192Sdas testfmt("9.0e+01", "%4.1e", 90.0); 207113192Sdas testfmt("1e+02", "%4.0e", 100.0); 208113162Stjr 209142842Sdas printf("ok 8 - printfloat\n"); 210142842Sdas 211124708Sdas /* 212142842Sdas * Decimal rounding 213142842Sdas */ 214142842Sdas fesetround(FE_DOWNWARD); 215142842Sdas testfmt("4.437", "%.3f", 4.4375); 216142842Sdas testfmt("-4.438", "%.3f", -4.4375); 217174205Sdas testfmt("4.437", "%.3Lf", 4.4375L); 218174205Sdas testfmt("-4.438", "%.3Lf", -4.4375L); 219142842Sdas 220142842Sdas fesetround(FE_UPWARD); 221142842Sdas testfmt("4.438", "%.3f", 4.4375); 222142842Sdas testfmt("-4.437", "%.3f", -4.4375); 223174205Sdas testfmt("4.438", "%.3Lf", 4.4375L); 224174205Sdas testfmt("-4.437", "%.3Lf", -4.4375L); 225142842Sdas 226142842Sdas fesetround(FE_TOWARDZERO); 227142842Sdas testfmt("4.437", "%.3f", 4.4375); 228142842Sdas testfmt("-4.437", "%.3f", -4.4375); 229174205Sdas testfmt("4.437", "%.3Lf", 4.4375L); 230174205Sdas testfmt("-4.437", "%.3Lf", -4.4375L); 231142842Sdas 232142842Sdas fesetround(FE_TONEAREST); 233142842Sdas testfmt("4.438", "%.3f", 4.4375); 234142842Sdas testfmt("-4.438", "%.3f", -4.4375); 235174205Sdas testfmt("4.438", "%.3Lf", 4.4375L); 236174205Sdas testfmt("-4.438", "%.3Lf", -4.4375L); 237142842Sdas 238142842Sdas printf("ok 9 - printfloat\n"); 239142842Sdas 240142842Sdas /* 241124708Sdas * Hexadecimal floating point (%a, %A) tests. Some of these 242124708Sdas * are only valid if the implementation converts to hex digits 243124708Sdas * on nibble boundaries. 244124708Sdas */ 245124708Sdas testfmt("0x0p+0", "%a", 0x0.0p0); 246124708Sdas testfmt("0X0.P+0", "%#LA", 0x0.0p0L); 247124708Sdas testfmt("inf", "%La", (long double)INFINITY); 248124708Sdas testfmt("+INF", "%+A", INFINITY); 249124708Sdas testfmt("nan", "%La", (long double)NAN); 250124708Sdas testfmt("NAN", "%A", NAN); 251124708Sdas 252124708Sdas testfmt(" 0x1.23p+0", "%10a", 0x1.23p0); 253124708Sdas testfmt(" 0x1.23p-500", "%12a", 0x1.23p-500); 254124708Sdas testfmt(" 0x1.2p+40", "%10.1a", 0x1.23p40); 255124708Sdas testfmt(" 0X1.230000000000000000000000P-4", "%32.24A", 0x1.23p-4); 256142842Sdas testfmt("0x1p-1074", "%a", 0x1p-1074); 257142842Sdas testfmt("0x1.2345p-1024", "%a", 0x1.2345p-1024); 258124708Sdas 259124708Sdas#if (LDBL_MANT_DIG == 64) && !defined(__i386__) 260178141Sdas testfmt("0x1.921fb54442d18468p+1", "%La", 0x3.243f6a8885a308dp0L); 261178141Sdas testfmt("0x1p-16445", "%La", 0x1p-16445L); 262178141Sdas testfmt("0x1.30ecap-16381", "%La", 0x9.8765p-16384L); 263124708Sdas#elif (LDBL_MANT_DIG == 113) 264124708Sdas testfmt("0x1.921fb54442d18469898cc51701b8p+1", "%La", 265124708Sdas 0x3.243f6a8885a308d313198a2e037p0L); 266142842Sdas testfmt("0x1p-16494", "%La", 0x1p-16494L); 267142842Sdas testfmt("0x1.2345p-16384", "%La", 0x1.2345p-16384L); 268124708Sdas#else 269230114Sdas testfmt("0x1.921fb54442d18p+1", "%La", 0x3.243f6a8885a31p0L); 270230114Sdas testfmt("0x1p-1074", "%La", 0x1p-1074L); 271230114Sdas testfmt("0x1.30ecap-1021", "%La", 0x9.8765p-1024L); 272124708Sdas#endif 273124708Sdas 274142842Sdas printf("ok 10 - printfloat\n"); 275142842Sdas 276142842Sdas /* 277142842Sdas * Hexadecimal rounding 278142842Sdas */ 279142842Sdas fesetround(FE_TOWARDZERO); 280142842Sdas testfmt("0X1.23456789ABCP+0", "%.11A", 0x1.23456789abcdep0); 281142842Sdas testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0); 282142842Sdas testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0); 283142842Sdas testfmt("0x1.234567p+0", "%.6a", 0x1.23456789abcdep0); 284142842Sdas testfmt("-0x1.234566p+0", "%.6a", -0x1.23456689abcdep0); 285142842Sdas 286142842Sdas fesetround(FE_DOWNWARD); 287142842Sdas testfmt("0X1.23456789ABCP+0", "%.11A", 0x1.23456789abcdep0); 288142842Sdas testfmt("-0x1.23457p+0", "%.5a", -0x1.23456789abcdep0); 289142842Sdas testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0); 290142842Sdas testfmt("0x1.234567p+0", "%.6a", 0x1.23456789abcdep0); 291142842Sdas testfmt("-0x1.234567p+0", "%.6a", -0x1.23456689abcdep0); 292142842Sdas 293142842Sdas fesetround(FE_UPWARD); 294142842Sdas testfmt("0X1.23456789ABDP+0", "%.11A", 0x1.23456789abcdep0); 295142842Sdas testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0); 296142842Sdas testfmt("0x1.23457p+0", "%.5a", 0x1.23456789abcdep0); 297142842Sdas testfmt("0x1.234568p+0", "%.6a", 0x1.23456789abcdep0); 298142842Sdas testfmt("-0x1.234566p+0", "%.6a", -0x1.23456689abcdep0); 299142842Sdas 300142842Sdas fesetround(FE_TONEAREST); 301124708Sdas testfmt("0x1.23456789abcdep+4", "%a", 0x1.23456789abcdep4); 302124708Sdas testfmt("0X1.23456789ABDP+0", "%.11A", 0x1.23456789abcdep0); 303124708Sdas testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0); 304142842Sdas testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0); 305124708Sdas testfmt("0x1.234568p+0", "%.6a", 0x1.23456789abcdep0); 306174205Sdas testfmt("-0x1.234567p+0", "%.6a", -0x1.23456689abcdep0); 307178141Sdas testfmt("0x1.00p-1029", "%.2a", 0x1.fffp-1030); 308178141Sdas testfmt("0x1.00p-1026", "%.2a", 0xf.fffp-1030); 309174205Sdas testfmt("0x1.83p+0", "%.2a", 1.51); 310124708Sdas 311142842Sdas printf("ok 11 - printfloat\n"); 312113147Sdas 313113147Sdas return (0); 314113147Sdas} 315113147Sdas 316113147Sdasvoid 317113147Sdassmash_stack(void) 318113147Sdas{ 319113147Sdas static uint32_t junk = 0xdeadbeef; 320113147Sdas uint32_t buf[512]; 321113147Sdas int i; 322113147Sdas 323113147Sdas for (i = 0; i < sizeof(buf) / sizeof(buf[0]); i++) 324113147Sdas buf[i] = junk; 325113147Sdas} 326113147Sdas 327113147Sdasvoid 328113147Sdas_testfmt(const char *result, int line, const char *argstr, const char *fmt,...) 329113147Sdas{ 330187963Sdas#define BUF 100 331187963Sdas wchar_t ws[BUF], wfmt[BUF], wresult[BUF]; 332187963Sdas char s[BUF]; 333187963Sdas va_list ap, ap2; 334113147Sdas 335113147Sdas va_start(ap, fmt); 336187963Sdas va_copy(ap2, ap); 337113147Sdas smash_stack(); 338113147Sdas vsnprintf(s, sizeof(s), fmt, ap); 339113147Sdas if (strcmp(result, s) != 0) { 340113147Sdas fprintf(stderr, 341113147Sdas "%d: printf(\"%s\", %s) ==> [%s], expected [%s]\n", 342113147Sdas line, fmt, argstr, s, result); 343113147Sdas abort(); 344113147Sdas } 345187963Sdas 346187963Sdas smash_stack(); 347187963Sdas mbstowcs(ws, s, BUF - 1); 348187963Sdas mbstowcs(wfmt, fmt, BUF - 1); 349187963Sdas mbstowcs(wresult, result, BUF - 1); 350187963Sdas vswprintf(ws, sizeof(ws) / sizeof(ws[0]), wfmt, ap2); 351187963Sdas if (wcscmp(wresult, ws) != 0) { 352187963Sdas fprintf(stderr, 353187963Sdas "%d: wprintf(\"%ls\", %s) ==> [%ls], expected [%ls]\n", 354187963Sdas line, wfmt, argstr, ws, wresult); 355187963Sdas abort(); 356187963Sdas } 357113147Sdas} 358