// RUN: %empty-directory(%t)
// RUN: %gyb %s -o %t/FloatingPointPrinting.swift
// RUN: %line-directive %t/FloatingPointPrinting.swift -- %target-build-swift %t/FloatingPointPrinting.swift -o %t/main.out
// RUN: %target-codesign %t/main.out
// RUN: %line-directive %t/FloatingPointPrinting.swift -- %target-run %t/main.out
// REQUIRES: executable_test

// rdar://77087867
// UNSUPPORTED: CPU=arm64_32 && OS=watchos

// Float printing and parsing on embedded are new features, not
// yet fully supported on WASM
// UNSUPPORTED: CPU=wasm32

// rdar://104232602
// UNSUPPORTED: CPU=x86_64 && (DARWIN_SIMULATOR=ios || DARWIN_SIMULATOR=watchos || DARWIN_SIMULATOR=tvos)

import StdlibUnittest
import SwiftPrivateLibcExtras
#if canImport(locale_h)
  import locale_h
#elseif canImport(Darwin)
  import Darwin
#elseif canImport(Glibc)
  import Glibc
#elseif os(WASI)
  import WASILibc
#elseif canImport(Android)
  import Android
#elseif os(Windows)
  import CRT
#else
#error("Unsupported platform")
#endif

// It takes about an hour to run the Float formatter over all 2 billion
// positive values to verify that it's correct.  Of course, we don't want
// to do that for the Swift standard library.
//
// Instead, I ran the same test against a version of the Float formatter that
// used only 45 bits precision (instead of 59) and collected all the values that
// failed with that reduced precision.  This should catch any future mistakes
// that inadvertently damage the accuracy of the formatter's internal
// calculations.
fileprivate let generatedCases_Float: [(Float, String)] = [
  (0x1.ab510cp-126, "1.9621416e-38"),
  (0x1.b2171p-126 , "1.993244e-38"),
  (0x1.b2171p-125 , "3.986488e-38"),
  (0x1.b2171p-124 , "7.972976e-38"),
  (0x1.1c01b4p-122, "2.0865513e-37"),
  (0x1.e41e3p-122 , "3.5567368e-37"),
  (0x1.070866p-120, "7.7298394e-37"),
  (0x1.0a4cap-120 , "7.825834e-37"),
  (0x1.2e92dep-118, "3.5567368e-36"),
  (0x1.225e0ap-117, "6.826503e-36"),
  (0x1.288e84p-117, "6.9720146e-36"),
  (0x1.732b26p-117, "8.726131e-36"),
  (0x1.ab8e9cp-117, "1.0051818e-35"),
  (0x1.ea228ap-117, "1.15230165e-35"),
  (0x1.fc5bb8p-117, "1.1951446e-35"),
  (0x1.9cfcbcp-113, "1.5534853e-34"),
  (0x1.e11c02p-112, "3.619465e-34"),
  (0x1.56f96cp-110, "1.0321008e-33"),
  (0x1.9d393ep-110, "1.2434995e-33"),
  (0x1.e11c02p-109, "2.895572e-33"),
  (0x1.0186b2p-107, "6.199717e-33"),
  (0x1.e11c02p-107, "1.1582288e-32"),
  (0x1.87454cp-106, "1.8838998e-32"),
  (0x1.a337f6p-105, "4.0369282e-32"),
  (0x1.71515ap-105, "3.556401e-32"),
  (0x1.5d594ep-101, "5.382571e-31"),
  (0x1.0d7e9ep-100, "8.304443e-31"),
  (0x1.5d594ep-100, "1.0765142e-30"),
  (0x1.fd0eacp-99 , "3.137308e-30"),
  (0x1.356bf6p-98 , "3.813917e-30"),
  (0x1.356bf6p-97 , "7.627834e-30"),
  (0x1.6256f8p-97 , "8.7351485e-30"),
  (0x1.6c524ep-97 , "8.9812184e-30"),
  (0x1.993d5p-97  , "1.0088533e-29"),
  (0x1.c62854p-97 , "1.11958476e-29"),
  (0x1.fd0eacp-97 , "1.2549232e-29"),
  (0x1.e41a56p-96 , "2.3868115e-29"),
  (0x1.266f8p-94  , "5.806717e-29"),
  (0x1.765118p-94 , "7.382097e-29"),
  (0x1.cb25fep-94 , "9.055106e-29"),
  (0x1.778decp-93 , "1.4813009e-28"),
  (0x1.23f5d8p-92 , "2.303161e-28"),
  (0x1.23f5d8p-90 , "9.212644e-28"),
  (0x1.a1f86p-90  , "1.3188814e-27"),
  (0x1.3db25cp-87 , "8.019793e-27"),
  (0x1.bbb4e2p-87 , "1.1200729e-26"),
  (0x1.83be04p-84 , "7.8303923e-26"),
  (0x1.5c87fap-84 , "7.038531e-26"),
  (0x1.b35478p-84 , "8.7914184e-26"),
  (0x1.54279p-83  , "1.3738732e-25"),
  (0x1.210beap-82 , "2.3348993e-25"),
  (0x1.98040cp-82 , "3.2959255e-25"),
  (0x1.d3801cp-81 , "7.552877e-25"),
  (0x1.296c54p-80 , "9.610261e-25"),
  (0x1.7ee2ccp-80 , "1.2371711e-24"),
  (0x1.d3801cp-80 , "1.5105754e-24"),
  (0x1.e8c296p-78 , "6.3170763e-24"),
  (0x1.09a3c4p-77 , "6.8666256e-24"),
  (0x1.7e7638p-77 , "9.886406e-24"),
  (0x1.d3ecbp-77  , "1.2095566e-23"),
  (0x1.5eada8p-76 , "1.8129645e-23"),
  (0x1.21517ap-74 , "5.9829616e-23"),
  (0x1.ab6668p-74 , "8.8384254e-23"),
  (0x1.91172cp-74 , "8.2943575e-23"),
  (0x1.be075ap-74 , "9.223658e-23"),
  (0x1.aeaacap-70 , "1.424958e-21"),
  (0x1.35db3cp-69 , "2.0504575e-21"),
  (0x1.74df2p-67  , "9.869829e-21"),
  (0x1.f5fa7ap-66 , "2.6574517e-20"),
  (0x1.aa969ep-64 , "9.0333597e-20"),
  (0x1.c77c72p-64 , "9.6452936e-20"),
  (0x1.7f3dep-64  , "8.1154587e-20"),
  (0x1.036eeap-57 , "7.0319526e-18"),
  (0x1.46b2fap-57 , "8.855198e-18"),
  (0x1.796e1ep-57 , "1.0230265e-17"),
  (0x1.ce5b7ap-57 , "1.25322205e-17"),
  (0x1.dee466p-57 , "1.2980399e-17"),
  (0x1.5b3fep-55  , "3.7648867e-17"),
  (0x1.3d11a2p-54 , "6.875335e-17"),
  (0x1.796e1ep-54 , "8.184212e-17"),
  (0x1.bbe57cp-54 , "9.625469e-17"),
  (0x1.d624acp-54 , "1.01946067e-16"),
  (0x1.f841f8p-54 , "1.0934346e-16"),
  (0x1.3d11a2p-53 , "1.375067e-16"),
  (0x1.b20fd8p-52 , "3.7648867e-16"),
  (0x1.928636p-47 , "1.1172293e-14"),
  (0x1.ba8a18p-47 , "1.2282937e-14"),
  (0x1.e28dfap-47 , "1.3393581e-14"),
  (0x1.374dcap-44 , "6.912334e-14"),
  (0x1.a0efd4p-44 , "9.257857e-14"),
  (0x1.7c8658p-44 , "8.4493474e-14"),
  (0x1.e62862p-44 , "1.07948705e-13"),
  (0x1.89537ap-40 , "1.397375e-12"),
  (0x1.981532p-39 , "2.8996026e-12"),
  (0x1.3e8744p-38 , "4.5265606e-12"),
  (0x1.431bf6p-37 , "9.183316e-12"),
  (0x1.525f7ep-37 , "9.6171395e-12"),
  (0x1.7a0ff2p-37 , "1.07451764e-11"),
  (0x1.cf8bp-37   , "1.3174684e-11"),
  (0x1.f637d2p-37 , "1.4273895e-11"),
  (0x1.4cc72ap-34 , "7.566495e-11"),
  (0x1.86e8aep-34 , "8.8882395e-11"),
  (0x1.9093e2p-34 , "9.1080816e-11"),
  (0x1.eef76ap-34 , "1.12542343e-10"),
  (0x1.f637d2p-34 , "1.1419116e-10"),
  (0x1.2cc742p+59 , "6.772926e+17"),
  (0x1.426638p+59 , "7.259787e+17"),
  (0x1.ac1062p+60 , "1.9278289e+18"),
  (0x1.3fb25ap+61 , "2.8795718e+18"),
  (0x1.28aacp+68  , "3.4203376e+20"),
  (0x1.21de92p+69 , "6.683934e+20"),
  (0x1.077b62p+69 , "6.0754804e+20"),
  (0x1.6dd68ep+69 , "8.435652e+20"),
  (0x1.5b7194p+69 , "8.0115055e+20"),
  (0x1.72d57p+71  , "3.4203376e+21"),
  (0x1.3f1b66p+74 , "2.3545942e+22"),
  (0x1.cf8accp+74 , "3.4203376e+22"),
  (0x1.15204ep+76 , "8.179321e+22"),
  (0x1.69167ep+76 , "1.0657433e+23"),
  (0x1.a3dfccp+77 , "2.4784999e+23"),
  (0x1.25ee82p+79 , "6.940265e+23"),
  (0x1.6d4a0cp+79 , "8.6251485e+23"),
  (0x1.9b811cp+79 , "9.716371e+23"),
  (0x1.45ee1ep+84 , "2.4626585e+25"),
  (0x1.84615ep+84 , "2.934519e+25"),
  (0x1.1b492p+87  , "1.7123566e+26"),
  (0x1.61594ap+87 , "2.1358624e+26"),
  (0x1.1c0b3ep+89 , "6.8677604e+26"),
  (0x1.3e5134p+89 , "7.696438e+26"),
  (0x1.cd7a02p+89 , "1.1157819e+27"),
  (0x1.621b68p+90 , "1.7123566e+27"),
  (0x1.baa242p+93 , "1.7123566e+28"),
  (0x1.d40dfp+94  , "3.6213959e+28"),
  (0x1.10287cp+96 , "8.422887e+28"),
  (0x1.8da532p+99 , "9.845221e+29"),
  (0x1.f58b6cp+100, "2.4835287e+30"),
  (0x1.e11158p+102, "9.5285285e+30"),
  (0x1.b61814p+103, "1.7354693e+31"),
  (0x1.0502cp+104 , "2.0679402e+31"),
  (0x1.772604p+106, "1.188893e+32"),
  (0x1.fe44a2p+106, "1.6171041e+32"),
  (0x1.9c7f7ap+108, "5.229033e+32"),
  (0x1.2c7314p+109, "7.6173e+32"),
  (0x1.19c658p+109, "7.143839e+32"),
  (0x1.89d2cp+109 , "9.984605e+32"),
  (0x1.af2c36p+109, "1.0931527e+33"),
  (0x1.c1d8f2p+109, "1.1404988e+33"),
  (0x1.89d2cp+110 , "1.996921e+33"),
  (0x1.97d44cp+110, "2.0679402e+33"),
  (0x1.89d2cp+111 , "3.993842e+33"),
  (0x1.2c7314p+112, "6.09384e+33"),
  (0x1.368a68p+112, "6.2985127e+33"),
  (0x1.89d2cp+112 , "7.987684e+33"),
  (0x1.5b22eap+112, "7.040762e+33"),
  (0x1.b88294p+112, "8.934606e+33"),
  (0x1.e7326ap+112, "9.881528e+33"),
  (0x1.672f5ap+114, "2.9140547e+34"),
  (0x1.103662p+115, "4.4168992e+34"),
  (0x1.4fd77p+116 , "1.0898681e+35"),
  (0x1.cf198ap+116, "1.5028446e+35"),
  (0x1.347374p+118, "4.0039227e+35"),
  (0x1.7ced98p+118, "4.9447295e+35"),
  (0x1.aa03cp+119 , "1.1059973e+36"),
  (0x1.3b315cp+122, "6.5462986e+36"),
  (0x1.3e2542p+122, "6.607624e+36"),
  (0x1.c4fb6p+122 , "9.408067e+36"),
  (0x1.f062b6p+122, "1.03095254e+37"),
  (0x1.2db58cp+123, "1.2532508e+37"),
  (0x1.a345d8p+126, "1.393273e+38"),
  (0x1.a345d8p+127, "2.786546e+38")
]

// Of course, exhaustive testing of Double (or Float80!) is not
// practical, so I used another approach to generate test cases
// for those:

// The Errol paper details a method for enumerating cases where the optimal
// base-10 form might be extremely close to the midpoint between two binary
// Doubles, and therefore at risk of being handled incorrectly by Grisu-style
// formatters that use fixed-precision arithmetic. These are the extreme cases
// for our algorithm, so if we get these right, we have pretty high confidence
// that we get everything right.

// I took that list and ran it through a reduced-precision version of the Double
// formatter to identify these worst-case values:
fileprivate let generatedCases_Double: [(Double, String)] = [
  (0x1.379f099a86228p-317, "4.559093100884257e-96"),
  (0x1.7c3fba45c1271p-307, "5.696647848853893e-93"),
  (0x1.4f14348a4c5dcp-299, "1.285104507361864e-90"),
  (0x1.4f14348a4c5dcp-298, "2.570209014723728e-90"),
  (0x1.a8c931c19b77ap-298, "3.258302752792233e-90"),
  (0x1.4f14348a4c5dcp-297, "5.140418029447456e-90"),
  (0x1.a8c931c19b77ap-297, "6.516605505584466e-90"),
  (0x1.97a2a205f591fp-294, "5.002799281833755e-89"),
  (0x1.387cf9cb4ad4fp-261, "3.294312317590731e-79"),
  (0x1.ddc7e975c5045p-247, "8.252392874408775e-75"),
  (0x1.ddc7e975c5045p-246, "1.650478574881755e-74"),
  (0x1.ddc7e975c5045p-245, "3.30095714976351e-74"),
  (0x1.ddc7e975c5045p-244, "6.60191429952702e-74"),
  (0x1.ddc7e975c5045p-243, "1.320382859905404e-73"),
  (0x1.ddc7e975c5045p-242, "2.640765719810808e-73"),
  (0x1.ddc7e975c5045p-241, "5.281531439621616e-73"),
  (0x1.9190e30e46c1ep-235, "2.840978519032327e-71"),
  (0x1.0ed9bd6bfd003p-234, "3.832399419240467e-71"),
  (0x1.9190e30e46c1ep-234, "5.681957038064654e-71"),
  (0x1.3b28b27523ea6p-229, "1.426989259361117e-69"),
  (0x1.3b28b27523ea6p-228, "2.853978518722234e-69"),
  (0x1.aedaa0fc32ac8p-222, "2.497072464210591e-67"),
  (0x1.aedaa0fc32ac8p-221, "4.994144928421182e-67"),
  (0x1.48050091c3c25p-219, "1.520865118855779e-66"),
  (0x1.48050091c3c25p-218, "3.041730237711558e-66"),
  (0x1.f5a18504dfaadp-215, "3.721305106071689e-65"),
  (0x1.f5a18504dfaadp-214, "7.442610212143378e-65"),
  (0x1.eef5e1f90ac34p-196, "1.925091640472375e-59"),
  (0x1.eef5e1f90ac34p-195, "3.85018328094475e-59"),
  (0x1.eef5e1f90ac34p-194, "7.7003665618895e-59"),
  (0x1.b20c2f4f8d49fp-138, "4.865841847892019e-42"),
  (0x1.25d342b1e33e6p-128, "3.372948296445563e-39"),
  (0x1.4faba79ea92edp-122, "2.466117547186101e-37"),
  (0x1.4faba79ea92edp-121, "4.932235094372202e-37"),
  (0x1.78cfcab31064dp-89 , "2.378016066134295e-27"),
  (0x1.78cfcab31064dp-88 , "4.75603213226859e-27"),
  (0x1.78cfcab31064dp-87 , "9.51206426453718e-27"),
  (0x1.78cfcab31064dp-86 , "1.902412852907436e-26"),
  (0x1.78cfcab31064dp-85 , "3.804825705814872e-26"),
  (0x1.56d589dc3d0e3p-78 , "4.431027338341785e-24"),
  (0x1.cd230a7ff47c4p+145, "8.034137530808823e+43"),
  (0x1.30d9a1c3890bp+151 , "3.399192475886301e+45"),
  (0x1.fc1562f08f125p+151, "5.665320793143835e+45"),
  (0x1.a32ac316fb3acp+186, "1.605929046641989e+56"),
  (0x1.a32ac316fb3acp+187, "3.211858093283978e+56"),
  (0x1.8862481ccada3p+188, "6.013265967485603e+56"),
  (0x1.a32ac316fb3acp+188, "6.423716186567956e+56"),
  (0x1.5564fb098c956p+201, "4.285935458457607e+60"),
  (0x1.f20b1a0d7f626p+207, "4.001624164855121e+62"),
  (0x1.f20b1a0d7f626p+208, "8.003248329710242e+62"),
  (0x1.a53bb31b369a2p+219, "1.386282306169174e+66"),
  (0x1.a53bb31b369a2p+220, "2.772564612338348e+66"),
  (0x1.a53bb31b369a2p+221, "5.545129224676696e+66"),
  (0x1.66a00a69c6c34p+224, "3.776763733298609e+67"),
  (0x1.e2785c3a2a20ap+227, "4.064803033949531e+68"),
  (0x1.e2785c3a2a20ap+228, "8.129606067899062e+68"),
  (0x1.454b1aef62c8dp+231, "4.384946084578497e+69"),
  (0x1.0fde34c996086p+233, "1.465909318208761e+70"),
  (0x1.0fde34c996086p+234, "2.931818636417522e+70"),
  (0x1.9a2c2a34ac2fap+234, "4.423291694721855e+70"),
  (0x1.9a2c2a34ac2fap+235, "8.84658338944371e+70"),
  (0x1.9a2c2a34ac2fap+236, "1.769316677888742e+71"),
  (0x1.9a2c2a34ac2fap+237, "3.538633355777484e+71"),
  (0x1.9a2c2a34ac2fap+238, "7.077266711554968e+71"),
  (0x1.ca9bade45b94ap+260, "3.318949537676913e+78"),
  (0x1.ca9bade45b94ap+261, "6.637899075353826e+78"),
  (0x1.b3a29c72cab91p+269, "1.614179517443508e+81"),
  (0x1.b3a29c72cab91p+270, "3.228359034887016e+81"),
  (0x1.b3a29c72cab91p+271, "6.456718069774032e+81"),
  (0x1.c84c524ab5ebp+277 , "4.328301679886463e+83"),
  (0x1.71760b3c0bc14p+287, "3.588703015985849e+86"),
  (0x1.11926d079e00ap+304, "3.482974734743573e+91"),
  (0x1.9d8f9fc2808d3p+321, "6.901257826767179e+96"),
  (0x1.63ed4a60c9c91p+324, "4.751595491707413e+97")
]

#if !os(Windows) && (arch(i386) || arch(x86_64))
// Float80 found via Errol technique.
//
// As with Double, except for Float80.  The original list in this
// case had 23 million test cases.  I filtered that against
// a Float80 formatter with 129 bits precision.
fileprivate let generatedCases_Float80: [(Float80, String)] = [
  (0xf.8f06b25f79a0ad9p-329, "1.4226714622425547106e-98"),
  (0xb.a14796a877c6939p-303, "7.136593768505787697e-91"),
  (0xf.8e473d72ad52a71p-296, "1.2218360180048428346e-88"),
  (0xb.c6f5bb0c6811badp-289, "1.1840575897174935119e-86"),
  (0xc.c2111d383f1adfp-236 , "1.1553302055733876345e-70"),
  (0xc.c2111d383f1adfp-233 , "9.242641644587101076e-70"),
  (0xf.be3d87da323be87p-156, "1.7235014706998294962e-46"),
  (0xb.d809f3772d38a59p-150, "8.298420730548195494e-45"),
  (0xb.61d88e478a80191p-136, "1.3066137006059396529e-40"),
  (0x8.7e6e301b42330f6p-115, "2.044824541427335683e-34"),
  (0xe.280cfad818ffc45p-115, "3.408040902378892805e-34"),
  (0x8.7e6e301b42330f6p-114, "4.089649082854671366e-34"),
  (0xe.280cfad818ffc45p-114, "6.81608180475778561e-34"),
  (0x8.7e6e301b42330f6p-113, "8.179298165709342732e-34"),
  (0xe.280cfad818ffc45p-113, "1.363216360951557122e-33"),
  (0xe.280cfad818ffc45p-112, "2.726432721903114244e-33"),
  (0xe.280cfad818ffc45p-111, "5.452865443806228488e-33"),
  (0xe.280cfad818ffc45p-110, "1.0905730887612456976e-32"),
  (0xc.09de12b2b8b462p+169 , "9.008308715099773956e+51"),
  (0xc.eb461a5ceb157bep+196, "1.2975058974374774429e+60"),
  (0xd.f29472fdfc52a5ep+202, "8.965157263531703087e+61"),
  (0x9.63a86496b5f39b5p+206, "9.656322849684964617e+62"),
  (0xf.aab4e43915de71bp+239, "1.3840439837858165139e+73"),
  (0xf.135bf3c301b911ap+239, "1.3318159089259743813e+73"),
  (0xe.7c03034ced93b19p+239, "1.2795878340661322487e+73"),
  (0xd.e4aa12d6d96e518p+239, "1.2273597592062901161e+73"),
  (0xd.4d512260c548f17p+239, "1.1751316843464479835e+73"),
  (0xc.b5f831eab123916p+239, "1.1229036094866058509e+73"),
  (0xc.1e9f41749cfe315p+239, "1.0706755346267637183e+73"),
  (0xa.efed608874b3713p+239, "9.662193849070794531e+72"),
  (0xa.58947012608e112p+239, "9.139913100472373205e+72"),
  (0x9.c13b7f9c4c68b11p+239, "8.617632351873951879e+72"),
  (0x9.29e28f26384351p+239 , "8.095351603275530553e+72"),
  (0x8.92899eb0241df0fp+239, "7.573070854677109227e+72"),
  (0xa.58947012608e112p+240, "1.827982620094474641e+73"),
  (0xa.58947012608e112p+241, "3.655965240188949282e+73"),
  (0xa.58947012608e112p+242, "7.311930480377898564e+73"),
  (0xd.4d512260c548f17p+242, "9.401053474771583868e+73"),
  (0xc.9240ee0f9d5e4d6p+252, "9.097859174935622588e+76"),
]
#endif

let PrintTests = TestSuite("FloatingPointPrinting")

// Float16 handled separately in PrintFloat16.swift
% for FloatType in ['Float', 'Double', 'Float80']:
% if FloatType == 'Float80':
#if !os(Windows) && (arch(i386) || arch(x86_64))
% end

// Verify that a particular value provides a specific description string.
// Also check that the generated strings actually satisfy our
// accuracy requirements.
fileprivate func expectDescription(_ expected: String, _ object: ${FloatType},
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  expectEqual(expected, object.description,
    message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  expectEqual(expected, object.debugDescription,
    message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  expectAccurateDescription(object,
    message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
}

// Verify our key requirements:
//
// * Accurate.  A formatted float should parse back to exactly the original
//   value.
//
// * Short. The formatted value should use the minimum number of digits needed
//   to be accurate.
//
// * Close. If there is more than one accurate and short value, we want the one
//   that is closest (as an infinitely-precise real number) to the original
//   binary float (interpreted as an infinitely-precise real number).
fileprivate func expectAccurateDescription(_ object: ${FloatType},
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if !object.isFinite {
    return
  }

  // Following checks all return early on failure, since it makes no sense to
  // check shortness if the result is inaccurate, etc.

  // Verify round-trip accuracy:
  let text = object.debugDescription
  if let roundTrip = ${FloatType}(text) {
    if object != roundTrip {
      expectationFailure("Round-trip inaccuracy: \(object) != \(roundTrip)",
        trace: message(),
        stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
      return
    }
  } else {
    expectationFailure("Failed to parse \(text)",
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
    return
  }

  // TODO: Verify shortness by trimming the last digit and checking
  // that the result does NOT round-trip.

  // TODO: Verify closeness by fuzzing the last digit and checking
  // that the result is not closer.  Note this requires higher-precision
  // arithmetic.
}
% if FloatType == 'Float80':
#endif
% end
% end

// Special helper for NaN values
fileprivate func expectNaN<T>(_ expected: String, _ object: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where T: FloatingPoint & CustomDebugStringConvertible & CustomStringConvertible {
  // Regular description always returns "nan"
  expectEqual("nan", object.description,
    message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

  // debugDescription tries to print details about NaNs, which is tricky to test.

/*
  // We cannot reliably test the exact expected string, because various
  // implementations force all NaNs quiet, discard payloads, or clear sign bits.
  // In some cases, just passing a NaN into a function (via an FP register) is
  // enough to mangle the value.
  expectEqual(expected, object.debugDescription,
    message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
*/

  // We can verify that the generated debugDescription text
  // follows the expected general format, even when we can't verify the exact value.
  var actual = object.debugDescription

  // Optional leading "-"
  if actual.hasPrefix("-") {
    actual = String(actual.dropFirst())
  }

  // Optional leading "s"
  if actual.hasPrefix("s") {
    actual = String(actual.dropFirst())
  }

  // Fixed text "nan"
  if actual.prefix(3) != "nan" {
    expectationFailure("Badly formatted NaN debug description (expected 'nan'): \(object.debugDescription)", trace:
      message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
    return
  }
  actual = String(actual.dropFirst(3))

  // Optional parenthesized payload after "nan"
  if actual.hasPrefix("(0x") {
    actual = String(actual.dropFirst(3))
    while !actual.isEmpty {
      if actual.hasPrefix(")") {
        if actual != ")" {
          expectationFailure("Malformed NaN: extra text after payload: \(object.debugDescription)", trace:
            message(),
            stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
        }
        return
      } else {
        // TODO: verify hex digit
      }
      actual = String(actual.dropFirst())
    }
    expectationFailure("Malformed NaN: no closing parenthesis after payload: \(object.debugDescription)", trace:
      message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  } else if !actual.isEmpty {
    expectationFailure("Badly formatted NaN debug description has invalid text after 'nan'.  Expected '(0x': \(object.debugDescription)", trace:
      message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

// Foundation's String(format:) isn't available here, so
// build up "1e-234" manually:
fileprivate func exponentialPowerOfTen(_ power: Int) -> String {
  let digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
  var s = "1e"
  var p = power
  if p < 0 {
    s += "-"
    p = -p
  } else {
    s += "+"
  }
  if (p > 999) {
    s += digits[ (p / 1000) % 10]
  }
  if (p > 99) {
    s += digits[ (p / 100) % 10]
  }
  s += digits[ (p / 10) % 10]
  s += digits[ p % 10]
  return s
}

// An earlier version of Swift's floating-point `.description` logic
// used potentially locale-sensitive C library functions, hence
// this logic to help verify that the output does not depend on
// the C locale.
PrintTests.setUp {
  if let localeArgIndex = CommandLine.arguments.firstIndex(of: "--locale") {
    let locale = CommandLine.arguments[localeArgIndex + 1]
    expectEqual("ru_RU.UTF-8", locale)
    setlocale(LC_ALL, locale)
  } else {
    setlocale(LC_ALL, "")
  }
}

// Check that all floating point types
// are CustomStringConvertible
PrintTests.test("CustomStringConvertible") {
  func hasDescription(_ any: Any) {
    expectTrue(any is CustomStringConvertible)
  }

  hasDescription(Float(1.0))
  hasDescription(Double(1.0))
#if !os(Windows) && (arch(i386) || arch(x86_64))
  hasDescription(Float80(1.0))
#endif
  hasDescription(CFloat(1.0))
  hasDescription(CDouble(1.0))
}

// Check that all floating point types
// are CustomDebugStringConvertible
PrintTests.test("CustomDebugStringConvertible") {
  func hasDebugDescription(_ any: Any) {
    expectTrue(any is CustomDebugStringConvertible)
  }

  hasDebugDescription(Float(1.0))
  hasDebugDescription(Double(1.0))
#if !os(Windows) && (arch(i386) || arch(x86_64))
  hasDebugDescription(Float80(1.0))
#endif
  hasDebugDescription(CFloat(1.0))
  hasDebugDescription(CDouble(1.0))
}

PrintTests.test("Printable_CFloat") {
  // Basic check for CFloat: Since it's a synonym for Float, we don't
  // need more detailed verification, just basic soundness.
  expectDescription("1.0", CFloat(1.0))
  expectDescription("1.1", CFloat(1.1))
  expectDescription("-1.0", CFloat(-1.0))
}

PrintTests.test("Printable_CDouble") {
  // Likewise for CDouble
  expectDescription("1.0", CDouble(1.0))
  expectDescription("1.1", CDouble(1.1))
  expectDescription("-1.0", CDouble(-1.0))
}

PrintTests.test("Printable_Float") {
  func asFloat32(_ f: Float32) -> Float32 { return f }

  // Basic soundness checks:
  let f = 100.125 as Float
  expectEqual("f = 100.125", "f = \(f)")

  expectDescription("0.0", asFloat32(0.0))
  expectDescription("-0.0", -asFloat32(0.0))
  expectDescription("0.1", asFloat32(0.1))
  expectDescription("-0.1", asFloat32(-0.1))
  expectDescription("1.0", asFloat32(1.0))
  expectDescription("-1.0", asFloat32(-1.0))
  expectDescription("1.1", asFloat32(1.1))
  expectDescription("100.125", asFloat32(100.125))
  expectDescription("-100.125", asFloat32(-100.125))

  // Standard special numbers:
  expectDescription("inf", Float.infinity)
  expectDescription("-inf", -Float.infinity)
  expectDescription("3.1415925", Float.pi)
  expectDescription("3.4028235e+38", Float.greatestFiniteMagnitude)
#if !arch(arm)
  expectDescription("1e-45", Float.leastNonzeroMagnitude)
#endif
  expectDescription("1.1754944e-38", Float.leastNormalMagnitude)

  // Special cases for the underlying algorithms:
  // Smallest Float that requires 9 digits to print accurately
  expectDescription("1.00000075e-36", 1.00000075e-36 as Float)
  // Worst case for shortness:
  // Float for which the shortest accurate decimal form is
  // closest to the midpoint between two binary floats
  expectDescription("7.0385313e-26", 7.0385313e-26 as Float)
  // Second-worst case for shortness:
  expectDescription("7.038531e-26", Float("7.038531e-26")!)
  // Note: The above test computes the reference value from a
  // string because `7.038531e-26 as Float` is broken.
  //
  // See https://github.com/apple/swift/issues/49672.

  // NaNs require special care in testing:
  // NaN is printed with additional detail to debugDescription, but not description
  expectNaN("nan", Float.nan)
  expectNaN("nan(0xffff)", Float(nan: 65535, signaling: false))
  expectNaN("nan(0x1fffff)", Float(bitPattern: 0x7fff_ffff))
  expectNaN("nan(0x1fffff)", Float(bitPattern: 0x7fdf_ffff))
  expectNaN("-nan", -Float.nan)
  expectNaN("-nan(0xffff)", -Float(nan: 65535, signaling: false))
  expectNaN("snan", Float.signalingNaN)
  expectNaN("-snan", -Float.signalingNaN)
  expectNaN("snan(0xffff)", Float(nan: 65535, signaling: true))
  expectNaN("-snan(0xffff)", -Float(nan: 65535, signaling: true))
  expectNaN("snan(0x1fffff)", Float(bitPattern: 0x7fbf_ffff))
  // Streamed, interpolated, and printed forms should always match "nan".
  do {
    let value = -Float(nan: 65535, signaling: true)
    var streamed = ""
    value.write(to: &streamed)
    expectEqual("nan", streamed)
    expectEqual("nan", "\(value)")
    var printed = ""
    print(value, terminator: "", to: &printed)
    expectEqual("nan", printed)
  }

  // Every power of 10 should print with only a single digit '1'
#if arch(arm)
  let lowerBound = -37
#else
  let lowerBound = -45
#endif
  for power in lowerBound ... 38 {
    let s: String
    if power < -4 || power > 7 { // Exponential form
      s = exponentialPowerOfTen(power)
    } else if power < 0 { // Fractional decimal form
      s = "0." + String(repeating: "0", count: -power - 1) + "1"
    } else { // Decimal form
      s = "1" + String(repeating: "0", count: power) + ".0"
    }
    let f = Float(s)!
    expectDescription(s, f)
  }

  // Test the 170 "worst cases" listed above.
  for (f,s) in generatedCases_Float {
    expectAccurateDescription(f.nextDown)
    expectDescription(s, f)
    expectAccurateDescription(f.nextUp)
  }

  // Float can represent all integers -(2^24)...(2^24)
  let maxDecimalForm = Float(1 << 24)
  expectDescription("16777216.0", maxDecimalForm)
  expectDescription("-16777216.0", -maxDecimalForm)
  // Outside of that range, use exponential form
  expectDescription("1.6777218e+07", maxDecimalForm.nextUp)
  expectDescription("-1.6777218e+07", -maxDecimalForm.nextUp)

  expectDescription("1.00001", asFloat32(1.00001))
  expectDescription("1.25e+17", asFloat32(125000000000000000.0))
  expectDescription("1.25e+16", asFloat32(12500000000000000.0))
  expectDescription("1.25e+15", asFloat32(1250000000000000.0))
  expectDescription("1.25e+14", asFloat32(125000000000000.0))
  expectDescription("1.25e+13", asFloat32(12500000000000.0))
  expectDescription("1.25e+12", asFloat32(1250000000000.0))
  expectDescription("1.25e+11", asFloat32(125000000000.0))
  expectDescription("1.25e+10", asFloat32(12500000000.0))
  expectDescription("1.25e+09", asFloat32(1250000000.0))
  expectDescription("1.25e+08", asFloat32(125000000.0))
  expectDescription("12500000.0", asFloat32(12500000.0))
  expectDescription("1250000.0", asFloat32(1250000.0))
  expectDescription("125000.0", asFloat32(125000.0))
  expectDescription("12500.0",  asFloat32(12500.0))
  expectDescription("1250.0",   asFloat32(1250.0))
  expectDescription("125.0",    asFloat32(125.0))
  expectDescription("12.5",     asFloat32(12.5))
  expectDescription("1.25",     asFloat32(1.25))
  expectDescription("0.125",    asFloat32(0.125))
  expectDescription("0.0125",   asFloat32(0.0125))
  expectDescription("0.00125",  asFloat32(0.00125))
  expectDescription("0.000125", asFloat32(0.000125))
  expectDescription("1.25e-05", asFloat32(0.0000125))
  expectDescription("1.25e-06", asFloat32(0.00000125))
  expectDescription("1.25e-07", asFloat32(0.000000125))
  expectDescription("1.25e-08", asFloat32(0.0000000125))
  expectDescription("1.25e-09", asFloat32(0.00000000125))
  expectDescription("1.25e-10", asFloat32(0.000000000125))
  expectDescription("1.25e-11", asFloat32(0.0000000000125))
  expectDescription("1.25e-12", asFloat32(0.00000000000125))
  expectDescription("1.25e-13", asFloat32(0.000000000000125))
  expectDescription("1.25e-14", asFloat32(0.0000000000000125))
  expectDescription("1.25e-15", asFloat32(0.00000000000000125))
  expectDescription("1.25e-16", asFloat32(0.000000000000000125))
  expectDescription("1.25e-17", asFloat32(0.0000000000000000125))
}

PrintTests.test("Printable_Double") {
  func asFloat64(_ f: Float64) -> Float64 { return f }

  // Soundness check
  let f = 100.125 as Double
  expectEqual("f = 100.125", "f = \(f)")

  expectDescription("0.0", asFloat64(0.0))
  expectDescription("-0.0", asFloat64(-0.0))
  expectDescription("0.1", asFloat64(0.1))
  expectDescription("-0.1", asFloat64(-0.1))
  expectDescription("1.0", asFloat64(1.0))
  expectDescription("-1.0", asFloat64(-1.0))
  expectDescription("1.1", asFloat64(1.1))
  expectDescription("100.125", asFloat64(100.125))
  expectDescription("-100.125", asFloat64(-100.125))

  // Special values
  expectDescription("3.141592653589793", Double.pi)
  expectDescription("1.7976931348623157e+308", Double.greatestFiniteMagnitude)
#if !arch(arm)
  expectDescription("5e-324", Double.leastNonzeroMagnitude)
#endif
  expectDescription("2.2250738585072014e-308", Double.leastNormalMagnitude)
  expectDescription("inf", Double.infinity)
  expectDescription("-inf", -Double.infinity)
  // Worst case for Double shortness:
  expectDescription("2.311989689387339e-82", 2.311989689387339e-82)

  // Verify NaNs
  expectNaN("nan", Double.nan)
  expectNaN("-nan", -Double.nan)
  expectNaN("nan(0xffff)", Double(nan: 65535, signaling: false))
  expectNaN("nan(0x3ffffffffffff)", Float64(bitPattern: 0x7fff_ffff_ffff_ffff))
  expectNaN("nan(0x3ffffffffffff)", Float64(bitPattern: 0x7ffb_ffff_ffff_ffff))
  expectNaN("-nan(0xffff)", -Double(nan: 65535, signaling: false))
  expectNaN("snan", Double.signalingNaN)
  expectNaN("-snan", -Double.signalingNaN)
  expectNaN("snan(0xffff)", Double(nan: 65535, signaling: true))
  expectNaN("-snan(0xffff)", -Double(nan: 65535, signaling: true))
  expectNaN("snan(0x3ffffffffffff)", Float64(bitPattern: 0x7ff7_ffff_ffff_ffff))

  // We know how every power of 10 should print
#if arch(arm)
  let lowerBound = -307
#else
  let lowerBound = -323
#endif
  for power in lowerBound ... 308 {
    let s: String
    if power < -4 || power > 15 { // Exponential form
      s = exponentialPowerOfTen(power)
    } else if power < 0 { // Fractional decimal form
      s = "0." + String(repeating: "0", count: -power - 1) + "1"
    } else { // Decimal form
      s = "1" + String(repeating: "0", count: power) + ".0"
    }
    let f = Double(s)!
    expectDescription(s, f)
  }

  // Verify 74 extreme values generated using a technique from the Errol paper,
  // plus many nearby values.
  for (d, s) in generatedCases_Double {
    expectDescription(s, d)

    // Also check nearby values.
    var upCase = d
    var downCase = d
    for _ in 0..<10 {
      upCase = upCase.nextUp
      expectAccurateDescription(upCase)
      downCase = downCase.nextDown
      expectAccurateDescription(downCase)
    }
  }

  // Double can represent all integers -(2^53)...(2^53)
  let maxDecimalForm = Double((1 as Int64) << 53)
  expectDescription("9007199254740992.0", maxDecimalForm)
  expectDescription("-9007199254740992.0", -maxDecimalForm)
  // Outside of that range, we use exponential form:
  expectDescription("9.007199254740994e+15", maxDecimalForm.nextUp)
  expectDescription("-9.007199254740994e+15", -maxDecimalForm.nextUp)

  expectDescription("1.00000000000001", asFloat64(1.00000000000001))
  expectDescription("1.25e+17", asFloat64(125000000000000000.0))
  expectDescription("1.25e+16", asFloat64(12500000000000000.0))
  expectDescription("1250000000000000.0", asFloat64(1250000000000000.0))
  expectDescription("125000000000000.0", asFloat64(125000000000000.0))
  expectDescription("12500000000000.0", asFloat64(12500000000000.0))
  expectDescription("1250000000000.0", asFloat64(1250000000000.0))
  expectDescription("125000000000.0", asFloat64(125000000000.0))
  expectDescription("12500000000.0", asFloat64(12500000000.0))
  expectDescription("1250000000.0", asFloat64(1250000000.0))
  expectDescription("125000000.0", asFloat64(125000000.0))
  expectDescription("12500000.0", asFloat64(12500000.0))
  expectDescription("1250000.0", asFloat64(1250000.0))
  expectDescription("125000.0", asFloat64(125000.0))
  expectDescription("12500.0", asFloat64(12500.0))
  expectDescription("1250.0", asFloat64(1250.0))
  expectDescription("125.0", asFloat64(125.0))
  expectDescription("12.5", asFloat64(12.5))
  expectDescription("1.25", asFloat64(1.25))
  expectDescription("0.125", asFloat64(0.125))
  expectDescription("0.0125", asFloat64(0.0125))
  expectDescription("0.00125", asFloat64(0.00125))
  expectDescription("0.000125", asFloat64(0.000125))
  expectDescription("1.25e-05", asFloat64(0.0000125))
  expectDescription("1.25e-06", asFloat64(0.00000125))
  expectDescription("1.25e-07", asFloat64(0.000000125))
  expectDescription("1.25e-08", asFloat64(0.0000000125))
  expectDescription("1.25e-09", asFloat64(0.00000000125))
  expectDescription("1.25e-10", asFloat64(0.000000000125))
  expectDescription("1.25e-11", asFloat64(0.0000000000125))
  expectDescription("1.25e-12", asFloat64(0.00000000000125))
  expectDescription("1.25e-13", asFloat64(0.000000000000125))
  expectDescription("1.25e-14", asFloat64(0.0000000000000125))
  expectDescription("1.25e-15", asFloat64(0.00000000000000125))
  expectDescription("1.25e-16", asFloat64(0.000000000000000125))
  expectDescription("1.25e-17", asFloat64(0.0000000000000000125))
}

PrintTests.test("Printable_Float80") {
#if !os(Windows) && (arch(i386) || arch(x86_64))
  func asFloat80(_ f: Swift.Float80) -> Swift.Float80 { return f }

  // Soundness
  let f = 100.125 as Float80
  expectEqual("f = 100.125", "f = \(f)")

  expectDescription("0.0", asFloat80(0.0))
  expectDescription("-0.0", -asFloat80(0.0))
  expectDescription("0.1", asFloat80(0.1))
  expectDescription("-0.1", asFloat80(-0.1))
  expectDescription("1.0", asFloat80(1.0))
  expectDescription("-1.0", asFloat80(-1.0))
  expectDescription("1.1", asFloat80(1.1))
  expectDescription("100.125", asFloat80(100.125))
  expectDescription("-100.125", asFloat80(-100.125))

  // Special values
  expectDescription("3.1415926535897932385", Float80.pi)
  expectDescription("1.189731495357231765e+4932", Float80.greatestFiniteMagnitude)
  expectDescription("4e-4951", Float80.leastNonzeroMagnitude)
  expectDescription("3.3621031431120935063e-4932", Float80.leastNormalMagnitude)
  expectDescription("inf", Float80.infinity)
  expectDescription("-inf", -Float80.infinity)

  // NaNs
  expectNaN("nan", Float80.nan)
  expectNaN("nan(0xffff)", Float80(nan: 65535, signaling: false))
  expectNaN("nan(0x1fffffffffffffff)", Float80(sign: .plus, exponentBitPattern: 0x7fff, significandBitPattern: 0xffff_ffff_ffff_ffff))
  expectNaN("nan(0x1fffffffffffffff)", Float80(sign: .plus, exponentBitPattern: 0x7fff, significandBitPattern: 0xdfff_ffff_ffff_ffff))
  expectNaN("-nan", -Float80.nan)
  expectNaN("-nan(0xffff)", -Float80(nan: 65535, signaling: false))
  expectNaN("snan", Float80.signalingNaN)
  expectNaN("-snan", -Float80.signalingNaN)
  expectNaN("snan(0xffff)", Float80(nan: 65535, signaling: true))
  expectNaN("-snan(0xffff)", -Float80(nan: 65535, signaling: true))
  expectNaN("snan(0x1fffffffffffffff)", Float80(sign: .plus, exponentBitPattern: 0x7fff, significandBitPattern: 0xbfff_ffff_ffff_ffff))

  // We know how every power of 10 should print
  for power in -4950 ... 4932 {
    let s: String
    if power < -4 || power > 19 { // Exponential form
      s = exponentialPowerOfTen(power)
    } else if power < 0 { // Fractional decimal form
      s = "0." + String(repeating: "0", count: -power - 1) + "1"
    } else { // Decimal form
      s = "1" + String(repeating: "0", count: power) + ".0"
    }
    let f = Float80(s)!
    expectDescription(s, f)
  }

  // Verify the extreme cases generated via the Errol technique.
  for (d, s) in generatedCases_Float80 {
    expectDescription(s, d)

    var upCase = d
    var downCase = d
    for _ in 0..<10 {
      upCase = upCase.nextUp
      expectAccurateDescription(upCase)
      downCase = downCase.nextDown
      expectAccurateDescription(downCase)
    }
  }

  // Float80 can represent all integers -(2^64)...(2^64):
  let maxDecimalForm = Float80(UInt64.max) + 1.0
  expectDescription("18446744073709551616.0", maxDecimalForm)
  expectDescription("-18446744073709551616.0", -maxDecimalForm)
  // Outside of that range, use exponential form
  expectDescription("1.8446744073709551618e+19", maxDecimalForm.nextUp)
  expectDescription("-1.8446744073709551618e+19", -maxDecimalForm.nextUp)

  expectDescription("1.00000000000000001", asFloat80(1.00000000000000001))
  expectDescription("1.25e+21", asFloat80(1250000000000000000000.0))
  expectDescription("1.25e+20", asFloat80(125000000000000000000.0))
  expectDescription("12500000000000000000.0", asFloat80(12500000000000000000.0))
  expectDescription("1250000000000000000.0", asFloat80(1250000000000000000.0))
  expectDescription("125000000000000000.0", asFloat80(125000000000000000.0))
  expectDescription("12500000000000000.0", asFloat80(12500000000000000.0))
  expectDescription("1250000000000000.0", asFloat80(1250000000000000.0))
  expectDescription("125000000000000.0", asFloat80(125000000000000.0))
  expectDescription("12500000000000.0", asFloat80(12500000000000.0))
  expectDescription("1250000000000.0", asFloat80(1250000000000.0))
  expectDescription("125000000000.0", asFloat80(125000000000.0))
  expectDescription("12500000000.0", asFloat80(12500000000.0))
  expectDescription("1250000000.0", asFloat80(1250000000.0))
  expectDescription("125000000.0", asFloat80(125000000.0))
  expectDescription("12500000.0", asFloat80(12500000.0))
  expectDescription("1250000.0", asFloat80(1250000.0))
  expectDescription("125000.0", asFloat80(125000.0))
  expectDescription("12500.0", asFloat80(12500.0))
  expectDescription("1250.0", asFloat80(1250.0))
  expectDescription("125.0", asFloat80(125.0))
  expectDescription("12.5", asFloat80(12.5))
  expectDescription("1.25", asFloat80(1.25))
  expectDescription("0.125", asFloat80(0.125))
  expectDescription("0.0125", asFloat80(0.0125))
  expectDescription("0.00125", asFloat80(0.00125))
  expectDescription("0.000125", asFloat80(0.000125))
  expectDescription("1.25e-05", asFloat80(0.0000125))
  expectDescription("1.25e-06", asFloat80(0.00000125))
  expectDescription("1.25e-07", asFloat80(0.000000125))
  expectDescription("1.25e-08", asFloat80(0.0000000125))
  expectDescription("1.25e-09", asFloat80(0.00000000125))
  expectDescription("1.25e-10", asFloat80(0.000000000125))
  expectDescription("1.25e-11", asFloat80(0.0000000000125))
  expectDescription("1.25e-12", asFloat80(0.00000000000125))
  expectDescription("1.25e-13", asFloat80(0.000000000000125))
  expectDescription("1.25e-14", asFloat80(0.0000000000000125))
  expectDescription("1.25e-15", asFloat80(0.00000000000000125))
  expectDescription("1.25e-16", asFloat80(0.000000000000000125))
  expectDescription("1.25e-17", asFloat80(0.0000000000000000125))
#endif
}

runAllTests()
