1// Written in the D programming language. 2 3/* 4 Helper functions for formatting floating point numbers. 5 6 Copyright: Copyright The D Language Foundation 2019 - 7 8 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 9 10 Authors: Bernhard Seckinger 11 12 Source: $(PHOBOSSRC std/format/internal/floats.d) 13 */ 14 15module std.format.internal.floats; 16 17import std.format.spec : FormatSpec; 18 19// wrapper for unittests 20private auto printFloat(T, Char)(const(T) val, FormatSpec!Char f) 21if (is(T == float) || is(T == double) 22 || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64))) 23{ 24 import std.array : appender; 25 auto w = appender!string(); 26 27 printFloat(w, val, f); 28 return w.data; 29} 30 31package(std.format) void printFloat(Writer, T, Char)(auto ref Writer w, const(T) val, FormatSpec!Char f) 32if (is(T == float) || is(T == double) 33 || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64))) 34{ 35 import std.math.operations : extractBitpattern, FloatingPointBitpattern; 36 37 auto bp = extractBitpattern(val); 38 39 ulong mnt = bp.mantissa; 40 int exp = bp.exponent; 41 string sgn = bp.negative ? "-" : ""; 42 43 if (sgn == "" && f.flPlus) sgn = "+"; 44 if (sgn == "" && f.flSpace) sgn = " "; 45 46 assert(f.spec == 'a' || f.spec == 'A' 47 || f.spec == 'e' || f.spec == 'E' 48 || f.spec == 'f' || f.spec == 'F' 49 || f.spec == 'g' || f.spec == 'G', "unsupported format specifier"); 50 bool is_upper = f.spec == 'A' || f.spec == 'E' || f.spec=='F' || f.spec=='G'; 51 52 // special treatment for nan and inf 53 if (exp == T.max_exp) 54 { 55 import std.format.internal.write : writeAligned; 56 57 f.flZero = false; 58 writeAligned(w, sgn, "", (mnt == 0) ? ( is_upper ? "INF" : "inf" ) : ( is_upper ? "NAN" : "nan" ), f); 59 return; 60 } 61 62 final switch (f.spec) 63 { 64 case 'a': case 'A': 65 printFloatA(w, val, f, sgn, exp, mnt, is_upper); 66 break; 67 case 'e': case 'E': 68 printFloatE!false(w, val, f, sgn, exp, mnt, is_upper); 69 break; 70 case 'f': case 'F': 71 printFloatF!false(w, val, f, sgn, exp, mnt, is_upper); 72 break; 73 case 'g': case 'G': 74 printFloatG(w, val, f, sgn, exp, mnt, is_upper); 75 break; 76 } 77} 78 79private void printFloatA(Writer, T, Char)(auto ref Writer w, const(T) val, 80 FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper) 81if (is(T == float) || is(T == double) 82 || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64))) 83{ 84 import std.algorithm.comparison : max; 85 import std.format.internal.write : writeAligned, PrecisionType; 86 87 char[3] prefix; 88 if (sgn != "") prefix[0] = sgn[0]; 89 prefix[1] = '0'; 90 prefix[2] = is_upper ? 'X' : 'x'; 91 92 // print exponent 93 if (mnt == 0) 94 { 95 if (f.precision == f.UNSPECIFIED) 96 f.precision = 0; 97 writeAligned(w, prefix[1 - sgn.length .. $], "0", ".", is_upper ? "P+0" : "p+0", 98 f, PrecisionType.fractionalDigits); 99 return; 100 } 101 102 // save integer part 103 char first = '0' + ((mnt >> (T.mant_dig - 1)) & 1); 104 mnt &= (1L << (T.mant_dig - 1)) - 1; 105 106 static if (is(T == float) || (is(T == real) && T.mant_dig == 64)) 107 { 108 mnt <<= 1; // make mnt dividable by 4 109 enum mant_len = T.mant_dig; 110 } 111 else 112 enum mant_len = T.mant_dig - 1; 113 static assert(mant_len % 4 == 0, "mantissa with wrong length"); 114 115 // print full mantissa 116 char[(mant_len - 1) / 4 + 3] hex_mant; 117 size_t hex_mant_pos = 2; 118 size_t pos = mant_len; 119 120 auto gap = 39 - 32 * is_upper; 121 while (pos >= 4 && (mnt & (((1L << (pos - 1)) - 1) << 1) + 1) != 0) 122 { 123 pos -= 4; 124 size_t tmp = (mnt >> pos) & 15; 125 // For speed reasons the better readable 126 // ... = tmp < 10 ? ('0' + tmp) : ((is_upper ? 'A' : 'a') + tmp - 10)) 127 // has been replaced with an expression without branches, doing the same 128 hex_mant[hex_mant_pos++] = cast(char) (tmp + gap * ((tmp + 6) >> 4) + '0'); 129 } 130 hex_mant[0] = first; 131 hex_mant[1] = '.'; 132 133 if (f.precision == f.UNSPECIFIED) 134 f.precision = cast(int) hex_mant_pos - 2; 135 136 auto exp_sgn = exp >= 0 ? '+' : '-'; 137 if (exp < 0) exp = -exp; 138 139 static if (is(T == real) && real.mant_dig == 64) 140 enum max_exp_digits = 8; 141 else static if (is(T == float)) 142 enum max_exp_digits = 5; 143 else 144 enum max_exp_digits = 6; 145 146 char[max_exp_digits] exp_str; 147 size_t exp_pos = max_exp_digits; 148 149 do 150 { 151 exp_str[--exp_pos] = '0' + exp % 10; 152 exp /= 10; 153 } while (exp > 0); 154 155 exp_str[--exp_pos] = exp_sgn; 156 exp_str[--exp_pos] = is_upper ? 'P' : 'p'; 157 158 if (f.precision < hex_mant_pos - 2) 159 { 160 import std.format.internal.write : RoundingClass, round; 161 162 RoundingClass rc; 163 164 if (hex_mant[f.precision + 2] == '0') 165 rc = RoundingClass.ZERO; 166 else if (hex_mant[f.precision + 2] < '8') 167 rc = RoundingClass.LOWER; 168 else if (hex_mant[f.precision + 2] > '8') 169 rc = RoundingClass.UPPER; 170 else 171 rc = RoundingClass.FIVE; 172 173 if (rc == RoundingClass.ZERO || rc == RoundingClass.FIVE) 174 { 175 foreach (i;f.precision + 3 .. hex_mant_pos) 176 { 177 if (hex_mant[i] > '0') 178 { 179 rc = rc == RoundingClass.ZERO ? RoundingClass.LOWER : RoundingClass.UPPER; 180 break; 181 } 182 } 183 } 184 185 hex_mant_pos = f.precision + 2; 186 187 round(hex_mant, 0, hex_mant_pos, rc, sgn == "-", is_upper ? 'F' : 'f'); 188 } 189 190 writeAligned(w, prefix[1 - sgn.length .. $], hex_mant[0 .. 1], hex_mant[1 .. hex_mant_pos], 191 exp_str[exp_pos .. $], f, PrecisionType.fractionalDigits); 192} 193 194@safe unittest 195{ 196 auto f = FormatSpec!dchar(""); 197 f.spec = 'a'; 198 assert(printFloat(float.nan, f) == "nan"); 199 assert(printFloat(-float.nan, f) == "-nan"); 200 assert(printFloat(float.infinity, f) == "inf"); 201 assert(printFloat(-float.infinity, f) == "-inf"); 202 assert(printFloat(0.0f, f) == "0x0p+0"); 203 assert(printFloat(-0.0f, f) == "-0x0p+0"); 204 205 assert(printFloat(double.nan, f) == "nan"); 206 assert(printFloat(-double.nan, f) == "-nan"); 207 assert(printFloat(double.infinity, f) == "inf"); 208 assert(printFloat(-double.infinity, f) == "-inf"); 209 assert(printFloat(0.0, f) == "0x0p+0"); 210 assert(printFloat(-0.0, f) == "-0x0p+0"); 211 212 static if (real.mant_dig > 64) 213 { 214 pragma(msg, "printFloat tests disabled because of unsupported `real` format"); 215 } 216 else 217 { 218 assert(printFloat(real.nan, f) == "nan"); 219 assert(printFloat(-real.nan, f) == "-nan"); 220 assert(printFloat(real.infinity, f) == "inf"); 221 assert(printFloat(-real.infinity, f) == "-inf"); 222 assert(printFloat(0.0L, f) == "0x0p+0"); 223 assert(printFloat(-0.0L, f) == "-0x0p+0"); 224 } 225 226 import std.math.operations : nextUp; 227 228 assert(printFloat(nextUp(0.0f), f) == "0x0.000002p-126"); 229 assert(printFloat(float.epsilon, f) == "0x1p-23"); 230 assert(printFloat(float.min_normal, f) == "0x1p-126"); 231 assert(printFloat(float.max, f) == "0x1.fffffep+127"); 232 233 assert(printFloat(nextUp(0.0), f) == "0x0.0000000000001p-1022"); 234 assert(printFloat(double.epsilon, f) == "0x1p-52"); 235 assert(printFloat(double.min_normal, f) == "0x1p-1022"); 236 assert(printFloat(double.max, f) == "0x1.fffffffffffffp+1023"); 237 238 static if (real.mant_dig == 64) 239 { 240 assert(printFloat(nextUp(0.0L), f) == "0x0.0000000000000002p-16382"); 241 assert(printFloat(real.epsilon, f) == "0x1p-63"); 242 assert(printFloat(real.min_normal, f) == "0x1p-16382"); 243 assert(printFloat(real.max, f) == "0x1.fffffffffffffffep+16383"); 244 } 245 246 import std.math.constants : E, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, 247 LN10, LN2, LOG2, LOG2E, LOG2T, LOG10E, SQRT2, SQRT1_2; 248 249 assert(printFloat(cast(float) E, f) == "0x1.5bf0a8p+1"); 250 assert(printFloat(cast(float) PI, f) == "0x1.921fb6p+1"); 251 assert(printFloat(cast(float) PI_2, f) == "0x1.921fb6p+0"); 252 assert(printFloat(cast(float) PI_4, f) == "0x1.921fb6p-1"); 253 assert(printFloat(cast(float) M_1_PI, f) == "0x1.45f306p-2"); 254 assert(printFloat(cast(float) M_2_PI, f) == "0x1.45f306p-1"); 255 assert(printFloat(cast(float) M_2_SQRTPI, f) == "0x1.20dd76p+0"); 256 assert(printFloat(cast(float) LN10, f) == "0x1.26bb1cp+1"); 257 assert(printFloat(cast(float) LN2, f) == "0x1.62e43p-1"); 258 assert(printFloat(cast(float) LOG2, f) == "0x1.344136p-2"); 259 assert(printFloat(cast(float) LOG2E, f) == "0x1.715476p+0"); 260 assert(printFloat(cast(float) LOG2T, f) == "0x1.a934fp+1"); 261 assert(printFloat(cast(float) LOG10E, f) == "0x1.bcb7b2p-2"); 262 assert(printFloat(cast(float) SQRT2, f) == "0x1.6a09e6p+0"); 263 assert(printFloat(cast(float) SQRT1_2, f) == "0x1.6a09e6p-1"); 264 265 assert(printFloat(cast(double) E, f) == "0x1.5bf0a8b145769p+1"); 266 assert(printFloat(cast(double) PI, f) == "0x1.921fb54442d18p+1"); 267 assert(printFloat(cast(double) PI_2, f) == "0x1.921fb54442d18p+0"); 268 assert(printFloat(cast(double) PI_4, f) == "0x1.921fb54442d18p-1"); 269 assert(printFloat(cast(double) M_1_PI, f) == "0x1.45f306dc9c883p-2"); 270 assert(printFloat(cast(double) M_2_PI, f) == "0x1.45f306dc9c883p-1"); 271 assert(printFloat(cast(double) M_2_SQRTPI, f) == "0x1.20dd750429b6dp+0"); 272 assert(printFloat(cast(double) LN10, f) == "0x1.26bb1bbb55516p+1"); 273 assert(printFloat(cast(double) LN2, f) == "0x1.62e42fefa39efp-1"); 274 assert(printFloat(cast(double) LOG2, f) == "0x1.34413509f79ffp-2"); 275 assert(printFloat(cast(double) LOG2E, f) == "0x1.71547652b82fep+0"); 276 assert(printFloat(cast(double) LOG2T, f) == "0x1.a934f0979a371p+1"); 277 assert(printFloat(cast(double) LOG10E, f) == "0x1.bcb7b1526e50ep-2"); 278 assert(printFloat(cast(double) SQRT2, f) == "0x1.6a09e667f3bcdp+0"); 279 assert(printFloat(cast(double) SQRT1_2, f) == "0x1.6a09e667f3bcdp-1"); 280 281 static if (real.mant_dig == 64) 282 { 283 assert(printFloat(E, f) == "0x1.5bf0a8b145769536p+1"); 284 assert(printFloat(PI, f) == "0x1.921fb54442d1846ap+1"); 285 assert(printFloat(PI_2, f) == "0x1.921fb54442d1846ap+0"); 286 assert(printFloat(PI_4, f) == "0x1.921fb54442d1846ap-1"); 287 assert(printFloat(M_1_PI, f) == "0x1.45f306dc9c882a54p-2"); 288 assert(printFloat(M_2_PI, f) == "0x1.45f306dc9c882a54p-1"); 289 assert(printFloat(M_2_SQRTPI, f) == "0x1.20dd750429b6d11ap+0"); 290 assert(printFloat(LN10, f) == "0x1.26bb1bbb5551582ep+1"); 291 assert(printFloat(LN2, f) == "0x1.62e42fefa39ef358p-1"); 292 assert(printFloat(LOG2, f) == "0x1.34413509f79fef32p-2"); 293 assert(printFloat(LOG2E, f) == "0x1.71547652b82fe178p+0"); 294 assert(printFloat(LOG2T, f) == "0x1.a934f0979a3715fcp+1"); 295 assert(printFloat(LOG10E, f) == "0x1.bcb7b1526e50e32ap-2"); 296 assert(printFloat(SQRT2, f) == "0x1.6a09e667f3bcc908p+0"); 297 assert(printFloat(SQRT1_2, f) == "0x1.6a09e667f3bcc908p-1"); 298 } 299} 300 301@safe unittest 302{ 303 auto f = FormatSpec!dchar(""); 304 f.spec = 'a'; 305 f.precision = 3; 306 307 assert(printFloat(1.0f, f) == "0x1.000p+0"); 308 assert(printFloat(3.3f, f) == "0x1.a66p+1"); 309 assert(printFloat(2.9f, f) == "0x1.733p+1"); 310 311 assert(printFloat(1.0, f) == "0x1.000p+0"); 312 assert(printFloat(3.3, f) == "0x1.a66p+1"); 313 assert(printFloat(2.9, f) == "0x1.733p+1"); 314 315 static if (real.mant_dig == 64) 316 { 317 assert(printFloat(1.0L, f) == "0x1.000p+0"); 318 assert(printFloat(3.3L, f) == "0x1.a66p+1"); 319 assert(printFloat(2.9L, f) == "0x1.733p+1"); 320 } 321} 322 323@safe unittest 324{ 325 auto f = FormatSpec!dchar(""); 326 f.spec = 'a'; 327 f.precision = 0; 328 329 assert(printFloat(1.0f, f) == "0x1p+0"); 330 assert(printFloat(3.3f, f) == "0x2p+1"); 331 assert(printFloat(2.9f, f) == "0x1p+1"); 332 333 assert(printFloat(1.0, f) == "0x1p+0"); 334 assert(printFloat(3.3, f) == "0x2p+1"); 335 assert(printFloat(2.9, f) == "0x1p+1"); 336 337 static if (real.mant_dig == 64) 338 { 339 assert(printFloat(1.0L, f) == "0x1p+0"); 340 assert(printFloat(3.3L, f) == "0x2p+1"); 341 assert(printFloat(2.9L, f) == "0x1p+1"); 342 } 343} 344 345@safe unittest 346{ 347 auto f = FormatSpec!dchar(""); 348 f.spec = 'a'; 349 f.precision = 0; 350 f.flHash = true; 351 352 assert(printFloat(1.0f, f) == "0x1.p+0"); 353 assert(printFloat(3.3f, f) == "0x2.p+1"); 354 assert(printFloat(2.9f, f) == "0x1.p+1"); 355 356 assert(printFloat(1.0, f) == "0x1.p+0"); 357 assert(printFloat(3.3, f) == "0x2.p+1"); 358 assert(printFloat(2.9, f) == "0x1.p+1"); 359 360 static if (real.mant_dig == 64) 361 { 362 assert(printFloat(1.0L, f) == "0x1.p+0"); 363 assert(printFloat(3.3L, f) == "0x2.p+1"); 364 assert(printFloat(2.9L, f) == "0x1.p+1"); 365 } 366} 367 368@safe unittest 369{ 370 auto f = FormatSpec!dchar(""); 371 f.spec = 'a'; 372 f.width = 22; 373 374 assert(printFloat(1.0f, f) == " 0x1p+0"); 375 assert(printFloat(3.3f, f) == " 0x1.a66666p+1"); 376 assert(printFloat(2.9f, f) == " 0x1.733334p+1"); 377 378 assert(printFloat(1.0, f) == " 0x1p+0"); 379 assert(printFloat(3.3, f) == " 0x1.a666666666666p+1"); 380 assert(printFloat(2.9, f) == " 0x1.7333333333333p+1"); 381 382 static if (real.mant_dig == 64) 383 { 384 f.width = 25; 385 assert(printFloat(1.0L, f) == " 0x1p+0"); 386 assert(printFloat(3.3L, f) == " 0x1.a666666666666666p+1"); 387 assert(printFloat(2.9L, f) == " 0x1.7333333333333334p+1"); 388 } 389} 390 391@safe unittest 392{ 393 auto f = FormatSpec!dchar(""); 394 f.spec = 'a'; 395 f.width = 22; 396 f.flDash = true; 397 398 assert(printFloat(1.0f, f) == "0x1p+0 "); 399 assert(printFloat(3.3f, f) == "0x1.a66666p+1 "); 400 assert(printFloat(2.9f, f) == "0x1.733334p+1 "); 401 402 assert(printFloat(1.0, f) == "0x1p+0 "); 403 assert(printFloat(3.3, f) == "0x1.a666666666666p+1 "); 404 assert(printFloat(2.9, f) == "0x1.7333333333333p+1 "); 405 406 static if (real.mant_dig == 64) 407 { 408 f.width = 25; 409 assert(printFloat(1.0L, f) == "0x1p+0 "); 410 assert(printFloat(3.3L, f) == "0x1.a666666666666666p+1 "); 411 assert(printFloat(2.9L, f) == "0x1.7333333333333334p+1 "); 412 } 413} 414 415@safe unittest 416{ 417 auto f = FormatSpec!dchar(""); 418 f.spec = 'a'; 419 f.width = 22; 420 f.flZero = true; 421 422 assert(printFloat(1.0f, f) == "0x00000000000000001p+0"); 423 assert(printFloat(3.3f, f) == "0x0000000001.a66666p+1"); 424 assert(printFloat(2.9f, f) == "0x0000000001.733334p+1"); 425 426 assert(printFloat(1.0, f) == "0x00000000000000001p+0"); 427 assert(printFloat(3.3, f) == "0x001.a666666666666p+1"); 428 assert(printFloat(2.9, f) == "0x001.7333333333333p+1"); 429 430 static if (real.mant_dig == 64) 431 { 432 f.width = 25; 433 assert(printFloat(1.0L, f) == "0x00000000000000000001p+0"); 434 assert(printFloat(3.3L, f) == "0x001.a666666666666666p+1"); 435 assert(printFloat(2.9L, f) == "0x001.7333333333333334p+1"); 436 } 437} 438 439@safe unittest 440{ 441 auto f = FormatSpec!dchar(""); 442 f.spec = 'a'; 443 f.width = 22; 444 f.flPlus = true; 445 446 assert(printFloat(1.0f, f) == " +0x1p+0"); 447 assert(printFloat(3.3f, f) == " +0x1.a66666p+1"); 448 assert(printFloat(2.9f, f) == " +0x1.733334p+1"); 449 450 assert(printFloat(1.0, f) == " +0x1p+0"); 451 assert(printFloat(3.3, f) == " +0x1.a666666666666p+1"); 452 assert(printFloat(2.9, f) == " +0x1.7333333333333p+1"); 453 454 static if (real.mant_dig == 64) 455 { 456 f.width = 25; 457 assert(printFloat(1.0L, f) == " +0x1p+0"); 458 assert(printFloat(3.3L, f) == " +0x1.a666666666666666p+1"); 459 assert(printFloat(2.9L, f) == " +0x1.7333333333333334p+1"); 460 } 461} 462 463@safe unittest 464{ 465 auto f = FormatSpec!dchar(""); 466 f.spec = 'a'; 467 f.width = 22; 468 f.flDash = true; 469 f.flSpace = true; 470 471 assert(printFloat(1.0f, f) == " 0x1p+0 "); 472 assert(printFloat(3.3f, f) == " 0x1.a66666p+1 "); 473 assert(printFloat(2.9f, f) == " 0x1.733334p+1 "); 474 475 assert(printFloat(1.0, f) == " 0x1p+0 "); 476 assert(printFloat(3.3, f) == " 0x1.a666666666666p+1 "); 477 assert(printFloat(2.9, f) == " 0x1.7333333333333p+1 "); 478 479 static if (real.mant_dig == 64) 480 { 481 f.width = 25; 482 assert(printFloat(1.0L, f) == " 0x1p+0 "); 483 assert(printFloat(3.3L, f) == " 0x1.a666666666666666p+1 "); 484 assert(printFloat(2.9L, f) == " 0x1.7333333333333334p+1 "); 485 } 486} 487 488@safe unittest 489{ 490 import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined 491 492 // std.math's FloatingPointControl isn't available on all target platforms 493 static if (is(FloatingPointControl)) 494 { 495 FloatingPointControl fpctrl; 496 497 auto f = FormatSpec!dchar(""); 498 f.spec = 'a'; 499 f.precision = 1; 500 501 fpctrl.rounding = FloatingPointControl.roundToNearest; 502 503 /* tiesAwayFromZero currently not supported 504 assert(printFloat(0x1.18p0, f) == "0x1.2p+0"); 505 assert(printFloat(0x1.28p0, f) == "0x1.3p+0"); 506 assert(printFloat(0x1.1ap0, f) == "0x1.2p+0"); 507 assert(printFloat(0x1.16p0, f) == "0x1.1p+0"); 508 assert(printFloat(0x1.10p0, f) == "0x1.1p+0"); 509 assert(printFloat(-0x1.18p0, f) == "-0x1.2p+0"); 510 assert(printFloat(-0x1.28p0, f) == "-0x1.3p+0"); 511 assert(printFloat(-0x1.1ap0, f) == "-0x1.2p+0"); 512 assert(printFloat(-0x1.16p0, f) == "-0x1.1p+0"); 513 assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0"); 514 */ 515 516 assert(printFloat(0x1.18p0, f) == "0x1.2p+0"); 517 assert(printFloat(0x1.28p0, f) == "0x1.2p+0"); 518 assert(printFloat(0x1.1ap0, f) == "0x1.2p+0"); 519 assert(printFloat(0x1.16p0, f) == "0x1.1p+0"); 520 assert(printFloat(0x1.10p0, f) == "0x1.1p+0"); 521 assert(printFloat(-0x1.18p0, f) == "-0x1.2p+0"); 522 assert(printFloat(-0x1.28p0, f) == "-0x1.2p+0"); 523 assert(printFloat(-0x1.1ap0, f) == "-0x1.2p+0"); 524 assert(printFloat(-0x1.16p0, f) == "-0x1.1p+0"); 525 assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0"); 526 527 fpctrl.rounding = FloatingPointControl.roundToZero; 528 529 assert(printFloat(0x1.18p0, f) == "0x1.1p+0"); 530 assert(printFloat(0x1.28p0, f) == "0x1.2p+0"); 531 assert(printFloat(0x1.1ap0, f) == "0x1.1p+0"); 532 assert(printFloat(0x1.16p0, f) == "0x1.1p+0"); 533 assert(printFloat(0x1.10p0, f) == "0x1.1p+0"); 534 assert(printFloat(-0x1.18p0, f) == "-0x1.1p+0"); 535 assert(printFloat(-0x1.28p0, f) == "-0x1.2p+0"); 536 assert(printFloat(-0x1.1ap0, f) == "-0x1.1p+0"); 537 assert(printFloat(-0x1.16p0, f) == "-0x1.1p+0"); 538 assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0"); 539 540 fpctrl.rounding = FloatingPointControl.roundUp; 541 542 assert(printFloat(0x1.18p0, f) == "0x1.2p+0"); 543 assert(printFloat(0x1.28p0, f) == "0x1.3p+0"); 544 assert(printFloat(0x1.1ap0, f) == "0x1.2p+0"); 545 assert(printFloat(0x1.16p0, f) == "0x1.2p+0"); 546 assert(printFloat(0x1.10p0, f) == "0x1.1p+0"); 547 assert(printFloat(-0x1.18p0, f) == "-0x1.1p+0"); 548 assert(printFloat(-0x1.28p0, f) == "-0x1.2p+0"); 549 assert(printFloat(-0x1.1ap0, f) == "-0x1.1p+0"); 550 assert(printFloat(-0x1.16p0, f) == "-0x1.1p+0"); 551 assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0"); 552 553 fpctrl.rounding = FloatingPointControl.roundDown; 554 555 assert(printFloat(0x1.18p0, f) == "0x1.1p+0"); 556 assert(printFloat(0x1.28p0, f) == "0x1.2p+0"); 557 assert(printFloat(0x1.1ap0, f) == "0x1.1p+0"); 558 assert(printFloat(0x1.16p0, f) == "0x1.1p+0"); 559 assert(printFloat(0x1.10p0, f) == "0x1.1p+0"); 560 assert(printFloat(-0x1.18p0, f) == "-0x1.2p+0"); 561 assert(printFloat(-0x1.28p0, f) == "-0x1.3p+0"); 562 assert(printFloat(-0x1.1ap0, f) == "-0x1.2p+0"); 563 assert(printFloat(-0x1.16p0, f) == "-0x1.2p+0"); 564 assert(printFloat(-0x1.10p0, f) == "-0x1.1p+0"); 565 } 566} 567 568// for 100% coverage 569@safe unittest 570{ 571 auto f = FormatSpec!dchar(""); 572 f.spec = 'a'; 573 f.precision = 3; 574 575 assert(printFloat(0x1.19f81p0, f) == "0x1.1a0p+0"); 576 assert(printFloat(0x1.19f01p0, f) == "0x1.19fp+0"); 577} 578 579@safe unittest 580{ 581 auto f = FormatSpec!dchar(""); 582 f.spec = 'A'; 583 f.precision = 3; 584 585 assert(printFloat(0x1.19f81p0, f) == "0X1.1A0P+0"); 586 assert(printFloat(0x1.19f01p0, f) == "0X1.19FP+0"); 587} 588 589private void printFloatE(bool g, Writer, T, Char)(auto ref Writer w, const(T) val, 590 FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper) 591if (is(T == float) || is(T == double) 592 || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64))) 593{ 594 import std.format.internal.write : writeAligned, PrecisionType, RoundingClass, round; 595 596 static if (!g) 597 { 598 if (f.precision == f.UNSPECIFIED) 599 f.precision = 6; 600 } 601 602 // special treatment for 0.0 603 if (mnt == 0) 604 { 605 static if (g) 606 writeAligned(w, sgn, "0", ".", "", f, PrecisionType.allDigits); 607 else 608 writeAligned(w, sgn, "0", ".", is_upper ? "E+00" : "e+00", f, PrecisionType.fractionalDigits); 609 return; 610 } 611 612 char[T.mant_dig + T.max_exp] dec_buf; 613 char[T.max_10_exp.stringof.length + 2] exp_buf; 614 615 int final_exp = 0; 616 617 RoundingClass rc; 618 619 // Depending on exp, we will use one of three algorithms: 620 // 621 // Algorithm A: For large exponents (exp >= T.mant_dig) 622 // Algorithm B: For small exponents (exp < T.mant_dig - 61) 623 // Algorithm C: For exponents close to 0. 624 // 625 // Algorithm A: 626 // The number to print looks like this: mantissa followed by several zeros. 627 // 628 // We know, that there is no fractional part, so we can just use integer division, 629 // consecutivly dividing by 10 and writing down the remainder from right to left. 630 // Unfortunately the integer is too large to fit in an ulong, so we use something 631 // like BigInt: An array of ulongs. We only use 60 bits of that ulongs, because 632 // this simplifies (and speeds up) the division to come. 633 // 634 // For the division we use integer division with reminder for each ulong and put 635 // the reminder of each step in the first 4 bits of ulong of the next step (think of 636 // long division for the rationale behind this). The final reminder is the next 637 // digit (from right to left). 638 // 639 // This results in the output we would have for the %f specifier. We now adjust this 640 // for %e: First we calculate the place, where the exponent should be printed, filling 641 // up with zeros if needed and second we move the leftmost digit one to the left 642 // and inserting a dot. 643 // 644 // After that we decide on the rounding type, using the digits right of the position, 645 // where the exponent will be printed (currently they are still there, but will be 646 // overwritten later). 647 // 648 // Algorithm B: 649 // The number to print looks like this: zero dot several zeros followed by the mantissa 650 // 651 // We know, that the number has no integer part. The algorithm consecutivly multiplies 652 // by 10. The integer part (rounded down) after the multiplication is the next digit 653 // (from left to right). This integer part is removed after each step. 654 // Again, the number is represented as an array of ulongs, with only 60 bits used of 655 // every ulong. 656 // 657 // For the multiplication we use normal integer multiplication, which can result in digits 658 // in the uppermost 4 bits. These 4 digits are the carry which is added to the result 659 // of the next multiplication and finally the last carry is the next digit. 660 // 661 // Other than for the %f specifier, this multiplication is splitted into two almost 662 // identical parts. The first part lasts as long as we find zeros. We need to do this 663 // to calculate the correct exponent. 664 // 665 // The second part will stop, when only zeros remain or when we've got enough digits 666 // for the requested precision. In the second case, we have to find out, which rounding 667 // we have. Aside from special cases we do this by calculating one more digit. 668 // 669 // Algorithm C: 670 // This time, we know, that the integral part and the fractional part each fit into a 671 // ulong. The mantissa might be partially in both parts or completely in the fractional 672 // part. 673 // 674 // We first calculate the integral part by consecutive division by 10. Depending on the 675 // precision this might result in more digits, than we need. In that case we calculate 676 // the position of the exponent and the rounding type. 677 // 678 // If there is no integral part, we need to find the first non zero digit. We do this by 679 // consecutive multiplication by 10, saving the first non zero digit followed by a dot. 680 // 681 // In either case, we continue filling up with the fractional part until we have enough 682 // digits. If still necessary, we decide the rounding type, mainly by looking at the 683 // next digit. 684 685 size_t right = 1; 686 size_t start = 1; 687 size_t left = 1; 688 689 static if (is(T == real) && real.mant_dig == 64) 690 { 691 enum small_bound = 0; 692 enum max_buf = 275; 693 } 694 else 695 { 696 enum small_bound = T.mant_dig - 61; 697 static if (is(T == float)) 698 enum max_buf = 4; 699 else 700 enum max_buf = 18; 701 } 702 703 ulong[max_buf] bigbuf; 704 if (exp >= T.mant_dig) 705 { 706 start = left = right = dec_buf.length; 707 708 // large number without fractional digits 709 // 710 // As this number does not fit in a ulong, we use an array of ulongs. We only use 60 of the 64 bits, 711 // because this makes it much more easy to implement the division by 10. 712 int count = exp / 60 + 1; 713 714 // only the first few ulongs contain the mantiassa. The rest are zeros. 715 int lower = 60 - (exp - T.mant_dig + 1) % 60; 716 717 static if (is(T == real) && real.mant_dig == 64) 718 { 719 // for x87 reals, the lowest ulong may contain more than 60 bits, 720 // because the mantissa is 63 (>60) bits long 721 // therefore we need one ulong less 722 if (lower <= 3) count--; 723 } 724 725 // saved in big endian format 726 ulong[] mybig = bigbuf[0 .. count]; 727 728 if (lower < T.mant_dig) 729 { 730 mybig[0] = mnt >> lower; 731 mybig[1] = (mnt & ((1L << lower) - 1)) << 60 - lower; 732 } 733 else 734 mybig[0] = (mnt & ((1L << lower) - 1)) << 60 - lower; 735 736 // Generation of digits by consecutive division with reminder by 10. 737 int msu = 0; // Most significant ulong; when it get's zero, we can ignore it further on 738 while (msu < count - 1 || mybig[$ - 1] != 0) 739 { 740 ulong mod = 0; 741 foreach (i;msu .. count) 742 { 743 mybig[i] |= mod << 60; 744 mod = mybig[i] % 10; 745 mybig[i] /= 10; 746 } 747 if (mybig[msu] == 0) 748 ++msu; 749 750 dec_buf[--left] = cast(byte) ('0' + mod); 751 ++final_exp; 752 } 753 --final_exp; 754 755 static if (g) 756 start = left + f.precision; 757 else 758 start = left + f.precision + 1; 759 760 // move leftmost digit one more left and add dot between 761 dec_buf[left - 1] = dec_buf[left]; 762 dec_buf[left] = '.'; 763 --left; 764 765 // rounding type 766 if (start >= right) 767 rc = RoundingClass.ZERO; 768 else if (dec_buf[start] != '0' && dec_buf[start] != '5') 769 rc = dec_buf[start] > '5' ? RoundingClass.UPPER : RoundingClass.LOWER; 770 else 771 { 772 rc = dec_buf[start] == '5' ? RoundingClass.FIVE : RoundingClass.ZERO; 773 foreach (i; start + 1 .. right) 774 if (dec_buf[i] > '0') 775 { 776 rc = rc == RoundingClass.FIVE ? RoundingClass.UPPER : RoundingClass.LOWER; 777 break; 778 } 779 } 780 781 if (start < right) right = start; 782 } 783 else if (exp < small_bound) 784 { 785 // small number without integer digits 786 // 787 // Again this number does not fit in a ulong and we use an array of ulongs. And again we 788 // only use 60 bits, because this simplifies the multiplication by 10. 789 int count = (T.mant_dig - exp - 2) / 60 + 1; 790 791 // saved in little endian format 792 ulong[] mybig = bigbuf[0 .. count]; 793 794 // only the last few ulongs contain the mantiassa. Because of little endian 795 // format these are the ulongs at index 0 and 1 (and 2 in case of x87 reals). 796 // The rest are zeros. 797 int upper = 60 - (-exp - 1) % 60; 798 799 static if (is(T == real) && real.mant_dig == 64) 800 { 801 if (upper < 4) 802 { 803 mybig[0] = (mnt & ((1L << (4 - upper)) - 1)) << 56 + upper; 804 mybig[1] = (mnt >> (4 - upper)) & ((1L << 60) - 1); 805 mybig[2] = mnt >> 64 - upper; 806 } 807 else 808 { 809 mybig[0] = (mnt & ((1L << (T.mant_dig - upper)) - 1)) << 60 - (T.mant_dig - upper); 810 mybig[1] = mnt >> (T.mant_dig - upper); 811 } 812 } 813 else 814 { 815 if (upper < T.mant_dig) 816 { 817 mybig[0] = (mnt & ((1L << (T.mant_dig - upper)) - 1)) << 60 - (T.mant_dig - upper); 818 mybig[1] = mnt >> (T.mant_dig - upper); 819 } 820 else 821 mybig[0] = mnt << (upper - T.mant_dig); 822 } 823 824 int lsu = 0; // Least significant ulong; when it get's zero, we can ignore it further on 825 826 // adding zeros, until we reach first nonzero 827 while (lsu < count - 1 || mybig[$ - 1]!=0) 828 { 829 ulong over = 0; 830 foreach (i; lsu .. count) 831 { 832 mybig[i] = mybig[i] * 10 + over; 833 over = mybig[i] >> 60; 834 mybig[i] &= (1L << 60) - 1; 835 } 836 if (mybig[lsu] == 0) 837 ++lsu; 838 --final_exp; 839 840 if (over != 0) 841 { 842 dec_buf[right++] = cast(byte) ('0' + over); 843 dec_buf[right++] = '.'; 844 break; 845 } 846 } 847 848 // adding more digits 849 static if (g) 850 start = right - 1; 851 else 852 start = right; 853 while ((lsu < count - 1 || mybig[$ - 1] != 0) && right - start < f.precision) 854 { 855 ulong over = 0; 856 foreach (i;lsu .. count) 857 { 858 mybig[i] = mybig[i] * 10 + over; 859 over = mybig[i] >> 60; 860 mybig[i] &= (1L << 60) - 1; 861 } 862 if (mybig[lsu] == 0) 863 ++lsu; 864 865 dec_buf[right++] = cast(byte) ('0' + over); 866 } 867 868 // rounding type 869 if (lsu >= count - 1 && mybig[count - 1] == 0) 870 rc = RoundingClass.ZERO; 871 else if (lsu == count - 1 && mybig[lsu] == 1L << 59) 872 rc = RoundingClass.FIVE; 873 else 874 { 875 ulong over = 0; 876 foreach (i;lsu .. count) 877 { 878 mybig[i] = mybig[i] * 10 + over; 879 over = mybig[i] >> 60; 880 mybig[i] &= (1L << 60) - 1; 881 } 882 rc = over >= 5 ? RoundingClass.UPPER : RoundingClass.LOWER; 883 } 884 } 885 else 886 { 887 // medium sized number, probably with integer and fractional digits 888 // this is fastest, because both parts fit into a ulong each 889 ulong int_part = mnt >> (T.mant_dig - 1 - exp); 890 ulong frac_part = mnt & ((1L << (T.mant_dig - 1 - exp)) - 1); 891 892 // for x87 reals the mantiassa might be up to 3 bits too long 893 // we need to save these bits as a tail and handle this separately 894 static if (is(T == real) && real.mant_dig == 64) 895 { 896 ulong tail = 0; 897 ulong tail_length = 0; 898 if (exp < 3) 899 { 900 tail = frac_part & ((1L << (3 - exp)) - 1); 901 tail_length = 3 - exp; 902 frac_part >>= 3 - exp; 903 exp = 3; 904 } 905 } 906 907 start = 0; 908 909 // could we already decide on the rounding mode in the integer part? 910 bool found = false; 911 912 if (int_part > 0) 913 { 914 import core.bitop : bsr; 915 left = right = int_part.bsr * 100 / 332 + 4; 916 917 // integer part, if there is something to print 918 while (int_part >= 10) 919 { 920 dec_buf[--left] = '0' + (int_part % 10); 921 int_part /= 10; 922 ++final_exp; 923 ++start; 924 } 925 926 dec_buf[--left] = '.'; 927 dec_buf[--left] = cast(byte) ('0' + int_part); 928 929 static if (g) 930 auto limit = f.precision + 1; 931 else 932 auto limit = f.precision + 2; 933 934 if (right - left > limit) 935 { 936 auto old_right = right; 937 right = left + limit; 938 939 if (dec_buf[right] == '5' || dec_buf[right] == '0') 940 { 941 rc = dec_buf[right] == '5' ? RoundingClass.FIVE : RoundingClass.ZERO; 942 if (frac_part != 0) 943 rc = rc == RoundingClass.FIVE ? RoundingClass.UPPER : RoundingClass.LOWER; 944 else 945 foreach (i;right + 1 .. old_right) 946 if (dec_buf[i] > '0') 947 { 948 rc = rc == RoundingClass.FIVE ? RoundingClass.UPPER : RoundingClass.LOWER; 949 break; 950 } 951 } 952 else 953 rc = dec_buf[right] > '5' ? RoundingClass.UPPER : RoundingClass.LOWER; 954 found = true; 955 } 956 } 957 else 958 { 959 // fractional part, skipping leading zeros 960 while (frac_part != 0) 961 { 962 --final_exp; 963 frac_part *= 10; 964 static if (is(T == real) && real.mant_dig == 64) 965 { 966 if (tail_length > 0) 967 { 968 // together this is *= 10; 969 tail *= 5; 970 tail_length--; 971 972 frac_part += tail >> tail_length; 973 if (tail_length > 0) 974 tail &= (1L << tail_length) - 1; 975 } 976 } 977 auto tmp = frac_part >> (T.mant_dig - 1 - exp); 978 frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1); 979 if (tmp > 0) 980 { 981 dec_buf[right++] = cast(byte) ('0' + tmp); 982 dec_buf[right++] = '.'; 983 break; 984 } 985 } 986 987 rc = RoundingClass.ZERO; 988 } 989 990 static if (g) 991 size_t limit = f.precision - 1; 992 else 993 size_t limit = f.precision; 994 995 // the fractional part after the zeros 996 while (frac_part != 0 && start < limit) 997 { 998 frac_part *= 10; 999 static if (is(T == real) && real.mant_dig == 64) 1000 { 1001 if (tail_length > 0) 1002 { 1003 // together this is *= 10; 1004 tail *= 5; 1005 tail_length--; 1006 1007 frac_part += tail >> tail_length; 1008 if (tail_length > 0) 1009 tail &= (1L << tail_length) - 1; 1010 } 1011 } 1012 dec_buf[right++] = cast(byte) ('0' + (frac_part >> (T.mant_dig - 1 - exp))); 1013 frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1); 1014 ++start; 1015 } 1016 1017 static if (g) 1018 limit = right - left - 1; 1019 else 1020 limit = start; 1021 1022 // rounding mode, if not allready known 1023 if (frac_part != 0 && !found) 1024 { 1025 frac_part *= 10; 1026 auto nextDigit = frac_part >> (T.mant_dig - 1 - exp); 1027 frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1); 1028 1029 if (nextDigit == 5 && frac_part == 0) 1030 rc = RoundingClass.FIVE; 1031 else if (nextDigit >= 5) 1032 rc = RoundingClass.UPPER; 1033 else 1034 rc = RoundingClass.LOWER; 1035 } 1036 } 1037 1038 if (round(dec_buf, left, right, rc, sgn == "-")) 1039 { 1040 left--; 1041 right--; 1042 dec_buf[left + 2] = dec_buf[left + 1]; 1043 dec_buf[left + 1] = '.'; 1044 final_exp++; 1045 } 1046 1047 // printing exponent 1048 auto neg = final_exp < 0; 1049 if (neg) final_exp = -final_exp; 1050 1051 size_t exp_pos = exp_buf.length; 1052 1053 do 1054 { 1055 exp_buf[--exp_pos] = '0' + final_exp%10; 1056 final_exp /= 10; 1057 } while (final_exp > 0); 1058 if (exp_buf.length - exp_pos == 1) 1059 exp_buf[--exp_pos] = '0'; 1060 exp_buf[--exp_pos] = neg ? '-' : '+'; 1061 exp_buf[--exp_pos] = is_upper ? 'E' : 'e'; 1062 1063 while (right > left + 1 && dec_buf[right - 1] == '0') right--; 1064 1065 if (right == left + 1) 1066 dec_buf[right++] = '.'; 1067 1068 static if (g) 1069 writeAligned(w, sgn, dec_buf[left .. left + 1], dec_buf[left + 1 .. right], 1070 exp_buf[exp_pos .. $], f, PrecisionType.allDigits); 1071 else 1072 writeAligned(w, sgn, dec_buf[left .. left + 1], dec_buf[left + 1 .. right], 1073 exp_buf[exp_pos .. $], f, PrecisionType.fractionalDigits); 1074} 1075 1076@safe unittest 1077{ 1078 auto f = FormatSpec!dchar(""); 1079 f.spec = 'e'; 1080 assert(printFloat(float.nan, f) == "nan"); 1081 assert(printFloat(-float.nan, f) == "-nan"); 1082 assert(printFloat(float.infinity, f) == "inf"); 1083 assert(printFloat(-float.infinity, f) == "-inf"); 1084 assert(printFloat(0.0f, f) == "0.000000e+00"); 1085 assert(printFloat(-0.0f, f) == "-0.000000e+00"); 1086 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 1087 assert(printFloat(cast(float) 1e-40, f) == "9.999946e-41"); 1088 assert(printFloat(cast(float) -1e-40, f) == "-9.999946e-41"); 1089 assert(printFloat(1e-30f, f) == "1.000000e-30"); 1090 assert(printFloat(-1e-30f, f) == "-1.000000e-30"); 1091 assert(printFloat(1e-10f, f) == "1.000000e-10"); 1092 assert(printFloat(-1e-10f, f) == "-1.000000e-10"); 1093 assert(printFloat(0.1f, f) == "1.000000e-01"); 1094 assert(printFloat(-0.1f, f) == "-1.000000e-01"); 1095 assert(printFloat(10.0f, f) == "1.000000e+01"); 1096 assert(printFloat(-10.0f, f) == "-1.000000e+01"); 1097 assert(printFloat(1e30f, f) == "1.000000e+30"); 1098 assert(printFloat(-1e30f, f) == "-1.000000e+30"); 1099 1100 import std.math.operations : nextUp, nextDown; 1101 assert(printFloat(nextUp(0.0f), f) == "1.401298e-45"); 1102 assert(printFloat(nextDown(-0.0f), f) == "-1.401298e-45"); 1103} 1104 1105@safe unittest 1106{ 1107 auto f = FormatSpec!dchar(""); 1108 f.spec = 'e'; 1109 f.width = 20; 1110 f.precision = 10; 1111 1112 assert(printFloat(float.nan, f) == " nan"); 1113 assert(printFloat(-float.nan, f) == " -nan"); 1114 assert(printFloat(float.infinity, f) == " inf"); 1115 assert(printFloat(-float.infinity, f) == " -inf"); 1116 assert(printFloat(0.0f, f) == " 0.0000000000e+00"); 1117 assert(printFloat(-0.0f, f) == " -0.0000000000e+00"); 1118 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 1119 assert(printFloat(cast(float) 1e-40, f) == " 9.9999461011e-41"); 1120 assert(printFloat(cast(float) -1e-40, f) == " -9.9999461011e-41"); 1121 assert(printFloat(1e-30f, f) == " 1.0000000032e-30"); 1122 assert(printFloat(-1e-30f, f) == " -1.0000000032e-30"); 1123 assert(printFloat(1e-10f, f) == " 1.0000000134e-10"); 1124 assert(printFloat(-1e-10f, f) == " -1.0000000134e-10"); 1125 assert(printFloat(0.1f, f) == " 1.0000000149e-01"); 1126 assert(printFloat(-0.1f, f) == " -1.0000000149e-01"); 1127 assert(printFloat(10.0f, f) == " 1.0000000000e+01"); 1128 assert(printFloat(-10.0f, f) == " -1.0000000000e+01"); 1129 assert(printFloat(1e30f, f) == " 1.0000000150e+30"); 1130 assert(printFloat(-1e30f, f) == " -1.0000000150e+30"); 1131 1132 import std.math.operations : nextUp, nextDown; 1133 assert(printFloat(nextUp(0.0f), f) == " 1.4012984643e-45"); 1134 assert(printFloat(nextDown(-0.0f), f) == " -1.4012984643e-45"); 1135} 1136 1137@safe unittest 1138{ 1139 auto f = FormatSpec!dchar(""); 1140 f.spec = 'e'; 1141 f.width = 20; 1142 f.precision = 10; 1143 f.flDash = true; 1144 1145 assert(printFloat(float.nan, f) == "nan "); 1146 assert(printFloat(-float.nan, f) == "-nan "); 1147 assert(printFloat(float.infinity, f) == "inf "); 1148 assert(printFloat(-float.infinity, f) == "-inf "); 1149 assert(printFloat(0.0f, f) == "0.0000000000e+00 "); 1150 assert(printFloat(-0.0f, f) == "-0.0000000000e+00 "); 1151 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 1152 assert(printFloat(cast(float) 1e-40, f) == "9.9999461011e-41 "); 1153 assert(printFloat(cast(float) -1e-40, f) == "-9.9999461011e-41 "); 1154 assert(printFloat(1e-30f, f) == "1.0000000032e-30 "); 1155 assert(printFloat(-1e-30f, f) == "-1.0000000032e-30 "); 1156 assert(printFloat(1e-10f, f) == "1.0000000134e-10 "); 1157 assert(printFloat(-1e-10f, f) == "-1.0000000134e-10 "); 1158 assert(printFloat(0.1f, f) == "1.0000000149e-01 "); 1159 assert(printFloat(-0.1f, f) == "-1.0000000149e-01 "); 1160 assert(printFloat(10.0f, f) == "1.0000000000e+01 "); 1161 assert(printFloat(-10.0f, f) == "-1.0000000000e+01 "); 1162 assert(printFloat(1e30f, f) == "1.0000000150e+30 "); 1163 assert(printFloat(-1e30f, f) == "-1.0000000150e+30 "); 1164 1165 import std.math.operations : nextUp, nextDown; 1166 assert(printFloat(nextUp(0.0f), f) == "1.4012984643e-45 "); 1167 assert(printFloat(nextDown(-0.0f), f) == "-1.4012984643e-45 "); 1168} 1169 1170@safe unittest 1171{ 1172 auto f = FormatSpec!dchar(""); 1173 f.spec = 'e'; 1174 f.width = 20; 1175 f.precision = 10; 1176 f.flZero = true; 1177 1178 assert(printFloat(float.nan, f) == " nan"); 1179 assert(printFloat(-float.nan, f) == " -nan"); 1180 assert(printFloat(float.infinity, f) == " inf"); 1181 assert(printFloat(-float.infinity, f) == " -inf"); 1182 assert(printFloat(0.0f, f) == "00000.0000000000e+00"); 1183 assert(printFloat(-0.0f, f) == "-0000.0000000000e+00"); 1184 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 1185 assert(printFloat(cast(float) 1e-40, f) == "00009.9999461011e-41"); 1186 assert(printFloat(cast(float) -1e-40, f) == "-0009.9999461011e-41"); 1187 assert(printFloat(1e-30f, f) == "00001.0000000032e-30"); 1188 assert(printFloat(-1e-30f, f) == "-0001.0000000032e-30"); 1189 assert(printFloat(1e-10f, f) == "00001.0000000134e-10"); 1190 assert(printFloat(-1e-10f, f) == "-0001.0000000134e-10"); 1191 assert(printFloat(0.1f, f) == "00001.0000000149e-01"); 1192 assert(printFloat(-0.1f, f) == "-0001.0000000149e-01"); 1193 assert(printFloat(10.0f, f) == "00001.0000000000e+01"); 1194 assert(printFloat(-10.0f, f) == "-0001.0000000000e+01"); 1195 assert(printFloat(1e30f, f) == "00001.0000000150e+30"); 1196 assert(printFloat(-1e30f, f) == "-0001.0000000150e+30"); 1197 1198 import std.math.operations : nextUp, nextDown; 1199 assert(printFloat(nextUp(0.0f), f) == "00001.4012984643e-45"); 1200 assert(printFloat(nextDown(-0.0f), f) == "-0001.4012984643e-45"); 1201} 1202 1203@safe unittest 1204{ 1205 import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined 1206 1207 // std.math's FloatingPointControl isn't available on all target platforms 1208 static if (is(FloatingPointControl)) 1209 { 1210 FloatingPointControl fpctrl; 1211 1212 auto f = FormatSpec!dchar(""); 1213 f.spec = 'e'; 1214 f.precision = 1; 1215 1216 fpctrl.rounding = FloatingPointControl.roundToNearest; 1217 1218 /* 1219 assert(printFloat(11.5f, f) == "1.2e+01"); 1220 assert(printFloat(12.5f, f) == "1.3e+01"); 1221 assert(printFloat(11.7f, f) == "1.2e+01"); 1222 assert(printFloat(11.3f, f) == "1.1e+01"); 1223 assert(printFloat(11.0f, f) == "1.1e+01"); 1224 assert(printFloat(-11.5f, f) == "-1.2e+01"); 1225 assert(printFloat(-12.5f, f) == "-1.3e+01"); 1226 assert(printFloat(-11.7f, f) == "-1.2e+01"); 1227 assert(printFloat(-11.3f, f) == "-1.1e+01"); 1228 assert(printFloat(-11.0f, f) == "-1.1e+01"); 1229 */ 1230 1231 assert(printFloat(11.5f, f) == "1.2e+01"); 1232 assert(printFloat(12.5f, f) == "1.2e+01"); 1233 assert(printFloat(11.7f, f) == "1.2e+01"); 1234 assert(printFloat(11.3f, f) == "1.1e+01"); 1235 assert(printFloat(11.0f, f) == "1.1e+01"); 1236 assert(printFloat(-11.5f, f) == "-1.2e+01"); 1237 assert(printFloat(-12.5f, f) == "-1.2e+01"); 1238 assert(printFloat(-11.7f, f) == "-1.2e+01"); 1239 assert(printFloat(-11.3f, f) == "-1.1e+01"); 1240 assert(printFloat(-11.0f, f) == "-1.1e+01"); 1241 1242 fpctrl.rounding = FloatingPointControl.roundToZero; 1243 1244 assert(printFloat(11.5f, f) == "1.1e+01"); 1245 assert(printFloat(12.5f, f) == "1.2e+01"); 1246 assert(printFloat(11.7f, f) == "1.1e+01"); 1247 assert(printFloat(11.3f, f) == "1.1e+01"); 1248 assert(printFloat(11.0f, f) == "1.1e+01"); 1249 assert(printFloat(-11.5f, f) == "-1.1e+01"); 1250 assert(printFloat(-12.5f, f) == "-1.2e+01"); 1251 assert(printFloat(-11.7f, f) == "-1.1e+01"); 1252 assert(printFloat(-11.3f, f) == "-1.1e+01"); 1253 assert(printFloat(-11.0f, f) == "-1.1e+01"); 1254 1255 fpctrl.rounding = FloatingPointControl.roundUp; 1256 1257 assert(printFloat(11.5f, f) == "1.2e+01"); 1258 assert(printFloat(12.5f, f) == "1.3e+01"); 1259 assert(printFloat(11.7f, f) == "1.2e+01"); 1260 assert(printFloat(11.3f, f) == "1.2e+01"); 1261 assert(printFloat(11.0f, f) == "1.1e+01"); 1262 assert(printFloat(-11.5f, f) == "-1.1e+01"); 1263 assert(printFloat(-12.5f, f) == "-1.2e+01"); 1264 assert(printFloat(-11.7f, f) == "-1.1e+01"); 1265 assert(printFloat(-11.3f, f) == "-1.1e+01"); 1266 assert(printFloat(-11.0f, f) == "-1.1e+01"); 1267 1268 fpctrl.rounding = FloatingPointControl.roundDown; 1269 1270 assert(printFloat(11.5f, f) == "1.1e+01"); 1271 assert(printFloat(12.5f, f) == "1.2e+01"); 1272 assert(printFloat(11.7f, f) == "1.1e+01"); 1273 assert(printFloat(11.3f, f) == "1.1e+01"); 1274 assert(printFloat(11.0f, f) == "1.1e+01"); 1275 assert(printFloat(-11.5f, f) == "-1.2e+01"); 1276 assert(printFloat(-12.5f, f) == "-1.3e+01"); 1277 assert(printFloat(-11.7f, f) == "-1.2e+01"); 1278 assert(printFloat(-11.3f, f) == "-1.2e+01"); 1279 assert(printFloat(-11.0f, f) == "-1.1e+01"); 1280 } 1281} 1282 1283@safe unittest 1284{ 1285 auto f = FormatSpec!dchar(""); 1286 f.spec = 'e'; 1287 assert(printFloat(double.nan, f) == "nan"); 1288 assert(printFloat(-double.nan, f) == "-nan"); 1289 assert(printFloat(double.infinity, f) == "inf"); 1290 assert(printFloat(-double.infinity, f) == "-inf"); 1291 assert(printFloat(0.0, f) == "0.000000e+00"); 1292 assert(printFloat(-0.0, f) == "-0.000000e+00"); 1293 // / 1000 needed due to https://issues.dlang.org/show_bug.cgi?id=20361 1294 assert(printFloat(1e-307 / 1000, f) == "1.000000e-310"); 1295 assert(printFloat(-1e-307 / 1000, f) == "-1.000000e-310"); 1296 assert(printFloat(1e-30, f) == "1.000000e-30"); 1297 assert(printFloat(-1e-30, f) == "-1.000000e-30"); 1298 assert(printFloat(1e-10, f) == "1.000000e-10"); 1299 assert(printFloat(-1e-10, f) == "-1.000000e-10"); 1300 assert(printFloat(0.1, f) == "1.000000e-01"); 1301 assert(printFloat(-0.1, f) == "-1.000000e-01"); 1302 assert(printFloat(10.0, f) == "1.000000e+01"); 1303 assert(printFloat(-10.0, f) == "-1.000000e+01"); 1304 assert(printFloat(1e300, f) == "1.000000e+300"); 1305 assert(printFloat(-1e300, f) == "-1.000000e+300"); 1306 1307 import std.math.operations : nextUp, nextDown; 1308 assert(printFloat(nextUp(0.0), f) == "4.940656e-324"); 1309 assert(printFloat(nextDown(-0.0), f) == "-4.940656e-324"); 1310} 1311 1312@safe unittest 1313{ 1314 static if (real.mant_dig > 64) 1315 { 1316 pragma(msg, "printFloat tests disabled because of unsupported `real` format"); 1317 } 1318 else 1319 { 1320 auto f = FormatSpec!dchar(""); 1321 f.spec = 'e'; 1322 assert(printFloat(real.nan, f) == "nan"); 1323 assert(printFloat(-real.nan, f) == "-nan"); 1324 assert(printFloat(real.infinity, f) == "inf"); 1325 assert(printFloat(-real.infinity, f) == "-inf"); 1326 } 1327} 1328 1329@safe unittest 1330{ 1331 auto f = FormatSpec!dchar(""); 1332 f.spec = 'e'; 1333 1334 import std.math.operations : nextUp; 1335 1336 double eps = nextUp(0.0); 1337 f.precision = 1000; 1338 assert(printFloat(eps, f) == 1339 "4.9406564584124654417656879286822137236505980261432476442558568250067550727020875186529983636163599" 1340 ~"23797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036" 1341 ~"88718636056998730723050006387409153564984387312473397273169615140031715385398074126238565591171026" 1342 ~"65855668676818703956031062493194527159149245532930545654440112748012970999954193198940908041656332" 1343 ~"45247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431" 1344 ~"93609238289345836806010601150616980975307834227731832924790498252473077637592724787465608477820373" 1345 ~"44696995336470179726777175851256605511991315048911014510378627381672509558373897335989936648099411" 1346 ~"64205702637090279242767544565229087538682506419718265533447265625000000000000000000000000000000000" 1347 ~"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 1348 ~"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 1349 ~"000000000000000000000e-324"); 1350 1351 f.precision = 50; 1352 assert(printFloat(double.max, f) == 1353 "1.79769313486231570814527423731704356798070567525845e+308"); 1354 assert(printFloat(double.epsilon, f) == 1355 "2.22044604925031308084726333618164062500000000000000e-16"); 1356 1357 f.precision = 10; 1358 assert(printFloat(1.0/3.0, f) == "3.3333333333e-01"); 1359 assert(printFloat(1.0/7.0, f) == "1.4285714286e-01"); 1360 assert(printFloat(1.0/9.0, f) == "1.1111111111e-01"); 1361} 1362 1363@safe unittest 1364{ 1365 auto f = FormatSpec!dchar(""); 1366 f.spec = 'e'; 1367 f.precision = 15; 1368 1369 import std.math.constants : E, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, 1370 LN10, LN2, LOG2, LOG2E, LOG2T, LOG10E, SQRT2, SQRT1_2; 1371 1372 assert(printFloat(cast(double) E, f) == "2.718281828459045e+00"); 1373 assert(printFloat(cast(double) PI, f) == "3.141592653589793e+00"); 1374 assert(printFloat(cast(double) PI_2, f) == "1.570796326794897e+00"); 1375 assert(printFloat(cast(double) PI_4, f) == "7.853981633974483e-01"); 1376 assert(printFloat(cast(double) M_1_PI, f) == "3.183098861837907e-01"); 1377 assert(printFloat(cast(double) M_2_PI, f) == "6.366197723675814e-01"); 1378 assert(printFloat(cast(double) M_2_SQRTPI, f) == "1.128379167095513e+00"); 1379 assert(printFloat(cast(double) LN10, f) == "2.302585092994046e+00"); 1380 assert(printFloat(cast(double) LN2, f) == "6.931471805599453e-01"); 1381 assert(printFloat(cast(double) LOG2, f) == "3.010299956639812e-01"); 1382 assert(printFloat(cast(double) LOG2E, f) == "1.442695040888963e+00"); 1383 assert(printFloat(cast(double) LOG2T, f) == "3.321928094887362e+00"); 1384 assert(printFloat(cast(double) LOG10E, f) == "4.342944819032518e-01"); 1385 assert(printFloat(cast(double) SQRT2, f) == "1.414213562373095e+00"); 1386 assert(printFloat(cast(double) SQRT1_2, f) == "7.071067811865476e-01"); 1387} 1388 1389// for 100% coverage 1390@safe unittest 1391{ 1392 import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined 1393 1394 auto f = FormatSpec!dchar(""); 1395 f.spec = 'E'; 1396 f.precision = 80; 1397 assert(printFloat(5.62776e+12f, f) == 1398 "5.62775982080000000000000000000000000000000000000000000000000000000000000000000000E+12"); 1399 1400 f.precision = 49; 1401 assert(printFloat(2.5997869e-12f, f) == 1402 "2.5997869221999758693186777236405760049819946289062E-12"); 1403 1404 f.precision = 6; 1405 assert(printFloat(-1.1418613e+07f, f) == "-1.141861E+07"); 1406 assert(printFloat(-1.368281e+07f, f) == "-1.368281E+07"); 1407 1408 f.precision = 1; 1409 assert(printFloat(-245.666f, f) == "-2.5E+02"); 1410 1411 static if (is(FloatingPointControl)) 1412 { 1413 FloatingPointControl fpctrl; 1414 1415 fpctrl.rounding = FloatingPointControl.roundUp; 1416 1417 f.precision = 0; 1418 assert(printFloat(709422.0f, f) == "8E+05"); 1419 } 1420} 1421 1422@safe unittest 1423{ 1424 static if (real.mant_dig > 64) 1425 { 1426 pragma(msg, "printFloat tests disabled because of unsupported `real` format"); 1427 } 1428 else 1429 { 1430 auto f = FormatSpec!dchar(""); 1431 f.spec = 'e'; 1432 assert(printFloat(real.nan, f) == "nan"); 1433 assert(printFloat(-real.nan, f) == "-nan"); 1434 assert(printFloat(real.infinity, f) == "inf"); 1435 assert(printFloat(-real.infinity, f) == "-inf"); 1436 assert(printFloat(0.0L, f) == "0.000000e+00"); 1437 assert(printFloat(-0.0L, f) == "-0.000000e+00"); 1438 } 1439 1440 static if (real.mant_dig == 64) 1441 { 1442 assert(printFloat(1e-4940L, f) == "1.000000e-4940"); 1443 assert(printFloat(-1e-4940L, f) == "-1.000000e-4940"); 1444 assert(printFloat(1e-30L, f) == "1.000000e-30"); 1445 assert(printFloat(-1e-30L, f) == "-1.000000e-30"); 1446 assert(printFloat(1e-10L, f) == "1.000000e-10"); 1447 assert(printFloat(-1e-10L, f) == "-1.000000e-10"); 1448 assert(printFloat(0.1L, f) == "1.000000e-01"); 1449 assert(printFloat(-0.1L, f) == "-1.000000e-01"); 1450 assert(printFloat(10.0L, f) == "1.000000e+01"); 1451 assert(printFloat(-10.0L, f) == "-1.000000e+01"); 1452 version (Windows) {} // issue 20972 1453 else 1454 { 1455 assert(printFloat(1e4000L, f) == "1.000000e+4000"); 1456 assert(printFloat(-1e4000L, f) == "-1.000000e+4000"); 1457 } 1458 1459 import std.math.operations : nextUp, nextDown; 1460 assert(printFloat(nextUp(0.0L), f) == "3.645200e-4951"); 1461 assert(printFloat(nextDown(-0.0L), f) == "-3.645200e-4951"); 1462 } 1463} 1464 1465@safe unittest 1466{ 1467 import std.exception : assertCTFEable; 1468 import std.math.exponential : log2; 1469 import std.math.operations : nextDown; 1470 1471 assertCTFEable!( 1472 { 1473 // log2 is broken for x87-reals on some computers in CTFE 1474 // the following tests excludes these computers from the tests 1475 // (issue 21757) 1476 enum test = cast(int) log2(3.05e2312L); 1477 static if (real.mant_dig == 64 && test == 7681) 1478 { 1479 auto f = FormatSpec!dchar(""); 1480 f.spec = 'e'; 1481 assert(printFloat(real.infinity, f) == "inf"); 1482 assert(printFloat(10.0L, f) == "1.000000e+01"); 1483 assert(printFloat(2.6080L, f) == "2.608000e+00"); 1484 assert(printFloat(3.05e2312L, f) == "3.050000e+2312"); 1485 1486 f.precision = 60; 1487 assert(printFloat(2.65e-54L, f) == 1488 "2.650000000000000000059009987400547013941028940935296547599415e-54"); 1489 1490 /* 1491 commented out, because CTFE is currently too slow for 5000 digits with extreme values 1492 1493 f.precision = 5000; 1494 auto result2 = printFloat(1.2119e-4822L, f); 1495 assert(result2.length == 5008); 1496 assert(result2[$ - 20 .. $] == "60729486595339e-4822"); 1497 auto result3 = printFloat(real.min_normal, f); 1498 assert(result3.length == 5008); 1499 assert(result3[$ - 20 .. $] == "20781410082267e-4932"); 1500 auto result4 = printFloat(real.min_normal.nextDown, f); 1501 assert(result4.length == 5008); 1502 assert(result4[$ - 20 .. $] == "81413263331006e-4932"); 1503 */ 1504 } 1505 }); 1506} 1507 1508private void printFloatF(bool g, Writer, T, Char)(auto ref Writer w, const(T) val, 1509 FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper) 1510if (is(T == float) || is(T == double) 1511 || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64))) 1512{ 1513 import std.format.internal.write : writeAligned, PrecisionType, RoundingClass, round; 1514 1515 static if (!g) 1516 { 1517 if (f.precision == f.UNSPECIFIED) 1518 f.precision = 6; 1519 } 1520 1521 // special treatment for 0.0 1522 if (exp == 0 && mnt == 0) 1523 { 1524 writeAligned(w, sgn, "0", ".", "", f, PrecisionType.fractionalDigits); 1525 return; 1526 } 1527 1528 char[T.max_exp + T.mant_dig + 1] dec_buf; 1529 1530 RoundingClass rc; 1531 1532 // Depending on exp, we will use one of three algorithms: 1533 // 1534 // Algorithm A: For large exponents (exp >= T.mant_dig) 1535 // Algorithm B: For small exponents (exp < T.mant_dig - 61) 1536 // Algorithm C: For exponents close to 0. 1537 // 1538 // Algorithm A: 1539 // The number to print looks like this: mantissa followed by several zeros. 1540 // 1541 // We know, that there is no fractional part, so we can just use integer division, 1542 // consecutivly dividing by 10 and writing down the remainder from right to left. 1543 // Unfortunately the integer is too large to fit in an ulong, so we use something 1544 // like BigInt: An array of ulongs. We only use 60 bits of that ulongs, because 1545 // this simplifies (and speeds up) the division to come. 1546 // 1547 // For the division we use integer division with reminder for each ulong and put 1548 // the reminder of each step in the first 4 bits of ulong of the next step (think of 1549 // long division for the rationale behind this). The final reminder is the next 1550 // digit (from right to left). 1551 // 1552 // Algorithm B: 1553 // The number to print looks like this: zero dot several zeros followed by the mantissa 1554 // 1555 // We know, that the number has no integer part. The algorithm consecutivly multiplies 1556 // by 10. The integer part (rounded down) after the multiplication is the next digit 1557 // (from left to right). This integer part is removed after each step. 1558 // Again, the number is represented as an array of ulongs, with only 60 bits used of 1559 // every ulong. 1560 // 1561 // For the multiplication we use normal integer multiplication, which can result in digits 1562 // in the uppermost 4 bits. These 4 digits are the carry which is added to the result 1563 // of the next multiplication and finally the last carry is the next digit. 1564 // 1565 // The calculation will stop, when only zeros remain or when we've got enough digits 1566 // for the requested precision. In the second case, we have to find out, which rounding 1567 // we have. Aside from special cases we do this by calculating one more digit. 1568 // 1569 // Algorithm C: 1570 // This time, we know, that the integral part and the fractional part each fit into a 1571 // ulong. The mantissa might be partially in both parts or completely in the fractional 1572 // part. 1573 // 1574 // We first calculate the integral part by consecutive division by 10. Then we calculate 1575 // the fractional part by consecutive multiplication by 10. Again only until we have enough 1576 // digits. Finally, we decide the rounding type, mainly by looking at the next digit. 1577 1578 static if (is(T == real) && real.mant_dig == 64) 1579 { 1580 enum small_bound = 0; 1581 enum max_buf = 275; 1582 } 1583 else 1584 { 1585 enum small_bound = T.mant_dig - 61; 1586 static if (is(T == float)) 1587 enum max_buf = 4; 1588 else 1589 enum max_buf = 18; 1590 } 1591 1592 size_t start = 2; 1593 size_t left = 2; 1594 size_t right = 2; 1595 1596 ulong[max_buf] bigbuf; 1597 if (exp >= T.mant_dig) 1598 { 1599 left = start = dec_buf.length - 1; 1600 right = dec_buf.length; 1601 dec_buf[start] = '.'; 1602 1603 // large number without fractional digits 1604 // 1605 // As this number does not fit in a ulong, we use an array of ulongs. We only use 60 of the 64 bits, 1606 // because this makes it much more easy to implement the division by 10. 1607 int count = exp / 60 + 1; 1608 1609 // only the first few ulongs contain the mantiassa. The rest are zeros. 1610 int lower = 60 - (exp - T.mant_dig + 1) % 60; 1611 1612 static if (is(T == real) && real.mant_dig == 64) 1613 { 1614 // for x87 reals, the lowest ulong may contain more than 60 bits, 1615 // because the mantissa is 63 (>60) bits long 1616 // therefore we need one ulong less 1617 if (lower <= 3) count--; 1618 } 1619 1620 // saved in big endian format 1621 ulong[] mybig = bigbuf[0 .. count]; 1622 1623 if (lower < T.mant_dig) 1624 { 1625 mybig[0] = mnt >> lower; 1626 mybig[1] = (mnt & ((1L << lower) - 1)) << 60 - lower; 1627 } 1628 else 1629 mybig[0] = (mnt & ((1L << lower) - 1)) << 60 - lower; 1630 1631 // Generation of digits by consecutive division with reminder by 10. 1632 int msu = 0; // Most significant ulong; when it get's zero, we can ignore it furtheron 1633 while (msu < count - 1 || mybig[$ - 1] != 0) 1634 { 1635 ulong mod = 0; 1636 foreach (i;msu .. count) 1637 { 1638 mybig[i] |= mod << 60; 1639 mod = mybig[i] % 10; 1640 mybig[i] /= 10; 1641 } 1642 if (mybig[msu] == 0) 1643 ++msu; 1644 1645 dec_buf[--left] = cast(byte) ('0' + mod); 1646 } 1647 1648 rc = RoundingClass.ZERO; 1649 } 1650 else if (exp < small_bound) 1651 { 1652 // small number without integer digits 1653 // 1654 // Again this number does not fit in a ulong and we use an array of ulongs. And again we 1655 // only use 60 bits, because this simplifies the multiplication by 10. 1656 int count = (T.mant_dig - exp - 2) / 60 + 1; 1657 1658 // saved in little endian format 1659 ulong[] mybig = bigbuf[0 .. count]; 1660 1661 // only the last few ulongs contain the mantiassa. Because of little endian 1662 // format these are the ulongs at index 0 and 1 (and 2 in case of x87 reals). 1663 // The rest are zeros. 1664 int upper = 60 - (-exp - 1) % 60; 1665 1666 static if (is(T == real) && real.mant_dig == 64) 1667 { 1668 if (upper < 4) 1669 { 1670 mybig[0] = (mnt & ((1L << (4 - upper)) - 1)) << 56 + upper; 1671 mybig[1] = (mnt >> (4 - upper)) & ((1L << 60) - 1); 1672 mybig[2] = mnt >> 64 - upper; 1673 } 1674 else 1675 { 1676 mybig[0] = (mnt & ((1L << (T.mant_dig - upper)) - 1)) << 60 - (T.mant_dig - upper); 1677 mybig[1] = mnt >> (T.mant_dig - upper); 1678 } 1679 } 1680 else 1681 { 1682 if (upper < T.mant_dig) 1683 { 1684 mybig[0] = (mnt & ((1L << (T.mant_dig - upper)) - 1)) << 60 - (T.mant_dig - upper); 1685 mybig[1] = mnt >> (T.mant_dig - upper); 1686 } 1687 else 1688 mybig[0] = mnt << (upper - T.mant_dig); 1689 } 1690 1691 dec_buf[--left] = '0'; // 0 left of the dot 1692 dec_buf[right++] = '.'; 1693 1694 static if (g) 1695 { 1696 // precision starts at first non zero, so we move start 1697 // to the right, until we found first non zero, thus avoiding 1698 // a premature break of the loop 1699 bool found = false; 1700 start = left + 1; 1701 } 1702 1703 // Generation of digits by consecutive multiplication by 10. 1704 int lsu = 0; // Least significant ulong; when it get's zero, we can ignore it furtheron 1705 while ((lsu < count - 1 || mybig[$ - 1] != 0) && right - start - 1 < f.precision) 1706 { 1707 ulong over = 0; 1708 foreach (i;lsu .. count) 1709 { 1710 mybig[i] = mybig[i] * 10 + over; 1711 over = mybig[i] >> 60; 1712 mybig[i] &= (1L << 60) - 1; 1713 } 1714 if (mybig[lsu] == 0) 1715 ++lsu; 1716 1717 dec_buf[right++] = cast(byte) ('0' + over); 1718 1719 static if (g) 1720 { 1721 if (dec_buf[right - 1] != '0') 1722 found = true; 1723 else if (!found) 1724 start++; 1725 } 1726 } 1727 1728 static if (g) start = 2; 1729 1730 if (lsu >= count - 1 && mybig[count - 1] == 0) 1731 rc = RoundingClass.ZERO; 1732 else if (lsu == count - 1 && mybig[lsu] == 1L << 59) 1733 rc = RoundingClass.FIVE; 1734 else 1735 { 1736 ulong over = 0; 1737 foreach (i;lsu .. count) 1738 { 1739 mybig[i] = mybig[i] * 10 + over; 1740 over = mybig[i] >> 60; 1741 mybig[i] &= (1L << 60) - 1; 1742 } 1743 rc = over >= 5 ? RoundingClass.UPPER : RoundingClass.LOWER; 1744 } 1745 } 1746 else 1747 { 1748 // medium sized number, probably with integer and fractional digits 1749 // this is fastest, because both parts fit into a ulong each 1750 ulong int_part = mnt >> (T.mant_dig - 1 - exp); 1751 ulong frac_part = mnt & ((1L << (T.mant_dig - 1 - exp)) - 1); 1752 1753 // for x87 reals the mantiassa might be up to 3 bits too long 1754 // we need to save these bits as a tail and handle this separately 1755 static if (is(T == real) && real.mant_dig == 64) 1756 { 1757 ulong tail = 0; 1758 ulong tail_length = 0; 1759 if (exp < 3) 1760 { 1761 tail = frac_part & ((1L << (3 - exp)) - 1); 1762 tail_length = 3 - exp; 1763 frac_part >>= 3 - exp; 1764 exp = 3; 1765 } 1766 } 1767 1768 static if (g) auto found = int_part > 0; // searching first non zero 1769 1770 // creating int part 1771 if (int_part == 0) 1772 dec_buf[--left] = '0'; 1773 else 1774 { 1775 import core.bitop : bsr; 1776 left = right = start = int_part.bsr * 100 / 332 + 4; 1777 1778 while (int_part > 0) 1779 { 1780 dec_buf[--left] = '0' + (int_part % 10); 1781 int_part /= 10; 1782 } 1783 } 1784 1785 static if (g) size_t save_start = right; 1786 1787 dec_buf[right++] = '.'; 1788 1789 // creating frac part 1790 static if (g) start = left + (found ? 0 : 1); 1791 while (frac_part != 0 && right - start - 1 < f.precision) 1792 { 1793 frac_part *= 10; 1794 static if (is(T == real) && real.mant_dig == 64) 1795 { 1796 if (tail_length > 0) 1797 { 1798 // together this is *= 10; 1799 tail *= 5; 1800 tail_length--; 1801 1802 frac_part += tail >> tail_length; 1803 if (tail_length > 0) 1804 tail &= (1L << tail_length) - 1; 1805 } 1806 } 1807 dec_buf[right++] = cast(byte)('0' + (frac_part >> (T.mant_dig - 1 - exp))); 1808 1809 static if (g) 1810 { 1811 if (dec_buf[right - 1] != '0') 1812 found = true; 1813 else if (!found) 1814 start++; 1815 } 1816 1817 frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1); 1818 } 1819 1820 static if (g) start = save_start; 1821 1822 if (frac_part == 0) 1823 rc = RoundingClass.ZERO; 1824 else 1825 { 1826 frac_part *= 10; 1827 auto nextDigit = frac_part >> (T.mant_dig - 1 - exp); 1828 frac_part &= ((1L << (T.mant_dig - 1 - exp)) - 1); 1829 1830 if (nextDigit == 5 && frac_part == 0) 1831 rc = RoundingClass.FIVE; 1832 else if (nextDigit >= 5) 1833 rc = RoundingClass.UPPER; 1834 else 1835 rc = RoundingClass.LOWER; 1836 } 1837 } 1838 1839 if (round(dec_buf, left, right, rc, sgn == "-")) left--; 1840 1841 while (right > start + 1 && dec_buf[right - 1] == '0') right--; 1842 1843 static if (g) 1844 writeAligned(w, sgn, dec_buf[left .. start], dec_buf[start .. right], "", f, PrecisionType.allDigits); 1845 else 1846 writeAligned(w, sgn, dec_buf[left .. start], dec_buf[start .. right], "", f, PrecisionType.fractionalDigits); 1847} 1848 1849@safe unittest 1850{ 1851 auto f = FormatSpec!dchar(""); 1852 f.spec = 'f'; 1853 assert(printFloat(float.nan, f) == "nan"); 1854 assert(printFloat(-float.nan, f) == "-nan"); 1855 assert(printFloat(float.infinity, f) == "inf"); 1856 assert(printFloat(-float.infinity, f) == "-inf"); 1857 assert(printFloat(0.0f, f) == "0.000000"); 1858 assert(printFloat(-0.0f, f) == "-0.000000"); 1859 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 1860 assert(printFloat(cast(float) 1e-40, f) == "0.000000"); 1861 assert(printFloat(cast(float) -1e-40, f) == "-0.000000"); 1862 assert(printFloat(1e-30f, f) == "0.000000"); 1863 assert(printFloat(-1e-30f, f) == "-0.000000"); 1864 assert(printFloat(1e-10f, f) == "0.000000"); 1865 assert(printFloat(-1e-10f, f) == "-0.000000"); 1866 assert(printFloat(0.1f, f) == "0.100000"); 1867 assert(printFloat(-0.1f, f) == "-0.100000"); 1868 assert(printFloat(10.0f, f) == "10.000000"); 1869 assert(printFloat(-10.0f, f) == "-10.000000"); 1870 assert(printFloat(1e30f, f) == "1000000015047466219876688855040.000000"); 1871 assert(printFloat(-1e30f, f) == "-1000000015047466219876688855040.000000"); 1872 1873 import std.math.operations : nextUp, nextDown; 1874 assert(printFloat(nextUp(0.0f), f) == "0.000000"); 1875 assert(printFloat(nextDown(-0.0f), f) == "-0.000000"); 1876} 1877 1878@safe unittest 1879{ 1880 auto f = FormatSpec!dchar(""); 1881 f.spec = 'f'; 1882 f.width = 20; 1883 f.precision = 10; 1884 1885 assert(printFloat(float.nan, f) == " nan"); 1886 assert(printFloat(-float.nan, f) == " -nan"); 1887 assert(printFloat(float.infinity, f) == " inf"); 1888 assert(printFloat(-float.infinity, f) == " -inf"); 1889 assert(printFloat(0.0f, f) == " 0.0000000000"); 1890 assert(printFloat(-0.0f, f) == " -0.0000000000"); 1891 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 1892 assert(printFloat(cast(float) 1e-40, f) == " 0.0000000000"); 1893 assert(printFloat(cast(float) -1e-40, f) == " -0.0000000000"); 1894 assert(printFloat(1e-30f, f) == " 0.0000000000"); 1895 assert(printFloat(-1e-30f, f) == " -0.0000000000"); 1896 assert(printFloat(1e-10f, f) == " 0.0000000001"); 1897 assert(printFloat(-1e-10f, f) == " -0.0000000001"); 1898 assert(printFloat(0.1f, f) == " 0.1000000015"); 1899 assert(printFloat(-0.1f, f) == " -0.1000000015"); 1900 assert(printFloat(10.0f, f) == " 10.0000000000"); 1901 assert(printFloat(-10.0f, f) == " -10.0000000000"); 1902 assert(printFloat(1e30f, f) == "1000000015047466219876688855040.0000000000"); 1903 assert(printFloat(-1e30f, f) == "-1000000015047466219876688855040.0000000000"); 1904 1905 import std.math.operations : nextUp, nextDown; 1906 assert(printFloat(nextUp(0.0f), f) == " 0.0000000000"); 1907 assert(printFloat(nextDown(-0.0f), f) == " -0.0000000000"); 1908} 1909 1910@safe unittest 1911{ 1912 auto f = FormatSpec!dchar(""); 1913 f.spec = 'f'; 1914 f.width = 20; 1915 f.precision = 10; 1916 f.flDash = true; 1917 1918 assert(printFloat(float.nan, f) == "nan "); 1919 assert(printFloat(-float.nan, f) == "-nan "); 1920 assert(printFloat(float.infinity, f) == "inf "); 1921 assert(printFloat(-float.infinity, f) == "-inf "); 1922 assert(printFloat(0.0f, f) == "0.0000000000 "); 1923 assert(printFloat(-0.0f, f) == "-0.0000000000 "); 1924 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 1925 assert(printFloat(cast(float) 1e-40, f) == "0.0000000000 "); 1926 assert(printFloat(cast(float) -1e-40, f) == "-0.0000000000 "); 1927 assert(printFloat(1e-30f, f) == "0.0000000000 "); 1928 assert(printFloat(-1e-30f, f) == "-0.0000000000 "); 1929 assert(printFloat(1e-10f, f) == "0.0000000001 "); 1930 assert(printFloat(-1e-10f, f) == "-0.0000000001 "); 1931 assert(printFloat(0.1f, f) == "0.1000000015 "); 1932 assert(printFloat(-0.1f, f) == "-0.1000000015 "); 1933 assert(printFloat(10.0f, f) == "10.0000000000 "); 1934 assert(printFloat(-10.0f, f) == "-10.0000000000 "); 1935 assert(printFloat(1e30f, f) == "1000000015047466219876688855040.0000000000"); 1936 assert(printFloat(-1e30f, f) == "-1000000015047466219876688855040.0000000000"); 1937 1938 import std.math.operations : nextUp, nextDown; 1939 assert(printFloat(nextUp(0.0f), f) == "0.0000000000 "); 1940 assert(printFloat(nextDown(-0.0f), f) == "-0.0000000000 "); 1941} 1942 1943@safe unittest 1944{ 1945 auto f = FormatSpec!dchar(""); 1946 f.spec = 'f'; 1947 f.width = 20; 1948 f.precision = 10; 1949 f.flZero = true; 1950 1951 assert(printFloat(float.nan, f) == " nan"); 1952 assert(printFloat(-float.nan, f) == " -nan"); 1953 assert(printFloat(float.infinity, f) == " inf"); 1954 assert(printFloat(-float.infinity, f) == " -inf"); 1955 assert(printFloat(0.0f, f) == "000000000.0000000000"); 1956 assert(printFloat(-0.0f, f) == "-00000000.0000000000"); 1957 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 1958 assert(printFloat(cast(float) 1e-40, f) == "000000000.0000000000"); 1959 assert(printFloat(cast(float) -1e-40, f) == "-00000000.0000000000"); 1960 assert(printFloat(1e-30f, f) == "000000000.0000000000"); 1961 assert(printFloat(-1e-30f, f) == "-00000000.0000000000"); 1962 assert(printFloat(1e-10f, f) == "000000000.0000000001"); 1963 assert(printFloat(-1e-10f, f) == "-00000000.0000000001"); 1964 assert(printFloat(0.1f, f) == "000000000.1000000015"); 1965 assert(printFloat(-0.1f, f) == "-00000000.1000000015"); 1966 assert(printFloat(10.0f, f) == "000000010.0000000000"); 1967 assert(printFloat(-10.0f, f) == "-00000010.0000000000"); 1968 assert(printFloat(1e30f, f) == "1000000015047466219876688855040.0000000000"); 1969 assert(printFloat(-1e30f, f) == "-1000000015047466219876688855040.0000000000"); 1970 1971 import std.math.operations : nextUp, nextDown; 1972 assert(printFloat(nextUp(0.0f), f) == "000000000.0000000000"); 1973 assert(printFloat(nextDown(-0.0f), f) == "-00000000.0000000000"); 1974} 1975 1976@safe unittest 1977{ 1978 import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined 1979 1980 // std.math's FloatingPointControl isn't available on all target platforms 1981 static if (is(FloatingPointControl)) 1982 { 1983 FloatingPointControl fpctrl; 1984 1985 auto f = FormatSpec!dchar(""); 1986 f.spec = 'f'; 1987 f.precision = 0; 1988 1989 fpctrl.rounding = FloatingPointControl.roundToNearest; 1990 1991 /* 1992 assert(printFloat(11.5f, f) == "12"); 1993 assert(printFloat(12.5f, f) == "13"); 1994 assert(printFloat(11.7f, f) == "12"); 1995 assert(printFloat(11.3f, f) == "11"); 1996 assert(printFloat(11.0f, f) == "11"); 1997 assert(printFloat(-11.5f, f) == "-12"); 1998 assert(printFloat(-12.5f, f) == "-13"); 1999 assert(printFloat(-11.7f, f) == "-12"); 2000 assert(printFloat(-11.3f, f) == "-11"); 2001 assert(printFloat(-11.0f, f) == "-11"); 2002 */ 2003 2004 assert(printFloat(11.5f, f) == "12"); 2005 assert(printFloat(12.5f, f) == "12"); 2006 assert(printFloat(11.7f, f) == "12"); 2007 assert(printFloat(11.3f, f) == "11"); 2008 assert(printFloat(11.0f, f) == "11"); 2009 assert(printFloat(-11.5f, f) == "-12"); 2010 assert(printFloat(-12.5f, f) == "-12"); 2011 assert(printFloat(-11.7f, f) == "-12"); 2012 assert(printFloat(-11.3f, f) == "-11"); 2013 assert(printFloat(-11.0f, f) == "-11"); 2014 2015 fpctrl.rounding = FloatingPointControl.roundToZero; 2016 2017 assert(printFloat(11.5f, f) == "11"); 2018 assert(printFloat(12.5f, f) == "12"); 2019 assert(printFloat(11.7f, f) == "11"); 2020 assert(printFloat(11.3f, f) == "11"); 2021 assert(printFloat(11.0f, f) == "11"); 2022 assert(printFloat(-11.5f, f) == "-11"); 2023 assert(printFloat(-12.5f, f) == "-12"); 2024 assert(printFloat(-11.7f, f) == "-11"); 2025 assert(printFloat(-11.3f, f) == "-11"); 2026 assert(printFloat(-11.0f, f) == "-11"); 2027 2028 fpctrl.rounding = FloatingPointControl.roundUp; 2029 2030 assert(printFloat(11.5f, f) == "12"); 2031 assert(printFloat(12.5f, f) == "13"); 2032 assert(printFloat(11.7f, f) == "12"); 2033 assert(printFloat(11.3f, f) == "12"); 2034 assert(printFloat(11.0f, f) == "11"); 2035 assert(printFloat(-11.5f, f) == "-11"); 2036 assert(printFloat(-12.5f, f) == "-12"); 2037 assert(printFloat(-11.7f, f) == "-11"); 2038 assert(printFloat(-11.3f, f) == "-11"); 2039 assert(printFloat(-11.0f, f) == "-11"); 2040 2041 fpctrl.rounding = FloatingPointControl.roundDown; 2042 2043 assert(printFloat(11.5f, f) == "11"); 2044 assert(printFloat(12.5f, f) == "12"); 2045 assert(printFloat(11.7f, f) == "11"); 2046 assert(printFloat(11.3f, f) == "11"); 2047 assert(printFloat(11.0f, f) == "11"); 2048 assert(printFloat(-11.5f, f) == "-12"); 2049 assert(printFloat(-12.5f, f) == "-13"); 2050 assert(printFloat(-11.7f, f) == "-12"); 2051 assert(printFloat(-11.3f, f) == "-12"); 2052 assert(printFloat(-11.0f, f) == "-11"); 2053 } 2054} 2055 2056@safe unittest 2057{ 2058 auto f = FormatSpec!dchar(""); 2059 f.spec = 'f'; 2060 assert(printFloat(double.nan, f) == "nan"); 2061 assert(printFloat(-double.nan, f) == "-nan"); 2062 assert(printFloat(double.infinity, f) == "inf"); 2063 assert(printFloat(-double.infinity, f) == "-inf"); 2064 assert(printFloat(0.0, f) == "0.000000"); 2065 assert(printFloat(-0.0, f) == "-0.000000"); 2066 // / 1000 needed due to https://issues.dlang.org/show_bug.cgi?id=20361 2067 assert(printFloat(1e-307 / 1000, f) == "0.000000"); 2068 assert(printFloat(-1e-307 / 1000, f) == "-0.000000"); 2069 assert(printFloat(1e-30, f) == "0.000000"); 2070 assert(printFloat(-1e-30, f) == "-0.000000"); 2071 assert(printFloat(1e-10, f) == "0.000000"); 2072 assert(printFloat(-1e-10, f) == "-0.000000"); 2073 assert(printFloat(0.1, f) == "0.100000"); 2074 assert(printFloat(-0.1, f) == "-0.100000"); 2075 assert(printFloat(10.0, f) == "10.000000"); 2076 assert(printFloat(-10.0, f) == "-10.000000"); 2077 assert(printFloat(1e300, f) == 2078 "100000000000000005250476025520442024870446858110815915491585411551180245798890819578637137508044786" 2079 ~"404370444383288387817694252323536043057564479218478670698284838720092657580373783023379478809005936" 2080 ~"895323497079994508111903896764088007465274278014249457925878882005684283811566947219638686545940054" 2081 ~"0160.000000"); 2082 assert(printFloat(-1e300, f) == 2083 "-100000000000000005250476025520442024870446858110815915491585411551180245798890819578637137508044786" 2084 ~"404370444383288387817694252323536043057564479218478670698284838720092657580373783023379478809005936" 2085 ~"895323497079994508111903896764088007465274278014249457925878882005684283811566947219638686545940054" 2086 ~"0160.000000"); 2087 2088 import std.math.operations : nextUp, nextDown; 2089 assert(printFloat(nextUp(0.0), f) == "0.000000"); 2090 assert(printFloat(nextDown(-0.0), f) == "-0.000000"); 2091} 2092 2093@safe unittest 2094{ 2095 static if (real.mant_dig > 64) 2096 { 2097 pragma(msg, "printFloat tests disabled because of unsupported `real` format"); 2098 } 2099 else 2100 { 2101 auto f = FormatSpec!dchar(""); 2102 f.spec = 'f'; 2103 assert(printFloat(real.nan, f) == "nan"); 2104 assert(printFloat(-real.nan, f) == "-nan"); 2105 assert(printFloat(real.infinity, f) == "inf"); 2106 assert(printFloat(-real.infinity, f) == "-inf"); 2107 assert(printFloat(0.0L, f) == "0.000000"); 2108 assert(printFloat(-0.0L, f) == "-0.000000"); 2109 } 2110 2111 static if (real.mant_dig == 64) 2112 { 2113 assert(printFloat(1e-4940L, f) == "0.000000"); 2114 assert(printFloat(-1e-4940L, f) == "-0.000000"); 2115 assert(printFloat(1e-30L, f) == "0.000000"); 2116 assert(printFloat(-1e-30L, f) == "-0.000000"); 2117 assert(printFloat(1e-10L, f) == "0.000000"); 2118 assert(printFloat(-1e-10L, f) == "-0.000000"); 2119 assert(printFloat(0.1L, f) == "0.100000"); 2120 assert(printFloat(-0.1L, f) == "-0.100000"); 2121 assert(printFloat(10.0L, f) == "10.000000"); 2122 assert(printFloat(-10.0L, f) == "-10.000000"); 2123 version (Windows) {} // issue 20972 2124 else 2125 { 2126 auto result1 = printFloat(1e4000L, f); 2127 assert(result1.length == 4007 && result1[0 .. 40] == "9999999999999999999965463873099623784932"); 2128 auto result2 = printFloat(-1e4000L, f); 2129 assert(result2.length == 4008 && result2[0 .. 40] == "-999999999999999999996546387309962378493"); 2130 } 2131 2132 import std.math.operations : nextUp, nextDown; 2133 assert(printFloat(nextUp(0.0L), f) == "0.000000"); 2134 assert(printFloat(nextDown(-0.0L), f) == "-0.000000"); 2135 } 2136} 2137 2138@safe unittest 2139{ 2140 import std.exception : assertCTFEable; 2141 import std.math.exponential : log2; 2142 import std.math.operations : nextDown; 2143 2144 assertCTFEable!( 2145 { 2146 // log2 is broken for x87-reals on some computers in CTFE 2147 // the following tests excludes these computers from the tests 2148 // (issue 21757) 2149 enum test = cast(int) log2(3.05e2312L); 2150 static if (real.mant_dig == 64 && test == 7681) 2151 { 2152 auto f = FormatSpec!dchar(""); 2153 f.spec = 'f'; 2154 assert(printFloat(real.infinity, f) == "inf"); 2155 assert(printFloat(10.0L, f) == "10.000000"); 2156 assert(printFloat(2.6080L, f) == "2.608000"); 2157 auto result1 = printFloat(3.05e2312L, f); 2158 assert(result1.length == 2320); 2159 assert(result1[0 .. 20] == "30499999999999999999"); 2160 2161 f.precision = 60; 2162 assert(printFloat(2.65e-54L, f) == 2163 "0.000000000000000000000000000000000000000000000000000002650000"); 2164 2165 /* 2166 commented out, because CTFE is currently too slow for 5000 digits with extreme values 2167 2168 f.precision = 5000; 2169 auto result2 = printFloat(1.2119e-4822L, f); 2170 assert(result2.length == 5002); 2171 assert(result2[$ - 20 .. $] == "60076763752233836613"); 2172 auto result3 = printFloat(real.min_normal, f); 2173 assert(result3.length == 5002); 2174 assert(result3[$ - 20 .. $] == "47124010882722980874"); 2175 auto result4 = printFloat(real.min_normal.nextDown, f); 2176 assert(result4.length == 5002); 2177 assert(result4[$ - 20 .. $] == "52925846892214823939"); 2178 */ 2179 } 2180 }); 2181} 2182 2183@safe unittest 2184{ 2185 auto f = FormatSpec!dchar(""); 2186 f.spec = 'f'; 2187 2188 import std.math.operations : nextUp; 2189 2190 double eps = nextUp(0.0); 2191 f.precision = 1000; 2192 assert(printFloat(eps, f) == 2193 "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 2194 ~"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 2195 ~"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 2196 ~"00000000000000000000000000000049406564584124654417656879286822137236505980261432476442558568250067" 2197 ~"55072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131" 2198 ~"90311404527845817167848982103688718636056998730723050006387409153564984387312473397273169615140031" 2199 ~"71538539807412623856559117102665855668676818703956031062493194527159149245532930545654440112748012" 2200 ~"97099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107" 2201 ~"49170333222684475333572083243193609238289345836806010601150616980975307834227731832924790498252473" 2202 ~"07763759272478746560847782037344696995336470179726777175851256605511991315048911014510378627381672" 2203 ~"509558373897335989937"); 2204 2205 f.precision = 0; 2206 assert(printFloat(double.max, f) == 2207 "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878" 2208 ~"17154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932894407" 2209 ~"58685084551339423045832369032229481658085593321233482747978262041447231687381771809192998812504040" 2210 ~"26184124858368"); 2211 2212 f.precision = 50; 2213 assert(printFloat(double.epsilon, f) == 2214 "0.00000000000000022204460492503130808472633361816406"); 2215 2216 f.precision = 10; 2217 assert(printFloat(1.0/3.0, f) == "0.3333333333"); 2218 assert(printFloat(1.0/7.0, f) == "0.1428571429"); 2219 assert(printFloat(1.0/9.0, f) == "0.1111111111"); 2220} 2221 2222@safe unittest 2223{ 2224 auto f = FormatSpec!dchar(""); 2225 f.spec = 'f'; 2226 f.precision = 15; 2227 2228 import std.math.constants : E, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, 2229 LN10, LN2, LOG2, LOG2E, LOG2T, LOG10E, SQRT2, SQRT1_2; 2230 2231 assert(printFloat(cast(double) E, f) == "2.718281828459045"); 2232 assert(printFloat(cast(double) PI, f) == "3.141592653589793"); 2233 assert(printFloat(cast(double) PI_2, f) == "1.570796326794897"); 2234 assert(printFloat(cast(double) PI_4, f) == "0.785398163397448"); 2235 assert(printFloat(cast(double) M_1_PI, f) == "0.318309886183791"); 2236 assert(printFloat(cast(double) M_2_PI, f) == "0.636619772367581"); 2237 assert(printFloat(cast(double) M_2_SQRTPI, f) == "1.128379167095513"); 2238 assert(printFloat(cast(double) LN10, f) == "2.302585092994046"); 2239 assert(printFloat(cast(double) LN2, f) == "0.693147180559945"); 2240 assert(printFloat(cast(double) LOG2, f) == "0.301029995663981"); 2241 assert(printFloat(cast(double) LOG2E, f) == "1.442695040888963"); 2242 assert(printFloat(cast(double) LOG2T, f) == "3.321928094887362"); 2243 assert(printFloat(cast(double) LOG10E, f) == "0.434294481903252"); 2244 assert(printFloat(cast(double) SQRT2, f) == "1.414213562373095"); 2245 assert(printFloat(cast(double) SQRT1_2, f) == "0.707106781186548"); 2246} 2247 2248// for 100% coverage 2249@safe unittest 2250{ 2251 auto f = FormatSpec!dchar(""); 2252 f.spec = 'f'; 2253 f.precision = 1; 2254 assert(printFloat(9.99, f) == "10.0"); 2255 2256 import std.math.operations : nextUp; 2257 2258 float eps = nextUp(0.0f); 2259 2260 f.precision = 148; 2261 assert(printFloat(eps, f) == 2262 "0.0000000000000000000000000000000000000000000014012984643248170709237295832899161312802619418765157" 2263 ~"717570682838897910826858606014866381883621215820312"); 2264 2265 f.precision = 149; 2266 assert(printFloat(eps, f) == 2267 "0.0000000000000000000000000000000000000000000014012984643248170709237295832899161312802619418765157" 2268 ~"7175706828388979108268586060148663818836212158203125"); 2269} 2270 2271private void printFloatG(Writer, T, Char)(auto ref Writer w, const(T) val, 2272 FormatSpec!Char f, string sgn, int exp, ulong mnt, bool is_upper) 2273if (is(T == float) || is(T == double) 2274 || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64))) 2275{ 2276 import core.math : abs = fabs; 2277 2278 if (f.precision == f.UNSPECIFIED) 2279 f.precision = 6; 2280 2281 if (f.precision == 0) 2282 f.precision = 1; 2283 2284 import std.math.hardware; 2285 import std.format.internal.write : RoundingMode; 2286 2287 auto rm = RoundingMode.toNearestTiesToEven; 2288 2289 if (!__ctfe) 2290 { 2291 // std.math's FloatingPointControl isn't available on all target platforms 2292 static if (is(FloatingPointControl)) 2293 { 2294 switch (FloatingPointControl.rounding) 2295 { 2296 case FloatingPointControl.roundUp: 2297 rm = RoundingMode.up; 2298 break; 2299 case FloatingPointControl.roundDown: 2300 rm = RoundingMode.down; 2301 break; 2302 case FloatingPointControl.roundToZero: 2303 rm = RoundingMode.toZero; 2304 break; 2305 case FloatingPointControl.roundToNearest: 2306 rm = RoundingMode.toNearestTiesToEven; 2307 break; 2308 default: assert(false, "Unknown floating point rounding mode"); 2309 } 2310 } 2311 } 2312 2313 bool useE = false; 2314 2315 final switch (rm) 2316 { 2317 case RoundingMode.up: 2318 useE = abs(val) >= 10.0 ^^ f.precision - (val > 0 ? 1 : 0) 2319 || abs(val) < 0.0001 - (val > 0 ? (10.0 ^^ (-4 - f.precision)) : 0); 2320 break; 2321 case RoundingMode.down: 2322 useE = abs(val) >= 10.0 ^^ f.precision - (val < 0 ? 1 : 0) 2323 || abs(val) < 0.0001 - (val < 0 ? (10.0 ^^ (-4 - f.precision)) : 0); 2324 break; 2325 case RoundingMode.toZero: 2326 useE = abs(val) >= 10.0 ^^ f.precision 2327 || abs(val) < 0.0001; 2328 break; 2329 case RoundingMode.toNearestTiesToEven: 2330 case RoundingMode.toNearestTiesAwayFromZero: 2331 useE = abs(val) >= 10.0 ^^ f.precision - 0.5 2332 || abs(val) < 0.0001 - 0.5 * (10.0 ^^ (-4 - f.precision)); 2333 break; 2334 } 2335 2336 if (useE) 2337 return printFloatE!true(w, val, f, sgn, exp, mnt, is_upper); 2338 else 2339 return printFloatF!true(w, val, f, sgn, exp, mnt, is_upper); 2340} 2341 2342@safe unittest 2343{ 2344 // This one tests the switch between e-like and f-like output. 2345 // There is a small gap left between the two, where the used 2346 // variation is not clearly defined. This is intentional and due 2347 // to the way, D handles floating point numbers. On different 2348 // computers with different reals the results may vary in this gap. 2349 2350 import std.math.operations : nextDown, nextUp; 2351 import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined 2352 2353 auto f = FormatSpec!dchar(""); 2354 f.spec = 'g'; 2355 2356 double val = 999999.5; 2357 assert(printFloat(val.nextUp, f) == "1e+06"); 2358 val = nextDown(val); 2359 assert(printFloat(val.nextDown, f) == "999999"); 2360 2361 val = 0.00009999995; 2362 assert(printFloat(val.nextUp, f) == "0.0001"); 2363 val = nextDown(val); 2364 assert(printFloat(val.nextDown, f) == "9.99999e-05"); 2365 2366 static if (is(FloatingPointControl)) 2367 { 2368 FloatingPointControl fpctrl; 2369 2370 fpctrl.rounding = FloatingPointControl.roundToZero; 2371 2372 val = 1000000; 2373 assert(printFloat(val.nextUp, f) == "1e+06"); 2374 val = nextDown(val); 2375 assert(printFloat(val.nextDown, f) == "999999"); 2376 2377 val = 0.0001; 2378 assert(printFloat(val.nextUp, f) == "0.0001"); 2379 val = nextDown(val); 2380 assert(printFloat(val.nextDown, f) == "9.99999e-05"); 2381 2382 fpctrl.rounding = FloatingPointControl.roundUp; 2383 2384 val = 999999; 2385 assert(printFloat(val.nextUp, f) == "1e+06"); 2386 val = nextDown(val); 2387 assert(printFloat(val.nextDown, f) == "999999"); 2388 2389 // 0.0000999999 is actually represented as 0.0000999998999..., which is 2390 // less than 0.0000999999, so we need to use nextUp to get the corner case here 2391 val = nextUp(0.0000999999); 2392 assert(printFloat(val.nextUp, f) == "0.0001"); 2393 val = nextDown(val); 2394 assert(printFloat(val.nextDown, f) == "9.99999e-05"); 2395 2396 fpctrl.rounding = FloatingPointControl.roundDown; 2397 2398 val = 1000000; 2399 assert(printFloat(val.nextUp, f) == "1e+06"); 2400 val = nextDown(val); 2401 assert(printFloat(val.nextDown, f) == "999999"); 2402 2403 val = 0.0001; 2404 assert(printFloat(val.nextUp, f) == "0.0001"); 2405 val = nextDown(val); 2406 assert(printFloat(val.nextDown, f) == "9.99999e-05"); 2407 } 2408} 2409 2410@safe unittest 2411{ 2412 auto f = FormatSpec!dchar(""); 2413 f.spec = 'g'; 2414 assert(printFloat(float.nan, f) == "nan"); 2415 assert(printFloat(-float.nan, f) == "-nan"); 2416 assert(printFloat(float.infinity, f) == "inf"); 2417 assert(printFloat(-float.infinity, f) == "-inf"); 2418 assert(printFloat(0.0f, f) == "0"); 2419 assert(printFloat(-0.0f, f) == "-0"); 2420 2421 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 2422 assert(printFloat(cast(float) 1e-40, f) == "9.99995e-41"); 2423 assert(printFloat(cast(float) -1e-40, f) == "-9.99995e-41"); 2424 assert(printFloat(1e-30f, f) == "1e-30"); 2425 assert(printFloat(-1e-30f, f) == "-1e-30"); 2426 assert(printFloat(1e-10f, f) == "1e-10"); 2427 assert(printFloat(-1e-10f, f) == "-1e-10"); 2428 assert(printFloat(0.1f, f) == "0.1"); 2429 assert(printFloat(-0.1f, f) == "-0.1"); 2430 assert(printFloat(10.0f, f) == "10"); 2431 assert(printFloat(-10.0f, f) == "-10"); 2432 assert(printFloat(1e30f, f) == "1e+30"); 2433 assert(printFloat(-1e30f, f) == "-1e+30"); 2434 2435 import std.math.operations : nextUp, nextDown; 2436 assert(printFloat(nextUp(0.0f), f) == "1.4013e-45"); 2437 assert(printFloat(nextDown(-0.0f), f) == "-1.4013e-45"); 2438} 2439 2440@safe unittest 2441{ 2442 auto f = FormatSpec!dchar(""); 2443 f.spec = 'g'; 2444 f.width = 20; 2445 f.precision = 10; 2446 2447 assert(printFloat(float.nan, f) == " nan"); 2448 assert(printFloat(-float.nan, f) == " -nan"); 2449 assert(printFloat(float.infinity, f) == " inf"); 2450 assert(printFloat(-float.infinity, f) == " -inf"); 2451 assert(printFloat(0.0f, f) == " 0"); 2452 assert(printFloat(-0.0f, f) == " -0"); 2453 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 2454 assert(printFloat(cast(float) 1e-40, f) == " 9.999946101e-41"); 2455 assert(printFloat(cast(float) -1e-40, f) == " -9.999946101e-41"); 2456 assert(printFloat(1e-30f, f) == " 1.000000003e-30"); 2457 assert(printFloat(-1e-30f, f) == " -1.000000003e-30"); 2458 assert(printFloat(1e-10f, f) == " 1.000000013e-10"); 2459 assert(printFloat(-1e-10f, f) == " -1.000000013e-10"); 2460 assert(printFloat(0.1f, f) == " 0.1000000015"); 2461 assert(printFloat(-0.1f, f) == " -0.1000000015"); 2462 assert(printFloat(10.0f, f) == " 10"); 2463 assert(printFloat(-10.0f, f) == " -10"); 2464 assert(printFloat(1e30f, f) == " 1.000000015e+30"); 2465 assert(printFloat(-1e30f, f) == " -1.000000015e+30"); 2466 2467 import std.math.operations : nextUp, nextDown; 2468 assert(printFloat(nextUp(0.0f), f) == " 1.401298464e-45"); 2469 assert(printFloat(nextDown(-0.0f), f) == " -1.401298464e-45"); 2470} 2471 2472@safe unittest 2473{ 2474 auto f = FormatSpec!dchar(""); 2475 f.spec = 'g'; 2476 f.width = 20; 2477 f.precision = 10; 2478 f.flDash = true; 2479 2480 assert(printFloat(float.nan, f) == "nan "); 2481 assert(printFloat(-float.nan, f) == "-nan "); 2482 assert(printFloat(float.infinity, f) == "inf "); 2483 assert(printFloat(-float.infinity, f) == "-inf "); 2484 assert(printFloat(0.0f, f) == "0 "); 2485 assert(printFloat(-0.0f, f) == "-0 "); 2486 2487 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 2488 assert(printFloat(cast(float) 1e-40, f) == "9.999946101e-41 "); 2489 assert(printFloat(cast(float) -1e-40, f) == "-9.999946101e-41 "); 2490 assert(printFloat(1e-30f, f) == "1.000000003e-30 "); 2491 assert(printFloat(-1e-30f, f) == "-1.000000003e-30 "); 2492 assert(printFloat(1e-10f, f) == "1.000000013e-10 "); 2493 assert(printFloat(-1e-10f, f) == "-1.000000013e-10 "); 2494 assert(printFloat(0.1f, f) == "0.1000000015 "); 2495 assert(printFloat(-0.1f, f) == "-0.1000000015 "); 2496 assert(printFloat(10.0f, f) == "10 "); 2497 assert(printFloat(-10.0f, f) == "-10 "); 2498 assert(printFloat(1e30f, f) == "1.000000015e+30 "); 2499 assert(printFloat(-1e30f, f) == "-1.000000015e+30 "); 2500 2501 import std.math.operations : nextUp, nextDown; 2502 assert(printFloat(nextUp(0.0f), f) == "1.401298464e-45 "); 2503 assert(printFloat(nextDown(-0.0f), f) == "-1.401298464e-45 "); 2504} 2505 2506@safe unittest 2507{ 2508 auto f = FormatSpec!dchar(""); 2509 f.spec = 'g'; 2510 f.width = 20; 2511 f.precision = 10; 2512 f.flZero = true; 2513 2514 assert(printFloat(float.nan, f) == " nan"); 2515 assert(printFloat(-float.nan, f) == " -nan"); 2516 assert(printFloat(float.infinity, f) == " inf"); 2517 assert(printFloat(-float.infinity, f) == " -inf"); 2518 assert(printFloat(0.0f, f) == "00000000000000000000"); 2519 assert(printFloat(-0.0f, f) == "-0000000000000000000"); 2520 2521 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 2522 assert(printFloat(cast(float) 1e-40, f) == "000009.999946101e-41"); 2523 assert(printFloat(cast(float) -1e-40, f) == "-00009.999946101e-41"); 2524 assert(printFloat(1e-30f, f) == "000001.000000003e-30"); 2525 assert(printFloat(-1e-30f, f) == "-00001.000000003e-30"); 2526 assert(printFloat(1e-10f, f) == "000001.000000013e-10"); 2527 assert(printFloat(-1e-10f, f) == "-00001.000000013e-10"); 2528 assert(printFloat(0.1f, f) == "000000000.1000000015"); 2529 assert(printFloat(-0.1f, f) == "-00000000.1000000015"); 2530 assert(printFloat(10.0f, f) == "00000000000000000010"); 2531 assert(printFloat(-10.0f, f) == "-0000000000000000010"); 2532 assert(printFloat(1e30f, f) == "000001.000000015e+30"); 2533 assert(printFloat(-1e30f, f) == "-00001.000000015e+30"); 2534 2535 import std.math.operations : nextUp, nextDown; 2536 assert(printFloat(nextUp(0.0f), f) == "000001.401298464e-45"); 2537 assert(printFloat(nextDown(-0.0f), f) == "-00001.401298464e-45"); 2538} 2539 2540@safe unittest 2541{ 2542 auto f = FormatSpec!dchar(""); 2543 f.spec = 'g'; 2544 f.precision = 10; 2545 f.flHash = true; 2546 2547 assert(printFloat(float.nan, f) == "nan"); 2548 assert(printFloat(-float.nan, f) == "-nan"); 2549 assert(printFloat(float.infinity, f) == "inf"); 2550 assert(printFloat(-float.infinity, f) == "-inf"); 2551 assert(printFloat(0.0f, f) == "0.000000000"); 2552 assert(printFloat(-0.0f, f) == "-0.000000000"); 2553 2554 // cast needed due to https://issues.dlang.org/show_bug.cgi?id=20361 2555 assert(printFloat(cast(float) 1e-40, f) == "9.999946101e-41"); 2556 assert(printFloat(cast(float) -1e-40, f) == "-9.999946101e-41"); 2557 assert(printFloat(1e-30f, f) == "1.000000003e-30"); 2558 assert(printFloat(-1e-30f, f) == "-1.000000003e-30"); 2559 assert(printFloat(1e-10f, f) == "1.000000013e-10"); 2560 assert(printFloat(-1e-10f, f) == "-1.000000013e-10"); 2561 assert(printFloat(0.1f, f) == "0.1000000015"); 2562 assert(printFloat(-0.1f, f) == "-0.1000000015"); 2563 assert(printFloat(10.0f, f) == "10.00000000"); 2564 assert(printFloat(-10.0f, f) == "-10.00000000"); 2565 assert(printFloat(1e30f, f) == "1.000000015e+30"); 2566 assert(printFloat(-1e30f, f) == "-1.000000015e+30"); 2567 2568 import std.math.operations : nextUp, nextDown; 2569 assert(printFloat(nextUp(0.0f), f) == "1.401298464e-45"); 2570 assert(printFloat(nextDown(-0.0f), f) == "-1.401298464e-45"); 2571} 2572 2573@safe unittest 2574{ 2575 import std.math.hardware; // cannot be selective, because FloatingPointControl might not be defined 2576 2577 // std.math's FloatingPointControl isn't available on all target platforms 2578 static if (is(FloatingPointControl)) 2579 { 2580 FloatingPointControl fpctrl; 2581 2582 char[256] buf; 2583 auto f = FormatSpec!dchar(""); 2584 f.spec = 'g'; 2585 f.precision = 2; 2586 2587 fpctrl.rounding = FloatingPointControl.roundToNearest; 2588 2589 /* 2590 assert(printFloat(11.5f, f, RoundingMode.toNearestTiesAwayFromZero) == "12"); 2591 assert(printFloat(12.5f, f, RoundingMode.toNearestTiesAwayFromZero) == "13"); 2592 assert(printFloat(11.7f, f, RoundingMode.toNearestTiesAwayFromZero) == "12"); 2593 assert(printFloat(11.3f, f, RoundingMode.toNearestTiesAwayFromZero) == "11"); 2594 assert(printFloat(11.0f, f, RoundingMode.toNearestTiesAwayFromZero) == "11"); 2595 assert(printFloat(-11.5f, f, RoundingMode.toNearestTiesAwayFromZero) == "-12"); 2596 assert(printFloat(-12.5f, f, RoundingMode.toNearestTiesAwayFromZero) == "-13"); 2597 assert(printFloat(-11.7f, f, RoundingMode.toNearestTiesAwayFromZero) == "-12"); 2598 assert(printFloat(-11.3f, f, RoundingMode.toNearestTiesAwayFromZero) == "-11"); 2599 assert(printFloat(-11.0f, f, RoundingMode.toNearestTiesAwayFromZero) == "-11"); 2600 */ 2601 2602 // ties to even 2603 assert(printFloat(11.5f, f) == "12"); 2604 assert(printFloat(12.5f, f) == "12"); 2605 assert(printFloat(11.7f, f) == "12"); 2606 assert(printFloat(11.3f, f) == "11"); 2607 assert(printFloat(11.0f, f) == "11"); 2608 assert(printFloat(-11.5f, f) == "-12"); 2609 assert(printFloat(-12.5f, f) == "-12"); 2610 assert(printFloat(-11.7f, f) == "-12"); 2611 assert(printFloat(-11.3f, f) == "-11"); 2612 assert(printFloat(-11.0f, f) == "-11"); 2613 2614 fpctrl.rounding = FloatingPointControl.roundToZero; 2615 2616 assert(printFloat(11.5f, f) == "11"); 2617 assert(printFloat(12.5f, f) == "12"); 2618 assert(printFloat(11.7f, f) == "11"); 2619 assert(printFloat(11.3f, f) == "11"); 2620 assert(printFloat(11.0f, f) == "11"); 2621 assert(printFloat(-11.5f, f) == "-11"); 2622 assert(printFloat(-12.5f, f) == "-12"); 2623 assert(printFloat(-11.7f, f) == "-11"); 2624 assert(printFloat(-11.3f, f) == "-11"); 2625 assert(printFloat(-11.0f, f) == "-11"); 2626 2627 fpctrl.rounding = FloatingPointControl.roundUp; 2628 2629 assert(printFloat(11.5f, f) == "12"); 2630 assert(printFloat(12.5f, f) == "13"); 2631 assert(printFloat(11.7f, f) == "12"); 2632 assert(printFloat(11.3f, f) == "12"); 2633 assert(printFloat(11.0f, f) == "11"); 2634 assert(printFloat(-11.5f, f) == "-11"); 2635 assert(printFloat(-12.5f, f) == "-12"); 2636 assert(printFloat(-11.7f, f) == "-11"); 2637 assert(printFloat(-11.3f, f) == "-11"); 2638 assert(printFloat(-11.0f, f) == "-11"); 2639 2640 fpctrl.rounding = FloatingPointControl.roundDown; 2641 2642 assert(printFloat(11.5f, f) == "11"); 2643 assert(printFloat(12.5f, f) == "12"); 2644 assert(printFloat(11.7f, f) == "11"); 2645 assert(printFloat(11.3f, f) == "11"); 2646 assert(printFloat(11.0f, f) == "11"); 2647 assert(printFloat(-11.5f, f) == "-12"); 2648 assert(printFloat(-12.5f, f) == "-13"); 2649 assert(printFloat(-11.7f, f) == "-12"); 2650 assert(printFloat(-11.3f, f) == "-12"); 2651 assert(printFloat(-11.0f, f) == "-11"); 2652 } 2653} 2654 2655@safe unittest 2656{ 2657 auto f = FormatSpec!dchar(""); 2658 f.spec = 'g'; 2659 2660 assert(printFloat(double.nan, f) == "nan"); 2661 assert(printFloat(-double.nan, f) == "-nan"); 2662 assert(printFloat(double.infinity, f) == "inf"); 2663 assert(printFloat(-double.infinity, f) == "-inf"); 2664 assert(printFloat(0.0, f) == "0"); 2665 assert(printFloat(-0.0, f) == "-0"); 2666 2667 // / 1000 needed due to https://issues.dlang.org/show_bug.cgi?id=20361 2668 assert(printFloat(1e-307 / 1000, f) == "1e-310"); 2669 assert(printFloat(-1e-307 / 1000, f) == "-1e-310"); 2670 assert(printFloat(1e-30, f) == "1e-30"); 2671 assert(printFloat(-1e-30, f) == "-1e-30"); 2672 assert(printFloat(1e-10, f) == "1e-10"); 2673 assert(printFloat(-1e-10, f) == "-1e-10"); 2674 assert(printFloat(0.1, f) == "0.1"); 2675 assert(printFloat(-0.1, f) == "-0.1"); 2676 assert(printFloat(10.0, f) == "10"); 2677 assert(printFloat(-10.0, f) == "-10"); 2678 assert(printFloat(1e300, f) == "1e+300"); 2679 assert(printFloat(-1e300, f) == "-1e+300"); 2680 2681 import std.math.operations : nextUp, nextDown; 2682 assert(printFloat(nextUp(0.0), f) == "4.94066e-324"); 2683 assert(printFloat(nextDown(-0.0), f) == "-4.94066e-324"); 2684} 2685 2686@safe unittest 2687{ 2688 static if (real.mant_dig > 64) 2689 { 2690 pragma(msg, "printFloat tests disabled because of unsupported `real` format"); 2691 } 2692 else 2693 { 2694 char[256] buf; 2695 auto f = FormatSpec!dchar(""); 2696 f.spec = 'g'; 2697 2698 assert(printFloat(real.nan, f) == "nan"); 2699 assert(printFloat(-real.nan, f) == "-nan"); 2700 assert(printFloat(real.infinity, f) == "inf"); 2701 assert(printFloat(-real.infinity, f) == "-inf"); 2702 } 2703} 2704 2705@safe unittest 2706{ 2707 auto f = FormatSpec!dchar(""); 2708 f.spec = 'g'; 2709 2710 import std.math.operations : nextUp; 2711 2712 double eps = nextUp(0.0); 2713 f.precision = 1000; 2714 assert(printFloat(eps, f) == 2715 "4.940656458412465441765687928682213723650598026143247644255856825006" 2716 ~ "755072702087518652998363616359923797965646954457177309266567103559" 2717 ~ "397963987747960107818781263007131903114045278458171678489821036887" 2718 ~ "186360569987307230500063874091535649843873124733972731696151400317" 2719 ~ "153853980741262385655911710266585566867681870395603106249319452715" 2720 ~ "914924553293054565444011274801297099995419319894090804165633245247" 2721 ~ "571478690147267801593552386115501348035264934720193790268107107491" 2722 ~ "703332226844753335720832431936092382893458368060106011506169809753" 2723 ~ "078342277318329247904982524730776375927247874656084778203734469699" 2724 ~ "533647017972677717585125660551199131504891101451037862738167250955" 2725 ~ "837389733598993664809941164205702637090279242767544565229087538682" 2726 ~ "506419718265533447265625e-324"); 2727 2728 f.precision = 50; 2729 assert(printFloat(double.max, f) == 2730 "1.7976931348623157081452742373170435679807056752584e+308"); 2731 assert(printFloat(double.epsilon, f) == 2732 "2.220446049250313080847263336181640625e-16"); 2733 2734 f.precision = 10; 2735 assert(printFloat(1.0/3.0, f) == "0.3333333333"); 2736 assert(printFloat(1.0/7.0, f) == "0.1428571429"); 2737 assert(printFloat(1.0/9.0, f) == "0.1111111111"); 2738} 2739 2740@safe unittest 2741{ 2742 auto f = FormatSpec!dchar(""); 2743 f.spec = 'g'; 2744 f.precision = 15; 2745 2746 import std.math.constants : E, PI, PI_2, PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, 2747 LN10, LN2, LOG2, LOG2E, LOG2T, LOG10E, SQRT2, SQRT1_2; 2748 2749 assert(printFloat(cast(double) E, f) == "2.71828182845905"); 2750 assert(printFloat(cast(double) PI, f) == "3.14159265358979"); 2751 assert(printFloat(cast(double) PI_2, f) == "1.5707963267949"); 2752 assert(printFloat(cast(double) PI_4, f) == "0.785398163397448"); 2753 assert(printFloat(cast(double) M_1_PI, f) == "0.318309886183791"); 2754 assert(printFloat(cast(double) M_2_PI, f) == "0.636619772367581"); 2755 assert(printFloat(cast(double) M_2_SQRTPI, f) == "1.12837916709551"); 2756 assert(printFloat(cast(double) LN10, f) == "2.30258509299405"); 2757 assert(printFloat(cast(double) LN2, f) == "0.693147180559945"); 2758 assert(printFloat(cast(double) LOG2, f) == "0.301029995663981"); 2759 assert(printFloat(cast(double) LOG2E, f) == "1.44269504088896"); 2760 assert(printFloat(cast(double) LOG2T, f) == "3.32192809488736"); 2761 assert(printFloat(cast(double) LOG10E, f) == "0.434294481903252"); 2762 assert(printFloat(cast(double) SQRT2, f) == "1.4142135623731"); 2763 assert(printFloat(cast(double) SQRT1_2, f) == "0.707106781186548"); 2764} 2765 2766// for 100% coverage 2767@safe unittest 2768{ 2769 auto f = FormatSpec!dchar(""); 2770 f.spec = 'g'; 2771 f.precision = 0; 2772 2773 assert(printFloat(0.009999, f) == "0.01"); 2774} 2775 2776@safe unittest 2777{ 2778 static if (real.mant_dig > 64) 2779 { 2780 pragma(msg, "printFloat tests disabled because of unsupported `real` format"); 2781 } 2782 else 2783 { 2784 auto f = FormatSpec!dchar(""); 2785 f.spec = 'g'; 2786 assert(printFloat(real.nan, f) == "nan"); 2787 assert(printFloat(-real.nan, f) == "-nan"); 2788 assert(printFloat(real.infinity, f) == "inf"); 2789 assert(printFloat(-real.infinity, f) == "-inf"); 2790 assert(printFloat(0.0L, f) == "0"); 2791 assert(printFloat(-0.0L, f) == "-0"); 2792 } 2793 2794 static if (real.mant_dig == 64) 2795 { 2796 assert(printFloat(1e-4940L, f) == "1e-4940"); 2797 assert(printFloat(-1e-4940L, f) == "-1e-4940"); 2798 assert(printFloat(1e-30L, f) == "1e-30"); 2799 assert(printFloat(-1e-30L, f) == "-1e-30"); 2800 assert(printFloat(1e-10L, f) == "1e-10"); 2801 assert(printFloat(-1e-10L, f) == "-1e-10"); 2802 assert(printFloat(0.1L, f) == "0.1"); 2803 assert(printFloat(-0.1L, f) == "-0.1"); 2804 assert(printFloat(10.0L, f) == "10"); 2805 assert(printFloat(-10.0L, f) == "-10"); 2806 version (Windows) {} // issue 20972 2807 else 2808 { 2809 assert(printFloat(1e4000L, f) == "1e+4000"); 2810 assert(printFloat(-1e4000L, f) == "-1e+4000"); 2811 } 2812 2813 import std.math.operations : nextUp, nextDown; 2814 assert(printFloat(nextUp(0.0L), f) == "3.6452e-4951"); 2815 assert(printFloat(nextDown(-0.0L), f) == "-3.6452e-4951"); 2816 } 2817} 2818 2819@safe unittest 2820{ 2821 import std.exception : assertCTFEable; 2822 import std.math.exponential : log2; 2823 import std.math.operations : nextDown; 2824 2825 assertCTFEable!( 2826 { 2827 // log2 is broken for x87-reals on some computers in CTFE 2828 // the following tests excludes these computers from the tests 2829 // (issue 21757) 2830 enum test = cast(int) log2(3.05e2312L); 2831 static if (real.mant_dig == 64 && test == 7681) 2832 { 2833 auto f = FormatSpec!dchar(""); 2834 f.spec = 'g'; 2835 assert(printFloat(real.infinity, f) == "inf"); 2836 assert(printFloat(10.0L, f) == "10"); 2837 assert(printFloat(2.6080L, f) == "2.608"); 2838 assert(printFloat(3.05e2312L, f) == "3.05e+2312"); 2839 2840 f.precision = 60; 2841 assert(printFloat(2.65e-54L, f) == 2842 "2.65000000000000000005900998740054701394102894093529654759941e-54"); 2843 2844 /* 2845 commented out, because CTFE is currently too slow for 5000 digits with extreme values 2846 2847 f.precision = 5000; 2848 auto result2 = printFloat(1.2119e-4822L, f); 2849 assert(result2.length == 5007); 2850 assert(result2[$ - 20 .. $] == "26072948659534e-4822"); 2851 auto result3 = printFloat(real.min_normal, f); 2852 assert(result3.length == 5007); 2853 assert(result3[$ - 20 .. $] == "72078141008227e-4932"); 2854 auto result4 = printFloat(real.min_normal.nextDown, f); 2855 assert(result4.length == 5007); 2856 assert(result4[$ - 20 .. $] == "48141326333101e-4932"); 2857 */ 2858 } 2859 }); 2860} 2861 2862// check no allocations 2863@safe unittest 2864{ 2865 import std.format : NoOpSink; 2866 auto w = NoOpSink(); 2867 2868 import core.memory; 2869 auto stats = () @trusted { return GC.stats; } (); 2870 2871 auto f = FormatSpec!dchar(""); 2872 f.spec = 'a'; 2873 printFloat(w, float.nan, f); 2874 printFloat(w, -float.infinity, f); 2875 printFloat(w, 0.0f, f); 2876 2877 printFloat(w, -double.nan, f); 2878 printFloat(w, double.infinity, f); 2879 printFloat(w, -0.0, f); 2880 2881 import std.math.operations : nextUp; 2882 import std.math.constants : E; 2883 2884 printFloat(w, nextUp(0.0f), f); 2885 printFloat(w, cast(float) E, f); 2886 2887 f.precision = 1000; 2888 printFloat(w, float.nan, f); 2889 printFloat(w, 0.0, f); 2890 printFloat(w, 1.23456789e+100, f); 2891 2892 f.spec = 'E'; 2893 f.precision = 80; 2894 printFloat(w, 5.62776e+12f, f); 2895 2896 f.precision = 6; 2897 printFloat(w, -1.1418613e+07f, f); 2898 2899 f.precision = 20; 2900 printFloat(w, double.max, f); 2901 printFloat(w, nextUp(0.0), f); 2902 2903 f.precision = 1000; 2904 printFloat(w, 1.0, f); 2905 2906 f.spec = 'f'; 2907 f.precision = 15; 2908 printFloat(w, cast(double) E, f); 2909 2910 f.precision = 20; 2911 printFloat(w, double.max, f); 2912 printFloat(w, nextUp(0.0), f); 2913 2914 f.precision = 1000; 2915 printFloat(w, 1.0, f); 2916 2917 f.spec = 'g'; 2918 f.precision = 15; 2919 printFloat(w, cast(double) E, f); 2920 2921 f.precision = 20; 2922 printFloat(w, double.max, f); 2923 printFloat(w, nextUp(0.0), f); 2924 2925 f.flHash = true; 2926 f.precision = 1000; 2927 printFloat(w, 1.0, f); 2928 2929 assert(() @trusted { return GC.stats.usedSize; } () == stats.usedSize); 2930} 2931