Skip to content

Instantly share code, notes, and snippets.

@timotheecour
Created May 26, 2021 03:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timotheecour/8f45eddc5b3533f5e166b305fde537f9 to your computer and use it in GitHub Desktop.
Save timotheecour/8f45eddc5b3533f5e166b305fde537f9 to your computer and use it in GitHub Desktop.
## Copyright 2020 Junekey Jeon
## Copyright 2020 Alexander Bolz
##
## Distributed under the Boost Software License, Version 1.0.
## (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
## char* output_end = Dtoa(buffer, value);
##
## Converts the given double-precision number into decimal form and stores the result in the given
## buffer.
##
## The buffer must be large enough, i.e. >= DtoaMinBufferLength.
## The output format is similar to printf("%g").
## The output is _not_ null-terminted.
##
## The output is optimal, i.e. the output string
## 1. rounds back to the input number when read in (using round-to-nearest-even)
## 2. is as short as possible,
## 3. is as close to the input number as possible.
##
## Note:
## This function may temporarily write up to DtoaMinBufferLength characters into the buffer.
var DtoaMinBufferLength*: cint = 64
proc Dtoa*(buffer: cstring; value: cdouble): cstring
## namespace dragonbox
## --------------------------------------------------------------------------------------------------
## This file contains an implementation of Junekey Jeon's Dragonbox algorithm.
##
## It is a simplified version of the reference implementation found here:
## https://github.com/jk-jeon/dragonbox
##
## The reference implementation also works with single-precision floating-point numbers and
## has options to configure the rounding mode.
## --------------------------------------------------------------------------------------------------
when defined(_MSC_VER):
discard
when not defined(DRAGONBOX_ASSERT):
template DRAGONBOX_ASSERT*(X: untyped): untyped =
assert(X)
## ==================================================================================================
##
## ==================================================================================================
proc ReinterpretBits*[Dest; Source](source: Source): Dest {.inline.} =
static_assert(sizeof((Dest)) == sizeof((Source)), "size mismatch")
var dest: Dest
memcpy(addr(dest), addr(source), sizeof((Source)))
return dest
type
Double* {.bycopy.} = object
bits*: bits_type ## = p (includes the hidden bit)
## static constexpr int32_t MaxExponent = std::numeric_limits<value_type>::max_exponent - 1 - (SignificandSize - 1);
## static constexpr int32_t MinExponent = std::numeric_limits<value_type>::min_exponent - 1 - (SignificandSize - 1);
## = 2^(p-1)
## = 2^(p-1) - 1
## !!!Ignored construct: static_assert ( std :: numeric_limits < double > :: is_iec559 && std :: numeric_limits < double > :: digits == 53 && std :: numeric_limits < double > :: max_exponent == 1024 , IEEE-754 double-precision implementation required ) ;
## Error: token expected: ) but got: ::!!!
type
value_type* = cdouble
bits_type* = uint64_t
const
SignificandSize*: int32_t = digits
const
ExponentBias*: int32_t = max_exponent - 1 + (SignificandSize - 1)
const
MaxIeeeExponent*: bits_type = bits_type(2 * max_exponent - 1)
const
HiddenBit*: bits_type = bits_type(1) shl (SignificandSize - 1)
const
SignificandMask*: bits_type = HiddenBit - 1
const
ExponentMask*: bits_type = MaxIeeeExponent shl (SignificandSize - 1)
const
SignMask*: bits_type = not (not bits_type(0) shr 1)
proc constructDouble*(bits_: bits_type): Double {.constructor.} =
discard
proc constructDouble*(value: value_type): Double {.constructor.} =
discard
proc PhysicalSignificand*(this: Double): bits_type {.noSideEffect.} =
return bits and SignificandMask
proc PhysicalExponent*(this: Double): bits_type {.noSideEffect.} =
return (bits and ExponentMask) shr (SignificandSize - 1)
proc IsFinite*(this: Double): bool {.noSideEffect.} =
return (bits and ExponentMask) != ExponentMask
proc IsInf*(this: Double): bool {.noSideEffect.} =
return (bits and ExponentMask) == ExponentMask and
(bits and SignificandMask) == 0
proc IsNaN*(this: Double): bool {.noSideEffect.} =
return (bits and ExponentMask) == ExponentMask and
(bits and SignificandMask) != 0
proc IsZero*(this: Double): bool {.noSideEffect.} =
return (bits and not SignMask) == 0
proc SignBit*(this: Double): bool {.noSideEffect.} =
return (bits and SignMask) != 0
## namespace
## ==================================================================================================
##
## ==================================================================================================
## Returns floor(x / 2^n).
##
## Technically, right-shift of negative integers is implementation defined...
## Should easily be optimized into SAR (or equivalent) instruction.
proc FloorDivPow2*(x: int32_t; n: int32_t): int32_t {.inline.} =
when 0:
return if x < 0: not (not x shr n) else: (x shr n)
else:
return x shr n
proc FloorLog2Pow10*(e: int32_t): int32_t {.inline.} =
DRAGONBOX_ASSERT(e >= -1233)
DRAGONBOX_ASSERT(e <= 1233)
return FloorDivPow2(e * 1741647, 19)
proc FloorLog10Pow2*(e: int32_t): int32_t {.inline.} =
DRAGONBOX_ASSERT(e >= -1500)
DRAGONBOX_ASSERT(e <= 1500)
return FloorDivPow2(e * 1262611, 22)
proc FloorLog10ThreeQuartersPow2*(e: int32_t): int32_t {.inline.} =
DRAGONBOX_ASSERT(e >= -1500)
DRAGONBOX_ASSERT(e <= 1500)
return FloorDivPow2(e * 1262611 - 524031, 22)
## ==================================================================================================
##
## ==================================================================================================
type
uint64x2* {.bycopy.} = object
hi*: uint64_t
lo*: uint64_t
proc ComputePow10*(k: int32_t): uint64x2 {.inline.} =
var kMin: int32_t = -292
var kMax: int32_t = 326
var Pow10: array[kMax - kMin + 1, uint64x2] = [[0xFF77B1FCBEBCDC4F'i64,
0x25E8E89C13BB0F7B'i64], [0x9FAACF3DF73609B1'i64, 0x77B191618C54E9AD'i64], [
0xC795830D75038C1D'i64, 0xD59DF5B9EF6A2418'i64], [0xF97AE3D0D2446F25'i64,
0x4B0573286B44AD1E'i64], [0x9BECCE62836AC577'i64, 0x4EE367F9430AEC33'i64], [
0xC2E801FB244576D5'i64, 0x229C41F793CDA740'i64], [0xF3A20279ED56D48A'i64,
0x6B43527578C11110'i64], [0x9845418C345644D6'i64, 0x830A13896B78AAAA'i64], [
0xBE5691EF416BD60C'i64, 0x23CC986BC656D554'i64], [0xEDEC366B11C6CB8F'i64,
0x2CBFBE86B7EC8AA9'i64], [0x94B3A202EB1C3F39'i64, 0x7BF7D71432F3D6AA'i64], [
0xB9E08A83A5E34F07'i64, 0xDAF5CCD93FB0CC54'i64], [0xE858AD248F5C22C9'i64,
0xD1B3400F8F9CFF69'i64], [0x91376C36D99995BE'i64, 0x23100809B9C21FA2'i64], [
0xB58547448FFFFB2D'i64, 0xABD40A0C2832A78B'i64], [0xE2E69915B3FFF9F9'i64,
0x16C90C8F323F516D'i64], [0x8DD01FAD907FFC3B'i64, 0xAE3DA7D97F6792E4'i64], [
0xB1442798F49FFB4A'i64, 0x99CD11CFDF41779D'i64], [0xDD95317F31C7FA1D'i64,
0x40405643D711D584'i64], [0x8A7D3EEF7F1CFC52'i64, 0x482835EA666B2573'i64], [
0xAD1C8EAB5EE43B66'i64, 0xDA3243650005EED0'i64], [0xD863B256369D4A40'i64,
0x90BED43E40076A83'i64], [0x873E4F75E2224E68'i64, 0x5A7744A6E804A292'i64], [
0xA90DE3535AAAE202'i64, 0x711515D0A205CB37'i64], [0xD3515C2831559A83'i64,
0x0D5A5B44CA873E04'i64], [0x8412D9991ED58091'i64, 0xE858790AFE9486C3'i64], [
0xA5178FFF668AE0B6'i64, 0x626E974DBE39A873'i64], [0xCE5D73FF402D98E3'i64,
0xFB0A3D212DC81290'i64], [0x80FA687F881C7F8E'i64, 0x7CE66634BC9D0B9A'i64], [
0xA139029F6A239F72'i64, 0x1C1FFFC1EBC44E81'i64], [0xC987434744AC874E'i64,
0xA327FFB266B56221'i64], [0xFBE9141915D7A922'i64, 0x4BF1FF9F0062BAA9'i64], [
0x9D71AC8FADA6C9B5'i64, 0x6F773FC3603DB4AA'i64], [0xC4CE17B399107C22'i64,
0xCB550FB4384D21D4'i64], [0xF6019DA07F549B2B'i64, 0x7E2A53A146606A49'i64], [
0x99C102844F94E0FB'i64, 0x2EDA7444CBFC426E'i64], [0xC0314325637A1939'i64,
0xFA911155FEFB5309'i64], [0xF03D93EEBC589F88'i64, 0x793555AB7EBA27CB'i64], [
0x96267C7535B763B5'i64, 0x4BC1558B2F3458DF'i64], [0xBBB01B9283253CA2'i64,
0x9EB1AAEDFB016F17'i64], [0xEA9C227723EE8BCB'i64, 0x465E15A979C1CADD'i64], [
0x92A1958A7675175F'i64, 0x0BFACD89EC191ECA'i64], [0xB749FAED14125D36'i64,
0xCEF980EC671F667C'i64], [0xE51C79A85916F484'i64, 0x82B7E12780E7401B'i64], [
0x8F31CC0937AE58D2'i64, 0xD1B2ECB8B0908811'i64], [0xB2FE3F0B8599EF07'i64,
0x861FA7E6DCB4AA16'i64], [0xDFBDCECE67006AC9'i64, 0x67A791E093E1D49B'i64], [
0x8BD6A141006042BD'i64, 0xE0C8BB2C5C6D24E1'i64], [0xAECC49914078536D'i64,
0x58FAE9F773886E19'i64], [0xDA7F5BF590966848'i64, 0xAF39A475506A899F'i64], [
0x888F99797A5E012D'i64, 0x6D8406C952429604'i64], [0xAAB37FD7D8F58178'i64,
0xC8E5087BA6D33B84'i64], [0xD5605FCDCF32E1D6'i64, 0xFB1E4A9A90880A65'i64], [
0x855C3BE0A17FCD26'i64, 0x5CF2EEA09A550680'i64], [0xA6B34AD8C9DFC06F'i64,
0xF42FAA48C0EA481F'i64], [0xD0601D8EFC57B08B'i64, 0xF13B94DAF124DA27'i64], [
0x823C12795DB6CE57'i64, 0x76C53D08D6B70859'i64], [0xA2CB1717B52481ED'i64,
0x54768C4B0C64CA6F'i64], [0xCB7DDCDDA26DA268'i64, 0xA9942F5DCF7DFD0A'i64], [
0xFE5D54150B090B02'i64, 0xD3F93B35435D7C4D'i64], [0x9EFA548D26E5A6E1'i64,
0xC47BC5014A1A6DB0'i64], [0xC6B8E9B0709F109A'i64, 0x359AB6419CA1091C'i64], [
0xF867241C8CC6D4C0'i64, 0xC30163D203C94B63'i64], [0x9B407691D7FC44F8'i64,
0x79E0DE63425DCF1E'i64], [0xC21094364DFB5636'i64, 0x985915FC12F542E5'i64], [
0xF294B943E17A2BC4'i64, 0x3E6F5B7B17B2939E'i64], [0x979CF3CA6CEC5B5A'i64,
0xA705992CEECF9C43'i64], [0xBD8430BD08277231'i64, 0x50C6FF782A838354'i64], [
0xECE53CEC4A314EBD'i64, 0xA4F8BF5635246429'i64], [0x940F4613AE5ED136'i64,
0x871B7795E136BE9A'i64], [0xB913179899F68584'i64, 0x28E2557B59846E40'i64], [
0xE757DD7EC07426E5'i64, 0x331AEADA2FE589D0'i64], [0x9096EA6F3848984F'i64,
0x3FF0D2C85DEF7622'i64], [0xB4BCA50B065ABE63'i64, 0x0FED077A756B53AA'i64], [
0xE1EBCE4DC7F16DFB'i64, 0xD3E8495912C62895'i64], [0x8D3360F09CF6E4BD'i64,
0x64712DD7ABBBD95D'i64], [0xB080392CC4349DEC'i64, 0xBD8D794D96AACFB4'i64], [
0xDCA04777F541C567'i64, 0xECF0D7A0FC5583A1'i64], [0x89E42CAAF9491B60'i64,
0xF41686C49DB57245'i64], [0xAC5D37D5B79B6239'i64, 0x311C2875C522CED6'i64], [
0xD77485CB25823AC7'i64, 0x7D633293366B828C'i64], [0x86A8D39EF77164BC'i64,
0xAE5DFF9C02033198'i64], [0xA8530886B54DBDEB'i64, 0xD9F57F830283FDFD'i64], [
0xD267CAA862A12D66'i64, 0xD072DF63C324FD7C'i64], [0x8380DEA93DA4BC60'i64,
0x4247CB9E59F71E6E'i64], [0xA46116538D0DEB78'i64, 0x52D9BE85F074E609'i64], [
0xCD795BE870516656'i64, 0x67902E276C921F8C'i64], [0x806BD9714632DFF6'i64,
0x00BA1CD8A3DB53B7'i64], [0xA086CFCD97BF97F3'i64, 0x80E8A40ECCD228A5'i64], [
0xC8A883C0FDAF7DF0'i64, 0x6122CD128006B2CE'i64], [0xFAD2A4B13D1B5D6C'i64,
0x796B805720085F82'i64], [0x9CC3A6EEC6311A63'i64, 0xCBE3303674053BB1'i64], [
0xC3F490AA77BD60FC'i64, 0xBEDBFC4411068A9D'i64], [0xF4F1B4D515ACB93B'i64,
0xEE92FB5515482D45'i64], [0x991711052D8BF3C5'i64, 0x751BDD152D4D1C4B'i64], [
0xBF5CD54678EEF0B6'i64, 0xD262D45A78A0635E'i64], [0xEF340A98172AACE4'i64,
0x86FB897116C87C35'i64], [0x9580869F0E7AAC0E'i64, 0xD45D35E6AE3D4DA1'i64], [
0xBAE0A846D2195712'i64, 0x8974836059CCA10A'i64], [0xE998D258869FACD7'i64,
0x2BD1A438703FC94C'i64], [0x91FF83775423CC06'i64, 0x7B6306A34627DDD0'i64], [
0xB67F6455292CBF08'i64, 0x1A3BC84C17B1D543'i64], [0xE41F3D6A7377EECA'i64,
0x20CABA5F1D9E4A94'i64], [0x8E938662882AF53E'i64, 0x547EB47B7282EE9D'i64], [
0xB23867FB2A35B28D'i64, 0xE99E619A4F23AA44'i64], [0xDEC681F9F4C31F31'i64,
0x6405FA00E2EC94D5'i64], [0x8B3C113C38F9F37E'i64, 0xDE83BC408DD3DD05'i64], [
0xAE0B158B4738705E'i64, 0x9624AB50B148D446'i64], [0xD98DDAEE19068C76'i64,
0x3BADD624DD9B0958'i64], [0x87F8A8D4CFA417C9'i64, 0xE54CA5D70A80E5D7'i64], [
0xA9F6D30A038D1DBC'i64, 0x5E9FCF4CCD211F4D'i64], [0xD47487CC8470652B'i64,
0x7647C32000696720'i64], [0x84C8D4DFD2C63F3B'i64, 0x29ECD9F40041E074'i64], [
0xA5FB0A17C777CF09'i64, 0xF468107100525891'i64], [0xCF79CC9DB955C2CC'i64,
0x7182148D4066EEB5'i64], [0x81AC1FE293D599BF'i64, 0xC6F14CD848405531'i64], [
0xA21727DB38CB002F'i64, 0xB8ADA00E5A506A7D'i64], [0xCA9CF1D206FDC03B'i64,
0xA6D90811F0E4851D'i64], [0xFD442E4688BD304A'i64, 0x908F4A166D1DA664'i64], [
0x9E4A9CEC15763E2E'i64, 0x9A598E4E043287FF'i64], [0xC5DD44271AD3CDBA'i64,
0x40EFF1E1853F29FE'i64], [0xF7549530E188C128'i64, 0xD12BEE59E68EF47D'i64], [
0x9A94DD3E8CF578B9'i64, 0x82BB74F8301958CF'i64], [0xC13A148E3032D6E7'i64,
0xE36A52363C1FAF02'i64], [0xF18899B1BC3F8CA1'i64, 0xDC44E6C3CB279AC2'i64], [
0x96F5600F15A7B7E5'i64, 0x29AB103A5EF8C0BA'i64], [0xBCB2B812DB11A5DE'i64,
0x7415D448F6B6F0E8'i64], [0xEBDF661791D60F56'i64, 0x111B495B3464AD22'i64], [
0x936B9FCEBB25C995'i64, 0xCAB10DD900BEEC35'i64], [0xB84687C269EF3BFB'i64,
0x3D5D514F40EEA743'i64], [0xE65829B3046B0AFA'i64, 0x0CB4A5A3112A5113'i64], [
0x8FF71A0FE2C2E6DC'i64, 0x47F0E785EABA72AC'i64], [0xB3F4E093DB73A093'i64,
0x59ED216765690F57'i64], [0xE0F218B8D25088B8'i64, 0x306869C13EC3532D'i64], [
0x8C974F7383725573'i64, 0x1E414218C73A13FC'i64], [0xAFBD2350644EEACF'i64,
0xE5D1929EF90898FB'i64], [0xDBAC6C247D62A583'i64, 0xDF45F746B74ABF3A'i64], [
0x894BC396CE5DA772'i64, 0x6B8BBA8C328EB784'i64], [0xAB9EB47C81F5114F'i64,
0x066EA92F3F326565'i64], [0xD686619BA27255A2'i64, 0xC80A537B0EFEFEBE'i64], [
0x8613FD0145877585'i64, 0xBD06742CE95F5F37'i64], [0xA798FC4196E952E7'i64,
0x2C48113823B73705'i64], [0xD17F3B51FCA3A7A0'i64, 0xF75A15862CA504C6'i64], [
0x82EF85133DE648C4'i64, 0x9A984D73DBE722FC'i64], [0xA3AB66580D5FDAF5'i64,
0xC13E60D0D2E0EBBB'i64], [0xCC963FEE10B7D1B3'i64, 0x318DF905079926A9'i64], [
0xFFBBCFE994E5C61F'i64, 0xFDF17746497F7053'i64], [0x9FD561F1FD0F9BD3'i64,
0xFEB6EA8BEDEFA634'i64], [0xC7CABA6E7C5382C8'i64, 0xFE64A52EE96B8FC1'i64], [
0xF9BD690A1B68637B'i64, 0x3DFDCE7AA3C673B1'i64], [0x9C1661A651213E2D'i64,
0x06BEA10CA65C084F'i64], [0xC31BFA0FE5698DB8'i64, 0x486E494FCFF30A63'i64], [
0xF3E2F893DEC3F126'i64, 0x5A89DBA3C3EFCCFB'i64], [0x986DDB5C6B3A76B7'i64,
0xF89629465A75E01D'i64], [0xBE89523386091465'i64, 0xF6BBB397F1135824'i64], [
0xEE2BA6C0678B597F'i64, 0x746AA07DED582E2D'i64], [0x94DB483840B717EF'i64,
0xA8C2A44EB4571CDD'i64], [0xBA121A4650E4DDEB'i64, 0x92F34D62616CE414'i64], [
0xE896A0D7E51E1566'i64, 0x77B020BAF9C81D18'i64], [0x915E2486EF32CD60'i64,
0x0ACE1474DC1D122F'i64], [0xB5B5ADA8AAFF80B8'i64, 0x0D819992132456BB'i64], [
0xE3231912D5BF60E6'i64, 0x10E1FFF697ED6C6A'i64], [0x8DF5EFABC5979C8F'i64,
0xCA8D3FFA1EF463C2'i64], [0xB1736B96B6FD83B3'i64, 0xBD308FF8A6B17CB3'i64], [
0xDDD0467C64BCE4A0'i64, 0xAC7CB3F6D05DDBDF'i64], [0x8AA22C0DBEF60EE4'i64,
0x6BCDF07A423AA96C'i64], [0xAD4AB7112EB3929D'i64, 0x86C16C98D2C953C7'i64], [
0xD89D64D57A607744'i64, 0xE871C7BF077BA8B8'i64], [0x87625F056C7C4A8B'i64,
0x11471CD764AD4973'i64], [0xA93AF6C6C79B5D2D'i64, 0xD598E40D3DD89BD0'i64], [
0xD389B47879823479'i64, 0x4AFF1D108D4EC2C4'i64], [0x843610CB4BF160CB'i64,
0xCEDF722A585139BB'i64], [0xA54394FE1EEDB8FE'i64, 0xC2974EB4EE658829'i64], [
0xCE947A3DA6A9273E'i64, 0x733D226229FEEA33'i64], [0x811CCC668829B887'i64,
0x0806357D5A3F5260'i64], [0xA163FF802A3426A8'i64, 0xCA07C2DCB0CF26F8'i64], [
0xC9BCFF6034C13052'i64, 0xFC89B393DD02F0B6'i64], [0xFC2C3F3841F17C67'i64,
0xBBAC2078D443ACE3'i64], [0x9D9BA7832936EDC0'i64, 0xD54B944B84AA4C0E'i64], [
0xC5029163F384A931'i64, 0x0A9E795E65D4DF12'i64], [0xF64335BCF065D37D'i64,
0x4D4617B5FF4A16D6'i64], [0x99EA0196163FA42E'i64, 0x504BCED1BF8E4E46'i64], [
0xC06481FB9BCF8D39'i64, 0xE45EC2862F71E1D7'i64], [0xF07DA27A82C37088'i64,
0x5D767327BB4E5A4D'i64], [0x964E858C91BA2655'i64, 0x3A6A07F8D510F870'i64], [
0xBBE226EFB628AFEA'i64, 0x890489F70A55368C'i64], [0xEADAB0ABA3B2DBE5'i64,
0x2B45AC74CCEA842F'i64], [0x92C8AE6B464FC96F'i64, 0x3B0B8BC90012929E'i64], [
0xB77ADA0617E3BBCB'i64, 0x09CE6EBB40173745'i64], [0xE55990879DDCAABD'i64,
0xCC420A6A101D0516'i64], [0x8F57FA54C2A9EAB6'i64, 0x9FA946824A12232E'i64], [
0xB32DF8E9F3546564'i64, 0x47939822DC96ABFA'i64], [0xDFF9772470297EBD'i64,
0x59787E2B93BC56F8'i64], [0x8BFBEA76C619EF36'i64, 0x57EB4EDB3C55B65B'i64], [
0xAEFAE51477A06B03'i64, 0xEDE622920B6B23F2'i64], [0xDAB99E59958885C4'i64,
0xE95FAB368E45ECEE'i64], [0x88B402F7FD75539B'i64, 0x11DBCB0218EBB415'i64], [
0xAAE103B5FCD2A881'i64, 0xD652BDC29F26A11A'i64], [0xD59944A37C0752A2'i64,
0x4BE76D3346F04960'i64], [0x857FCAE62D8493A5'i64, 0x6F70A4400C562DDC'i64], [
0xA6DFBD9FB8E5B88E'i64, 0xCB4CCD500F6BB953'i64], [0xD097AD07A71F26B2'i64,
0x7E2000A41346A7A8'i64], [0x825ECC24C873782F'i64, 0x8ED400668C0C28C9'i64], [
0xA2F67F2DFA90563B'i64, 0x728900802F0F32FB'i64], [0xCBB41EF979346BCA'i64,
0x4F2B40A03AD2FFBA'i64], [0xFEA126B7D78186BC'i64, 0xE2F610C84987BFA9'i64], [
0x9F24B832E6B0F436'i64, 0x0DD9CA7D2DF4D7CA'i64], [0xC6EDE63FA05D3143'i64,
0x91503D1C79720DBC'i64], [0xF8A95FCF88747D94'i64, 0x75A44C6397CE912B'i64], [
0x9B69DBE1B548CE7C'i64, 0xC986AFBE3EE11ABB'i64], [0xC24452DA229B021B'i64,
0xFBE85BADCE996169'i64], [0xF2D56790AB41C2A2'i64, 0xFAE27299423FB9C4'i64], [
0x97C560BA6B0919A5'i64, 0xDCCD879FC967D41B'i64], [0xBDB6B8E905CB600F'i64,
0x5400E987BBC1C921'i64], [0xED246723473E3813'i64, 0x290123E9AAB23B69'i64], [
0x9436C0760C86E30B'i64, 0xF9A0B6720AAF6522'i64], [0xB94470938FA89BCE'i64,
0xF808E40E8D5B3E6A'i64], [0xE7958CB87392C2C2'i64, 0xB60B1D1230B20E05'i64], [
0x90BD77F3483BB9B9'i64, 0xB1C6F22B5E6F48C3'i64], [0xB4ECD5F01A4AA828'i64,
0x1E38AEB6360B1AF4'i64], [0xE2280B6C20DD5232'i64, 0x25C6DA63C38DE1B1'i64], [
0x8D590723948A535F'i64, 0x579C487E5A38AD0F'i64], [0xB0AF48EC79ACE837'i64,
0x2D835A9DF0C6D852'i64], [0xDCDB1B2798182244'i64, 0xF8E431456CF88E66'i64], [
0x8A08F0F8BF0F156B'i64, 0x1B8E9ECB641B5900'i64], [0xAC8B2D36EED2DAC5'i64,
0xE272467E3D222F40'i64], [0xD7ADF884AA879177'i64, 0x5B0ED81DCC6ABB10'i64], [
0x86CCBB52EA94BAEA'i64, 0x98E947129FC2B4EA'i64], [0xA87FEA27A539E9A5'i64,
0x3F2398D747B36225'i64], [0xD29FE4B18E88640E'i64, 0x8EEC7F0D19A03AAE'i64], [
0x83A3EEEEF9153E89'i64, 0x1953CF68300424AD'i64], [0xA48CEAAAB75A8E2B'i64,
0x5FA8C3423C052DD8'i64], [0xCDB02555653131B6'i64, 0x3792F412CB06794E'i64], [
0x808E17555F3EBF11'i64, 0xE2BBD88BBEE40BD1'i64], [0xA0B19D2AB70E6ED6'i64,
0x5B6ACEAEAE9D0EC5'i64], [0xC8DE047564D20A8B'i64, 0xF245825A5A445276'i64], [
0xFB158592BE068D2E'i64, 0xEED6E2F0F0D56713'i64], [0x9CED737BB6C4183D'i64,
0x55464DD69685606C'i64], [0xC428D05AA4751E4C'i64, 0xAA97E14C3C26B887'i64], [
0xF53304714D9265DF'i64, 0xD53DD99F4B3066A9'i64], [0x993FE2C6D07B7FAB'i64,
0xE546A8038EFE402A'i64], [0xBF8FDB78849A5F96'i64, 0xDE98520472BDD034'i64], [
0xEF73D256A5C0F77C'i64, 0x963E66858F6D4441'i64], [0x95A8637627989AAD'i64,
0xDDE7001379A44AA9'i64], [0xBB127C53B17EC159'i64, 0x5560C018580D5D53'i64], [
0xE9D71B689DDE71AF'i64, 0xAAB8F01E6E10B4A7'i64], [0x9226712162AB070D'i64,
0xCAB3961304CA70E9'i64], [0xB6B00D69BB55C8D1'i64, 0x3D607B97C5FD0D23'i64], [
0xE45C10C42A2B3B05'i64, 0x8CB89A7DB77C506B'i64], [0x8EB98A7A9A5B04E3'i64,
0x77F3608E92ADB243'i64], [0xB267ED1940F1C61C'i64, 0x55F038B237591ED4'i64], [
0xDF01E85F912E37A3'i64, 0x6B6C46DEC52F6689'i64], [0x8B61313BBABCE2C6'i64,
0x2323AC4B3B3DA016'i64], [0xAE397D8AA96C1B77'i64, 0xABEC975E0A0D081B'i64], [
0xD9C7DCED53C72255'i64, 0x96E7BD358C904A22'i64], [0x881CEA14545C7575'i64,
0x7E50D64177DA2E55'i64], [0xAA242499697392D2'i64, 0xDDE50BD1D5D0B9EA'i64], [
0xD4AD2DBFC3D07787'i64, 0x955E4EC64B44E865'i64], [0x84EC3C97DA624AB4'i64,
0xBD5AF13BEF0B113F'i64], [0xA6274BBDD0FADD61'i64, 0xECB1AD8AEACDD58F'i64], [
0xCFB11EAD453994BA'i64, 0x67DE18EDA5814AF3'i64], [0x81CEB32C4B43FCF4'i64,
0x80EACF948770CED8'i64], [0xA2425FF75E14FC31'i64, 0xA1258379A94D028E'i64], [
0xCAD2F7F5359A3B3E'i64, 0x096EE45813A04331'i64], [0xFD87B5F28300CA0D'i64,
0x8BCA9D6E188853FD'i64], [0x9E74D1B791E07E48'i64, 0x775EA264CF55347E'i64], [
0xC612062576589DDA'i64, 0x95364AFE032A819E'i64], [0xF79687AED3EEC551'i64,
0x3A83DDBD83F52205'i64], [0x9ABE14CD44753B52'i64, 0xC4926A9672793543'i64], [
0xC16D9A0095928A27'i64, 0x75B7053C0F178294'i64], [0xF1C90080BAF72CB1'i64,
0x5324C68B12DD6339'i64], [0x971DA05074DA7BEE'i64, 0xD3F6FC16EBCA5E04'i64], [
0xBCE5086492111AEA'i64, 0x88F4BB1CA6BCF585'i64], [0xEC1E4A7DB69561A5'i64,
0x2B31E9E3D06C32E6'i64], [0x9392EE8E921D5D07'i64, 0x3AFF322E62439FD0'i64], [
0xB877AA3236A4B449'i64, 0x09BEFEB9FAD487C3'i64], [0xE69594BEC44DE15B'i64,
0x4C2EBE687989A9B4'i64], [0x901D7CF73AB0ACD9'i64, 0x0F9D37014BF60A11'i64], [
0xB424DC35095CD80F'i64, 0x538484C19EF38C95'i64], [0xE12E13424BB40E13'i64,
0x2865A5F206B06FBA'i64], [0x8CBCCC096F5088CB'i64, 0xF93F87B7442E45D4'i64], [
0xAFEBFF0BCB24AAFE'i64, 0xF78F69A51539D749'i64], [0xDBE6FECEBDEDD5BE'i64,
0xB573440E5A884D1C'i64], [0x89705F4136B4A597'i64, 0x31680A88F8953031'i64], [
0xABCC77118461CEFC'i64, 0xFDC20D2B36BA7C3E'i64], [0xD6BF94D5E57A42BC'i64,
0x3D32907604691B4D'i64], [0x8637BD05AF6C69B5'i64, 0xA63F9A49C2C1B110'i64], [
0xA7C5AC471B478423'i64, 0x0FCF80DC33721D54'i64], [0xD1B71758E219652B'i64,
0xD3C36113404EA4A9'i64], [0x83126E978D4FDF3B'i64, 0x645A1CAC083126EA'i64], [
0xA3D70A3D70A3D70A'i64, 0x3D70A3D70A3D70A4'i64], [0xCCCCCCCCCCCCCCCC'i64,
0xCCCCCCCCCCCCCCCD'i64], [0x8000000000000000'i64, 0x0000000000000000'i64], [
0xA000000000000000'i64, 0x0000000000000000'i64], [0xC800000000000000'i64,
0x0000000000000000'i64], [0xFA00000000000000'i64, 0x0000000000000000'i64], [
0x9C40000000000000'i64, 0x0000000000000000'i64], [0xC350000000000000'i64,
0x0000000000000000'i64], [0xF424000000000000'i64, 0x0000000000000000'i64], [
0x9896800000000000'i64, 0x0000000000000000'i64], [0xBEBC200000000000'i64,
0x0000000000000000'i64], [0xEE6B280000000000'i64, 0x0000000000000000'i64], [
0x9502F90000000000'i64, 0x0000000000000000'i64], [0xBA43B74000000000'i64,
0x0000000000000000'i64], [0xE8D4A51000000000'i64, 0x0000000000000000'i64], [
0x9184E72A00000000'i64, 0x0000000000000000'i64], [0xB5E620F480000000'i64,
0x0000000000000000'i64], [0xE35FA931A0000000'i64, 0x0000000000000000'i64], [
0x8E1BC9BF04000000'i64, 0x0000000000000000'i64], [0xB1A2BC2EC5000000'i64,
0x0000000000000000'i64], [0xDE0B6B3A76400000'i64, 0x0000000000000000'i64], [
0x8AC7230489E80000'i64, 0x0000000000000000'i64], [0xAD78EBC5AC620000'i64,
0x0000000000000000'i64], [0xD8D726B7177A8000'i64, 0x0000000000000000'i64], [
0x878678326EAC9000'i64, 0x0000000000000000'i64], [0xA968163F0A57B400'i64,
0x0000000000000000'i64], [0xD3C21BCECCEDA100'i64, 0x0000000000000000'i64], [
0x84595161401484A0'i64, 0x0000000000000000'i64], [0xA56FA5B99019A5C8'i64,
0x0000000000000000'i64], [0xCECB8F27F4200F3A'i64, 0x0000000000000000'i64], [
0x813F3978F8940984'i64, 0x4000000000000000'i64], [0xA18F07D736B90BE5'i64,
0x5000000000000000'i64], [0xC9F2C9CD04674EDE'i64, 0xA400000000000000'i64], [
0xFC6F7C4045812296'i64, 0x4D00000000000000'i64], [0x9DC5ADA82B70B59D'i64,
0xF020000000000000'i64], [0xC5371912364CE305'i64, 0x6C28000000000000'i64], [
0xF684DF56C3E01BC6'i64, 0xC732000000000000'i64], [0x9A130B963A6C115C'i64,
0x3C7F400000000000'i64], [0xC097CE7BC90715B3'i64, 0x4B9F100000000000'i64], [
0xF0BDC21ABB48DB20'i64, 0x1E86D40000000000'i64], [0x96769950B50D88F4'i64,
0x1314448000000000'i64], [0xBC143FA4E250EB31'i64, 0x17D955A000000000'i64], [
0xEB194F8E1AE525FD'i64, 0x5DCFAB0800000000'i64], [0x92EFD1B8D0CF37BE'i64,
0x5AA1CAE500000000'i64], [0xB7ABC627050305AD'i64, 0xF14A3D9E40000000'i64], [
0xE596B7B0C643C719'i64, 0x6D9CCD05D0000000'i64], [0x8F7E32CE7BEA5C6F'i64,
0xE4820023A2000000'i64], [0xB35DBF821AE4F38B'i64, 0xDDA2802C8A800000'i64], [
0xE0352F62A19E306E'i64, 0xD50B2037AD200000'i64], [0x8C213D9DA502DE45'i64,
0x4526F422CC340000'i64], [0xAF298D050E4395D6'i64, 0x9670B12B7F410000'i64], [
0xDAF3F04651D47B4C'i64, 0x3C0CDD765F114000'i64], [0x88D8762BF324CD0F'i64,
0xA5880A69FB6AC800'i64], [0xAB0E93B6EFEE0053'i64, 0x8EEA0D047A457A00'i64], [
0xD5D238A4ABE98068'i64, 0x72A4904598D6D880'i64], [0x85A36366EB71F041'i64,
0x47A6DA2B7F864750'i64], [0xA70C3C40A64E6C51'i64, 0x999090B65F67D924'i64], [
0xD0CF4B50CFE20765'i64, 0xFFF4B4E3F741CF6D'i64], [0x82818F1281ED449F'i64,
0xBFF8F10E7A8921A4'i64], [0xA321F2D7226895C7'i64, 0xAFF72D52192B6A0D'i64], [
0xCBEA6F8CEB02BB39'i64, 0x9BF4F8A69F764490'i64], [0xFEE50B7025C36A08'i64,
0x02F236D04753D5B4'i64], [0x9F4F2726179A2245'i64, 0x01D762422C946590'i64], [
0xC722F0EF9D80AAD6'i64, 0x424D3AD2B7B97EF5'i64], [0xF8EBAD2B84E0D58B'i64,
0xD2E0898765A7DEB2'i64], [0x9B934C3B330C8577'i64, 0x63CC55F49F88EB2F'i64], [
0xC2781F49FFCFA6D5'i64, 0x3CBF6B71C76B25FB'i64], [0xF316271C7FC3908A'i64,
0x8BEF464E3945EF7A'i64], [0x97EDD871CFDA3A56'i64, 0x97758BF0E3CBB5AC'i64], [
0xBDE94E8E43D0C8EC'i64, 0x3D52EEED1CBEA317'i64], [0xED63A231D4C4FB27'i64,
0x4CA7AAA863EE4BDD'i64], [0x945E455F24FB1CF8'i64, 0x8FE8CAA93E74EF6A'i64], [
0xB975D6B6EE39E436'i64, 0xB3E2FD538E122B44'i64], [0xE7D34C64A9C85D44'i64,
0x60DBBCA87196B616'i64], [0x90E40FBEEA1D3A4A'i64, 0xBC8955E946FE31CD'i64], [
0xB51D13AEA4A488DD'i64, 0x6BABAB6398BDBE41'i64], [0xE264589A4DCDAB14'i64,
0xC696963C7EED2DD1'i64], [0x8D7EB76070A08AEC'i64, 0xFC1E1DE5CF543CA2'i64], [
0xB0DE65388CC8ADA8'i64, 0x3B25A55F43294BCB'i64], [0xDD15FE86AFFAD912'i64,
0x49EF0EB713F39EBE'i64], [0x8A2DBF142DFCC7AB'i64, 0x6E3569326C784337'i64], [
0xACB92ED9397BF996'i64, 0x49C2C37F07965404'i64], [0xD7E77A8F87DAF7FB'i64,
0xDC33745EC97BE906'i64], [0x86F0AC99B4E8DAFD'i64, 0x69A028BB3DED71A3'i64], [
0xA8ACD7C0222311BC'i64, 0xC40832EA0D68CE0C'i64], [0xD2D80DB02AABD62B'i64,
0xF50A3FA490C30190'i64], [0x83C7088E1AAB65DB'i64, 0x792667C6DA79E0FA'i64], [
0xA4B8CAB1A1563F52'i64, 0x577001B891185938'i64], [0xCDE6FD5E09ABCF26'i64,
0xED4C0226B55E6F86'i64], [0x80B05E5AC60B6178'i64, 0x544F8158315B05B4'i64], [
0xA0DC75F1778E39D6'i64, 0x696361AE3DB1C721'i64], [0xC913936DD571C84C'i64,
0x03BC3A19CD1E38E9'i64], [0xFB5878494ACE3A5F'i64, 0x04AB48A04065C723'i64], [
0x9D174B2DCEC0E47B'i64, 0x62EB0D64283F9C76'i64], [0xC45D1DF942711D9A'i64,
0x3BA5D0BD324F8394'i64], [0xF5746577930D6500'i64, 0xCA8F44EC7EE36479'i64], [
0x9968BF6ABBE85F20'i64, 0x7E998B13CF4E1ECB'i64], [0xBFC2EF456AE276E8'i64,
0x9E3FEDD8C321A67E'i64], [0xEFB3AB16C59B14A2'i64, 0xC5CFE94EF3EA101E'i64], [
0x95D04AEE3B80ECE5'i64, 0xBBA1F1D158724A12'i64], [0xBB445DA9CA61281F'i64,
0x2A8A6E45AE8EDC97'i64], [0xEA1575143CF97226'i64, 0xF52D09D71A3293BD'i64], [
0x924D692CA61BE758'i64, 0x593C2626705F9C56'i64], [0xB6E0C377CFA2E12E'i64,
0x6F8B2FB00C77836C'i64], [0xE498F455C38B997A'i64, 0x0B6DFB9C0F956447'i64], [
0x8EDF98B59A373FEC'i64, 0x4724BD4189BD5EAC'i64], [0xB2977EE300C50FE7'i64,
0x58EDEC91EC2CB657'i64], [0xDF3D5E9BC0F653E1'i64, 0x2F2967B66737E3ED'i64], [
0x8B865B215899F46C'i64, 0xBD79E0D20082EE74'i64], [0xAE67F1E9AEC07187'i64,
0xECD8590680A3AA11'i64], [0xDA01EE641A708DE9'i64, 0xE80E6F4820CC9495'i64], [
0x884134FE908658B2'i64, 0x3109058D147FDCDD'i64], [0xAA51823E34A7EEDE'i64,
0xBD4B46F0599FD415'i64], [0xD4E5E2CDC1D1EA96'i64, 0x6C9E18AC7007C91A'i64], [
0x850FADC09923329E'i64, 0x03E2CF6BC604DDB0'i64], [0xA6539930BF6BFF45'i64,
0x84DB8346B786151C'i64], [0xCFE87F7CEF46FF16'i64, 0xE612641865679A63'i64], [
0x81F14FAE158C5F6E'i64, 0x4FCB7E8F3F60C07E'i64], [0xA26DA3999AEF7749'i64,
0xE3BE5E330F38F09D'i64], [0xCB090C8001AB551C'i64, 0x5CADF5BFD3072CC5'i64], [
0xFDCB4FA002162A63'i64, 0x73D9732FC7C8F7F6'i64], [0x9E9F11C4014DDA7E'i64,
0x2867E7FDDCDD9AFA'i64], [0xC646D63501A1511D'i64, 0xB281E1FD541501B8'i64], [
0xF7D88BC24209A565'i64, 0x1F225A7CA91A4226'i64], [0x9AE757596946075F'i64,
0x3375788DE9B06958'i64], [0xC1A12D2FC3978937'i64, 0x0052D6B1641C83AE'i64], [
0xF209787BB47D6B84'i64, 0xC0678C5DBD23A49A'i64], [0x9745EB4D50CE6332'i64,
0xF840B7BA963646E0'i64], [0xBD176620A501FBFF'i64, 0xB650E5A93BC3D898'i64], [
0xEC5D3FA8CE427AFF'i64, 0xA3E51F138AB4CEBE'i64], [0x93BA47C980E98CDF'i64,
0xC66F336C36B10137'i64], [0xB8A8D9BBE123F017'i64, 0xB80B0047445D4184'i64], [
0xE6D3102AD96CEC1D'i64, 0xA60DC059157491E5'i64], [0x9043EA1AC7E41392'i64,
0x87C89837AD68DB2F'i64], [0xB454E4A179DD1877'i64, 0x29BABE4598C311FB'i64], [
0xE16A1DC9D8545E94'i64, 0xF4296DD6FEF3D67A'i64], [0x8CE2529E2734BB1D'i64,
0x1899E4A65F58660C'i64], [0xB01AE745B101E9E4'i64, 0x5EC05DCFF72E7F8F'i64], [
0xDC21A1171D42645D'i64, 0x76707543F4FA1F73'i64], [0x899504AE72497EBA'i64,
0x6A06494A791C53A8'i64], [0xABFA45DA0EDBDE69'i64, 0x0487DB9D17636892'i64], [
0xD6F8D7509292D603'i64, 0x45A9D2845D3C42B6'i64], [0x865B86925B9BC5C2'i64,
0x0B8A2392BA45A9B2'i64], [0xA7F26836F282B732'i64, 0x8E6CAC7768D7141E'i64], [
0xD1EF0244AF2364FF'i64, 0x3207D795430CD926'i64], [0x8335616AED761F1F'i64,
0x7F44E6BD49E807B8'i64], [0xA402B9C5A8D3A6E7'i64, 0x5F16206C9C6209A6'i64], [
0xCD036837130890A1'i64, 0x36DBA887C37A8C0F'i64], [0x802221226BE55A64'i64,
0xC2494954DA2C9789'i64], [0xA02AA96B06DEB0FD'i64, 0xF2DB9BAA10B7BD6C'i64], [
0xC83553C5C8965D3D'i64, 0x6F92829494E5ACC7'i64], [0xFA42A8B73ABBF48C'i64,
0xCB772339BA1F17F9'i64], [0x9C69A97284B578D7'i64, 0xFF2A760414536EFB'i64], [
0xC38413CF25E2D70D'i64, 0xFEF5138519684ABA'i64], [0xF46518C2EF5B8CD1'i64,
0x7EB258665FC25D69'i64], [0x98BF2F79D5993802'i64, 0xEF2F773FFBD97A61'i64], [
0xBEEEFB584AFF8603'i64, 0xAAFB550FFACFD8FA'i64], [0xEEAABA2E5DBF6784'i64,
0x95BA2A53F983CF38'i64], [0x952AB45CFA97A0B2'i64, 0xDD945A747BF26183'i64], [
0xBA756174393D88DF'i64, 0x94F971119AEEF9E4'i64], [0xE912B9D1478CEB17'i64,
0x7A37CD5601AAB85D'i64], [0x91ABB422CCB812EE'i64, 0xAC62E055C10AB33A'i64], [
0xB616A12B7FE617AA'i64, 0x577B986B314D6009'i64], [0xE39C49765FDF9D94'i64,
0xED5A7E85FDA0B80B'i64], [0x8E41ADE9FBEBC27D'i64, 0x14588F13BE847307'i64], [
0xB1D219647AE6B31C'i64, 0x596EB2D8AE258FC8'i64], [0xDE469FBD99A05FE3'i64,
0x6FCA5F8ED9AEF3BB'i64], [0x8AEC23D680043BEE'i64, 0x25DE7BB9480D5854'i64], [
0xADA72CCC20054AE9'i64, 0xAF561AA79A10AE6A'i64], [0xD910F7FF28069DA4'i64,
0x1B2BA1518094DA04'i64], [0x87AA9AFF79042286'i64, 0x90FB44D2F05D0842'i64], [
0xA99541BF57452B28'i64, 0x353A1607AC744A53'i64], [0xD3FA922F2D1675F2'i64,
0x42889B8997915CE8'i64], [0x847C9B5D7C2E09B7'i64, 0x69956135FEBADA11'i64], [
0xA59BC234DB398C25'i64, 0x43FAB9837E699095'i64], [0xCF02B2C21207EF2E'i64,
0x94F967E45E03F4BB'i64], [0x8161AFB94B44F57D'i64, 0x1D1BE0EEBAC278F5'i64], [
0xA1BA1BA79E1632DC'i64, 0x6462D92A69731732'i64], [0xCA28A291859BBF93'i64,
0x7D7B8F7503CFDCFE'i64], [0xFCB2CB35E702AF78'i64, 0x5CDA735244C3D43E'i64], [
0x9DEFBF01B061ADAB'i64, 0x3A0888136AFA64A7'i64], [0xC56BAEC21C7A1916'i64,
0x088AAA1845B8FDD0'i64], [0xF6C69A72A3989F5B'i64, 0x8AAD549E57273D45'i64], [
0x9A3C2087A63F6399'i64, 0x36AC54E2F678864B'i64], [0xC0CB28A98FCF3C7F'i64,
0x84576A1BB416A7DD'i64], [0xF0FDF2D3F3C30B9F'i64, 0x656D44A2A11C51D5'i64], [
0x969EB7C47859E743'i64, 0x9F644AE5A4B1B325'i64], [0xBC4665B596706114'i64,
0x873D5D9F0DDE1FEE'i64], [0xEB57FF22FC0C7959'i64, 0xA90CB506D155A7EA'i64], [
0x9316FF75DD87CBD8'i64, 0x09A7F12442D588F2'i64], [0xB7DCBF5354E9BECE'i64,
0x0C11ED6D538AEB2F'i64], [0xE5D3EF282A242E81'i64, 0x8F1668C8A86DA5FA'i64], [
0x8FA475791A569D10'i64, 0xF96E017D694487BC'i64], [0xB38D92D760EC4455'i64,
0x37C981DCC395A9AC'i64], [0xE070F78D3927556A'i64, 0x85BBE253F47B1417'i64], [
0x8C469AB843B89562'i64, 0x93956D7478CCEC8E'i64], [0xAF58416654A6BABB'i64,
0x387AC8D1970027B2'i64], [0xDB2E51BFE9D0696A'i64, 0x06997B05FCC0319E'i64], [
0x88FCF317F22241E2'i64, 0x441FECE3BDF81F03'i64], [0xAB3C2FDDEEAAD25A'i64,
0xD527E81CAD7626C3'i64], [0xD60B3BD56A5586F1'i64, 0x8A71E223D8D3B074'i64], [
0x85C7056562757456'i64, 0xF6872D5667844E49'i64], [0xA738C6BEBB12D16C'i64,
0xB428F8AC016561DB'i64], [0xD106F86E69D785C7'i64, 0xE13336D701BEBA52'i64], [
0x82A45B450226B39C'i64, 0xECC0024661173473'i64], [0xA34D721642B06084'i64,
0x27F002D7F95D0190'i64], [0xCC20CE9BD35C78A5'i64, 0x31EC038DF7B441F4'i64], [
0xFF290242C83396CE'i64, 0x7E67047175A15271'i64], [0x9F79A169BD203E41'i64,
0x0F0062C6E984D386'i64], [0xC75809C42C684DD1'i64, 0x52C07B78A3E60868'i64], [
0xF92E0C3537826145'i64, 0xA7709A56CCDF8A82'i64], [0x9BBCC7A142B17CCB'i64,
0x88A66076400BB691'i64], [0xC2ABF989935DDBFE'i64, 0x6ACFF893D00EA435'i64], [
0xF356F7EBF83552FE'i64, 0x0583F6B8C4124D43'i64], [0x98165AF37B2153DE'i64,
0xC3727A337A8B704A'i64], [0xBE1BF1B059E9A8D6'i64, 0x744F18C0592E4C5C'i64], [
0xEDA2EE1C7064130C'i64, 0x1162DEF06F79DF73'i64], [0x9485D4D1C63E8BE7'i64,
0x8ADDCB5645AC2BA8'i64], [0xB9A74A0637CE2EE1'i64, 0x6D953E2BD7173692'i64], [
0xE8111C87C5C1BA99'i64, 0xC8FA8DB6CCDD0437'i64], [0x910AB1D4DB9914A0'i64,
0x1D9C9892400A22A2'i64], [0xB54D5E4A127F59C8'i64, 0x2503BEB6D00CAB4B'i64], [
0xE2A0B5DC971F303A'i64, 0x2E44AE64840FD61D'i64], [0x8DA471A9DE737E24'i64,
0x5CEAECFED289E5D2'i64], [0xB10D8E1456105DAD'i64, 0x7425A83E872C5F47'i64], [
0xDD50F1996B947518'i64, 0xD12F124E28F77719'i64], [0x8A5296FFE33CC92F'i64,
0x82BD6B70D99AAA6F'i64], [0xACE73CBFDC0BFB7B'i64, 0x636CC64D1001550B'i64], [
0xD8210BEFD30EFA5A'i64, 0x3C47F7E05401AA4E'i64], [0x8714A775E3E95C78'i64,
0x65ACFAEC34810A71'i64], [0xA8D9D1535CE3B396'i64, 0x7F1839A741A14D0D'i64], [
0xD31045A8341CA07C'i64, 0x1EDE48111209A050'i64], [0x83EA2B892091E44D'i64,
0x934AED0AAB460432'i64], [0xA4E4B66B68B65D60'i64, 0xF81DA84D5617853F'i64], [
0xCE1DE40642E3F4B9'i64, 0x36251260AB9D668E'i64], [0x80D2AE83E9CE78F3'i64,
0xC1D72B7C6B426019'i64], [0xA1075A24E4421730'i64, 0xB24CF65B8612F81F'i64], [
0xC94930AE1D529CFC'i64, 0xDEE033F26797B627'i64], [0xFB9B7CD9A4A7443C'i64,
0x169840EF017DA3B1'i64], [0x9D412E0806E88AA5'i64, 0x8E1F289560EE864E'i64], [
0xC491798A08A2AD4E'i64, 0xF1A6F2BAB92A27E2'i64], [0xF5B5D7EC8ACB58A2'i64,
0xAE10AF696774B1DB'i64], [0x9991A6F3D6BF1765'i64, 0xACCA6DA1E0A8EF29'i64], [
0xBFF610B0CC6EDD3F'i64, 0x17FD090A58D32AF3'i64], [0xEFF394DCFF8A948E'i64,
0xDDFC4B4CEF07F5B0'i64], [0x95F83D0A1FB69CD9'i64, 0x4ABDAF101564F98E'i64], [
0xBB764C4CA7A4440F'i64, 0x9D6D1AD41ABE37F1'i64], [0xEA53DF5FD18D5513'i64,
0x84C86189216DC5ED'i64], [0x92746B9BE2F8552C'i64, 0x32FD3CF5B4E49BB4'i64], [
0xB7118682DBB66A77'i64, 0x3FBC8C33221DC2A1'i64], [0xE4D5E82392A40515'i64,
0x0FABAF3FEAA5334A'i64], [0x8F05B1163BA6832D'i64, 0x29CB4D87F2A7400E'i64], [
0xB2C71D5BCA9023F8'i64, 0x743E20E9EF511012'i64], [0xDF78E4B2BD342CF6'i64,
0x914DA9246B255416'i64], [0x8BAB8EEFB6409C1A'i64, 0x1AD089B6C2F7548E'i64], [
0xAE9672ABA3D0C320'i64, 0xA184AC2473B529B1'i64], [0xDA3C0F568CC4F3E8'i64,
0xC9E5D72D90A2741E'i64], [0x8865899617FB1871'i64, 0x7E2FA67C7A658892'i64], [
0xAA7EEBFB9DF9DE8D'i64, 0xDDBB901B98FEEAB7'i64], [0xD51EA6FA85785631'i64,
0x552A74227F3EA565'i64], [0x8533285C936B35DE'i64, 0xD53A88958F87275F'i64], [
0xA67FF273B8460356'i64, 0x8A892ABAF368F137'i64], [0xD01FEF10A657842C'i64,
0x2D2B7569B0432D85'i64], [0x8213F56A67F6B29B'i64, 0x9C3B29620E29FC73'i64], [
0xA298F2C501F45F42'i64, 0x8349F3BA91B47B8F'i64], [0xCB3F2F7642717713'i64,
0x241C70A936219A73'i64], [0xFE0EFB53D30DD4D7'i64, 0xED238CD383AA0110'i64], [
0x9EC95D1463E8A506'i64, 0xF4363804324A40AA'i64], [0xC67BB4597CE2CE48'i64,
0xB143C6053EDCD0D5'i64], [0xF81AA16FDC1B81DA'i64, 0xDD94B7868E94050A'i64], [
0x9B10A4E5E9913128'i64, 0xCA7CF2B4191C8326'i64], [0xC1D4CE1F63F57D72'i64,
0xFD1C2F611F63A3F0'i64], [0xF24A01A73CF2DCCF'i64, 0xBC633B39673C8CEC'i64], [
0x976E41088617CA01'i64, 0xD5BE0503E085D813'i64], [0xBD49D14AA79DBC82'i64,
0x4B2D8644D8A74E18'i64], [0xEC9C459D51852BA2'i64, 0xDDF8E7D60ED1219E'i64], [
0x93E1AB8252F33B45'i64, 0xCABB90E5C942B503'i64], [0xB8DA1662E7B00A17'i64,
0x3D6A751F3B936243'i64], [0xE7109BFBA19C0C9D'i64, 0x0CC512670A783AD4'i64], [
0x906A617D450187E2'i64, 0x27FB2B80668B24C5'i64], [0xB484F9DC9641E9DA'i64,
0xB1F9F660802DEDF6'i64], [0xE1A63853BBD26451'i64, 0x5E7873F8A0396973'i64], [
0x8D07E33455637EB2'i64, 0xDB0B487B6423E1E8'i64], [0xB049DC016ABC5E5F'i64,
0x91CE1A9A3D2CDA62'i64], [0xDC5C5301C56B75F7'i64, 0x7641A140CC7810FB'i64], [
0x89B9B3E11B6329BA'i64, 0xA9E904C87FCB0A9D'i64], [0xAC2820D9623BF429'i64,
0x546345FA9FBDCD44'i64], [0xD732290FBACAF133'i64, 0xA97C177947AD4095'i64], [
0x867F59A9D4BED6C0'i64, 0x49ED8EABCCCC485D'i64], [0xA81F301449EE8C70'i64,
0x5C68F256BFFF5A74'i64], [0xD226FC195C6A2F8C'i64, 0x73832EEC6FFF3111'i64], [
0x83585D8FD9C25DB7'i64, 0xC831FD53C5FF7EAB'i64], [0xA42E74F3D032F525'i64,
0xBA3E7CA8B77F5E55'i64], [0xCD3A1230C43FB26F'i64, 0x28CE1BD2E55F35EB'i64], [
0x80444B5E7AA7CF85'i64, 0x7980D163CF5B81B3'i64], [0xA0555E361951C366'i64,
0xD7E105BCC332621F'i64], [0xC86AB5C39FA63440'i64, 0x8DD9472BF3FEFAA7'i64], [
0xFA856334878FC150'i64, 0xB14F98F6F0FEB951'i64], [0x9C935E00D4B9D8D2'i64,
0x6ED1BF9A569F33D3'i64], [0xC3B8358109E84F07'i64, 0x0A862F80EC4700C8'i64], [
0xF4A642E14C6262C8'i64, 0xCD27BB612758C0FA'i64], [0x98E7E9CCCFBD7DBD'i64,
0x8038D51CB897789C'i64], [0xBF21E44003ACDD2C'i64, 0xE0470A63E6BD56C3'i64], [
0xEEEA5D5004981478'i64, 0x1858CCFCE06CAC74'i64], [0x95527A5202DF0CCB'i64,
0x0F37801E0C43EBC8'i64], [0xBAA718E68396CFFD'i64, 0xD30560258F54E6BA'i64], [
0xE950DF20247C83FD'i64, 0x47C6B82EF32A2069'i64], [0x91D28B7416CDD27E'i64,
0x4CDC331D57FA5441'i64], [0xB6472E511C81471D'i64, 0xE0133FE4ADF8E952'i64], [
0xE3D8F9E563A198E5'i64, 0x58180FDDD97723A6'i64], [0x8E679C2F5E44FF8F'i64,
0x570F09EAA7EA7648'i64], [0xB201833B35D63F73'i64, 0x2CD2CC6551E513DA'i64], [
0xDE81E40A034BCF4F'i64, 0xF8077F7EA65E58D1'i64], [0x8B112E86420F6191'i64,
0xFB04AFAF27FAF782'i64], [0xADD57A27D29339F6'i64, 0x79C5DB9AF1F9B563'i64], [
0xD94AD8B1C7380874'i64, 0x18375281AE7822BC'i64], [0x87CEC76F1C830548'i64,
0x8F2293910D0B15B5'i64], [0xA9C2794AE3A3C69A'i64, 0xB2EB3875504DDB22'i64], [
0xD433179D9C8CB841'i64, 0x5FA60692A46151EB'i64], [0x849FEEC281D7F328'i64,
0xDBC7C41BA6BCD333'i64], [0xA5C7EA73224DEFF3'i64, 0x12B9B522906C0800'i64], [
0xCF39E50FEAE16BEF'i64, 0xD768226B34870A00'i64], [0x81842F29F2CCE375'i64,
0xE6A1158300D46640'i64], [0xA1E53AF46F801C53'i64, 0x60495AE3C1097FD0'i64], [
0xCA5E89B18B602368'i64, 0x385BB19CB14BDFC4'i64], [0xFCF62C1DEE382C42'i64,
0x46729E03DD9ED7B5'i64], [0x9E19DB92B4E31BA9'i64, 0x6C07A2C26A8346D1'i64], [
0xC5A05277621BE293'i64, 0xC7098B7305241885'i64], [0xF70867153AA2DB38'i64,
0xB8CBEE4FC66D1EA7'i64]]
DRAGONBOX_ASSERT(k >= kMin)
DRAGONBOX_ASSERT(k <= kMax)
return Pow10[static_cast[uint32_t](k - kMin)]
## Returns whether value is divisible by 2^e2
proc MultipleOfPow2*(value: uint64_t; e2: int32_t): bool {.inline.} =
DRAGONBOX_ASSERT(e2 >= 0)
return e2 < 64 and (value and ((uint64_t(1) shl e2) - 1)) == 0
## Returns whether value is divisible by 5^e5
proc MultipleOfPow5*(value: uint64_t; e5: int32_t): bool {.inline.} =
type
MulCmp {.bycopy.} = object
mul: uint64_t
cmp: uint64_t
var Mod5: UncheckedArray[MulCmp] = [[0x0000000000000001'i64, 0xFFFFFFFFFFFFFFFF'i64], [
0xCCCCCCCCCCCCCCCD'i64, 0x3333333333333333'i64], [0x8F5C28F5C28F5C29'i64,
0x0A3D70A3D70A3D70'i64], [0x1CAC083126E978D5'i64, 0x020C49BA5E353F7C'i64], [
0xD288CE703AFB7E91'i64, 0x0068DB8BAC710CB2'i64], [0x5D4E8FB00BCBE61D'i64,
0x0014F8B588E368F0'i64], [0x790FB65668C26139'i64, 0x000431BDE82D7B63'i64], [
0xE5032477AE8D46A5'i64, 0x0000D6BF94D5E57A'i64], [0xC767074B22E90E21'i64,
0x00002AF31DC46118'i64], [0x8E47CE423A2E9C6D'i64, 0x0000089705F4136B'i64], [
0x4FA7F60D3ED61F49'i64, 0x000001B7CDFD9D7B'i64], [0x0FEE64690C913975'i64,
0x00000057F5FF85E5'i64], [0x3662E0E1CF503EB1'i64, 0x000000119799812D'i64], [
0xA47A2CF9F6433FBD'i64, 0x0000000384B84D09'i64], [0x54186F653140A659'i64,
0x00000000B424DC35'i64], [0x7738164770402145'i64, 0x0000000024075F3D'i64], [
0xE4A4D1417CD9A041'i64, 0x000000000734ACA5'i64], [0xC75429D9E5C5200D'i64,
0x000000000170EF54'i64], [0xC1773B91FAC10669'i64, 0x000000000049C977'i64], [
0x26B172506559CE15'i64, 0x00000000000EC1E4'i64], [0xD489E3A9ADDEC2D1'i64,
0x000000000002F394'i64], [0x90E860BB892C8D5D'i64, 0x000000000000971D'i64], [
0x502E79BF1B6F4F79'i64, 0x0000000000001E39'i64], [0xDCD618596BE30FE5'i64,
0x000000000000060B'i64], [0x2C2AD1AB7BFA3661'i64, 0x0000000000000135'i64]]
DRAGONBOX_ASSERT(e5 >= 0)
DRAGONBOX_ASSERT(e5 <= 24)
var m5: MulCmp = Mod5[static_cast[cuint](e5)]
return value * m5.mul <= m5.cmp
type
FloatingDecimal64* {.bycopy.} = object
significand*: uint64_t
exponent*: int32_t
proc ToDecimal64_asymmetric_interval*(e2: int32_t): FloatingDecimal64 {.inline.} =
## NB:
## accept_lower_endpoint = true
## accept_upper_endpoint = true
var P: int32_t = SignificandSize
## Compute k and beta
var minus_k: int32_t = FloorLog10ThreeQuartersPow2(e2)
var beta_minus_1: int32_t = e2 + FloorLog2Pow10(-minus_k)
## Compute xi and zi
var pow10: uint64x2 = ComputePow10(-minus_k)
var lower_endpoint: uint64_t = (pow10.hi - (pow10.hi shr (P + 1))) shr
(64 - P - beta_minus_1)
var upper_endpoint: uint64_t = (pow10.hi + (pow10.hi shr (P + 0))) shr
(64 - P - beta_minus_1)
## If we don't accept the left endpoint (but we do!) or
## if the left endpoint is not an integer, increase it
var lower_endpoint_is_integer: bool = (2 <= e2 and e2 <= 3)
var xi: uint64_t = lower_endpoint + not lower_endpoint_is_integer
var zi: uint64_t = upper_endpoint
## Try bigger divisor
var q: uint64_t = zi div 10
if q * 10 >= xi:
return (q, minus_k + 1)
q = ((pow10.hi shr (64 - (P + 1) - beta_minus_1)) + 1) div 2
## When tie occurs, choose one of them according to the rule
if e2 == -77:
dec(q, (q mod 2 != 0))
## Round to even.
else:
inc(q, (q < xi))
return (q, minus_k)
proc ComputeDelta*(pow10: uint64x2; beta_minus_1: int32_t): uint32_t {.inline.} =
DRAGONBOX_ASSERT(beta_minus_1 >= 0)
DRAGONBOX_ASSERT(beta_minus_1 <= 63)
return static_cast[uint32_t](pow10.hi shr (64 - 1 - beta_minus_1))
when defined(__SIZEOF_INT128__):
proc Mul128*(x: uint64_t; y: uint64_t): uint64x2 {.inline.} =
## 1 mulx
## !!!Ignored construct: __extension__ using uint128_t = unsigned __int128 ;
## Error: token expected: ; but got: [identifier]!!!
var p: uint128_t = uint128_t(x) * y
var hi: uint64_t = static_cast[uint64_t](p shr 64)
var lo: uint64_t = static_cast[uint64_t](p)
return (hi, lo)
elif defined(_MSC_VER) and defined(_M_X64):
proc Mul128*(x: uint64_t; y: uint64_t): uint64x2 {.inline.} =
var hi: uint64_t = 0
var lo: uint64_t = _umul128(x, y, addr(hi))
return (hi, lo)
else:
proc Lo32*(x: uint64_t): uint32_t {.inline.} =
return static_cast[uint32_t](x)
proc Hi32*(x: uint64_t): uint32_t {.inline.} =
return static_cast[uint32_t](x shr 32)
proc Mul128*(a: uint64_t; b: uint64_t): uint64x2 {.inline.} =
var b00: uint64_t = uint64_t(Lo32(a)) * Lo32(b)
var b01: uint64_t = uint64_t(Lo32(a)) * Hi32(b)
var b10: uint64_t = uint64_t(Hi32(a)) * Lo32(b)
var b11: uint64_t = uint64_t(Hi32(a)) * Hi32(b)
var mid1: uint64_t = b10 + Hi32(b00)
var mid2: uint64_t = b01 + Lo32(mid1)
var hi: uint64_t = b11 + Hi32(mid1) + Hi32(mid2)
var lo: uint64_t = Lo32(b00) or uint64_t(Lo32(mid2)) shl 32
return (hi, lo)
## Returns (x * y) / 2^128
proc MulShift*(x: uint64_t; y: uint64x2): uint64_t {.inline.} =
## 2 mulx
var p1: uint64x2 = Mul128(x, y.hi)
var p0: uint64x2 = Mul128(x, y.lo)
inc(p1.lo, p0.hi)
inc(p1.hi, p1.lo < p0.hi)
return p1.hi
proc MulParity*(two_f: uint64_t; pow10: uint64x2; beta_minus_1: int32_t): bool {.inline.} =
## 1 mulx, 1 mul
DRAGONBOX_ASSERT(beta_minus_1 >= 1)
DRAGONBOX_ASSERT(beta_minus_1 <= 63)
var p01: uint64_t = two_f * pow10.hi
var p10: uint64_t = Mul128(two_f, pow10.lo).hi
var mid: uint64_t = p01 + p10
return (mid and (uint64_t(1) shl (64 - beta_minus_1))) != 0
proc IsIntegralEndpoint*(two_f: uint64_t; e2: int32_t; minus_k: int32_t): bool {.inline.} =
if e2 < -2:
return false
if e2 <= 9:
return true
if e2 <= 86:
return MultipleOfPow5(two_f, minus_k)
return false
proc IsIntegralMidpoint*(two_f: uint64_t; e2: int32_t; minus_k: int32_t): bool {.inline.} =
if e2 < -4:
return MultipleOfPow2(two_f, minus_k - e2 + 1)
if e2 <= 9:
return true
if e2 <= 86:
return MultipleOfPow5(two_f, minus_k)
return false
proc ToDecimal64*(ieee_significand: uint64_t; ieee_exponent: uint64_t): FloatingDecimal64 {.
inline.} =
var Kappa: int32_t = 2
var BigDivisor: uint32_t = 1000
## 10^(kappa + 1)
var SmallDivisor: uint32_t = 100
## 10^(kappa)
##
## Step 1:
## integer promotion & Schubfach multiplier calculation.
##
var m2: uint64_t
var e2: int32_t
if ieee_exponent != 0:
m2 = HiddenBit or ieee_significand
e2 = static_cast[int32_t](ieee_exponent) - ExponentBias
if 0 <= -e2 and -e2 < SignificandSize and MultipleOfPow2(m2, -e2):
## Small integer.
return (m2 shr -e2, 0)
if ieee_significand == 0 and ieee_exponent > 1:
## Shorter interval case; proceed like Schubfach.
return ToDecimal64_asymmetric_interval(e2)
else:
## Subnormal case; interval is always regular.
m2 = ieee_significand
e2 = 1 - ExponentBias
var is_even: bool = (m2 mod 2 == 0)
var accept_lower: bool = is_even
var accept_upper: bool = is_even
## Compute k and beta.
var minus_k: int32_t = FloorLog10Pow2(e2) - Kappa
var beta_minus_1: int32_t = e2 + FloorLog2Pow10(-minus_k)
DRAGONBOX_ASSERT(beta_minus_1 >= 6)
DRAGONBOX_ASSERT(beta_minus_1 <= 9)
var pow10: uint64x2 = ComputePow10(-minus_k)
## Compute delta
## 10^kappa <= delta < 10^(kappa + 1)
## 100 <= delta < 1000
var delta: uint32_t = ComputeDelta(pow10, beta_minus_1)
DRAGONBOX_ASSERT(delta >= SmallDivisor)
DRAGONBOX_ASSERT(delta < BigDivisor)
var two_fl: uint64_t = 2 * m2 - 1
var two_fc: uint64_t = 2 * m2
var two_fr: uint64_t = 2 * m2 + 1
## (54 bits)
## Compute zi
## (54 + 9 = 63 bits)
var zi: uint64_t = MulShift(two_fr shl beta_minus_1, pow10)
## 2 mulx
##
## Step 2:
## Try larger divisor.
##
var q: uint64_t = zi div BigDivisor
## uint64_t q = Mul128(zi, 0x83126E978D4FDF3Cu).hi >> 9; // 1 mulx
var r: uint32_t = static_cast[uint32_t](zi) -
BigDivisor * static_cast[uint32_t](q)
## r = zi % BigDivisor
## 0 <= r < 1000
if r < delta: ## likely ~50% ?!
## (r > deltai)
## Exclude the right endpoint if necessary
if r != 0 or accept_upper or not IsIntegralEndpoint(two_fr, e2, minus_k):
return (q, minus_k + Kappa + 1)
DRAGONBOX_ASSERT(q != 0)
dec(q)
r = BigDivisor
elif r == delta: ## unlikely
## Compare fractional parts.
## Check conditions in the order different from the paper
## to take advantage of short-circuiting
if (accept_lower and IsIntegralEndpoint(two_fl, e2, minus_k)) or
MulParity(two_fl, pow10, beta_minus_1):
return (q, minus_k + Kappa + 1)
else:
discard
##
## Step 3:
## Find the significand with the smaller divisor
##
q = q * 10
## 1 hmul
## 0 <= r <= 1000
var dist: uint32_t = r - (delta div 2) + (SmallDivisor div 2)
var dist_q: uint32_t = dist div 100
## 1 mul
## const uint32_t dist_r = dist % 100;
inc(q, dist_q)
## if /*likely*/ (dist_r == 0)
if dist == dist_q * 100:
## const bool approx_y_parity = ((dist ^ (SmallDivisor / 2)) & 1) != 0;
var approx_y_parity: bool = (dist and 1) != 0
## Check z^(f) >= epsilon^(f)
## We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1,
## where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f)
## Since there are only 2 possibilities, we only need to care about the
## parity. Also, zi and r should have the same parity since the divisor
## is an even number
if MulParity(two_fc, pow10, beta_minus_1) != approx_y_parity:
dec(q)
elif q mod 2 != 0 and IsIntegralMidpoint(two_fc, e2, minus_k):
dec(q)
return (q, minus_k + Kappa)
## ==================================================================================================
## ToChars
## ==================================================================================================
proc Utoa_2Digits*(buf: cstring; digits: uint32_t) {.inline.} =
var Digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5',
'0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1',
'1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7',
'1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3',
'2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
'3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5',
'3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
'4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7',
'4', '8', '4', '9', '5', '0', '5', '1', '5', '2', '5', '3',
'5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5',
'6', '6', '6', '7', '6', '8', '6', '9', '7', '0', '7', '1',
'7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7',
'7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3',
'8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
'9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5',
'9', '6', '9', '7', '9', '8', '9', '9']
DRAGONBOX_ASSERT(digits <= 99)
memcpy(buf, addr(Digits100[2 * digits]), 2 * sizeof((char)))
proc TrailingZeros_2Digits*(digits: uint32_t): int32_t {.inline.} =
var TrailingZeros100: array[100, int8_t] = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0]
DRAGONBOX_ASSERT(digits <= 99)
return TrailingZeros100[digits]
proc Utoa_8Digits_skip_trailing_zeros*(buf: cstring; digits: uint32_t): int32_t {.
inline.} =
DRAGONBOX_ASSERT(digits >= 1)
DRAGONBOX_ASSERT(digits <= 99999999)
var q: uint32_t = digits div 10000
var r: uint32_t = digits mod 10000
var qH: uint32_t = q div 100
var qL: uint32_t = q mod 100
Utoa_2Digits(buf + 0, qH)
Utoa_2Digits(buf + 2, qL)
if r == 0:
return TrailingZeros_2Digits(if qL == 0: qH else: qL) + (if qL == 0: 6 else: 4)
else:
var rH: uint32_t = r div 100
var rL: uint32_t = r mod 100
Utoa_2Digits(buf + 4, rH)
Utoa_2Digits(buf + 6, rL)
return TrailingZeros_2Digits(if rL == 0: rH else: rL) + (if rL == 0: 2 else: 0)
proc PrintDecimalDigitsBackwards*(buf: cstring; output64: uint64_t): int32_t {.inline.} =
var tz: int32_t = 0
## number of trailing zeros removed.
var nd: int32_t = 0
## number of decimal digits processed.
## At most 17 digits remaining
if output64 >= 100000000:
var q: uint64_t = output64 div 100000000
var r: uint32_t = static_cast[uint32_t](output64 mod 100000000)
output64 = q
dec(buf, 8)
if r != 0:
tz = Utoa_8Digits_skip_trailing_zeros(buf, r)
DRAGONBOX_ASSERT(tz >= 0)
DRAGONBOX_ASSERT(tz <= 7)
else:
tz = 8
nd = 8
DRAGONBOX_ASSERT(output64 <= UINT32_MAX)
var output: uint32_t = static_cast[uint32_t](output64)
if output >= 10000:
var q: uint32_t = output div 10000
var r: uint32_t = output mod 10000
output = q
dec(buf, 4)
if r != 0:
var rH: uint32_t = r div 100
var rL: uint32_t = r mod 100
Utoa_2Digits(buf + 0, rH)
Utoa_2Digits(buf + 2, rL)
if tz == nd:
inc(tz, TrailingZeros_2Digits(if rL == 0: rH else: rL) +
(if rL == 0: 2 else: 0))
else:
if tz == nd:
inc(tz, 4)
else:
memset(buf, '0', 4)
## (actually not required...)
inc(nd, 4)
if output >= 100:
var q: uint32_t = output div 100
var r: uint32_t = output mod 100
output = q
dec(buf, 2)
Utoa_2Digits(buf, r)
if tz == nd:
inc(tz, TrailingZeros_2Digits(r))
inc(nd, 2)
if output >= 100:
var q2: uint32_t = output div 100
var r2: uint32_t = output mod 100
output = q2
dec(buf, 2)
Utoa_2Digits(buf, r2)
if tz == nd:
inc(tz, TrailingZeros_2Digits(r2))
inc(nd, 2)
DRAGONBOX_ASSERT(output >= 1)
DRAGONBOX_ASSERT(output <= 99)
if output >= 10:
var q: uint32_t = output
dec(buf, 2)
Utoa_2Digits(buf, q)
if tz == nd:
inc(tz, TrailingZeros_2Digits(q))
else:
var q: uint32_t = output
DRAGONBOX_ASSERT(q >= 1)
DRAGONBOX_ASSERT(q <= 9)
dec(buf)[] = static_cast[char]('0' + q)
return tz
proc DecimalLength*(v: uint64_t): int32_t {.inline.} =
DRAGONBOX_ASSERT(v >= 1)
DRAGONBOX_ASSERT(v <= 99999999999999999'i64)
if static_cast[uint32_t](v shr 32) != 0:
if v >= 10000000000000000'i64:
return 17
if v >= 1000000000000000'i64:
return 16
if v >= 100000000000000'i64:
return 15
if v >= 10000000000000'i64:
return 14
if v >= 1000000000000'i64:
return 13
if v >= 100000000000'i64:
return 12
if v >= 10000000000'i64:
return 11
return 10
var v32: uint32_t = static_cast[uint32_t](v)
if v32 >= 1000000000:
return 10
if v32 >= 100000000:
return 9
if v32 >= 10000000:
return 8
if v32 >= 1000000:
return 7
if v32 >= 100000:
return 6
if v32 >= 10000:
return 5
if v32 >= 1000:
return 4
if v32 >= 100:
return 3
if v32 >= 10:
return 2
return 1
proc FormatDigits*(buffer: cstring; digits: uint64_t; decimal_exponent: int32_t;
force_trailing_dot_zero: bool = false): cstring {.inline.} =
var MinFixedDecimalPoint: int32_t = -6
var MaxFixedDecimalPoint: int32_t = 17
static_assert(MinFixedDecimalPoint <= -1, "internal error")
static_assert(MaxFixedDecimalPoint >= 17, "internal error")
DRAGONBOX_ASSERT(digits >= 1)
DRAGONBOX_ASSERT(digits <= 99999999999999999'i64)
DRAGONBOX_ASSERT(decimal_exponent >= -999)
DRAGONBOX_ASSERT(decimal_exponent <= 999)
var num_digits: int32_t = DecimalLength(digits)
var decimal_point: int32_t = num_digits + decimal_exponent
var use_fixed: bool = MinFixedDecimalPoint <= decimal_point and
decimal_point <= MaxFixedDecimalPoint
## Prepare the buffer.
## Avoid calling memset/memcpy with variable arguments below...
memset(buffer + 0, '0', 16)
memset(buffer + 16, '0', 16)
static_assert(MinFixedDecimalPoint >= -30, "internal error")
static_assert(MaxFixedDecimalPoint <= 32, "internal error")
var decimal_digits_position: int32_t
if use_fixed:
if decimal_point <= 0:
## 0.[000]digits
decimal_digits_position = 2 - decimal_point
else:
## dig.its
## digits[000]
decimal_digits_position = 0
else:
## dE+123 or d.igitsE+123
decimal_digits_position = 1
var digits_end: cstring = buffer + decimal_digits_position + num_digits
var tz: int32_t = PrintDecimalDigitsBackwards(digits_end, digits)
dec(digits_end, tz)
dec(num_digits, tz)
## decimal_exponent += tz; // => decimal_point unchanged.
if use_fixed:
if decimal_point <= 0:
## 0.[000]digits
buffer[1] = '.'
buffer = digits_end
elif decimal_point < num_digits:
## dig.its
when defined(_MSC_VER) and not defined(__clang__):
## VC does not inline the memmove call below. (Even if compiled with /arch:AVX2.)
## However, memcpy will be inlined.
var tmp: array[16, uint8_t]
var src: cstring = buffer + decimal_point
var dst: cstring = src + 1
memcpy(tmp, src, 16)
memcpy(dst, tmp, 16)
else:
memmove(buffer + decimal_point + 1, buffer + decimal_point, 16)
buffer[decimal_point] = '.'
buffer = digits_end + 1
else:
## digits[000]
inc(buffer, decimal_point)
if force_trailing_dot_zero:
memcpy(buffer, ".0", 2)
inc(buffer, 2)
else:
## Copy the first digit one place to the left.
buffer[0] = buffer[1]
if num_digits == 1:
## dE+123
inc(buffer)
else:
## d.igitsE+123
buffer[1] = '.'
buffer = digits_end
var scientific_exponent: int32_t = decimal_point - 1
## SF_ASSERT(scientific_exponent != 0);
memcpy(buffer, if scientific_exponent < 0: "e-" else: "e+", 2)
inc(buffer, 2)
var k: uint32_t = static_cast[uint32_t](if scientific_exponent < 0: -scientific_exponent else: scientific_exponent)
if k < 10:
inc(buffer)[] = static_cast[char]('0' + k)
elif k < 100:
Utoa_2Digits(buffer, k)
inc(buffer, 2)
else:
var q: uint32_t = k div 100
var r: uint32_t = k mod 100
inc(buffer)[] = static_cast[char]('0' + q)
Utoa_2Digits(buffer, r)
inc(buffer, 2)
return buffer
proc ToChars*(buffer: cstring; value: cdouble; force_trailing_dot_zero: bool = false): cstring {.
inline.} =
proc v(a1: value): Double
var significand: uint64_t = v.PhysicalSignificand()
var exponent: uint64_t = v.PhysicalExponent()
if exponent != MaxIeeeExponent:
## Finite
buffer[0] = '-'
inc(buffer, v.SignBit())
if exponent != 0 or significand != 0:
## != 0
var dec: auto = ToDecimal64(significand, exponent)
return FormatDigits(buffer, dec.significand, dec.exponent,
force_trailing_dot_zero)
else:
memcpy(buffer, "0.0 ", 4)
inc(buffer, if force_trailing_dot_zero: 3 else: 1)
return buffer
if significand == 0:
buffer[0] = '-'
inc(buffer, v.SignBit())
memcpy(buffer, "inf ", 4)
return buffer + 3
else:
memcpy(buffer, "nan ", 4)
return buffer + 3
## ==================================================================================================
##
## ==================================================================================================
proc Dtoa*(buffer: cstring; value: cdouble): cstring =
return ToChars(buffer, value)
proc nim_dragonbox_Dtoa*(buffer: cstring; value: cdouble): cstring =
return ToChars(buffer, value)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment