Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 1 | // Copyright 2018 The Abseil Authors. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "absl/strings/charconv.h" |
| 16 | |
| 17 | #include <cstdlib> |
| 18 | #include <string> |
| 19 | |
| 20 | #include "gmock/gmock.h" |
| 21 | #include "gtest/gtest.h" |
| 22 | #include "absl/strings/internal/pow10_helper.h" |
| 23 | #include "absl/strings/str_cat.h" |
| 24 | #include "absl/strings/str_format.h" |
| 25 | |
| 26 | #ifdef _MSC_FULL_VER |
| 27 | #define ABSL_COMPILER_DOES_EXACT_ROUNDING 0 |
| 28 | #define ABSL_STRTOD_HANDLES_NAN_CORRECTLY 0 |
| 29 | #else |
| 30 | #define ABSL_COMPILER_DOES_EXACT_ROUNDING 1 |
| 31 | #define ABSL_STRTOD_HANDLES_NAN_CORRECTLY 1 |
| 32 | #endif |
| 33 | |
| 34 | namespace { |
| 35 | |
| 36 | using absl::strings_internal::Pow10; |
| 37 | |
| 38 | #if ABSL_COMPILER_DOES_EXACT_ROUNDING |
| 39 | |
| 40 | // Tests that the given string is accepted by absl::from_chars, and that it |
| 41 | // converts exactly equal to the given number. |
| 42 | void TestDoubleParse(absl::string_view str, double expected_number) { |
| 43 | SCOPED_TRACE(str); |
| 44 | double actual_number = 0.0; |
| 45 | absl::from_chars_result result = |
| 46 | absl::from_chars(str.data(), str.data() + str.length(), actual_number); |
| 47 | EXPECT_EQ(result.ec, std::errc()); |
| 48 | EXPECT_EQ(result.ptr, str.data() + str.length()); |
| 49 | EXPECT_EQ(actual_number, expected_number); |
| 50 | } |
| 51 | |
| 52 | void TestFloatParse(absl::string_view str, float expected_number) { |
| 53 | SCOPED_TRACE(str); |
| 54 | float actual_number = 0.0; |
| 55 | absl::from_chars_result result = |
| 56 | absl::from_chars(str.data(), str.data() + str.length(), actual_number); |
| 57 | EXPECT_EQ(result.ec, std::errc()); |
| 58 | EXPECT_EQ(result.ptr, str.data() + str.length()); |
| 59 | EXPECT_EQ(actual_number, expected_number); |
| 60 | } |
| 61 | |
| 62 | // Tests that the given double or single precision floating point literal is |
| 63 | // parsed correctly by absl::from_chars. |
| 64 | // |
| 65 | // These convenience macros assume that the C++ compiler being used also does |
| 66 | // fully correct decimal-to-binary conversions. |
| 67 | #define FROM_CHARS_TEST_DOUBLE(number) \ |
| 68 | { \ |
| 69 | TestDoubleParse(#number, number); \ |
| 70 | TestDoubleParse("-" #number, -number); \ |
| 71 | } |
| 72 | |
| 73 | #define FROM_CHARS_TEST_FLOAT(number) \ |
| 74 | { \ |
| 75 | TestFloatParse(#number, number##f); \ |
| 76 | TestFloatParse("-" #number, -number##f); \ |
| 77 | } |
| 78 | |
| 79 | TEST(FromChars, NearRoundingCases) { |
| 80 | // Cases from "A Program for Testing IEEE Decimal-Binary Conversion" |
| 81 | // by Vern Paxson. |
| 82 | |
| 83 | // Forms that should round towards zero. (These are the hardest cases for |
| 84 | // each decimal mantissa size.) |
| 85 | FROM_CHARS_TEST_DOUBLE(5.e125); |
| 86 | FROM_CHARS_TEST_DOUBLE(69.e267); |
| 87 | FROM_CHARS_TEST_DOUBLE(999.e-026); |
| 88 | FROM_CHARS_TEST_DOUBLE(7861.e-034); |
| 89 | FROM_CHARS_TEST_DOUBLE(75569.e-254); |
| 90 | FROM_CHARS_TEST_DOUBLE(928609.e-261); |
| 91 | FROM_CHARS_TEST_DOUBLE(9210917.e080); |
| 92 | FROM_CHARS_TEST_DOUBLE(84863171.e114); |
| 93 | FROM_CHARS_TEST_DOUBLE(653777767.e273); |
| 94 | FROM_CHARS_TEST_DOUBLE(5232604057.e-298); |
| 95 | FROM_CHARS_TEST_DOUBLE(27235667517.e-109); |
| 96 | FROM_CHARS_TEST_DOUBLE(653532977297.e-123); |
| 97 | FROM_CHARS_TEST_DOUBLE(3142213164987.e-294); |
| 98 | FROM_CHARS_TEST_DOUBLE(46202199371337.e-072); |
| 99 | FROM_CHARS_TEST_DOUBLE(231010996856685.e-073); |
| 100 | FROM_CHARS_TEST_DOUBLE(9324754620109615.e212); |
| 101 | FROM_CHARS_TEST_DOUBLE(78459735791271921.e049); |
| 102 | FROM_CHARS_TEST_DOUBLE(272104041512242479.e200); |
| 103 | FROM_CHARS_TEST_DOUBLE(6802601037806061975.e198); |
| 104 | FROM_CHARS_TEST_DOUBLE(20505426358836677347.e-221); |
| 105 | FROM_CHARS_TEST_DOUBLE(836168422905420598437.e-234); |
| 106 | FROM_CHARS_TEST_DOUBLE(4891559871276714924261.e222); |
| 107 | FROM_CHARS_TEST_FLOAT(5.e-20); |
| 108 | FROM_CHARS_TEST_FLOAT(67.e14); |
| 109 | FROM_CHARS_TEST_FLOAT(985.e15); |
| 110 | FROM_CHARS_TEST_FLOAT(7693.e-42); |
| 111 | FROM_CHARS_TEST_FLOAT(55895.e-16); |
| 112 | FROM_CHARS_TEST_FLOAT(996622.e-44); |
| 113 | FROM_CHARS_TEST_FLOAT(7038531.e-32); |
| 114 | FROM_CHARS_TEST_FLOAT(60419369.e-46); |
| 115 | FROM_CHARS_TEST_FLOAT(702990899.e-20); |
| 116 | FROM_CHARS_TEST_FLOAT(6930161142.e-48); |
| 117 | FROM_CHARS_TEST_FLOAT(25933168707.e-13); |
| 118 | FROM_CHARS_TEST_FLOAT(596428896559.e20); |
| 119 | |
| 120 | // Similarly, forms that should round away from zero. |
| 121 | FROM_CHARS_TEST_DOUBLE(9.e-265); |
| 122 | FROM_CHARS_TEST_DOUBLE(85.e-037); |
| 123 | FROM_CHARS_TEST_DOUBLE(623.e100); |
| 124 | FROM_CHARS_TEST_DOUBLE(3571.e263); |
| 125 | FROM_CHARS_TEST_DOUBLE(81661.e153); |
| 126 | FROM_CHARS_TEST_DOUBLE(920657.e-023); |
| 127 | FROM_CHARS_TEST_DOUBLE(4603285.e-024); |
| 128 | FROM_CHARS_TEST_DOUBLE(87575437.e-309); |
| 129 | FROM_CHARS_TEST_DOUBLE(245540327.e122); |
| 130 | FROM_CHARS_TEST_DOUBLE(6138508175.e120); |
| 131 | FROM_CHARS_TEST_DOUBLE(83356057653.e193); |
| 132 | FROM_CHARS_TEST_DOUBLE(619534293513.e124); |
| 133 | FROM_CHARS_TEST_DOUBLE(2335141086879.e218); |
| 134 | FROM_CHARS_TEST_DOUBLE(36167929443327.e-159); |
| 135 | FROM_CHARS_TEST_DOUBLE(609610927149051.e-255); |
| 136 | FROM_CHARS_TEST_DOUBLE(3743626360493413.e-165); |
| 137 | FROM_CHARS_TEST_DOUBLE(94080055902682397.e-242); |
| 138 | FROM_CHARS_TEST_DOUBLE(899810892172646163.e283); |
| 139 | FROM_CHARS_TEST_DOUBLE(7120190517612959703.e120); |
| 140 | FROM_CHARS_TEST_DOUBLE(25188282901709339043.e-252); |
| 141 | FROM_CHARS_TEST_DOUBLE(308984926168550152811.e-052); |
| 142 | FROM_CHARS_TEST_DOUBLE(6372891218502368041059.e064); |
| 143 | FROM_CHARS_TEST_FLOAT(3.e-23); |
| 144 | FROM_CHARS_TEST_FLOAT(57.e18); |
| 145 | FROM_CHARS_TEST_FLOAT(789.e-35); |
| 146 | FROM_CHARS_TEST_FLOAT(2539.e-18); |
| 147 | FROM_CHARS_TEST_FLOAT(76173.e28); |
| 148 | FROM_CHARS_TEST_FLOAT(887745.e-11); |
| 149 | FROM_CHARS_TEST_FLOAT(5382571.e-37); |
| 150 | FROM_CHARS_TEST_FLOAT(82381273.e-35); |
| 151 | FROM_CHARS_TEST_FLOAT(750486563.e-38); |
| 152 | FROM_CHARS_TEST_FLOAT(3752432815.e-39); |
| 153 | FROM_CHARS_TEST_FLOAT(75224575729.e-45); |
| 154 | FROM_CHARS_TEST_FLOAT(459926601011.e15); |
| 155 | } |
| 156 | |
| 157 | #undef FROM_CHARS_TEST_DOUBLE |
| 158 | #undef FROM_CHARS_TEST_FLOAT |
| 159 | #endif |
| 160 | |
| 161 | float ToFloat(absl::string_view s) { |
| 162 | float f; |
| 163 | absl::from_chars(s.data(), s.data() + s.size(), f); |
| 164 | return f; |
| 165 | } |
| 166 | |
| 167 | double ToDouble(absl::string_view s) { |
| 168 | double d; |
| 169 | absl::from_chars(s.data(), s.data() + s.size(), d); |
| 170 | return d; |
| 171 | } |
| 172 | |
| 173 | // A duplication of the test cases in "NearRoundingCases" above, but with |
| 174 | // expected values expressed with integers, using ldexp/ldexpf. These test |
| 175 | // cases will work even on compilers that do not accurately round floating point |
| 176 | // literals. |
| 177 | TEST(FromChars, NearRoundingCasesExplicit) { |
| 178 | EXPECT_EQ(ToDouble("5.e125"), ldexp(6653062250012735, 365)); |
| 179 | EXPECT_EQ(ToDouble("69.e267"), ldexp(4705683757438170, 841)); |
| 180 | EXPECT_EQ(ToDouble("999.e-026"), ldexp(6798841691080350, -129)); |
| 181 | EXPECT_EQ(ToDouble("7861.e-034"), ldexp(8975675289889240, -153)); |
| 182 | EXPECT_EQ(ToDouble("75569.e-254"), ldexp(6091718967192243, -880)); |
| 183 | EXPECT_EQ(ToDouble("928609.e-261"), ldexp(7849264900213743, -900)); |
| 184 | EXPECT_EQ(ToDouble("9210917.e080"), ldexp(8341110837370930, 236)); |
| 185 | EXPECT_EQ(ToDouble("84863171.e114"), ldexp(4625202867375927, 353)); |
| 186 | EXPECT_EQ(ToDouble("653777767.e273"), ldexp(5068902999763073, 884)); |
| 187 | EXPECT_EQ(ToDouble("5232604057.e-298"), ldexp(5741343011915040, -1010)); |
| 188 | EXPECT_EQ(ToDouble("27235667517.e-109"), ldexp(6707124626673586, -380)); |
| 189 | EXPECT_EQ(ToDouble("653532977297.e-123"), ldexp(7078246407265384, -422)); |
| 190 | EXPECT_EQ(ToDouble("3142213164987.e-294"), ldexp(8219991337640559, -988)); |
| 191 | EXPECT_EQ(ToDouble("46202199371337.e-072"), ldexp(5224462102115359, -246)); |
| 192 | EXPECT_EQ(ToDouble("231010996856685.e-073"), ldexp(5224462102115359, -247)); |
| 193 | EXPECT_EQ(ToDouble("9324754620109615.e212"), ldexp(5539753864394442, 705)); |
| 194 | EXPECT_EQ(ToDouble("78459735791271921.e049"), ldexp(8388176519442766, 166)); |
| 195 | EXPECT_EQ(ToDouble("272104041512242479.e200"), ldexp(5554409530847367, 670)); |
| 196 | EXPECT_EQ(ToDouble("6802601037806061975.e198"), ldexp(5554409530847367, 668)); |
| 197 | EXPECT_EQ(ToDouble("20505426358836677347.e-221"), |
| 198 | ldexp(4524032052079546, -722)); |
| 199 | EXPECT_EQ(ToDouble("836168422905420598437.e-234"), |
| 200 | ldexp(5070963299887562, -760)); |
| 201 | EXPECT_EQ(ToDouble("4891559871276714924261.e222"), |
| 202 | ldexp(6452687840519111, 757)); |
| 203 | EXPECT_EQ(ToFloat("5.e-20"), ldexpf(15474250, -88)); |
| 204 | EXPECT_EQ(ToFloat("67.e14"), ldexpf(12479722, 29)); |
| 205 | EXPECT_EQ(ToFloat("985.e15"), ldexpf(14333636, 36)); |
| 206 | EXPECT_EQ(ToFloat("7693.e-42"), ldexpf(10979816, -150)); |
| 207 | EXPECT_EQ(ToFloat("55895.e-16"), ldexpf(12888509, -61)); |
| 208 | EXPECT_EQ(ToFloat("996622.e-44"), ldexpf(14224264, -150)); |
| 209 | EXPECT_EQ(ToFloat("7038531.e-32"), ldexpf(11420669, -107)); |
| 210 | EXPECT_EQ(ToFloat("60419369.e-46"), ldexpf(8623340, -150)); |
| 211 | EXPECT_EQ(ToFloat("702990899.e-20"), ldexpf(16209866, -61)); |
| 212 | EXPECT_EQ(ToFloat("6930161142.e-48"), ldexpf(9891056, -150)); |
| 213 | EXPECT_EQ(ToFloat("25933168707.e-13"), ldexpf(11138211, -32)); |
| 214 | EXPECT_EQ(ToFloat("596428896559.e20"), ldexpf(12333860, 82)); |
| 215 | |
| 216 | |
| 217 | EXPECT_EQ(ToDouble("9.e-265"), ldexp(8168427841980010, -930)); |
| 218 | EXPECT_EQ(ToDouble("85.e-037"), ldexp(6360455125664090, -169)); |
| 219 | EXPECT_EQ(ToDouble("623.e100"), ldexp(6263531988747231, 289)); |
| 220 | EXPECT_EQ(ToDouble("3571.e263"), ldexp(6234526311072170, 833)); |
| 221 | EXPECT_EQ(ToDouble("81661.e153"), ldexp(6696636728760206, 472)); |
| 222 | EXPECT_EQ(ToDouble("920657.e-023"), ldexp(5975405561110124, -109)); |
| 223 | EXPECT_EQ(ToDouble("4603285.e-024"), ldexp(5975405561110124, -110)); |
| 224 | EXPECT_EQ(ToDouble("87575437.e-309"), ldexp(8452160731874668, -1053)); |
| 225 | EXPECT_EQ(ToDouble("245540327.e122"), ldexp(4985336549131723, 381)); |
| 226 | EXPECT_EQ(ToDouble("6138508175.e120"), ldexp(4985336549131723, 379)); |
| 227 | EXPECT_EQ(ToDouble("83356057653.e193"), ldexp(5986732817132056, 625)); |
| 228 | EXPECT_EQ(ToDouble("619534293513.e124"), ldexp(4798406992060657, 399)); |
| 229 | EXPECT_EQ(ToDouble("2335141086879.e218"), ldexp(5419088166961646, 713)); |
| 230 | EXPECT_EQ(ToDouble("36167929443327.e-159"), ldexp(8135819834632444, -536)); |
| 231 | EXPECT_EQ(ToDouble("609610927149051.e-255"), ldexp(4576664294594737, -850)); |
| 232 | EXPECT_EQ(ToDouble("3743626360493413.e-165"), ldexp(6898586531774201, -549)); |
| 233 | EXPECT_EQ(ToDouble("94080055902682397.e-242"), ldexp(6273271706052298, -800)); |
| 234 | EXPECT_EQ(ToDouble("899810892172646163.e283"), ldexp(7563892574477827, 947)); |
| 235 | EXPECT_EQ(ToDouble("7120190517612959703.e120"), ldexp(5385467232557565, 409)); |
| 236 | EXPECT_EQ(ToDouble("25188282901709339043.e-252"), |
| 237 | ldexp(5635662608542340, -825)); |
| 238 | EXPECT_EQ(ToDouble("308984926168550152811.e-052"), |
| 239 | ldexp(5644774693823803, -157)); |
| 240 | EXPECT_EQ(ToDouble("6372891218502368041059.e064"), |
| 241 | ldexp(4616868614322430, 233)); |
| 242 | |
| 243 | EXPECT_EQ(ToFloat("3.e-23"), ldexpf(9507380, -98)); |
| 244 | EXPECT_EQ(ToFloat("57.e18"), ldexpf(12960300, 42)); |
| 245 | EXPECT_EQ(ToFloat("789.e-35"), ldexpf(10739312, -130)); |
| 246 | EXPECT_EQ(ToFloat("2539.e-18"), ldexpf(11990089, -72)); |
| 247 | EXPECT_EQ(ToFloat("76173.e28"), ldexpf(9845130, 86)); |
| 248 | EXPECT_EQ(ToFloat("887745.e-11"), ldexpf(9760860, -40)); |
| 249 | EXPECT_EQ(ToFloat("5382571.e-37"), ldexpf(11447463, -124)); |
| 250 | EXPECT_EQ(ToFloat("82381273.e-35"), ldexpf(8554961, -113)); |
| 251 | EXPECT_EQ(ToFloat("750486563.e-38"), ldexpf(9975678, -120)); |
| 252 | EXPECT_EQ(ToFloat("3752432815.e-39"), ldexpf(9975678, -121)); |
| 253 | EXPECT_EQ(ToFloat("75224575729.e-45"), ldexpf(13105970, -137)); |
| 254 | EXPECT_EQ(ToFloat("459926601011.e15"), ldexpf(12466336, 65)); |
| 255 | } |
| 256 | |
| 257 | // Common test logic for converting a string which lies exactly halfway between |
| 258 | // two target floats. |
| 259 | // |
| 260 | // mantissa and exponent represent the precise value between two floating point |
| 261 | // numbers, `expected_low` and `expected_high`. The floating point |
| 262 | // representation to parse in `StrCat(mantissa, "e", exponent)`. |
| 263 | // |
| 264 | // This function checks that an input just slightly less than the exact value |
| 265 | // is rounded down to `expected_low`, and an input just slightly greater than |
| 266 | // the exact value is rounded up to `expected_high`. |
| 267 | // |
| 268 | // The exact value should round to `expected_half`, which must be either |
| 269 | // `expected_low` or `expected_high`. |
| 270 | template <typename FloatType> |
| 271 | void TestHalfwayValue(const std::string& mantissa, int exponent, |
| 272 | FloatType expected_low, FloatType expected_high, |
| 273 | FloatType expected_half) { |
| 274 | std::string low_rep = mantissa; |
| 275 | low_rep[low_rep.size() - 1] -= 1; |
| 276 | absl::StrAppend(&low_rep, std::string(1000, '9'), "e", exponent); |
| 277 | |
| 278 | FloatType actual_low = 0; |
| 279 | absl::from_chars(low_rep.data(), low_rep.data() + low_rep.size(), actual_low); |
| 280 | EXPECT_EQ(expected_low, actual_low); |
| 281 | |
| 282 | std::string high_rep = |
| 283 | absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent); |
| 284 | FloatType actual_high = 0; |
| 285 | absl::from_chars(high_rep.data(), high_rep.data() + high_rep.size(), |
| 286 | actual_high); |
| 287 | EXPECT_EQ(expected_high, actual_high); |
| 288 | |
| 289 | std::string halfway_rep = absl::StrCat(mantissa, "e", exponent); |
| 290 | FloatType actual_half = 0; |
| 291 | absl::from_chars(halfway_rep.data(), halfway_rep.data() + halfway_rep.size(), |
| 292 | actual_half); |
| 293 | EXPECT_EQ(expected_half, actual_half); |
| 294 | } |
| 295 | |
| 296 | TEST(FromChars, DoubleRounding) { |
| 297 | const double zero = 0.0; |
| 298 | const double first_subnormal = nextafter(zero, 1.0); |
| 299 | const double second_subnormal = nextafter(first_subnormal, 1.0); |
| 300 | |
| 301 | const double first_normal = DBL_MIN; |
| 302 | const double last_subnormal = nextafter(first_normal, 0.0); |
| 303 | const double second_normal = nextafter(first_normal, 1.0); |
| 304 | |
| 305 | const double last_normal = DBL_MAX; |
| 306 | const double penultimate_normal = nextafter(last_normal, 0.0); |
| 307 | |
| 308 | // Various test cases for numbers between two representable floats. Each |
| 309 | // call to TestHalfwayValue tests a number just below and just above the |
| 310 | // halfway point, as well as the number exactly between them. |
| 311 | |
| 312 | // Test between zero and first_subnormal. Round-to-even tie rounds down. |
| 313 | TestHalfwayValue( |
| 314 | "2." |
| 315 | "470328229206232720882843964341106861825299013071623822127928412503377536" |
| 316 | "351043759326499181808179961898982823477228588654633283551779698981993873" |
| 317 | "980053909390631503565951557022639229085839244910518443593180284993653615" |
| 318 | "250031937045767824921936562366986365848075700158576926990370631192827955" |
| 319 | "855133292783433840935197801553124659726357957462276646527282722005637400" |
| 320 | "648549997709659947045402082816622623785739345073633900796776193057750674" |
| 321 | "017632467360096895134053553745851666113422376667860416215968046191446729" |
| 322 | "184030053005753084904876539171138659164623952491262365388187963623937328" |
| 323 | "042389101867234849766823508986338858792562830275599565752445550725518931" |
| 324 | "369083625477918694866799496832404970582102851318545139621383772282614543" |
| 325 | "7693412532098591327667236328125", |
| 326 | -324, zero, first_subnormal, zero); |
| 327 | |
| 328 | // first_subnormal and second_subnormal. Round-to-even tie rounds up. |
| 329 | TestHalfwayValue( |
| 330 | "7." |
| 331 | "410984687618698162648531893023320585475897039214871466383785237510132609" |
| 332 | "053131277979497545424539885696948470431685765963899850655339096945981621" |
| 333 | "940161728171894510697854671067917687257517734731555330779540854980960845" |
| 334 | "750095811137303474765809687100959097544227100475730780971111893578483867" |
| 335 | "565399878350301522805593404659373979179073872386829939581848166016912201" |
| 336 | "945649993128979841136206248449867871357218035220901702390328579173252022" |
| 337 | "052897402080290685402160661237554998340267130003581248647904138574340187" |
| 338 | "552090159017259254714629617513415977493871857473787096164563890871811984" |
| 339 | "127167305601704549300470526959016576377688490826798697257336652176556794" |
| 340 | "107250876433756084600398490497214911746308553955635418864151316847843631" |
| 341 | "3080237596295773983001708984375", |
| 342 | -324, first_subnormal, second_subnormal, second_subnormal); |
| 343 | |
| 344 | // last_subnormal and first_normal. Round-to-even tie rounds up. |
| 345 | TestHalfwayValue( |
| 346 | "2." |
| 347 | "225073858507201136057409796709131975934819546351645648023426109724822222" |
| 348 | "021076945516529523908135087914149158913039621106870086438694594645527657" |
| 349 | "207407820621743379988141063267329253552286881372149012981122451451889849" |
| 350 | "057222307285255133155755015914397476397983411801999323962548289017107081" |
| 351 | "850690630666655994938275772572015763062690663332647565300009245888316433" |
| 352 | "037779791869612049497390377829704905051080609940730262937128958950003583" |
| 353 | "799967207254304360284078895771796150945516748243471030702609144621572289" |
| 354 | "880258182545180325707018860872113128079512233426288368622321503775666622" |
| 355 | "503982534335974568884423900265498198385487948292206894721689831099698365" |
| 356 | "846814022854243330660339850886445804001034933970427567186443383770486037" |
| 357 | "86162277173854562306587467901408672332763671875", |
| 358 | -308, last_subnormal, first_normal, first_normal); |
| 359 | |
| 360 | // first_normal and second_normal. Round-to-even tie rounds down. |
| 361 | TestHalfwayValue( |
| 362 | "2." |
| 363 | "225073858507201630123055637955676152503612414573018013083228724049586647" |
| 364 | "606759446192036794116886953213985520549032000903434781884412325572184367" |
| 365 | "563347617020518175998922941393629966742598285899994830148971433555578567" |
| 366 | "693279306015978183162142425067962460785295885199272493577688320732492479" |
| 367 | "924816869232247165964934329258783950102250973957579510571600738343645738" |
| 368 | "494324192997092179207389919761694314131497173265255020084997973676783743" |
| 369 | "155205818804439163810572367791175177756227497413804253387084478193655533" |
| 370 | "073867420834526162513029462022730109054820067654020201547112002028139700" |
| 371 | "141575259123440177362244273712468151750189745559978653234255886219611516" |
| 372 | "335924167958029604477064946470184777360934300451421683607013647479513962" |
| 373 | "13837722826145437693412532098591327667236328125", |
| 374 | -308, first_normal, second_normal, first_normal); |
| 375 | |
| 376 | // penultimate_normal and last_normal. Round-to-even rounds down. |
| 377 | TestHalfwayValue( |
| 378 | "1." |
| 379 | "797693134862315608353258760581052985162070023416521662616611746258695532" |
| 380 | "672923265745300992879465492467506314903358770175220871059269879629062776" |
| 381 | "047355692132901909191523941804762171253349609463563872612866401980290377" |
| 382 | "995141836029815117562837277714038305214839639239356331336428021390916694" |
| 383 | "57927874464075218944", |
| 384 | 308, penultimate_normal, last_normal, penultimate_normal); |
| 385 | } |
| 386 | |
| 387 | // Same test cases as DoubleRounding, now with new and improved Much Smaller |
| 388 | // Precision! |
| 389 | TEST(FromChars, FloatRounding) { |
| 390 | const float zero = 0.0; |
| 391 | const float first_subnormal = nextafterf(zero, 1.0); |
| 392 | const float second_subnormal = nextafterf(first_subnormal, 1.0); |
| 393 | |
| 394 | const float first_normal = FLT_MIN; |
| 395 | const float last_subnormal = nextafterf(first_normal, 0.0); |
| 396 | const float second_normal = nextafterf(first_normal, 1.0); |
| 397 | |
| 398 | const float last_normal = FLT_MAX; |
| 399 | const float penultimate_normal = nextafterf(last_normal, 0.0); |
| 400 | |
| 401 | // Test between zero and first_subnormal. Round-to-even tie rounds down. |
| 402 | TestHalfwayValue( |
| 403 | "7." |
| 404 | "006492321624085354618647916449580656401309709382578858785341419448955413" |
| 405 | "42930300743319094181060791015625", |
| 406 | -46, zero, first_subnormal, zero); |
| 407 | |
| 408 | // first_subnormal and second_subnormal. Round-to-even tie rounds up. |
| 409 | TestHalfwayValue( |
| 410 | "2." |
| 411 | "101947696487225606385594374934874196920392912814773657635602425834686624" |
| 412 | "028790902229957282543182373046875", |
| 413 | -45, first_subnormal, second_subnormal, second_subnormal); |
| 414 | |
| 415 | // last_subnormal and first_normal. Round-to-even tie rounds up. |
| 416 | TestHalfwayValue( |
| 417 | "1." |
| 418 | "175494280757364291727882991035766513322858992758990427682963118425003064" |
| 419 | "9651730385585324256680905818939208984375", |
| 420 | -38, last_subnormal, first_normal, first_normal); |
| 421 | |
| 422 | // first_normal and second_normal. Round-to-even tie rounds down. |
| 423 | TestHalfwayValue( |
| 424 | "1." |
| 425 | "175494420887210724209590083408724842314472120785184615334540294131831453" |
| 426 | "9442813071445925743319094181060791015625", |
| 427 | -38, first_normal, second_normal, first_normal); |
| 428 | |
| 429 | // penultimate_normal and last_normal. Round-to-even rounds down. |
| 430 | TestHalfwayValue("3.40282336497324057985868971510891282432", 38, |
| 431 | penultimate_normal, last_normal, penultimate_normal); |
| 432 | } |
| 433 | |
| 434 | TEST(FromChars, Underflow) { |
| 435 | // Check that underflow is handled correctly, according to the specification |
| 436 | // in DR 3081. |
| 437 | double d; |
| 438 | float f; |
| 439 | absl::from_chars_result result; |
| 440 | |
| 441 | std::string negative_underflow = "-1e-1000"; |
| 442 | const char* begin = negative_underflow.data(); |
| 443 | const char* end = begin + negative_underflow.size(); |
| 444 | d = 100.0; |
| 445 | result = absl::from_chars(begin, end, d); |
| 446 | EXPECT_EQ(result.ptr, end); |
| 447 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 448 | EXPECT_TRUE(std::signbit(d)); // negative |
| 449 | EXPECT_GE(d, -std::numeric_limits<double>::min()); |
| 450 | f = 100.0; |
| 451 | result = absl::from_chars(begin, end, f); |
| 452 | EXPECT_EQ(result.ptr, end); |
| 453 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 454 | EXPECT_TRUE(std::signbit(f)); // negative |
| 455 | EXPECT_GE(f, -std::numeric_limits<float>::min()); |
| 456 | |
| 457 | std::string positive_underflow = "1e-1000"; |
| 458 | begin = positive_underflow.data(); |
| 459 | end = begin + positive_underflow.size(); |
| 460 | d = -100.0; |
| 461 | result = absl::from_chars(begin, end, d); |
| 462 | EXPECT_EQ(result.ptr, end); |
| 463 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 464 | EXPECT_FALSE(std::signbit(d)); // positive |
| 465 | EXPECT_LE(d, std::numeric_limits<double>::min()); |
| 466 | f = -100.0; |
| 467 | result = absl::from_chars(begin, end, f); |
| 468 | EXPECT_EQ(result.ptr, end); |
| 469 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 470 | EXPECT_FALSE(std::signbit(f)); // positive |
| 471 | EXPECT_LE(f, std::numeric_limits<float>::min()); |
| 472 | } |
| 473 | |
| 474 | TEST(FromChars, Overflow) { |
| 475 | // Check that overflow is handled correctly, according to the specification |
| 476 | // in DR 3081. |
| 477 | double d; |
| 478 | float f; |
| 479 | absl::from_chars_result result; |
| 480 | |
| 481 | std::string negative_overflow = "-1e1000"; |
| 482 | const char* begin = negative_overflow.data(); |
| 483 | const char* end = begin + negative_overflow.size(); |
| 484 | d = 100.0; |
| 485 | result = absl::from_chars(begin, end, d); |
| 486 | EXPECT_EQ(result.ptr, end); |
| 487 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 488 | EXPECT_TRUE(std::signbit(d)); // negative |
| 489 | EXPECT_EQ(d, -std::numeric_limits<double>::max()); |
| 490 | f = 100.0; |
| 491 | result = absl::from_chars(begin, end, f); |
| 492 | EXPECT_EQ(result.ptr, end); |
| 493 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 494 | EXPECT_TRUE(std::signbit(f)); // negative |
| 495 | EXPECT_EQ(f, -std::numeric_limits<float>::max()); |
| 496 | |
| 497 | std::string positive_overflow = "1e1000"; |
| 498 | begin = positive_overflow.data(); |
| 499 | end = begin + positive_overflow.size(); |
| 500 | d = -100.0; |
| 501 | result = absl::from_chars(begin, end, d); |
| 502 | EXPECT_EQ(result.ptr, end); |
| 503 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 504 | EXPECT_FALSE(std::signbit(d)); // positive |
| 505 | EXPECT_EQ(d, std::numeric_limits<double>::max()); |
| 506 | f = -100.0; |
| 507 | result = absl::from_chars(begin, end, f); |
| 508 | EXPECT_EQ(result.ptr, end); |
| 509 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 510 | EXPECT_FALSE(std::signbit(f)); // positive |
| 511 | EXPECT_EQ(f, std::numeric_limits<float>::max()); |
| 512 | } |
| 513 | |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 514 | TEST(FromChars, RegressionTestsFromFuzzer) { |
| 515 | absl::string_view src = "0x21900000p00000000099"; |
| 516 | float f; |
| 517 | auto result = absl::from_chars(src.data(), src.data() + src.size(), f); |
| 518 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 519 | } |
| 520 | |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 521 | TEST(FromChars, ReturnValuePtr) { |
| 522 | // Check that `ptr` points one past the number scanned, even if that number |
| 523 | // is not representable. |
| 524 | double d; |
| 525 | absl::from_chars_result result; |
| 526 | |
| 527 | std::string normal = "3.14@#$%@#$%"; |
| 528 | result = absl::from_chars(normal.data(), normal.data() + normal.size(), d); |
| 529 | EXPECT_EQ(result.ec, std::errc()); |
| 530 | EXPECT_EQ(result.ptr - normal.data(), 4); |
| 531 | |
| 532 | std::string overflow = "1e1000@#$%@#$%"; |
| 533 | result = absl::from_chars(overflow.data(), |
| 534 | overflow.data() + overflow.size(), d); |
| 535 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 536 | EXPECT_EQ(result.ptr - overflow.data(), 6); |
| 537 | |
| 538 | std::string garbage = "#$%@#$%"; |
| 539 | result = absl::from_chars(garbage.data(), |
| 540 | garbage.data() + garbage.size(), d); |
| 541 | EXPECT_EQ(result.ec, std::errc::invalid_argument); |
| 542 | EXPECT_EQ(result.ptr - garbage.data(), 0); |
| 543 | } |
| 544 | |
| 545 | // Check for a wide range of inputs that strtod() and absl::from_chars() exactly |
| 546 | // agree on the conversion amount. |
| 547 | // |
| 548 | // This test assumes the platform's strtod() uses perfect round_to_nearest |
| 549 | // rounding. |
| 550 | TEST(FromChars, TestVersusStrtod) { |
| 551 | for (int mantissa = 1000000; mantissa <= 9999999; mantissa += 501) { |
| 552 | for (int exponent = -300; exponent < 300; ++exponent) { |
| 553 | std::string candidate = absl::StrCat(mantissa, "e", exponent); |
| 554 | double strtod_value = strtod(candidate.c_str(), nullptr); |
| 555 | double absl_value = 0; |
| 556 | absl::from_chars(candidate.data(), candidate.data() + candidate.size(), |
| 557 | absl_value); |
| 558 | ASSERT_EQ(strtod_value, absl_value) << candidate; |
| 559 | } |
| 560 | } |
| 561 | } |
| 562 | |
| 563 | // Check for a wide range of inputs that strtof() and absl::from_chars() exactly |
| 564 | // agree on the conversion amount. |
| 565 | // |
| 566 | // This test assumes the platform's strtof() uses perfect round_to_nearest |
| 567 | // rounding. |
| 568 | TEST(FromChars, TestVersusStrtof) { |
| 569 | for (int mantissa = 1000000; mantissa <= 9999999; mantissa += 501) { |
| 570 | for (int exponent = -43; exponent < 32; ++exponent) { |
| 571 | std::string candidate = absl::StrCat(mantissa, "e", exponent); |
| 572 | float strtod_value = strtof(candidate.c_str(), nullptr); |
| 573 | float absl_value = 0; |
| 574 | absl::from_chars(candidate.data(), candidate.data() + candidate.size(), |
| 575 | absl_value); |
| 576 | ASSERT_EQ(strtod_value, absl_value) << candidate; |
| 577 | } |
| 578 | } |
| 579 | } |
| 580 | |
| 581 | // Tests if two floating point values have identical bit layouts. (EXPECT_EQ |
| 582 | // is not suitable for NaN testing, since NaNs are never equal.) |
| 583 | template <typename Float> |
| 584 | bool Identical(Float a, Float b) { |
| 585 | return 0 == memcmp(&a, &b, sizeof(Float)); |
| 586 | } |
| 587 | |
| 588 | // Check that NaNs are parsed correctly. The spec requires that |
| 589 | // std::from_chars on "NaN(123abc)" return the same value as std::nan("123abc"). |
| 590 | // How such an n-char-sequence affects the generated NaN is unspecified, so we |
| 591 | // just test for symmetry with std::nan and strtod here. |
| 592 | // |
| 593 | // (In Linux, this parses the value as a number and stuffs that number into the |
| 594 | // free bits of a quiet NaN.) |
| 595 | TEST(FromChars, NaNDoubles) { |
| 596 | for (std::string n_char_sequence : |
| 597 | {"", "1", "2", "3", "fff", "FFF", "200000", "400000", "4000000000000", |
| 598 | "8000000000000", "abc123", "legal_but_unexpected", |
| 599 | "99999999999999999999999", "_"}) { |
| 600 | std::string input = absl::StrCat("nan(", n_char_sequence, ")"); |
| 601 | SCOPED_TRACE(input); |
| 602 | double from_chars_double; |
| 603 | absl::from_chars(input.data(), input.data() + input.size(), |
| 604 | from_chars_double); |
| 605 | double std_nan_double = std::nan(n_char_sequence.c_str()); |
| 606 | EXPECT_TRUE(Identical(from_chars_double, std_nan_double)); |
| 607 | |
| 608 | // Also check that we match strtod()'s behavior. This test assumes that the |
| 609 | // platform has a compliant strtod(). |
| 610 | #if ABSL_STRTOD_HANDLES_NAN_CORRECTLY |
| 611 | double strtod_double = strtod(input.c_str(), nullptr); |
| 612 | EXPECT_TRUE(Identical(from_chars_double, strtod_double)); |
| 613 | #endif // ABSL_STRTOD_HANDLES_NAN_CORRECTLY |
| 614 | |
| 615 | // Check that we can parse a negative NaN |
| 616 | std::string negative_input = "-" + input; |
| 617 | double negative_from_chars_double; |
| 618 | absl::from_chars(negative_input.data(), |
| 619 | negative_input.data() + negative_input.size(), |
| 620 | negative_from_chars_double); |
| 621 | EXPECT_TRUE(std::signbit(negative_from_chars_double)); |
| 622 | EXPECT_FALSE(Identical(negative_from_chars_double, from_chars_double)); |
| 623 | from_chars_double = std::copysign(from_chars_double, -1.0); |
| 624 | EXPECT_TRUE(Identical(negative_from_chars_double, from_chars_double)); |
| 625 | } |
| 626 | } |
| 627 | |
| 628 | TEST(FromChars, NaNFloats) { |
| 629 | for (std::string n_char_sequence : |
| 630 | {"", "1", "2", "3", "fff", "FFF", "200000", "400000", "4000000000000", |
| 631 | "8000000000000", "abc123", "legal_but_unexpected", |
| 632 | "99999999999999999999999", "_"}) { |
| 633 | std::string input = absl::StrCat("nan(", n_char_sequence, ")"); |
| 634 | SCOPED_TRACE(input); |
| 635 | float from_chars_float; |
| 636 | absl::from_chars(input.data(), input.data() + input.size(), |
| 637 | from_chars_float); |
| 638 | float std_nan_float = std::nanf(n_char_sequence.c_str()); |
| 639 | EXPECT_TRUE(Identical(from_chars_float, std_nan_float)); |
| 640 | |
| 641 | // Also check that we match strtof()'s behavior. This test assumes that the |
| 642 | // platform has a compliant strtof(). |
| 643 | #if ABSL_STRTOD_HANDLES_NAN_CORRECTLY |
| 644 | float strtof_float = strtof(input.c_str(), nullptr); |
| 645 | EXPECT_TRUE(Identical(from_chars_float, strtof_float)); |
| 646 | #endif // ABSL_STRTOD_HANDLES_NAN_CORRECTLY |
| 647 | |
| 648 | // Check that we can parse a negative NaN |
| 649 | std::string negative_input = "-" + input; |
| 650 | float negative_from_chars_float; |
| 651 | absl::from_chars(negative_input.data(), |
| 652 | negative_input.data() + negative_input.size(), |
| 653 | negative_from_chars_float); |
| 654 | EXPECT_TRUE(std::signbit(negative_from_chars_float)); |
| 655 | EXPECT_FALSE(Identical(negative_from_chars_float, from_chars_float)); |
Austin Schuh | b4691e9 | 2020-12-31 12:37:18 -0800 | [diff] [blame^] | 656 | // Use the (float, float) overload of std::copysign to prevent narrowing; |
| 657 | // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98251. |
| 658 | from_chars_float = std::copysign(from_chars_float, -1.0f); |
Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame] | 659 | EXPECT_TRUE(Identical(negative_from_chars_float, from_chars_float)); |
| 660 | } |
| 661 | } |
| 662 | |
| 663 | // Returns an integer larger than step. The values grow exponentially. |
| 664 | int NextStep(int step) { |
| 665 | return step + (step >> 2) + 1; |
| 666 | } |
| 667 | |
| 668 | // Test a conversion on a family of input strings, checking that the calculation |
| 669 | // is correct for in-bounds values, and that overflow and underflow are done |
| 670 | // correctly for out-of-bounds values. |
| 671 | // |
| 672 | // input_generator maps from an integer index to a string to test. |
| 673 | // expected_generator maps from an integer index to an expected Float value. |
| 674 | // from_chars conversion of input_generator(i) should result in |
| 675 | // expected_generator(i). |
| 676 | // |
| 677 | // lower_bound and upper_bound denote the smallest and largest values for which |
| 678 | // the conversion is expected to succeed. |
| 679 | template <typename Float> |
| 680 | void TestOverflowAndUnderflow( |
| 681 | const std::function<std::string(int)>& input_generator, |
| 682 | const std::function<Float(int)>& expected_generator, int lower_bound, |
| 683 | int upper_bound) { |
| 684 | // test legal values near lower_bound |
| 685 | int index, step; |
| 686 | for (index = lower_bound, step = 1; index < upper_bound; |
| 687 | index += step, step = NextStep(step)) { |
| 688 | std::string input = input_generator(index); |
| 689 | SCOPED_TRACE(input); |
| 690 | Float expected = expected_generator(index); |
| 691 | Float actual; |
| 692 | auto result = |
| 693 | absl::from_chars(input.data(), input.data() + input.size(), actual); |
| 694 | EXPECT_EQ(result.ec, std::errc()); |
| 695 | EXPECT_EQ(expected, actual) |
| 696 | << absl::StrFormat("%a vs %a", expected, actual); |
| 697 | } |
| 698 | // test legal values near upper_bound |
| 699 | for (index = upper_bound, step = 1; index > lower_bound; |
| 700 | index -= step, step = NextStep(step)) { |
| 701 | std::string input = input_generator(index); |
| 702 | SCOPED_TRACE(input); |
| 703 | Float expected = expected_generator(index); |
| 704 | Float actual; |
| 705 | auto result = |
| 706 | absl::from_chars(input.data(), input.data() + input.size(), actual); |
| 707 | EXPECT_EQ(result.ec, std::errc()); |
| 708 | EXPECT_EQ(expected, actual) |
| 709 | << absl::StrFormat("%a vs %a", expected, actual); |
| 710 | } |
| 711 | // Test underflow values below lower_bound |
| 712 | for (index = lower_bound - 1, step = 1; index > -1000000; |
| 713 | index -= step, step = NextStep(step)) { |
| 714 | std::string input = input_generator(index); |
| 715 | SCOPED_TRACE(input); |
| 716 | Float actual; |
| 717 | auto result = |
| 718 | absl::from_chars(input.data(), input.data() + input.size(), actual); |
| 719 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 720 | EXPECT_LT(actual, 1.0); // check for underflow |
| 721 | } |
| 722 | // Test overflow values above upper_bound |
| 723 | for (index = upper_bound + 1, step = 1; index < 1000000; |
| 724 | index += step, step = NextStep(step)) { |
| 725 | std::string input = input_generator(index); |
| 726 | SCOPED_TRACE(input); |
| 727 | Float actual; |
| 728 | auto result = |
| 729 | absl::from_chars(input.data(), input.data() + input.size(), actual); |
| 730 | EXPECT_EQ(result.ec, std::errc::result_out_of_range); |
| 731 | EXPECT_GT(actual, 1.0); // check for overflow |
| 732 | } |
| 733 | } |
| 734 | |
| 735 | // Check that overflow and underflow are caught correctly for hex doubles. |
| 736 | // |
| 737 | // The largest representable double is 0x1.fffffffffffffp+1023, and the |
| 738 | // smallest representable subnormal is 0x0.0000000000001p-1022, which equals |
| 739 | // 0x1p-1074. Therefore 1023 and -1074 are the limits of acceptable exponents |
| 740 | // in this test. |
| 741 | TEST(FromChars, HexdecimalDoubleLimits) { |
| 742 | auto input_gen = [](int index) { return absl::StrCat("0x1.0p", index); }; |
| 743 | auto expected_gen = [](int index) { return std::ldexp(1.0, index); }; |
| 744 | TestOverflowAndUnderflow<double>(input_gen, expected_gen, -1074, 1023); |
| 745 | } |
| 746 | |
| 747 | // Check that overflow and underflow are caught correctly for hex floats. |
| 748 | // |
| 749 | // The largest representable float is 0x1.fffffep+127, and the smallest |
| 750 | // representable subnormal is 0x0.000002p-126, which equals 0x1p-149. |
| 751 | // Therefore 127 and -149 are the limits of acceptable exponents in this test. |
| 752 | TEST(FromChars, HexdecimalFloatLimits) { |
| 753 | auto input_gen = [](int index) { return absl::StrCat("0x1.0p", index); }; |
| 754 | auto expected_gen = [](int index) { return std::ldexp(1.0f, index); }; |
| 755 | TestOverflowAndUnderflow<float>(input_gen, expected_gen, -149, 127); |
| 756 | } |
| 757 | |
| 758 | // Check that overflow and underflow are caught correctly for decimal doubles. |
| 759 | // |
| 760 | // The largest representable double is about 1.8e308, and the smallest |
| 761 | // representable subnormal is about 5e-324. '1e-324' therefore rounds away from |
| 762 | // the smallest representable positive value. -323 and 308 are the limits of |
| 763 | // acceptable exponents in this test. |
| 764 | TEST(FromChars, DecimalDoubleLimits) { |
| 765 | auto input_gen = [](int index) { return absl::StrCat("1.0e", index); }; |
| 766 | auto expected_gen = [](int index) { return Pow10(index); }; |
| 767 | TestOverflowAndUnderflow<double>(input_gen, expected_gen, -323, 308); |
| 768 | } |
| 769 | |
| 770 | // Check that overflow and underflow are caught correctly for decimal floats. |
| 771 | // |
| 772 | // The largest representable float is about 3.4e38, and the smallest |
| 773 | // representable subnormal is about 1.45e-45. '1e-45' therefore rounds towards |
| 774 | // the smallest representable positive value. -45 and 38 are the limits of |
| 775 | // acceptable exponents in this test. |
| 776 | TEST(FromChars, DecimalFloatLimits) { |
| 777 | auto input_gen = [](int index) { return absl::StrCat("1.0e", index); }; |
| 778 | auto expected_gen = [](int index) { return Pow10(index); }; |
| 779 | TestOverflowAndUnderflow<float>(input_gen, expected_gen, -45, 38); |
| 780 | } |
| 781 | |
| 782 | } // namespace |