/* ** fp_uscale.c - Unrounded Scaling float conversion ** ** Unified float formatting and parsing using the uscale algorithm. ** Based on Russ Cox's "Unrounded Scaling" approach. ** See https://research.swtch.com/fp ** ** Replaces fmt_fp.c (formatting) and readfloat.c (parsing). */ #include #ifndef MRB_NO_FLOAT #include #include #include /* ======== Platform support ======== */ #if defined(__SIZEOF_INT128__) static inline void mul64(uint64_t a, uint64_t b, uint64_t *hi, uint64_t *lo) { __uint128_t r = (__uint128_t)a * b; *hi = (uint64_t)(r >> 64); *lo = (uint64_t)r; } #elif defined(_MSC_VER) && defined(_M_X64) #include static inline void mul64(uint64_t a, uint64_t b, uint64_t *hi, uint64_t *lo) { *lo = _umul128(a, b, hi); } #else static inline void mul64(uint64_t a, uint64_t b, uint64_t *hi, uint64_t *lo) { uint64_t a_lo = (uint32_t)a, a_hi = a >> 32; uint64_t b_lo = (uint32_t)b, b_hi = b >> 32; uint64_t p0 = a_lo * b_lo; uint64_t p1 = a_lo * b_hi; uint64_t p2 = a_hi * b_lo; uint64_t p3 = a_hi * b_hi; uint64_t mid = (p0 >> 32) + (uint32_t)p1 + (uint32_t)p2; *lo = (p0 & 0xFFFFFFFFULL) | (mid << 32); *hi = p3 + (p1 >> 32) + (p2 >> 32) + (mid >> 32); } #endif #if defined(__GNUC__) || defined(__clang__) #define clz64(x) __builtin_clzll(x) #elif defined(_MSC_VER) && defined(_M_X64) static inline int clz64(uint64_t x) { unsigned long idx; _BitScanReverse64(&idx, x); return 63 - (int)idx; } #else static inline int clz64(uint64_t x) { int n = 0; if (x <= 0x00000000FFFFFFFFULL) { n += 32; x <<= 32; } if (x <= 0x0000FFFFFFFFFFFFULL) { n += 16; x <<= 16; } if (x <= 0x00FFFFFFFFFFFFFFULL) { n += 8; x <<= 8; } if (x <= 0x0FFFFFFFFFFFFFFFULL) { n += 4; x <<= 4; } if (x <= 0x3FFFFFFFFFFFFFFFULL) { n += 2; x <<= 2; } if (x <= 0x7FFFFFFFFFFFFFFFULL) { n += 1; } return n; } #endif #define bits_len64(x) (64 - clz64(x)) /* ======== pow10 table ======== */ typedef struct { uint64_t hi; uint64_t lo; } pow10_entry; #define POW10_MIN (-343) #define POW10_MAX 341 #define POW10_TAB_SIZE (POW10_MAX - POW10_MIN + 1) /* generated by tools/gen_pow10_tab.rb */ static const pow10_entry pow10_tab[POW10_TAB_SIZE] = { {0xbf29dcaba82fdeafULL, 0x8bcd1178c77f03ccULL}, {0xeef453d6923bd65bULL, 0xeec055d6f95ec4c0ULL}, {0x9558b4661b6565f9ULL, 0xb53835a65bdb3af8ULL}, {0xbaaee17fa23ebf77ULL, 0xa286430ff2d209b6ULL}, {0xe95a99df8ace6f54ULL, 0x0b27d3d3ef868c23ULL}, {0x91d8a02bb6c10595ULL, 0x86f8e46475b41796ULL}, {0xb64ec836a47146faULL, 0x68b71d7d93211d7bULL}, {0xe3e27a444d8d98b8ULL, 0x02e4e4dcf7e964daULL}, {0x8e6d8c6ab0787f73ULL, 0x01cf0f0a1af1df08ULL}, {0xb208ef855c969f50ULL, 0x4242d2cca1ae56caULL}, {0xde8b2b66b3bc4724ULL, 0x52d3877fca19ec7dULL}, {0x8b16fb203055ac77ULL, 0xb3c434afde5033ceULL}, {0xaddcb9e83c6b1794ULL, 0x20b541dbd5e440c2ULL}, {0xd953e8624b85dd79ULL, 0x28e29252cb5d50f2ULL}, {0x87d4713d6f33aa6cULL, 0x798d9b73bf1a5297ULL}, {0xa9c98d8ccb009507ULL, 0x97f10250aee0e73dULL}, {0xd43bf0effdc0ba49ULL, 0xfded42e4da99210dULL}, {0x84a57695fe98746eULL, 0xfeb449cf089fb4a8ULL}, {0xa5ced43b7e3e9189ULL, 0xbe615c42cac7a1d2ULL}, {0xcf42894a5dce35ebULL, 0xadf9b3537d798a46ULL}, {0x818995ce7aa0e1b3ULL, 0x8cbc10142e6bf66cULL}, {0xa1ebfb4219491a20ULL, 0xefeb14193a06f407ULL}, {0xca66fa129f9b60a7ULL, 0x2be5d91f8888b109ULL}, {0xfd00b897478238d1ULL, 0x76df4f676aaadd4bULL}, {0x9e20735e8cb16383ULL, 0xaa4b91a0a2aaca4fULL}, {0xc5a890362fddbc63ULL, 0x14de7608cb557ce2ULL}, {0xf712b443bbd52b7cULL, 0x5a16138afe2adc1bULL}, {0x9a6bb0aa55653b2eULL, 0xb84dcc36dedac991ULL}, {0xc1069cd4eabe89f9ULL, 0x66613f4496917bf5ULL}, {0xf148440a256e2c77ULL, 0x3ff98f15bc35daf2ULL}, {0x96cd2a865764dbcbULL, 0xc7fbf96d95a1a8d7ULL}, {0xbc807527ed3e12bdULL, 0x39faf7c8fb0a130dULL}, {0xeba09271e88d976cULL, 0x0879b5bb39cc97d1ULL}, {0x93445b8731587ea4ULL, 0x854c1195041fdee2ULL}, {0xb8157268fdae9e4dULL, 0xa69f15fa4527d69bULL}, {0xe61acf033d1a45e0ULL, 0x9046db78d671cc42ULL}, {0x8fd0c16206306bacULL, 0x5a2c492b86071fa9ULL}, {0xb3c4f1ba87bc8697ULL, 0x70b75b766788e793ULL}, {0xe0b62e2929aba83dULL, 0xcce53254016b2178ULL}, {0x8c71dcd9ba0b4926ULL, 0x600f3f7480e2f4ebULL}, {0xaf8e5410288e1b70ULL, 0xf8130f51a11bb226ULL}, {0xdb71e91432b1a24bULL, 0x3617d32609629eafULL}, {0x892731ac9faf056fULL, 0x41cee3f7c5dda32dULL}, {0xab70fe17c79ac6cbULL, 0x92429cf5b7550bf9ULL}, {0xd64d3d9db981787eULL, 0xf6d34433252a4ef7ULL}, {0x85f0468293f0eb4fULL, 0xda440a9ff73a715aULL}, {0xa76c582338ed2622ULL, 0x50d50d47f5090db1ULL}, {0xd1476e2c07286fabULL, 0xe50a5099f24b511eULL}, {0x82cca4db847945cbULL, 0xaf267260376f12b2ULL}, {0xa37fce126597973dULL, 0x1af00ef8454ad75fULL}, {0xcc5fc196fefd7d0dULL, 0xe1ac12b6569d8d37ULL}, {0xff77b1fcbebcdc50ULL, 0xda171763ec44f085ULL}, {0x9faacf3df73609b2ULL, 0x884e6e9e73ab1653ULL}, {0xc795830d75038c1eULL, 0x2a620a461095dbe8ULL}, {0xf97ae3d0d2446f26ULL, 0xb4fa8cd794bb52e2ULL}, {0x9becce62836ac578ULL, 0xb11c9806bcf513cdULL}, {0xc2e801fb244576d6ULL, 0xdd63be086c3258c0ULL}, {0xf3a20279ed56d48bULL, 0x94bcad8a873eeef0ULL}, {0x9845418c345644d7ULL, 0x7cf5ec7694875556ULL}, {0xbe5691ef416bd60dULL, 0xdc33679439a92aacULL}, {0xedec366b11c6cb90ULL, 0xd340417948137557ULL}, {0x94b3a202eb1c3f3aULL, 0x840828ebcd0c2956ULL}, {0xb9e08a83a5e34f08ULL, 0x250a3326c04f33acULL}, {0xe858ad248f5c22caULL, 0x2e4cbff070630097ULL}, {0x91376c36d99995bfULL, 0xdceff7f6463de05eULL}, {0xb58547448ffffb2eULL, 0x542bf5f3d7cd5875ULL}, {0xe2e69915b3fff9faULL, 0xe936f370cdc0ae93ULL}, {0x8dd01fad907ffc3cULL, 0x51c2582680986d1cULL}, {0xb1442798f49ffb4bULL, 0x6632ee3020be8863ULL}, {0xdd95317f31c7fa1eULL, 0xbfbfa9bc28ee2a7cULL}, {0x8a7d3eef7f1cfc53ULL, 0xb7d7ca159994da8dULL}, {0xad1c8eab5ee43b67ULL, 0x25cdbc9afffa1130ULL}, {0xd863b256369d4a41ULL, 0x6f412bc1bff8957dULL}, {0x873e4f75e2224e69ULL, 0xa588bb5917fb5d6eULL}, {0xa90de3535aaae203ULL, 0x8eeaea2f5dfa34c9ULL}, {0xd3515c2831559a84ULL, 0xf2a5a4bb3578c1fcULL}, {0x8412d9991ed58092ULL, 0x17a786f5016b793dULL}, {0xa5178fff668ae0b7ULL, 0x9d9168b241c6578dULL}, {0xce5d73ff402d98e4ULL, 0x04f5c2ded237ed70ULL}, {0x80fa687f881c7f8fULL, 0x831999cb4362f466ULL}, {0xa139029f6a239f73ULL, 0xe3e0003e143bb17fULL}, {0xc987434744ac874fULL, 0x5cd8004d994a9ddfULL}, {0xfbe9141915d7a923ULL, 0xb40e0060ff9d4557ULL}, {0x9d71ac8fada6c9b6ULL, 0x9088c03c9fc24b56ULL}, {0xc4ce17b399107c23ULL, 0x34aaf04bc7b2de2cULL}, {0xf6019da07f549b2cULL, 0x81d5ac5eb99f95b7ULL}, {0x99c102844f94e0fcULL, 0xd1258bbb3403bd92ULL}, {0xc0314325637a193aULL, 0x056eeeaa0104acf7ULL}, {0xf03d93eebc589f89ULL, 0x86caaa548145d835ULL}, {0x96267c7535b763b6ULL, 0xb43eaa74d0cba721ULL}, {0xbbb01b9283253ca3ULL, 0x614e551204fe90e9ULL}, {0xea9c227723ee8bccULL, 0xb9a1ea56863e3523ULL}, {0x92a1958a76751760ULL, 0xf405327613e6e136ULL}, {0xb749faed14125d37ULL, 0x31067f1398e09984ULL}, {0xe51c79a85916f485ULL, 0x7d481ed87f18bfe5ULL}, {0x8f31cc0937ae58d3ULL, 0x2e4d13474f6f77efULL}, {0xb2fe3f0b8599ef08ULL, 0x79e05819234b55eaULL}, {0xdfbdcece67006acaULL, 0x98586e1f6c1e2b65ULL}, {0x8bd6a141006042beULL, 0x1f3744d3a392db1fULL}, {0xaecc49914078536eULL, 0xa70516088c7791e7ULL}, {0xda7f5bf590966849ULL, 0x50c65b8aaf957661ULL}, {0x888f99797a5e012eULL, 0x927bf936adbd69fcULL}, {0xaab37fd7d8f58179ULL, 0x371af784592cc47cULL}, {0xd5605fcdcf32e1d7ULL, 0x04e1b5656f77f59bULL}, {0x855c3be0a17fcd27ULL, 0xa30d115f65aaf980ULL}, {0xa6b34ad8c9dfc070ULL, 0x0bd055b73f15b7e1ULL}, {0xd0601d8efc57b08cULL, 0x0ec46b250edb25d9ULL}, {0x823c12795db6ce58ULL, 0x893ac2f72948f7a7ULL}, {0xa2cb1717b52481eeULL, 0xab8973b4f39b3591ULL}, {0xcb7ddcdda26da269ULL, 0x566bd0a2308202f6ULL}, {0xfe5d54150b090b03ULL, 0x2c06c4cabca283b3ULL}, {0x9efa548d26e5a6e2ULL, 0x3b843afeb5e59250ULL}, {0xc6b8e9b0709f109bULL, 0xca6549be635ef6e4ULL}, {0xf867241c8cc6d4c1ULL, 0x3cfe9c2dfc36b49dULL}, {0x9b407691d7fc44f9ULL, 0x861f219cbda230e2ULL}, {0xc21094364dfb5637ULL, 0x67a6ea03ed0abd1bULL}, {0xf294b943e17a2bc5ULL, 0xc190a484e84d6c62ULL}, {0x979cf3ca6cec5b5bULL, 0x58fa66d3113063bdULL}, {0xbd8430bd08277232ULL, 0xaf390087d57c7cacULL}, {0xece53cec4a314ebeULL, 0x5b0740a9cadb9bd7ULL}, {0x940f4613ae5ed137ULL, 0x78e4886a1ec94166ULL}, {0xb913179899f68585ULL, 0xd71daa84a67b91c0ULL}, {0xe757dd7ec07426e6ULL, 0xcce51525d01a7630ULL}, {0x9096ea6f38489850ULL, 0xc00f2d37a21089deULL}, {0xb4bca50b065abe64ULL, 0xf012f8858a94ac56ULL}, {0xe1ebce4dc7f16dfcULL, 0x2c17b6a6ed39d76bULL}, {0x8d3360f09cf6e4beULL, 0x9b8ed228544426a3ULL}, {0xb080392cc4349dedULL, 0x427286b26955304cULL}, {0xdca04777f541c568ULL, 0x130f285f03aa7c5fULL}, {0x89e42caaf9491b61ULL, 0x0be9793b624a8dbbULL}, {0xac5d37d5b79b623aULL, 0xcee3d78a3add312aULL}, {0xd77485cb25823ac8ULL, 0x829ccd6cc9947d74ULL}, {0x86a8d39ef77164bdULL, 0x51a20063fdfcce68ULL}, {0xa8530886b54dbdecULL, 0x260a807cfd7c0203ULL}, {0xd267caa862a12d67ULL, 0x2f8d209c3cdb0284ULL}, {0x8380dea93da4bc61ULL, 0xbdb83461a608e192ULL}, {0xa46116538d0deb79ULL, 0xad26417a0f8b19f7ULL}, {0xcd795be870516657ULL, 0x986fd1d8936de074ULL}, {0x806bd9714632dff7ULL, 0xff45e3275c24ac49ULL}, {0xa086cfcd97bf97f4ULL, 0x7f175bf1332dd75bULL}, {0xc8a883c0fdaf7df1ULL, 0x9edd32ed7ff94d32ULL}, {0xfad2a4b13d1b5d6dULL, 0x86947fa8dff7a07eULL}, {0x9cc3a6eec6311a64ULL, 0x341ccfc98bfac44fULL}, {0xc3f490aa77bd60fdULL, 0x412403bbeef97563ULL}, {0xf4f1b4d515acb93cULL, 0x116d04aaeab7d2bbULL}, {0x991711052d8bf3c6ULL, 0x8ae422ead2b2e3b5ULL}, {0xbf5cd54678eef0b7ULL, 0x2d9d2ba5875f9ca2ULL}, {0xef340a98172aace5ULL, 0x7904768ee93783cbULL}, {0x9580869f0e7aac0fULL, 0x2ba2ca1951c2b25fULL}, {0xbae0a846d2195713ULL, 0x768b7c9fa6335ef6ULL}, {0xe998d258869facd8ULL, 0xd42e5bc78fc036b4ULL}, {0x91ff83775423cc07ULL, 0x849cf95cb9d82230ULL}, {0xb67f6455292cbf09ULL, 0xe5c437b3e84e2abdULL}, {0xe41f3d6a7377eecbULL, 0xdf3545a0e261b56cULL}, {0x8e938662882af53fULL, 0xab814b848d7d1163ULL}, {0xb23867fb2a35b28eULL, 0x16619e65b0dc55bcULL}, {0xdec681f9f4c31f32ULL, 0x9bfa05ff1d136b2bULL}, {0x8b3c113c38f9f37fULL, 0x217c43bf722c22fbULL}, {0xae0b158b4738705fULL, 0x69db54af4eb72bbaULL}, {0xd98ddaee19068c77ULL, 0xc45229db2264f6a8ULL}, {0x87f8a8d4cfa417caULL, 0x1ab35a28f57f1a29ULL}, {0xa9f6d30a038d1dbdULL, 0xa16030b332dee0b3ULL}, {0xd47487cc8470652cULL, 0x89b83cdfff9698e0ULL}, {0x84c8d4dfd2c63f3cULL, 0xd613260bffbe1f8cULL}, {0xa5fb0a17c777cf0aULL, 0x0b97ef8effada76fULL}, {0xcf79cc9db955c2cdULL, 0x8e7deb72bf99114bULL}, {0x81ac1fe293d599c0ULL, 0x390eb327b7bfaacfULL}, {0xa21727db38cb0030ULL, 0x47525ff1a5af9583ULL}, {0xca9cf1d206fdc03cULL, 0x5926f7ee0f1b7ae3ULL}, {0xfd442e4688bd304bULL, 0x6f70b5e992e2599cULL}, {0x9e4a9cec15763e2fULL, 0x65a671b1fbcd7801ULL}, {0xc5dd44271ad3cdbbULL, 0xbf100e1e7ac0d602ULL}, {0xf7549530e188c129ULL, 0x2ed411a619710b83ULL}, {0x9a94dd3e8cf578baULL, 0x7d448b07cfe6a731ULL}, {0xc13a148e3032d6e8ULL, 0x1c95adc9c3e050feULL}, {0xf18899b1bc3f8ca2ULL, 0x23bb193c34d8653eULL}, {0x96f5600f15a7b7e6ULL, 0xd654efc5a1073f46ULL}, {0xbcb2b812db11a5dfULL, 0x8bea2bb709490f18ULL}, {0xebdf661791d60f57ULL, 0xeee4b6a4cb9b52deULL}, {0x936b9fcebb25c996ULL, 0x354ef226ff4113cbULL}, {0xb84687c269ef3bfcULL, 0xc2a2aeb0bf1158bdULL}, {0xe65829b3046b0afbULL, 0xf34b5a5ceed5aeedULL}, {0x8ff71a0fe2c2e6ddULL, 0xb80f187a15458d54ULL}, {0xb3f4e093db73a094ULL, 0xa612de989a96f0a9ULL}, {0xe0f218b8d25088b9ULL, 0xcf97963ec13cacd3ULL}, {0x8c974f7383725574ULL, 0xe1bebde738c5ec04ULL}, {0xafbd2350644eead0ULL, 0x1a2e6d6106f76705ULL}, {0xdbac6c247d62a584ULL, 0x20ba08b948b540c6ULL}, {0x894bc396ce5da773ULL, 0x94744573cd71487cULL}, {0xab9eb47c81f51150ULL, 0xf99156d0c0cd9a9bULL}, {0xd686619ba27255a3ULL, 0x37f5ac84f1010142ULL}, {0x8613fd0145877586ULL, 0x42f98bd316a0a0c9ULL}, {0xa798fc4196e952e8ULL, 0xd3b7eec7dc48c8fbULL}, {0xd17f3b51fca3a7a1ULL, 0x08a5ea79d35afb3aULL}, {0x82ef85133de648c5ULL, 0x6567b28c2418dd04ULL}, {0xa3ab66580d5fdaf6ULL, 0x3ec19f2f2d1f1445ULL}, {0xcc963fee10b7d1b4ULL, 0xce7206faf866d957ULL}, {0xffbbcfe994e5c620ULL, 0x020e88b9b6808fadULL}, {0x9fd561f1fd0f9bd4ULL, 0x01491574121059ccULL}, {0xc7caba6e7c5382c9ULL, 0x019b5ad11694703fULL}, {0xf9bd690a1b68637cULL, 0xc20231855c398c4fULL}, {0x9c1661a651213e2eULL, 0xf9415ef359a3f7b1ULL}, {0xc31bfa0fe5698db9ULL, 0xb791b6b0300cf59dULL}, {0xf3e2f893dec3f127ULL, 0xa576245c3c103305ULL}, {0x986ddb5c6b3a76b8ULL, 0x0769d6b9a58a1fe3ULL}, {0xbe89523386091466ULL, 0x09444c680eeca7dcULL}, {0xee2ba6c0678b5980ULL, 0x8b955f8212a7d1d3ULL}, {0x94db483840b717f0ULL, 0x573d5bb14ba8e323ULL}, {0xba121a4650e4ddecULL, 0x6d0cb29d9e931becULL}, {0xe896a0d7e51e1567ULL, 0x884fdf450637e2e8ULL}, {0x915e2486ef32cd61ULL, 0xf531eb8b23e2edd1ULL}, {0xb5b5ada8aaff80b9ULL, 0xf27e666decdba945ULL}, {0xe3231912d5bf60e7ULL, 0xef1e000968129396ULL}, {0x8df5efabc5979c90ULL, 0x3572c005e10b9c3eULL}, {0xb1736b96b6fd83b4ULL, 0x42cf7007594e834dULL}, {0xddd0467c64bce4a1ULL, 0x53834c092fa22421ULL}, {0x8aa22c0dbef60ee5ULL, 0x94320f85bdc55694ULL}, {0xad4ab7112eb3929eULL, 0x793e93672d36ac39ULL}, {0xd89d64d57a607745ULL, 0x178e3840f8845748ULL}, {0x87625f056c7c4a8cULL, 0xeeb8e3289b52b68dULL}, {0xa93af6c6c79b5d2eULL, 0x2a671bf2c2276430ULL}, {0xd389b4787982347aULL, 0xb500e2ef72b13d3cULL}, {0x843610cb4bf160ccULL, 0x31208dd5a7aec645ULL}, {0xa54394fe1eedb8ffULL, 0x3d68b14b119a77d7ULL}, {0xce947a3da6a9273fULL, 0x8cc2dd9dd60115cdULL}, {0x811ccc668829b888ULL, 0xf7f9ca82a5c0ada0ULL}, {0xa163ff802a3426a9ULL, 0x35f83d234f30d908ULL}, {0xc9bcff6034c13053ULL, 0x03764c6c22fd0f4aULL}, {0xfc2c3f3841f17c68ULL, 0x4453df872bbc531dULL}, {0x9d9ba7832936edc1ULL, 0x2ab46bb47b55b3f2ULL}, {0xc5029163f384a932ULL, 0xf56186a19a2b20eeULL}, {0xf64335bcf065d37eULL, 0xb2b9e84a00b5e92aULL}, {0x99ea0196163fa42fULL, 0xafb4312e4071b1baULL}, {0xc06481fb9bcf8d3aULL, 0x1ba13d79d08e1e29ULL}, {0xf07da27a82c37089ULL, 0xa2898cd844b1a5b3ULL}, {0x964e858c91ba2656ULL, 0xc595f8072aef0790ULL}, {0xbbe226efb628afebULL, 0x76fb7608f5aac974ULL}, {0xeadab0aba3b2dbe6ULL, 0xd4ba538b33157bd1ULL}, {0x92c8ae6b464fc970ULL, 0xc4f47436ffed6d62ULL}, {0xb77ada0617e3bbccULL, 0xf6319144bfe8c8bbULL}, {0xe55990879ddcaabeULL, 0x33bdf595efe2faeaULL}, {0x8f57fa54c2a9eab7ULL, 0x6056b97db5eddcd2ULL}, {0xb32df8e9f3546565ULL, 0xb86c67dd23695406ULL}, {0xdff9772470297ebeULL, 0xa68781d46c43a908ULL}, {0x8bfbea76c619ef37ULL, 0xa814b124c3aa49a5ULL}, {0xaefae51477a06b04ULL, 0x1219dd6df494dc0eULL}, {0xdab99e59958885c5ULL, 0x16a054c971ba1312ULL}, {0x88b402f7fd75539cULL, 0xee2434fde7144bebULL}, {0xaae103b5fcd2a882ULL, 0x29ad423d60d95ee6ULL}, {0xd59944a37c0752a3ULL, 0xb41892ccb90fb6a0ULL}, {0x857fcae62d8493a6ULL, 0x908f5bbff3a9d224ULL}, {0xa6dfbd9fb8e5b88fULL, 0x34b332aff09446adULL}, {0xd097ad07a71f26b3ULL, 0x81dfff5becb95858ULL}, {0x825ecc24c8737830ULL, 0x712bff9973f3d737ULL}, {0xa2f67f2dfa90563cULL, 0x8d76ff7fd0f0cd05ULL}, {0xcbb41ef979346bcbULL, 0xb0d4bf5fc52d0046ULL}, {0xfea126b7d78186bdULL, 0x1d09ef37b6784057ULL}, {0x9f24b832e6b0f437ULL, 0xf2263582d20b2836ULL}, {0xc6ede63fa05d3144ULL, 0x6eafc2e3868df244ULL}, {0xf8a95fcf88747d95ULL, 0x8a5bb39c68316ed5ULL}, {0x9b69dbe1b548ce7dULL, 0x36795041c11ee545ULL}, {0xc24452da229b021cULL, 0x0417a45231669e97ULL}, {0xf2d56790ab41c2a3ULL, 0x051d8d66bdc0463cULL}, {0x97c560ba6b0919a6ULL, 0x2332786036982be5ULL}, {0xbdb6b8e905cb6010ULL, 0xabff1678443e36dfULL}, {0xed246723473e3814ULL, 0xd6fedc16554dc497ULL}, {0x9436c0760c86e30cULL, 0x065f498df5509adeULL}, {0xb94470938fa89bcfULL, 0x07f71bf172a4c196ULL}, {0xe7958cb87392c2c3ULL, 0x49f4e2edcf4df1fbULL}, {0x90bd77f3483bb9baULL, 0x4e390dd4a190b73dULL}, {0xb4ecd5f01a4aa829ULL, 0xe1c75149c9f4e50cULL}, {0xe2280b6c20dd5233ULL, 0xda39259c3c721e4fULL}, {0x8d590723948a5360ULL, 0xa863b781a5c752f1ULL}, {0xb0af48ec79ace838ULL, 0xd27ca5620f3927aeULL}, {0xdcdb1b2798182245ULL, 0x071bceba9307719aULL}, {0x8a08f0f8bf0f156cULL, 0xe47161349be4a700ULL}, {0xac8b2d36eed2dac6ULL, 0x1d8db981c2ddd0c0ULL}, {0xd7adf884aa879178ULL, 0xa4f127e2339544f0ULL}, {0x86ccbb52ea94baebULL, 0x6716b8ed603d4b16ULL}, {0xa87fea27a539e9a6ULL, 0xc0dc6728b84c9ddbULL}, {0xd29fe4b18e88640fULL, 0x711380f2e65fc552ULL}, {0x83a3eeeef9153e8aULL, 0xe6ac3097cffbdb53ULL}, {0xa48ceaaab75a8e2cULL, 0xa0573cbdc3fad228ULL}, {0xcdb02555653131b7ULL, 0xc86d0bed34f986b2ULL}, {0x808e17555f3ebf12ULL, 0x1d442774411bf42fULL}, {0xa0b19d2ab70e6ed7ULL, 0xa49531515162f13bULL}, {0xc8de047564d20a8cULL, 0x0dba7da5a5bbad8aULL}, {0xfb158592be068d2fULL, 0x11291d0f0f2a98edULL}, {0x9ced737bb6c4183eULL, 0xaab9b229697a9f94ULL}, {0xc428d05aa4751e4dULL, 0x55681eb3c3d94779ULL}, {0xf53304714d9265e0ULL, 0x2ac22660b4cf9957ULL}, {0x993fe2c6d07b7facULL, 0x1ab957fc7101bfd6ULL}, {0xbf8fdb78849a5f97ULL, 0x2167adfb8d422fccULL}, {0xef73d256a5c0f77dULL, 0x69c1997a7092bbbfULL}, {0x95a8637627989aaeULL, 0x2218ffec865bb557ULL}, {0xbb127c53b17ec15aULL, 0xaa9f3fe7a7f2a2adULL}, {0xe9d71b689dde71b0ULL, 0x55470fe191ef4b59ULL}, {0x9226712162ab070eULL, 0x354c69ecfb358f17ULL}, {0xb6b00d69bb55c8d2ULL, 0xc29f84683a02f2ddULL}, {0xe45c10c42a2b3b06ULL, 0x734765824883af95ULL}, {0x8eb98a7a9a5b04e4ULL, 0x880c9f716d524dbdULL}, {0xb267ed1940f1c61dULL, 0xaa0fc74dc8a6e12cULL}, {0xdf01e85f912e37a4ULL, 0x9493b9213ad09977ULL}, {0x8b61313bbabce2c7ULL, 0xdcdc53b4c4c25feaULL}, {0xae397d8aa96c1b78ULL, 0x541368a1f5f2f7e5ULL}, {0xd9c7dced53c72256ULL, 0x691842ca736fb5deULL}, {0x881cea14545c7576ULL, 0x81af29be8825d1abULL}, {0xaa242499697392d3ULL, 0x221af42e2a2f4616ULL}, {0xd4ad2dbfc3d07788ULL, 0x6aa1b139b4bb179bULL}, {0x84ec3c97da624ab5ULL, 0x42a50ec410f4eec1ULL}, {0xa6274bbdd0fadd62ULL, 0x134e527515322a71ULL}, {0xcfb11ead453994bbULL, 0x9821e7125a7eb50dULL}, {0x81ceb32c4b43fcf5ULL, 0x7f15306b788f3128ULL}, {0xa2425ff75e14fc32ULL, 0x5eda7c8656b2fd72ULL}, {0xcad2f7f5359a3b3fULL, 0xf6911ba7ec5fbccfULL}, {0xfd87b5f28300ca0eULL, 0x74356291e777ac03ULL}, {0x9e74d1b791e07e49ULL, 0x88a15d9b30aacb82ULL}, {0xc612062576589ddbULL, 0x6ac9b501fcd57e62ULL}, {0xf79687aed3eec552ULL, 0xc57c22427c0addfbULL}, {0x9abe14cd44753b53ULL, 0x3b6d95698d86cabdULL}, {0xc16d9a0095928a28ULL, 0x8a48fac3f0e87d6cULL}, {0xf1c90080baf72cb2ULL, 0xacdb3974ed229cc7ULL}, {0x971da05074da7befULL, 0x2c0903e91435a1fcULL}, {0xbce5086492111aebULL, 0x770b44e359430a7bULL}, {0xec1e4a7db69561a6ULL, 0xd4ce161c2f93cd1aULL}, {0x9392ee8e921d5d08ULL, 0xc500cdd19dbc6030ULL}, {0xb877aa3236a4b44aULL, 0xf6410146052b783dULL}, {0xe69594bec44de15cULL, 0xb3d141978676564cULL}, {0x901d7cf73ab0acdaULL, 0xf062c8feb409f5efULL}, {0xb424dc35095cd810ULL, 0xac7b7b3e610c736bULL}, {0xe12e13424bb40e14ULL, 0xd79a5a0df94f9046ULL}, {0x8cbccc096f5088ccULL, 0x06c07848bbd1ba2cULL}, {0xafebff0bcb24aaffULL, 0x0870965aeac628b7ULL}, {0xdbe6fecebdedd5bfULL, 0x4a8cbbf1a577b2e4ULL}, {0x89705f4136b4a598ULL, 0xce97f577076acfcfULL}, {0xabcc77118461cefdULL, 0x023df2d4c94583c2ULL}, {0xd6bf94d5e57a42bdULL, 0xc2cd6f89fb96e4b3ULL}, {0x8637bd05af6c69b6ULL, 0x59c065b63d3e4ef0ULL}, {0xa7c5ac471b478424ULL, 0xf0307f23cc8de2acULL}, {0xd1b71758e219652cULL, 0x2c3c9eecbfb15b57ULL}, {0x83126e978d4fdf3cULL, 0x9ba5e353f7ced916ULL}, {0xa3d70a3d70a3d70bULL, 0xc28f5c28f5c28f5cULL}, {0xcccccccccccccccdULL, 0x3333333333333333ULL}, {0x8000000000000000ULL, 0x0000000000000000ULL}, {0xa000000000000000ULL, 0x0000000000000000ULL}, {0xc800000000000000ULL, 0x0000000000000000ULL}, {0xfa00000000000000ULL, 0x0000000000000000ULL}, {0x9c40000000000000ULL, 0x0000000000000000ULL}, {0xc350000000000000ULL, 0x0000000000000000ULL}, {0xf424000000000000ULL, 0x0000000000000000ULL}, {0x9896800000000000ULL, 0x0000000000000000ULL}, {0xbebc200000000000ULL, 0x0000000000000000ULL}, {0xee6b280000000000ULL, 0x0000000000000000ULL}, {0x9502f90000000000ULL, 0x0000000000000000ULL}, {0xba43b74000000000ULL, 0x0000000000000000ULL}, {0xe8d4a51000000000ULL, 0x0000000000000000ULL}, {0x9184e72a00000000ULL, 0x0000000000000000ULL}, {0xb5e620f480000000ULL, 0x0000000000000000ULL}, {0xe35fa931a0000000ULL, 0x0000000000000000ULL}, {0x8e1bc9bf04000000ULL, 0x0000000000000000ULL}, {0xb1a2bc2ec5000000ULL, 0x0000000000000000ULL}, {0xde0b6b3a76400000ULL, 0x0000000000000000ULL}, {0x8ac7230489e80000ULL, 0x0000000000000000ULL}, {0xad78ebc5ac620000ULL, 0x0000000000000000ULL}, {0xd8d726b7177a8000ULL, 0x0000000000000000ULL}, {0x878678326eac9000ULL, 0x0000000000000000ULL}, {0xa968163f0a57b400ULL, 0x0000000000000000ULL}, {0xd3c21bcecceda100ULL, 0x0000000000000000ULL}, {0x84595161401484a0ULL, 0x0000000000000000ULL}, {0xa56fa5b99019a5c8ULL, 0x0000000000000000ULL}, {0xcecb8f27f4200f3aULL, 0x0000000000000000ULL}, {0x813f3978f8940985ULL, 0xc000000000000000ULL}, {0xa18f07d736b90be6ULL, 0xb000000000000000ULL}, {0xc9f2c9cd04674edfULL, 0x5c00000000000000ULL}, {0xfc6f7c4045812297ULL, 0xb300000000000000ULL}, {0x9dc5ada82b70b59eULL, 0x0fe0000000000000ULL}, {0xc5371912364ce306ULL, 0x93d8000000000000ULL}, {0xf684df56c3e01bc7ULL, 0x38ce000000000000ULL}, {0x9a130b963a6c115dULL, 0xc380c00000000000ULL}, {0xc097ce7bc90715b4ULL, 0xb460f00000000000ULL}, {0xf0bdc21abb48db21ULL, 0xe1792c0000000000ULL}, {0x96769950b50d88f5ULL, 0xecebbb8000000000ULL}, {0xbc143fa4e250eb32ULL, 0xe826aa6000000000ULL}, {0xeb194f8e1ae525feULL, 0xa23054f800000000ULL}, {0x92efd1b8d0cf37bfULL, 0xa55e351b00000000ULL}, {0xb7abc627050305aeULL, 0x0eb5c261c0000000ULL}, {0xe596b7b0c643c71aULL, 0x926332fa30000000ULL}, {0x8f7e32ce7bea5c70ULL, 0x1b7dffdc5e000000ULL}, {0xb35dbf821ae4f38cULL, 0x225d7fd375800000ULL}, {0xe0352f62a19e306fULL, 0x2af4dfc852e00000ULL}, {0x8c213d9da502de46ULL, 0xbad90bdd33cc0000ULL}, {0xaf298d050e4395d7ULL, 0x698f4ed480bf0000ULL}, {0xdaf3f04651d47b4dULL, 0xc3f32289a0eec000ULL}, {0x88d8762bf324cd10ULL, 0x5a77f59604953800ULL}, {0xab0e93b6efee0054ULL, 0x7115f2fb85ba8600ULL}, {0xd5d238a4abe98069ULL, 0x8d5b6fba67292780ULL}, {0x85a36366eb71f042ULL, 0xb85925d48079b8b0ULL}, {0xa70c3c40a64e6c52ULL, 0x666f6f49a09826dcULL}, {0xd0cf4b50cfe20766ULL, 0x000b4b1c08be3093ULL}, {0x82818f1281ed44a0ULL, 0x40070ef18576de5bULL}, {0xa321f2d7226895c8ULL, 0x5008d2ade6d495f2ULL}, {0xcbea6f8ceb02bb3aULL, 0x640b07596089bb6fULL}, {0xfee50b7025c36a09ULL, 0xfd0dc92fb8ac2a4bULL}, {0x9f4f2726179a2246ULL, 0xfe289dbdd36b9a6fULL}, {0xc722f0ef9d80aad7ULL, 0xbdb2c52d4846810aULL}, {0xf8ebad2b84e0d58cULL, 0x2d1f76789a58214dULL}, {0x9b934c3b330c8578ULL, 0x9c33aa0b607714d0ULL}, {0xc2781f49ffcfa6d6ULL, 0xc340948e3894da04ULL}, {0xf316271c7fc3908bULL, 0x7410b9b1c6ba1085ULL}, {0x97edd871cfda3a57ULL, 0x688a740f1c344a53ULL}, {0xbde94e8e43d0c8edULL, 0xc2ad1112e3415ce8ULL}, {0xed63a231d4c4fb28ULL, 0xb35855579c11b422ULL}, {0x945e455f24fb1cf9ULL, 0x70173556c18b1095ULL}, {0xb975d6b6ee39e437ULL, 0x4c1d02ac71edd4bbULL}, {0xe7d34c64a9c85d45ULL, 0x9f2443578e6949e9ULL}, {0x90e40fbeea1d3a4bULL, 0x4376aa16b901ce32ULL}, {0xb51d13aea4a488deULL, 0x9454549c674241beULL}, {0xe264589a4dcdab15ULL, 0x396969c38112d22eULL}, {0x8d7eb76070a08aedULL, 0x03e1e21a30abc35dULL}, {0xb0de65388cc8ada9ULL, 0xc4da5aa0bcd6b434ULL}, {0xdd15fe86affad913ULL, 0xb610f148ec0c6141ULL}, {0x8a2dbf142dfcc7acULL, 0x91ca96cd9387bcc8ULL}, {0xacb92ed9397bf997ULL, 0xb63d3c80f869abfbULL}, {0xd7e77a8f87daf7fcULL, 0x23cc8ba1368416f9ULL}, {0x86f0ac99b4e8dafeULL, 0x965fd744c2128e5cULL}, {0xa8acd7c0222311bdULL, 0x3bf7cd15f29731f3ULL}, {0xd2d80db02aabd62cULL, 0x0af5c05b6f3cfe6fULL}, {0x83c7088e1aab65dcULL, 0x86d9983925861f05ULL}, {0xa4b8cab1a1563f53ULL, 0xa88ffe476ee7a6c7ULL}, {0xcde6fd5e09abcf27ULL, 0x12b3fdd94aa19079ULL}, {0x80b05e5ac60b6179ULL, 0xabb07ea7cea4fa4bULL}, {0xa0dc75f1778e39d7ULL, 0x969c9e51c24e38deULL}, {0xc913936dd571c84dULL, 0xfc43c5e632e1c716ULL}, {0xfb5878494ace3a60ULL, 0xfb54b75fbf9a38dcULL}, {0x9d174b2dcec0e47cULL, 0x9d14f29bd7c06389ULL}, {0xc45d1df942711d9bULL, 0xc45a2f42cdb07c6bULL}, {0xf5746577930d6501ULL, 0x3570bb13811c9b86ULL}, {0x9968bf6abbe85f21ULL, 0x816674ec30b1e134ULL}, {0xbfc2ef456ae276e9ULL, 0x61c012273cde5981ULL}, {0xefb3ab16c59b14a3ULL, 0x3a3016b10c15efe1ULL}, {0x95d04aee3b80ece6ULL, 0x445e0e2ea78db5edULL}, {0xbb445da9ca612820ULL, 0xd57591ba51712368ULL}, {0xea1575143cf97227ULL, 0x0ad2f628e5cd6c42ULL}, {0x924d692ca61be759ULL, 0xa6c3d9d98fa063a9ULL}, {0xb6e0c377cfa2e12fULL, 0x9074d04ff3887c93ULL}, {0xe498f455c38b997bULL, 0xf4920463f06a9bb8ULL}, {0x8edf98b59a373fedULL, 0xb8db42be7642a153ULL}, {0xb2977ee300c50fe8ULL, 0xa712136e13d349a8ULL}, {0xdf3d5e9bc0f653e2ULL, 0xd0d6984998c81c12ULL}, {0x8b865b215899f46dULL, 0x42861f2dff7d118bULL}, {0xae67f1e9aec07188ULL, 0x1327a6f97f5c55eeULL}, {0xda01ee641a708deaULL, 0x17f190b7df336b6aULL}, {0x884134fe908658b3ULL, 0xcef6fa72eb802322ULL}, {0xaa51823e34a7eedfULL, 0x42b4b90fa6602beaULL}, {0xd4e5e2cdc1d1ea97ULL, 0x9361e7538ff836e5ULL}, {0x850fadc09923329fULL, 0xfc1d309439fb224fULL}, {0xa6539930bf6bff46ULL, 0x7b247cb94879eae3ULL}, {0xcfe87f7cef46ff17ULL, 0x19ed9be79a98659cULL}, {0x81f14fae158c5f6fULL, 0xb0348170c09f3f81ULL}, {0xa26da3999aef774aULL, 0x1c41a1ccf0c70f62ULL}, {0xcb090c8001ab551dULL, 0xa3520a402cf8d33aULL}, {0xfdcb4fa002162a64ULL, 0x8c268cd038370809ULL}, {0x9e9f11c4014dda7fULL, 0xd798180223226505ULL}, {0xc646d63501a1511eULL, 0x4d7e1e02abeafe47ULL}, {0xf7d88bc24209a566ULL, 0xe0dda58356e5bdd9ULL}, {0x9ae7575969460760ULL, 0xcc8a8772164f96a7ULL}, {0xc1a12d2fc3978938ULL, 0xffad294e9be37c51ULL}, {0xf209787bb47d6b85ULL, 0x3f9873a242dc5b65ULL}, {0x9745eb4d50ce6333ULL, 0x07bf484569c9b91fULL}, {0xbd176620a501fc00ULL, 0x49af1a56c43c2767ULL}, {0xec5d3fa8ce427b00ULL, 0x5c1ae0ec754b3141ULL}, {0x93ba47c980e98ce0ULL, 0x3990cc93c94efec8ULL}, {0xb8a8d9bbe123f018ULL, 0x47f4ffb8bba2be7bULL}, {0xe6d3102ad96cec1eULL, 0x59f23fa6ea8b6e1aULL}, {0x9043ea1ac7e41393ULL, 0x783767c8529724d0ULL}, {0xb454e4a179dd1878ULL, 0xd64541ba673cee04ULL}, {0xe16a1dc9d8545e95ULL, 0x0bd69229010c2985ULL}, {0x8ce2529e2734bb1eULL, 0xe7661b59a0a799f3ULL}, {0xb01ae745b101e9e5ULL, 0xa13fa23008d18070ULL}, {0xdc21a1171d42645eULL, 0x898f8abc0b05e08cULL}, {0x899504ae72497ebbULL, 0x95f9b6b586e3ac57ULL}, {0xabfa45da0edbde6aULL, 0xfb782462e89c976dULL}, {0xd6f8d7509292d604ULL, 0xba562d7ba2c3bd49ULL}, {0x865b86925b9bc5c3ULL, 0xf475dc6d45ba564dULL}, {0xa7f26836f282b733ULL, 0x719353889728ebe1ULL}, {0xd1ef0244af236500ULL, 0xcdf8286abcf326d9ULL}, {0x8335616aed761f20ULL, 0x80bb1942b617f847ULL}, {0xa402b9c5a8d3a6e8ULL, 0xa0e9df93639df659ULL}, {0xcd036837130890a2ULL, 0xc92457783c8573f0ULL}, {0x802221226be55a65ULL, 0x3db6b6ab25d36876ULL}, {0xa02aa96b06deb0feULL, 0x0d246455ef484293ULL}, {0xc83553c5c8965d3eULL, 0x906d7d6b6b1a5338ULL}, {0xfa42a8b73abbf48dULL, 0x3488dcc645e0e806ULL}, {0x9c69a97284b578d8ULL, 0x00d589fbebac9104ULL}, {0xc38413cf25e2d70eULL, 0x010aec7ae697b545ULL}, {0xf46518c2ef5b8cd2ULL, 0x814da799a03da296ULL}, {0x98bf2f79d5993803ULL, 0x10d088c00426859eULL}, {0xbeeefb584aff8604ULL, 0x5504aaf005302705ULL}, {0xeeaaba2e5dbf6785ULL, 0x6a45d5ac067c30c7ULL}, {0x952ab45cfa97a0b3ULL, 0x226ba58b840d9e7cULL}, {0xba756174393d88e0ULL, 0x6b068eee6511061bULL}, {0xe912b9d1478ceb18ULL, 0x85c832a9fe5547a2ULL}, {0x91abb422ccb812efULL, 0x539d1faa3ef54cc5ULL}, {0xb616a12b7fe617abULL, 0xa8846794ceb29ff6ULL}, {0xe39c49765fdf9d95ULL, 0x12a5817a025f47f4ULL}, {0x8e41ade9fbebc27eULL, 0xeba770ec417b8cf8ULL}, {0xb1d219647ae6b31dULL, 0xa6914d2751da7037ULL}, {0xde469fbd99a05fe4ULL, 0x9035a07126510c44ULL}, {0x8aec23d680043befULL, 0xda218446b7f2a7abULL}, {0xada72ccc20054aeaULL, 0x50a9e55865ef5195ULL}, {0xd910f7ff28069da5ULL, 0xe4d45eae7f6b25fbULL}, {0x87aa9aff79042287ULL, 0x6f04bb2d0fa2f7bdULL}, {0xa99541bf57452b29ULL, 0xcac5e9f8538bb5acULL}, {0xd3fa922f2d1675f3ULL, 0xbd776476686ea317ULL}, {0x847c9b5d7c2e09b8ULL, 0x966a9eca014525eeULL}, {0xa59bc234db398c26ULL, 0xbc05467c81966f6aULL}, {0xcf02b2c21207ef2fULL, 0x6b06981ba1fc0b44ULL}, {0x8161afb94b44f57eULL, 0xe2e41f11453d870aULL}, {0xa1ba1ba79e1632ddULL, 0x9b9d26d5968ce8cdULL}, {0xca28a291859bbf94ULL, 0x8284708afc302301ULL}, {0xfcb2cb35e702af79ULL, 0xa3258cadbb3c2bc1ULL}, {0x9defbf01b061adacULL, 0xc5f777ec95059b58ULL}, {0xc56baec21c7a1917ULL, 0xf77555e7ba47022fULL}, {0xf6c69a72a3989f5cULL, 0x7552ab61a8d8c2baULL}, {0x9a3c2087a63f639aULL, 0xc953ab1d098779b4ULL}, {0xc0cb28a98fcf3c80ULL, 0x7ba895e44be95822ULL}, {0xf0fdf2d3f3c30ba0ULL, 0x9a92bb5d5ee3ae2aULL}, {0x969eb7c47859e744ULL, 0x609bb51a5b4e4cdaULL}, {0xbc4665b596706115ULL, 0x78c2a260f221e011ULL}, {0xeb57ff22fc0c795aULL, 0x56f34af92eaa5815ULL}, {0x9316ff75dd87cbd9ULL, 0xf6580edbbd2a770dULL}, {0xb7dcbf5354e9becfULL, 0xf3ee1292ac7514d0ULL}, {0xe5d3ef282a242e82ULL, 0x70e9973757925a05ULL}, {0x8fa475791a569d11ULL, 0x0691fe8296bb7843ULL}, {0xb38d92d760ec4456ULL, 0xc8367e233c6a5653ULL}, {0xe070f78d3927556bULL, 0x7a441dac0b84ebe8ULL}, {0x8c469ab843b89563ULL, 0x6c6a928b87331371ULL}, {0xaf58416654a6babcULL, 0xc785372e68ffd84dULL}, {0xdb2e51bfe9d0696bULL, 0xf96684fa033fce61ULL}, {0x88fcf317f22241e3ULL, 0xbbe0131c4207e0fcULL}, {0xab3c2fddeeaad25bULL, 0x2ad817e35289d93cULL}, {0xd60b3bd56a5586f2ULL, 0x758e1ddc272c4f8bULL}, {0x85c7056562757457ULL, 0x0978d2a9987bb1b6ULL}, {0xa738c6bebb12d16dULL, 0x4bd70753fe9a9e24ULL}, {0xd106f86e69d785c8ULL, 0x1eccc928fe4145adULL}, {0x82a45b450226b39dULL, 0x133ffdb99ee8cb8cULL}, {0xa34d721642b06085ULL, 0xd80ffd2806a2fe6fULL}, {0xcc20ce9bd35c78a6ULL, 0xce13fc72084bbe0bULL}, {0xff290242c83396cfULL, 0x8198fb8e8a5ead8eULL}, {0x9f79a169bd203e42ULL, 0xf0ff9d39167b2c79ULL}, {0xc75809c42c684dd2ULL, 0xad3f84875c19f797ULL}, {0xf92e0c3537826146ULL, 0x588f65a93320757dULL}, {0x9bbcc7a142b17cccULL, 0x77599f89bff4496eULL}, {0xc2abf989935ddbffULL, 0x9530076c2ff15bcaULL}, {0xf356f7ebf83552ffULL, 0xfa7c09473bedb2bcULL}, {0x98165af37b2153dfULL, 0x3c8d85cc85748fb5ULL}, {0xbe1bf1b059e9a8d7ULL, 0x8bb0e73fa6d1b3a3ULL}, {0xeda2ee1c7064130dULL, 0xee9d210f9086208cULL}, {0x9485d4d1c63e8be8ULL, 0x752234a9ba53d457ULL}, {0xb9a74a0637ce2ee2ULL, 0x926ac1d428e8c96dULL}, {0xe8111c87c5c1ba9aULL, 0x370572493322fbc8ULL}, {0x910ab1d4db9914a1ULL, 0xe263676dbff5dd5dULL}, {0xb54d5e4a127f59c9ULL, 0xdafc41492ff354b4ULL}, {0xe2a0b5dc971f303bULL, 0xd1bb519b7bf029e2ULL}, {0x8da471a9de737e25ULL, 0xa31513012d761a2dULL}, {0xb10d8e1456105daeULL, 0x8bda57c178d3a0b8ULL}, {0xdd50f1996b947519ULL, 0x2ed0edb1d70888e6ULL}, {0x8a5296ffe33cc930ULL, 0x7d42948f26655590ULL}, {0xace73cbfdc0bfb7cULL, 0x9c9339b2effeaaf4ULL}, {0xd8210befd30efa5bULL, 0xc3b8081fabfe55b1ULL}, {0x8714a775e3e95c79ULL, 0x9a530513cb7ef58eULL}, {0xa8d9d1535ce3b397ULL, 0x80e7c658be5eb2f2ULL}, {0xd31045a8341ca07dULL, 0xe121b7eeedf65fafULL}, {0x83ea2b892091e44eULL, 0x6cb512f554b9fbcdULL}, {0xa4e4b66b68b65d61ULL, 0x07e257b2a9e87ac0ULL}, {0xce1de40642e3f4baULL, 0xc9daed9f54629971ULL}, {0x80d2ae83e9ce78f4ULL, 0x3e28d48394bd9fe6ULL}, {0xa1075a24e4421731ULL, 0x4db309a479ed07e0ULL}, {0xc94930ae1d529cfdULL, 0x211fcc0d986849d8ULL}, {0xfb9b7cd9a4a7443dULL, 0xe967bf10fe825c4eULL}, {0x9d412e0806e88aa6ULL, 0x71e0d76a9f1179b1ULL}, {0xc491798a08a2ad4fULL, 0x0e590d4546d5d81dULL}, {0xf5b5d7ec8acb58a3ULL, 0x51ef5096988b4e24ULL}, {0x9991a6f3d6bf1766ULL, 0x5335925e1f5710d6ULL}, {0xbff610b0cc6edd40ULL, 0xe802f6f5a72cd50cULL}, {0xeff394dcff8a948fULL, 0x2203b4b310f80a4fULL}, {0x95f83d0a1fb69cdaULL, 0xb54250efea9b0671ULL}, {0xbb764c4ca7a44410ULL, 0x6292e52be541c80eULL}, {0xea53df5fd18d5514ULL, 0x7b379e76de923a12ULL}, {0x92746b9be2f8552dULL, 0xcd02c30a4b1b644bULL}, {0xb7118682dbb66a78ULL, 0xc04373ccdde23d5eULL}, {0xe4d5e82392a40516ULL, 0xf05450c0155accb5ULL}, {0x8f05b1163ba6832eULL, 0xd634b2780d58bff1ULL}, {0xb2c71d5bca9023f9ULL, 0x8bc1df1610aeefedULL}, {0xdf78e4b2bd342cf7ULL, 0x6eb256db94daabe9ULL}, {0x8bab8eefb6409c1bULL, 0xe52f76493d08ab71ULL}, {0xae9672aba3d0c321ULL, 0x5e7b53db8c4ad64eULL}, {0xda3c0f568cc4f3e9ULL, 0x361a28d26f5d8be1ULL}, {0x8865899617fb1872ULL, 0x81d05983859a776dULL}, {0xaa7eebfb9df9de8eULL, 0x22446fe467011548ULL}, {0xd51ea6fa85785632ULL, 0xaad58bdd80c15a9aULL}, {0x8533285c936b35dfULL, 0x2ac5776a7078d8a0ULL}, {0xa67ff273b8460357ULL, 0x7576d5450c970ec8ULL}, {0xd01fef10a657842dULL, 0xd2d48a964fbcd27aULL}, {0x8213f56a67f6b29cULL, 0x63c4d69df1d6038cULL}, {0xa298f2c501f45f43ULL, 0x7cb60c456e4b8470ULL}, {0xcb3f2f7642717714ULL, 0xdbe38f56c9de658cULL}, {0xfe0efb53d30dd4d8ULL, 0x12dc732c7c55feefULL}, {0x9ec95d1463e8a507ULL, 0x0bc9c7fbcdb5bf55ULL}, {0xc67bb4597ce2ce49ULL, 0x4ebc39fac1232f2aULL}, {0xf81aa16fdc1b81dbULL, 0x226b4879716bfaf5ULL}, {0x9b10a4e5e9913129ULL, 0x35830d4be6e37cd9ULL}, {0xc1d4ce1f63f57d73ULL, 0x02e3d09ee09c5c0fULL}, {0xf24a01a73cf2dcd0ULL, 0x439cc4c698c37313ULL}, {0x976e41088617ca02ULL, 0x2a41fafc1f7a27ecULL}, {0xbd49d14aa79dbc83ULL, 0xb4d279bb2758b1e7ULL}, {0xec9c459d51852ba3ULL, 0x22071829f12ede61ULL}, {0x93e1ab8252f33b46ULL, 0x35446f1a36bd4afcULL}, {0xb8da1662e7b00a18ULL, 0xc2958ae0c46c9dbcULL}, {0xe7109bfba19c0c9eULL, 0xf33aed98f587c52bULL}, {0x906a617d450187e3ULL, 0xd804d47f9974db3aULL}, {0xb484f9dc9641e9dbULL, 0x4e06099f7fd21209ULL}, {0xe1a63853bbd26452ULL, 0xa1878c075fc6968cULL}, {0x8d07e33455637eb3ULL, 0x24f4b7849bdc1e17ULL}, {0xb049dc016abc5e60ULL, 0x6e31e565c2d3259dULL}, {0xdc5c5301c56b75f8ULL, 0x89be5ebf3387ef04ULL}, {0x89b9b3e11b6329bbULL, 0x5616fb378034f562ULL}, {0xac2820d9623bf42aULL, 0xab9cba05604232bbULL}, {0xd732290fbacaf134ULL, 0x5683e886b852bf6aULL}, {0x867f59a9d4bed6c1ULL, 0xb61271543333b7a2ULL}, {0xa81f301449ee8c71ULL, 0xa3970da94000a58bULL}, {0xd226fc195c6a2f8dULL, 0x8c7cd1139000ceeeULL}, {0x83585d8fd9c25db8ULL, 0x37ce02ac3a008154ULL}, {0xa42e74f3d032f526ULL, 0x45c183574880a1aaULL}, {0xcd3a1230c43fb270ULL, 0xd731e42d1aa0ca14ULL}, {0x80444b5e7aa7cf86ULL, 0x867f2e9c30a47e4cULL}, {0xa0555e361951c367ULL, 0x281efa433ccd9de0ULL}, {0xc86ab5c39fa63441ULL, 0x7226b8d40c010558ULL}, {0xfa856334878fc151ULL, 0x4eb067090f0146aeULL}, {0x9c935e00d4b9d8d3ULL, 0x912e4065a960cc2cULL}, {0xc3b8358109e84f08ULL, 0xf579d07f13b8ff37ULL}, {0xf4a642e14c6262c9ULL, 0x32d8449ed8a73f05ULL}, {0x98e7e9cccfbd7dbeULL, 0x7fc72ae347688763ULL}, {0xbf21e44003acdd2dULL, 0x1fb8f59c1942a93cULL}, {0xeeea5d5004981479ULL, 0xe7a733031f93538bULL}, {0x95527a5202df0cccULL, 0xf0c87fe1f3bc1437ULL}, {0xbaa718e68396cffeULL, 0x2cfa9fda70ab1945ULL}, {0xe950df20247c83feULL, 0xb83947d10cd5df96ULL}, {0x91d28b7416cdd27fULL, 0xb323cce2a805abbeULL}, {0xb6472e511c81471eULL, 0x1fecc01b520716adULL}, {0xe3d8f9e563a198e6ULL, 0xa7e7f0222688dc59ULL}, {0x8e679c2f5e44ff90ULL, 0xa8f0f615581589b7ULL}, {0xb201833b35d63f74ULL, 0xd32d339aae1aec25ULL}, {0xde81e40a034bcf50ULL, 0x07f8808159a1a72eULL}, {0x8b112e86420f6192ULL, 0x04fb5050d805087dULL}, {0xadd57a27d29339f7ULL, 0x863a24650e064a9cULL}, {0xd94ad8b1c7380875ULL, 0xe7c8ad7e5187dd43ULL}, {0x87cec76f1c830549ULL, 0x70dd6c6ef2f4ea4aULL}, {0xa9c2794ae3a3c69bULL, 0x4d14c78aafb224ddULL}, {0xd433179d9c8cb842ULL, 0xa059f96d5b9eae14ULL}, {0x849feec281d7f329ULL, 0x24383be459432cccULL}, {0xa5c7ea73224deff4ULL, 0xed464add6f93f7ffULL}, {0xcf39e50feae16bf0ULL, 0x2897dd94cb78f5ffULL}, {0x81842f29f2cce376ULL, 0x195eea7cff2b99bfULL}, {0xa1e53af46f801c54ULL, 0x9fb6a51c3ef6802fULL}, {0xca5e89b18b602369ULL, 0xc7a44e634eb4203bULL}, {0xfcf62c1dee382c43ULL, 0xb98d61fc2261284aULL}, {0x9e19db92b4e31baaULL, 0x93f85d3d957cb92eULL}, {0xc5a05277621be294ULL, 0x38f6748cfadbe77aULL}, {0xf70867153aa2db39ULL, 0x473411b03992e158ULL}, {0x9a65406d44a5c904ULL, 0x8c808b0e23fbccd7ULL}, {0xc0fe908895cf3b45ULL, 0xafa0add1acfac00dULL}, {0xf13e34aabb430a16ULL, 0x9b88d94618397010ULL}, {0x96c6e0eab509e64eULL, 0xa13587cbcf23e60aULL}, {0xbc789925624c5fe1ULL, 0x4982e9bec2ecdf8dULL}, {0xeb96bf6ebadf77d9ULL, 0x1be3a42e73a81770ULL}, {0x933e37a534cbaae8ULL, 0x716e469d08490ea6ULL}, {0xb80dc58e81fe95a2ULL, 0x8dc9d8444a5b524fULL}, {0xe61136f2227e3b0aULL, 0x313c4e555cf226e3ULL}, {0x8fcac257558ee4e7ULL, 0xdec5b0f55a17584eULL}, {0xb3bd72ed2af29e20ULL, 0x56771d32b09d2e62ULL}, {0xe0accfa875af45a8ULL, 0x6c14e47f5cc479faULL}, {0x8c6c01c9498d8b89ULL, 0x438d0ecf99facc3cULL}, {0xaf87023b9bf0ee6bULL, 0x1470528380797f4bULL}, {0xdb68c2ca82ed2a06ULL, 0x598c67246097df1eULL}, }; /* ======== Uscale core ======== */ static inline int log10_pow2(int x) { return (x * 78913) >> 18; } static inline int log2_pow10(int x) { return (x * 108853) >> 15; } typedef struct { pow10_entry pm; int s; } scaler; static inline scaler prescale(int e, int p, int lp) { scaler c; c.pm = pow10_tab[p - POW10_MIN]; c.s = -(e + lp + 3); return c; } typedef uint64_t unrounded; static inline uint64_t ur_floor(unrounded u) { return (u + 0) >> 2; } static inline uint64_t ur_round(unrounded u) { return (u + 1 + ((u >> 2) & 1)) >> 2; } static inline uint64_t ur_ceil(unrounded u) { return (u + 3) >> 2; } static inline unrounded ur_div(unrounded u, uint64_t d) { return (u / d) | (u & 1) | (u % d != 0 ? 1 : 0); } static inline unrounded ur_nudge(unrounded u, int delta) { return u + delta; } static unrounded uscale(uint64_t x, scaler c) { uint64_t hi, mid, mid2, lo_unused; mul64(x, c.pm.hi, &hi, &mid); uint64_t sticky = 1; if (c.s >= 64) { /* x * 10^p < 2^(c.s-64), i.e. < 1 in the unrounded "1.0 = 4" encoding; rounds to 0 with sticky=1 */ return sticky; } uint64_t mask = (1ULL << c.s) - 1; if ((hi & mask) == 0) { mul64(x, c.pm.lo, &mid2, &lo_unused); sticky = (mid - mid2) > 1 ? 1 : 0; hi -= (mid < mid2) ? 1 : 0; } return (hi >> c.s) | sticky; } static void unpack64(double f, uint64_t *m, int *e) { const int shift = 64 - 53; const int min_exp = -(1074 + shift); union { double d; uint64_t u; } u; u.d = f; uint64_t bits = u.u; int exp; *m = (1ULL << 63) | ((bits & ((1ULL << 52) - 1)) << shift); exp = (int)((bits >> 52) & ((1 << shift) - 1)); if (exp == 0) { int s; *m &= ~(1ULL << 63); *e = min_exp; s = clz64(*m); *m <<= s; *e -= s; } else { *e = (exp - 1) + min_exp; } } static double pack64(uint64_t m, int e) { union { double d; uint64_t u; } u; if ((m & (1ULL << 52)) == 0) { /* subnormal */ u.u = m; } else { int biased = 1075 + e; if (biased >= 2047) { /* exponent overflow -> infinity */ u.u = 0x7FF0000000000000ULL; } else { u.u = (m & ~(1ULL << 52)) | ((uint64_t)biased << 52); } } return u.d; } /* ======== Algorithm helpers ======== */ static const uint64_t uint64_pow10[20] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL, 1000000000ULL, 10000000000ULL, 100000000000ULL, 1000000000000ULL, 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL, 10000000000000000000ULL, }; static int count_digits(uint64_t d) { if (d == 0) return 1; /* clz64(0) is UB; "0" is one digit */ int nd = log10_pow2(bits_len64(d)); return nd + (d >= uint64_pow10[nd] ? 1 : 0); } static void fixed_width(double f, int n, uint64_t *d, int *p) { uint64_t m; int e; unrounded u; unpack64(f, &m, &e); *p = n - 1 - log10_pow2(e + 63); u = uscale(m, prescale(e, *p, log2_pow10(*p))); *d = ur_round(u); if (*d >= uint64_pow10[n]) { *d = ur_round(ur_div(u, 10)); (*p)--; } *p = -(*p); } /* * skewed returns floor(log10(3/4 * 2^e)) * Used for shortest-width printing at powers of 2 */ static inline int skewed(int e) { return (e * 631305 - 261663) >> 21; } /* * trim_zeros removes trailing zeros from x * 10^p */ static void trim_zeros(uint64_t *x, int *p) { const uint64_t inv5 = 0xcccccccccccccccdULL; const uint64_t inv5p2 = 0x8f5c28f5c28f5c29ULL; const uint64_t inv5p4 = 0xd288ce703afb7e91ULL; const uint64_t inv5p8 = 0xc767074b22e90e21ULL; uint64_t d; /* cut 1 zero, or else return */ d = (*x * inv5); d = (d >> 1) | (d << 63); if (d <= UINT64_MAX / 10) { *x = d; (*p)++; } else { return; } /* cut 8 zeros */ d = (*x * inv5p8); d = (d >> 8) | (d << 56); if (d <= UINT64_MAX / 100000000ULL) { *x = d; *p += 8; } /* cut 4 zeros */ d = (*x * inv5p4); d = (d >> 4) | (d << 60); if (d <= UINT64_MAX / 10000) { *x = d; *p += 4; } /* cut 2 zeros */ d = (*x * inv5p2); d = (d >> 2) | (d << 62); if (d <= UINT64_MAX / 100) { *x = d; *p += 2; } /* cut 1 zero */ d = (*x * inv5); d = (d >> 1) | (d << 63); if (d <= UINT64_MAX / 10) { *x = d; (*p)++; } } /* * shortest computes the shortest formatting of f * Returns d and p such that d * 10^p equals f when parsed */ static void shortest(double f, uint64_t *d, int *p) { const int min_exp = -1085; uint64_t m, min, max; int e, z, odd, lp; scaler pre; uint64_t dmin, dmax; unpack64(f, &m, &e); z = 11; if (m == (1ULL << 63) && e > min_exp) { *p = -skewed(e + z); min = m - (1ULL << (z - 2)); } else { if (e < min_exp) { z = 11 + (min_exp - e); } *p = -log10_pow2(e + z); min = m - (1ULL << (z - 1)); } max = m + (1ULL << (z - 1)); odd = (int)((m >> z) & 1); lp = log2_pow10(*p); pre = prescale(e, *p, lp); dmin = ur_ceil(ur_nudge(uscale(min, pre), +odd)); dmax = ur_floor(ur_nudge(uscale(max, pre), -odd)); /* check if a multiple of 10 is in range */ *d = dmax / 10; if (*d * 10 >= dmin) { int new_p = -(*p - 1); trim_zeros(d, &new_p); *p = new_p; return; } /* multiple valid values: pick the rounded one */ if (dmin < dmax) { *d = ur_round(uscale(m, pre)); } else { *d = dmin; } *p = -(*p); } static double parse_decimal(uint64_t d, int p) { int b, lp, e; unrounded u; uint64_t m; if (d == 0) return 0.0; b = bits_len64(d); lp = log2_pow10(p); e = 53 - b - lp; if (e > 1074) e = 1074; u = uscale(d << (64 - b), prescale(e - (64 - b), p, lp)); m = ur_round(u); if (m >= (1ULL << 53)) { u = (u >> 1) | (u & 1); m = ur_round(u); e--; } return pack64(m, -e); } /* ======== Formatting helpers ======== */ static const char i2a[] = "00010203040506070809" "10111213141516171819" "20212223242526272829" "30313233343536373839" "40414243444546474849" "50515253545556575859" "60616263646566676869" "70717273747576777879" "80818283848586878889" "90919293949596979899"; static void format_base10(char *buf, int nd, uint64_t u) { int idx; while (nd >= 2) { nd -= 2; idx = (int)(u % 100) * 2; u /= 100; buf[nd] = i2a[idx]; buf[nd + 1] = i2a[idx + 1]; } if (nd > 0) { buf[0] = '0' + (char)u; } } static int emit_exp(char *s, char e_char, int exp) { char *p = s; *p++ = e_char; if (exp < 0) { *p++ = '-'; exp = -exp; } else { *p++ = '+'; } if (exp >= 100) { *p++ = '0' + exp / 100; exp %= 100; } *p++ = '0' + exp / 10; *p++ = '0' + exp % 10; return (int)(p - s); } /* ======== mrb_format_float ======== */ #ifdef MRB_USE_FLOAT32 #define FLT_MIN_BUF_SIZE 6 #else #define FLT_MIN_BUF_SIZE 7 #endif int mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, char sign) { char *s = buf; int buf_remaining = (int)buf_size - 1; int alt_form = 0; char e_char; if ((uint8_t)fmt & 0x80) { fmt &= 0x7f; alt_form = 1; } if (buf_size <= (size_t)FLT_MIN_BUF_SIZE) { if (buf_size >= 2) *s++ = '?'; if (buf_size >= 1) *s = '\0'; return buf_size >= 2; } if (signbit(f)) { *s++ = '-'; f = -f; } else if (sign) { *s++ = sign; } buf_remaining -= (int)(s - buf); { char uc = fmt & 0x20; if (isinf(f)) { *s++ = 'I' ^ uc; *s++ = 'N' ^ uc; *s++ = 'F' ^ uc; goto done; } if (isnan(f)) { *s++ = 'N' ^ uc; *s++ = 'A' ^ uc; *s++ = 'N' ^ uc; goto done; } } { int use_shortest = (prec == -2); if (prec < 0) prec = 6; e_char = 'E' | (fmt & 0x20); fmt |= 0x20; if (fmt == 'g') { if (use_shortest) fmt = 'S'; /* shortest mode */ else if (prec == 0) prec = 1; } } if (f == 0.0) { /* zero */ if (fmt == 'e') { *s++ = '0'; if (prec > 0 || alt_form) { int i; if (prec > buf_remaining - 5) prec = buf_remaining - 5; *s++ = '.'; for (i = 0; i < prec; i++) *s++ = '0'; } s += emit_exp(s, e_char, 0); } else if (fmt == 'f') { int i; if (prec > buf_remaining - 2) prec = buf_remaining - 2; *s++ = '0'; if (prec > 0 || alt_form) { *s++ = '.'; for (i = 0; i < prec; i++) *s++ = '0'; } } else { /* g */ *s++ = '0'; if (alt_form && prec > 1) { int i; *s++ = '.'; for (i = 1; i < prec; i++) *s++ = '0'; } } } else { /* nonzero finite */ uint64_t d; int p, nd, exp; char digs[20] = {0}; /* gcc -Wmaybe-uninitialized false positive: count_digits() always returns >= 1 */ if (fmt == 'S') { /* shortest representation for to_s */ int i; shortest((double)f, &d, &p); nd = count_digits(d); exp = p + nd - 1; format_base10(digs, nd, d); #ifdef MRB_USE_FLOAT32 if (exp < -4 || exp >= 7) { #else if (exp < -4 || exp >= 15) { #endif /* e format */ *s++ = digs[0]; if (nd > 1) { *s++ = '.'; for (i = 1; i < nd; i++) *s++ = digs[i]; } s += emit_exp(s, e_char, exp); } else { /* f format */ if (exp < 0) { *s++ = '0'; *s++ = '.'; for (i = 0; i < -(exp + 1); i++) *s++ = '0'; for (i = 0; i < nd; i++) *s++ = digs[i]; } else { for (i = 0; i <= exp && i < nd; i++) *s++ = digs[i]; for (; i <= exp; i++) *s++ = '0'; if (nd > exp + 1) { *s++ = '.'; for (i = exp + 1; i < nd; i++) *s++ = digs[i]; } } } } else if (fmt == 'g') { /* g/G format */ int fprec, n = prec; if (n > 18) n = 18; if (n < 1) n = 1; fixed_width((double)f, n, &d, &p); nd = count_digits(d); exp = p + nd - 1; if (exp < -4 || exp >= prec) { /* use e format with prec-1 fractional digits */ fprec = prec - 1; format_base10(digs, nd, d); *s++ = digs[0]; if (fprec > 0 || alt_form) { int i, end = fprec < nd - 1 ? fprec : nd - 1; *s++ = '.'; for (i = 0; i < end; i++) *s++ = digs[1 + i]; for (; i < fprec; i++) *s++ = '0'; } if (!alt_form) { /* strip trailing zeros */ while (s > buf && s[-1] == '0') s--; if (s > buf && s[-1] == '.') s--; } s += emit_exp(s, e_char, exp); } else { /* use f format with prec-(exp+1) fractional digits */ int i; fprec = prec - (exp + 1); format_base10(digs, nd, d); /* integer part */ if (exp < 0) { *s++ = '0'; } else { for (i = 0; i <= exp && i < nd; i++) *s++ = digs[i]; for (; i <= exp; i++) *s++ = '0'; } if (fprec > 0 || alt_form) { int frac_avail; *s++ = '.'; if (exp < 0) { int zeros = -(exp + 1); for (i = 0; i < zeros && i < fprec; i++) *s++ = '0'; frac_avail = fprec - zeros; for (i = 0; i < frac_avail && i < nd; i++) *s++ = digs[i]; for (; i < frac_avail; i++) *s++ = '0'; } else { frac_avail = nd - exp - 1; if (frac_avail < 0) frac_avail = 0; for (i = 0; i < frac_avail && i < fprec; i++) *s++ = digs[exp + 1 + i]; for (; i < fprec; i++) *s++ = '0'; } } if (!alt_form && fprec > 0) { while (s[-1] == '0') s--; if (s[-1] == '.') s--; } } } else if (fmt == 'e') { /* e/E format */ int n = prec + 1; int i; if (n > 18) n = 18; if (n < 1) n = 1; fixed_width((double)f, n, &d, &p); nd = count_digits(d); exp = p + nd - 1; format_base10(digs, nd, d); *s++ = digs[0]; if (prec > 0 || alt_form) { *s++ = '.'; for (i = 1; i < nd; i++) *s++ = digs[i]; for (i = nd - 1; i < prec; i++) *s++ = '0'; } s += emit_exp(s, e_char, exp); } else { /* f/F format */ int exp_est, i; union { double d; uint64_t u; } uf; uf.d = (double)f; exp_est = log10_pow2((int)((uf.u >> 52) & 0x7FF) - 1023); if (exp_est >= buf_remaining) { /* too big for f, use e */ int n = prec + 1; if (n > 18) n = 18; if (n < 1) n = 1; fixed_width((double)f, n, &d, &p); nd = count_digits(d); exp = p + nd - 1; format_base10(digs, nd, d); *s++ = digs[0]; if (prec > 0 || alt_form) { *s++ = '.'; for (i = 1; i < nd; i++) *s++ = digs[i]; for (i = nd - 1; i < prec; i++) *s++ = '0'; } s += emit_exp(s, e_char, exp); } else { if ((exp_est + prec + 2) > buf_remaining) { prec = buf_remaining - exp_est - 2; if (prec < 0) prec = 0; } if (exp_est + prec <= 17) { /* Direct uscale: compute round(f * 10^prec) */ uint64_t m; int e, lp; unrounded u; unpack64((double)f, &m, &e); lp = log2_pow10(prec); u = uscale(m, prescale(e, prec, lp)); d = ur_round(u); nd = count_digits(d); exp = nd - prec - 1; } else { /* Large number: use fixed_width, pad with zeros */ int n = 18; fixed_width((double)f, n, &d, &p); nd = count_digits(d); exp = p + nd - 1; } format_base10(digs, nd, d); if (exp >= 0) { for (i = 0; i < nd && i <= exp; i++) *s++ = digs[i]; for (; i <= exp; i++) *s++ = '0'; if (prec > 0 || alt_form) { int frac_avail = nd - exp - 1; if (frac_avail < 0) frac_avail = 0; *s++ = '.'; for (i = 0; i < frac_avail && i < prec; i++) *s++ = digs[exp + 1 + i]; for (; i < prec; i++) *s++ = '0'; } } else { int zeros, frac_avail; *s++ = '0'; if (prec > 0 || alt_form) { *s++ = '.'; zeros = -(exp + 1); for (i = 0; i < zeros && i < prec; i++) *s++ = '0'; frac_avail = prec - zeros; for (i = 0; i < frac_avail && i < nd; i++) *s++ = digs[i]; for (; i < frac_avail; i++) *s++ = '0'; } } } } } done: *s = '\0'; return (int)(s - buf); } /* ======== mrb_read_float ======== */ MRB_API mrb_bool mrb_read_float(const char *str, char **endp, double *fp) { const char *p = str; const char *a = p; uint64_t d = 0; int nd = 0; int dp = 0; int trunc = 0; int sign = 1; int any_digits = 0; while (ISSPACE((unsigned char)*p)) p++; if (*p == '-') { sign = -1; p++; } else if (*p == '+') p++; /* skip leading zeros */ while (*p == '0') { p++; any_digits = 1; } /* integer part */ while (ISDIGIT(*p)) { if (nd < 19) { d = d * 10 + (*p - '0'); nd++; } else { trunc++; } any_digits = 1; a = ++p; } /* fractional part */ if (*p == '.') { p++; if (nd == 0) { while (*p == '0') { dp++; p++; any_digits = 1; } } while (ISDIGIT(*p)) { if (nd < 19) { d = d * 10 + (*p - '0'); nd++; dp++; } any_digits = 1; p++; } a = p; } if (!any_digits) { if (endp) *endp = (char*)str; *fp = 0.0; return FALSE; } /* exponent (optional). On malformed exponent ("5e", "5e+"), keep `a` pointing at the 'e' so the caller's *endp reflects where parsing stopped, and fall through using the mantissa-only result. */ int final_p = trunc - dp; if ((*p | 32) == 'e') { int e = 0; int exp_sign = 1; p++; if (*p == '-') { exp_sign = -1; p++; } else if (*p == '+') p++; if (ISDIGIT(*p)) { while (ISDIGIT(*p)) { if (e < 10000) e = e * 10 + (*p - '0'); p++; } final_p += e * exp_sign; a = p; } } { double res; if (d == 0) { res = 0.0; } else if (final_p > 308) { res = HUGE_VAL; } else if (final_p < -342 - nd) { res = 0.0; } else { res = parse_decimal(d, final_p); } if (sign < 0) res = -res; *fp = res; } if (endp) *endp = (char*)a; return TRUE; } #endif /* MRB_NO_FLOAT */