Нет описания
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

BurstString.Float.cs 83KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947
  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using System.Runtime.InteropServices;
  4. #if UNITY_DOTSRUNTIME
  5. using Unity.Collections.LowLevel.Unsafe;
  6. #endif
  7. namespace Unity.Burst
  8. {
  9. #if BURST_COMPILER_SHARED
  10. internal static partial class BurstStringInternal
  11. #else
  12. internal static partial class BurstString
  13. #endif
  14. {
  15. // This file provides an implementation for formatting floating point numbers that is compatible
  16. // with Burst
  17. // ------------------------------------------------------------------------------
  18. // Part of code translated to C# from http://www.ryanjuckett.com/programming/printing-floating-point-numbers
  19. // with the following license:
  20. /******************************************************************************
  21. Copyright (c) 2014 Ryan Juckett
  22. http://www.ryanjuckett.com/
  23. This software is provided 'as-is', without any express or implied
  24. warranty. In no event will the authors be held liable for any damages
  25. arising from the use of this software.
  26. Permission is granted to anyone to use this software for any purpose,
  27. including commercial applications, and to alter it and redistribute it
  28. freely, subject to the following restrictions:
  29. 1. The origin of this software must not be misrepresented; you must not
  30. claim that you wrote the original software. If you use this software
  31. in a product, an acknowledgment in the product documentation would be
  32. appreciated but is not required.
  33. 2. Altered source versions must be plainly marked as such, and must not be
  34. misrepresented as being the original software.
  35. 3. This notice may not be removed or altered from any source
  36. distribution.
  37. ******************************************************************************/
  38. //******************************************************************************
  39. // Get the log base 2 of a 32-bit unsigned integer.
  40. // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
  41. //******************************************************************************
  42. private static readonly byte[] logTable = new byte[256]
  43. {
  44. 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
  45. 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
  46. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  47. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  48. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  49. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  50. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  51. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  52. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  53. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  54. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  55. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  56. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  57. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  58. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  59. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
  60. };
  61. private static uint LogBase2(uint val)
  62. {
  63. uint temp;
  64. temp = val >> 24;
  65. if (temp != 0)
  66. return (uint)(24 + logTable[(int)temp]);
  67. temp = val >> 16;
  68. if (temp != 0)
  69. return (uint)(16 + logTable[temp]);
  70. temp = val >> 8;
  71. if (temp != 0)
  72. return (uint)(8 + logTable[temp]);
  73. return logTable[val];
  74. }
  75. //******************************************************************************
  76. // This structure stores a high precision unsigned integer. It uses a buffer
  77. // of 32 bit integer blocks along with a length. The lowest bits of the integer
  78. // are stored at the start of the buffer and the length is set to the minimum
  79. // value that contains the integer. Thus, there are never any zero blocks at the
  80. // end of the buffer.
  81. //******************************************************************************
  82. public unsafe struct tBigInt
  83. {
  84. //******************************************************************************
  85. // Maximum number of 32 bit blocks needed in high precision arithmetic
  86. // to print out 64 bit IEEE floating point values.
  87. //******************************************************************************
  88. const int c_BigInt_MaxBlocks = 35;
  89. //// Copy integer
  90. //tBigInt & operator=(tBigInt &rhs)
  91. //{
  92. // uint length = rhs.m_length;
  93. // uint* pLhsCur = m_blocks;
  94. // for (uint* pRhsCur = rhs.m_blocks, *pRhsEnd = pRhsCur + length;
  95. // pRhsCur != pRhsEnd;
  96. // ++pLhsCur, ++pRhsCur)
  97. // {
  98. // *pLhsCur = *pRhsCur;
  99. // }
  100. // m_length = length;
  101. // return *this;
  102. //}
  103. // Data accessors
  104. public int GetLength() { return m_length; }
  105. public uint GetBlock(int idx) { return m_blocks[idx]; }
  106. // Zero helper functions
  107. public void SetZero() { m_length = 0; }
  108. public bool IsZero() { return m_length == 0; }
  109. // Basic type accessors
  110. public void SetU64(ulong val)
  111. {
  112. if (val > 0xFFFFFFFF)
  113. {
  114. m_blocks[0] = (uint)(val & 0xFFFFFFFF);
  115. m_blocks[1] = (uint)(val >> 32 & 0xFFFFFFFF);
  116. m_length = 2;
  117. }
  118. else if (val != 0)
  119. {
  120. m_blocks[0] = (uint)(val & 0xFFFFFFFF);
  121. m_length = 1;
  122. }
  123. else
  124. {
  125. m_length = 0;
  126. }
  127. }
  128. public void SetU32(uint val)
  129. {
  130. if (val != 0)
  131. {
  132. m_blocks[0] = val;
  133. m_length = (val != 0) ? 1 : 0;
  134. }
  135. else
  136. {
  137. m_length = 0;
  138. }
  139. }
  140. public uint GetU32() { return (m_length == 0) ? 0 : m_blocks[0]; }
  141. // Member data
  142. public int m_length;
  143. public fixed uint m_blocks[c_BigInt_MaxBlocks];
  144. }
  145. //******************************************************************************
  146. // Returns 0 if (lhs = rhs), negative if (lhs < rhs), positive if (lhs > rhs)
  147. //******************************************************************************
  148. private static unsafe int BigInt_Compare(in tBigInt lhs, in tBigInt rhs)
  149. {
  150. // A bigger length implies a bigger number.
  151. int lengthDiff = lhs.m_length - rhs.m_length;
  152. if (lengthDiff != 0)
  153. return lengthDiff;
  154. // Compare blocks one by one from high to low.
  155. for (int i = (int)lhs.m_length - 1; i >= 0; --i)
  156. {
  157. if (lhs.m_blocks[i] == rhs.m_blocks[i])
  158. continue;
  159. else if (lhs.m_blocks[i] > rhs.m_blocks[i])
  160. return 1;
  161. else
  162. return -1;
  163. }
  164. // no blocks differed
  165. return 0;
  166. }
  167. //******************************************************************************
  168. // result = lhs + rhs
  169. //******************************************************************************
  170. private static unsafe void BigInt_Add(out tBigInt pResult, in tBigInt lhs, in tBigInt rhs)
  171. {
  172. if (lhs.m_length < rhs.m_length)
  173. {
  174. BigInt_Add_internal(out pResult, rhs, lhs);
  175. }
  176. else
  177. {
  178. BigInt_Add_internal(out pResult, lhs, rhs);
  179. }
  180. }
  181. private static unsafe void BigInt_Add_internal(out tBigInt pResult, in tBigInt pLarge, in tBigInt pSmall)
  182. {
  183. int largeLen = pLarge.m_length;
  184. int smallLen = pSmall.m_length;
  185. // The output will be at least as long as the largest input
  186. pResult.m_length = largeLen;
  187. // Add each block and add carry the overflow to the next block
  188. ulong carry = 0;
  189. fixed (uint * pLargeCur1 = pLarge.m_blocks)
  190. fixed (uint * pSmallCur1 = pSmall.m_blocks)
  191. fixed (uint * pResultCur1 = pResult.m_blocks)
  192. {
  193. uint* pLargeCur = pLargeCur1;
  194. uint* pSmallCur = pSmallCur1;
  195. uint* pResultCur = pResultCur1;
  196. uint* pLargeEnd = pLargeCur + largeLen;
  197. uint* pSmallEnd = pSmallCur + smallLen;
  198. while (pSmallCur != pSmallEnd)
  199. {
  200. ulong sum = carry + (ulong) (*pLargeCur) + (ulong) (*pSmallCur);
  201. carry = sum >> 32;
  202. (*pResultCur) = (uint)(sum & 0xFFFFFFFF);
  203. ++pLargeCur;
  204. ++pSmallCur;
  205. ++pResultCur;
  206. }
  207. // Add the carry to any blocks that only exist in the large operand
  208. while (pLargeCur != pLargeEnd)
  209. {
  210. ulong sum = carry + (ulong) (*pLargeCur);
  211. carry = sum >> 32;
  212. (*pResultCur) = (uint)(sum & 0xFFFFFFFF);
  213. ++pLargeCur;
  214. ++pResultCur;
  215. }
  216. // If there's still a carry, append a new block
  217. if (carry != 0)
  218. {
  219. //RJ_ASSERT(carry == 1);
  220. //RJ_ASSERT((uint)(pResultCur - pResult.m_blocks) == largeLen && (largeLen < c_BigInt_MaxBlocks));
  221. *pResultCur = 1;
  222. pResult.m_length = largeLen + 1;
  223. }
  224. else
  225. {
  226. pResult.m_length = largeLen;
  227. }
  228. }
  229. }
  230. //******************************************************************************
  231. // result = lhs * rhs
  232. //******************************************************************************
  233. private static unsafe void BigInt_Multiply(out tBigInt pResult, in tBigInt lhs, in tBigInt rhs)
  234. {
  235. if (lhs.m_length < rhs.m_length)
  236. {
  237. BigInt_Multiply_internal(out pResult, rhs, lhs);
  238. }
  239. else
  240. {
  241. BigInt_Multiply_internal(out pResult, lhs, rhs);
  242. }
  243. }
  244. private static unsafe void BigInt_Multiply_internal(out tBigInt pResult, in tBigInt pLarge, in tBigInt pSmall)
  245. {
  246. // set the maximum possible result length
  247. int maxResultLen = pLarge.m_length + pSmall.m_length;
  248. // RJ_ASSERT( maxResultLen <= c_BigInt_MaxBlocks );
  249. // clear the result data
  250. // uint * pCur = pResult.m_blocks, *pEnd = pCur + maxResultLen; pCur != pEnd; ++pCur
  251. for (int i = 0; i < maxResultLen; i++)
  252. pResult.m_blocks[i] = 0;
  253. // perform standard long multiplication
  254. fixed (uint *pLargeBeg1 = pLarge.m_blocks)
  255. {
  256. uint* pLargeBeg = pLargeBeg1;
  257. uint* pLargeEnd = pLargeBeg + pLarge.m_length;
  258. // for each small block
  259. fixed (uint* pResultStart1 = pResult.m_blocks)
  260. fixed (uint* pSmallCur1 = pSmall.m_blocks)
  261. {
  262. uint* pSmallCur = pSmallCur1;
  263. uint* pSmallEnd = pSmallCur + pSmall.m_length;
  264. uint* pResultStart = pResultStart1;
  265. for (; pSmallCur != pSmallEnd; ++pSmallCur, ++pResultStart)
  266. {
  267. // if non-zero, multiply against all the large blocks and add into the result
  268. uint multiplier = *pSmallCur;
  269. if (multiplier != 0)
  270. {
  271. uint* pLargeCur = pLargeBeg;
  272. uint* pResultCur = pResultStart;
  273. ulong carry = 0;
  274. do
  275. {
  276. ulong product = (*pResultCur) + (*pLargeCur) * (ulong) multiplier + carry;
  277. carry = product >> 32;
  278. *pResultCur = (uint)(product & 0xFFFFFFFF);
  279. ++pLargeCur;
  280. ++pResultCur;
  281. } while (pLargeCur != pLargeEnd);
  282. //RJ_ASSERT(pResultCur < pResult.m_blocks + maxResultLen);
  283. *pResultCur = (uint) (carry & 0xFFFFFFFF);
  284. }
  285. }
  286. // check if the terminating block has no set bits
  287. if (maxResultLen > 0 && pResult.m_blocks[maxResultLen - 1] == 0)
  288. pResult.m_length = maxResultLen - 1;
  289. else
  290. pResult.m_length = maxResultLen;
  291. }
  292. }
  293. }
  294. //******************************************************************************
  295. // result = lhs * rhs
  296. //******************************************************************************
  297. private static unsafe void BigInt_Multiply(out tBigInt pResult, in tBigInt lhs, uint rhs)
  298. {
  299. // perform long multiplication
  300. uint carry = 0;
  301. fixed (uint* pResultCur1 = pResult.m_blocks)
  302. fixed (uint* pLhsCur1 = lhs.m_blocks)
  303. {
  304. uint* pResultCur = pResultCur1;
  305. uint* pLhsCur = pLhsCur1;
  306. uint* pLhsEnd = pLhsCur + lhs.m_length;
  307. for (; pLhsCur != pLhsEnd; ++pLhsCur, ++pResultCur)
  308. {
  309. ulong product = (ulong) (*pLhsCur) * rhs + carry;
  310. *pResultCur = (uint) (product & 0xFFFFFFFF);
  311. carry = (uint)(product >> 32);
  312. }
  313. // if there is a remaining carry, grow the array
  314. if (carry != 0)
  315. {
  316. // grow the array
  317. //RJ_ASSERT(lhs.m_length + 1 <= c_BigInt_MaxBlocks);
  318. *pResultCur = (uint) carry;
  319. pResult.m_length = lhs.m_length + 1;
  320. }
  321. else
  322. {
  323. pResult.m_length = lhs.m_length;
  324. }
  325. }
  326. }
  327. //******************************************************************************
  328. // result = in * 2
  329. //******************************************************************************
  330. private static unsafe void BigInt_Multiply2(out tBigInt pResult, in tBigInt input)
  331. {
  332. // shift all the blocks by one
  333. uint carry = 0;
  334. fixed (uint* pResultCur1 = pResult.m_blocks)
  335. fixed (uint* pLhsCur1 = input.m_blocks)
  336. {
  337. uint* pResultCur = pResultCur1;
  338. uint* pLhsCur = pLhsCur1;
  339. uint* pLhsEnd = pLhsCur + input.m_length;
  340. for (; pLhsCur != pLhsEnd; ++pLhsCur, ++pResultCur)
  341. {
  342. uint cur = *pLhsCur;
  343. *pResultCur = (cur << 1) | carry;
  344. carry = cur >> 31;
  345. }
  346. if (carry != 0)
  347. {
  348. // grow the array
  349. // RJ_ASSERT(input.m_length + 1 <= c_BigInt_MaxBlocks);
  350. *pResultCur = carry;
  351. pResult.m_length = input.m_length + 1;
  352. }
  353. else
  354. {
  355. pResult.m_length = input.m_length;
  356. }
  357. }
  358. }
  359. //******************************************************************************
  360. // result = result * 2
  361. //******************************************************************************
  362. private static unsafe void BigInt_Multiply2(ref tBigInt pResult)
  363. {
  364. // shift all the blocks by one
  365. uint carry = 0;
  366. fixed (uint* pCur1 = pResult.m_blocks)
  367. {
  368. uint* pCur = pCur1;
  369. uint* pEnd = pCur + pResult.m_length;
  370. for (; pCur != pEnd; ++pCur)
  371. {
  372. uint cur = *pCur;
  373. *pCur = (cur << 1) | carry;
  374. carry = cur >> 31;
  375. }
  376. if (carry != 0)
  377. {
  378. // grow the array
  379. // RJ_ASSERT(pResult.m_length + 1 <= c_BigInt_MaxBlocks);
  380. *pCur = carry;
  381. ++pResult.m_length;
  382. }
  383. }
  384. }
  385. //******************************************************************************
  386. // result = result * 10
  387. //******************************************************************************
  388. private static unsafe void BigInt_Multiply10(ref tBigInt pResult)
  389. {
  390. // multiply all the blocks
  391. ulong carry = 0;
  392. fixed (uint* pCur1 = pResult.m_blocks)
  393. {
  394. uint* pCur = pCur1;
  395. uint* pEnd = pCur + pResult.m_length;
  396. for (; pCur != pEnd; ++pCur)
  397. {
  398. ulong product = (ulong) (*pCur) * 10 + carry;
  399. (*pCur) = (uint) (product & 0xFFFFFFFF);
  400. carry = product >> 32;
  401. }
  402. if (carry != 0)
  403. {
  404. // grow the array
  405. //RJ_ASSERT(pResult.m_length + 1 <= c_BigInt_MaxBlocks);
  406. *pCur = (uint) carry;
  407. ++pResult.m_length;
  408. }
  409. }
  410. }
  411. //******************************************************************************
  412. //******************************************************************************
  413. private static readonly uint[] g_PowerOf10_U32 = new uint[]
  414. {
  415. 1, // 10 ^ 0
  416. 10, // 10 ^ 1
  417. 100, // 10 ^ 2
  418. 1000, // 10 ^ 3
  419. 10000, // 10 ^ 4
  420. 100000, // 10 ^ 5
  421. 1000000, // 10 ^ 6
  422. 10000000, // 10 ^ 7
  423. };
  424. //******************************************************************************
  425. // Note: This has a lot of wasted space in the big integer structures of the
  426. // early table entries. It wouldn't be terribly hard to make the multiply
  427. // function work on integer pointers with an array length instead of
  428. // the tBigInt struct which would allow us to store a minimal amount of
  429. // data here.
  430. //******************************************************************************
  431. private static unsafe tBigInt g_PowerOf10_Big(int i)
  432. {
  433. tBigInt result;
  434. // 10 ^ 8
  435. if (i == 0)
  436. {
  437. // { 1, { 100000000 } },
  438. result.m_length = 1;
  439. result.m_blocks[0] = 100000000;
  440. }
  441. else if (i == 1)
  442. {
  443. // 10 ^ 16
  444. // { 2, { 0x6fc10000, 0x002386f2 } },
  445. result.m_length = 2;
  446. result.m_blocks[0] = 0x6fc10000;
  447. result.m_blocks[1] = 0x002386f2;
  448. }
  449. else if (i == 2)
  450. {
  451. // 10 ^ 32
  452. // { 4, { 0x00000000, 0x85acef81, 0x2d6d415b, 0x000004ee, } },
  453. result.m_length = 4;
  454. result.m_blocks[0] = 0x00000000;
  455. result.m_blocks[1] = 0x85acef81;
  456. result.m_blocks[2] = 0x2d6d415b;
  457. result.m_blocks[3] = 0x000004ee;
  458. }
  459. else if (i == 3)
  460. {
  461. // 10 ^ 64
  462. // { 7, { 0x00000000, 0x00000000, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x00184f03, } },
  463. result.m_length = 7;
  464. result.m_blocks[0] = 0x00000000;
  465. result.m_blocks[1] = 0x00000000;
  466. result.m_blocks[2] = 0xbf6a1f01;
  467. result.m_blocks[3] = 0x6e38ed64;
  468. result.m_blocks[4] = 0xdaa797ed;
  469. result.m_blocks[5] = 0xe93ff9f4;
  470. result.m_blocks[6] = 0x00184f03;
  471. }
  472. else if (i == 4)
  473. {
  474. // 10 ^ 128
  475. //{
  476. // 14, {
  477. // 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2e953e01, 0x03df9909, 0x0f1538fd,
  478. // 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da, 0xa6337f19, 0xe91f2603, 0x0000024e, }
  479. //},
  480. result.m_length = 14;
  481. result.m_blocks[0] = 0x00000000;
  482. result.m_blocks[1] = 0x00000000;
  483. result.m_blocks[2] = 0x00000000;
  484. result.m_blocks[3] = 0x00000000;
  485. result.m_blocks[4] = 0x2e953e01;
  486. result.m_blocks[5] = 0x03df9909;
  487. result.m_blocks[6] = 0x0f1538fd;
  488. result.m_blocks[7] = 0x2374e42f;
  489. result.m_blocks[8] = 0xd3cff5ec;
  490. result.m_blocks[9] = 0xc404dc08;
  491. result.m_blocks[10] = 0xbccdb0da;
  492. result.m_blocks[11] = 0xa6337f19;
  493. result.m_blocks[12] = 0xe91f2603;
  494. result.m_blocks[13] = 0x0000024e;
  495. }
  496. else
  497. {
  498. // 10 ^ 256
  499. //{
  500. // 27, {
  501. // 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
  502. // 0x00000000, 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70,
  503. // 0xd595d80f, 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0,
  504. // 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x000553f7,
  505. // }
  506. //}
  507. result.m_length = 27;
  508. result.m_blocks[0] = 0x00000000;
  509. result.m_blocks[1] = 0x00000000;
  510. result.m_blocks[2] = 0x00000000;
  511. result.m_blocks[3] = 0x00000000;
  512. result.m_blocks[4] = 0x00000000;
  513. result.m_blocks[5] = 0x00000000;
  514. result.m_blocks[6] = 0x00000000;
  515. result.m_blocks[7] = 0x00000000;
  516. result.m_blocks[8] = 0x982e7c01;
  517. result.m_blocks[9] = 0xbed3875b;
  518. result.m_blocks[10] = 0xd8d99f72;
  519. result.m_blocks[11] = 0x12152f87;
  520. result.m_blocks[12] = 0x6bde50c6;
  521. result.m_blocks[13] = 0xcf4a6e70;
  522. result.m_blocks[14] = 0xd595d80f;
  523. result.m_blocks[15] = 0x26b2716e;
  524. result.m_blocks[16] = 0xadc666b0;
  525. result.m_blocks[17] = 0x1d153624;
  526. result.m_blocks[18] = 0x3c42d35a;
  527. result.m_blocks[19] = 0x63ff540e;
  528. result.m_blocks[20] = 0xcc5573c0;
  529. result.m_blocks[21] = 0x65f9ef17;
  530. result.m_blocks[22] = 0x55bc28f2;
  531. result.m_blocks[23] = 0x80dcc7f7;
  532. result.m_blocks[24] = 0xf46eeddc;
  533. result.m_blocks[25] = 0x5fdcefce;
  534. result.m_blocks[26] = 0x000553f7;
  535. }
  536. return result;
  537. }
  538. //******************************************************************************
  539. // result = 10^exponent
  540. //******************************************************************************
  541. private static void BigInt_Pow10(out tBigInt pResult, uint exponent)
  542. {
  543. // make sure the exponent is within the bounds of the lookup table data
  544. // RJ_ASSERT(exponent < 512);
  545. // create two temporary values to reduce large integer copy operations
  546. tBigInt temp1 = default;
  547. tBigInt temp2 = default;
  548. ref tBigInt pCurTemp = ref temp1;
  549. ref tBigInt pNextTemp = ref temp2;
  550. // initialize the result by looking up a 32-bit power of 10 corresponding to the first 3 bits
  551. uint smallExponent = exponent & 0x7;
  552. pCurTemp.SetU32(g_PowerOf10_U32[smallExponent]);
  553. // remove the low bits that we used for the 32-bit lookup table
  554. exponent >>= 3;
  555. int tableIdx = 0;
  556. // while there are remaining bits in the exponent to be processed
  557. while (exponent != 0)
  558. {
  559. // if the current bit is set, multiply it with the corresponding power of 10
  560. if ((exponent & 1) != 0)
  561. {
  562. // multiply into the next temporary
  563. BigInt_Multiply(out pNextTemp, pCurTemp, g_PowerOf10_Big(tableIdx));
  564. // swap to the next temporary
  565. ref tBigInt pSwap = ref pCurTemp;
  566. pCurTemp = pNextTemp;
  567. pNextTemp = pSwap;
  568. }
  569. // advance to the next bit
  570. ++tableIdx;
  571. exponent >>= 1;
  572. }
  573. // output the result
  574. pResult = pCurTemp;
  575. }
  576. //******************************************************************************
  577. // result = in * 10^exponent
  578. //******************************************************************************
  579. private static unsafe void BigInt_MultiplyPow10(out tBigInt pResult, in tBigInt input, uint exponent)
  580. {
  581. // make sure the exponent is within the bounds of the lookup table data
  582. // RJ_ASSERT(exponent < 512);
  583. // create two temporary values to reduce large integer copy operations
  584. tBigInt temp1 = default;
  585. tBigInt temp2 = default;
  586. ref tBigInt pCurTemp = ref temp1;
  587. ref tBigInt pNextTemp = ref temp2;
  588. // initialize the result by looking up a 32-bit power of 10 corresponding to the first 3 bits
  589. uint smallExponent = exponent & 0x7;
  590. if (smallExponent != 0)
  591. {
  592. BigInt_Multiply(out pCurTemp, input, g_PowerOf10_U32[smallExponent]);
  593. }
  594. else
  595. {
  596. pCurTemp = input;
  597. }
  598. // remove the low bits that we used for the 32-bit lookup table
  599. exponent >>= 3;
  600. int tableIdx = 0;
  601. // while there are remaining bits in the exponent to be processed
  602. while (exponent != 0)
  603. {
  604. // if the current bit is set, multiply it with the corresponding power of 10
  605. if((exponent & 1) != 0)
  606. {
  607. // multiply into the next temporary
  608. BigInt_Multiply( out pNextTemp, pCurTemp, g_PowerOf10_Big(tableIdx) );
  609. // swap to the next temporary
  610. ref tBigInt pSwap = ref pCurTemp;
  611. pCurTemp = pNextTemp;
  612. pNextTemp = pSwap;
  613. }
  614. // advance to the next bit
  615. ++tableIdx;
  616. exponent >>= 1;
  617. }
  618. // output the result
  619. pResult = pCurTemp;
  620. }
  621. //******************************************************************************
  622. // result = 2^exponent
  623. //******************************************************************************
  624. private static unsafe void BigInt_Pow2(out tBigInt pResult, uint exponent)
  625. {
  626. int blockIdx = (int)exponent / 32;
  627. //RJ_ASSERT(blockIdx < c_BigInt_MaxBlocks);
  628. for (uint i = 0; i <= blockIdx; ++i)
  629. pResult.m_blocks[i] = 0;
  630. pResult.m_length = blockIdx + 1;
  631. int bitIdx = ((int)exponent % 32);
  632. pResult.m_blocks[blockIdx] |= (uint)(1 << bitIdx);
  633. }
  634. //******************************************************************************
  635. // This function will divide two large numbers under the assumption that the
  636. // result is within the range [0,10) and the input numbers have been shifted
  637. // to satisfy:
  638. // - The highest block of the divisor is greater than or equal to 8 such that
  639. // there is enough precision to make an accurate first guess at the quotient.
  640. // - The highest block of the divisor is less than the maximum value on an
  641. // unsigned 32-bit integer such that we can safely increment without overflow.
  642. // - The dividend does not contain more blocks than the divisor such that we
  643. // can estimate the quotient by dividing the equivalently placed high blocks.
  644. //
  645. // quotient = floor(dividend / divisor)
  646. // remainder = dividend - quotient*divisor
  647. //
  648. // pDividend is updated to be the remainder and the quotient is returned.
  649. //******************************************************************************
  650. private static unsafe uint BigInt_DivideWithRemainder_MaxQuotient9(ref tBigInt pDividend, in tBigInt divisor)
  651. {
  652. // Check that the divisor has been correctly shifted into range and that it is not
  653. // smaller than the dividend in length.
  654. //RJ_ASSERT( !divisor.IsZero() &&
  655. // divisor.m_blocks[divisor.m_length-1] >= 8 &&
  656. // divisor.m_blocks[divisor.m_length-1] < 0xFFFFFFFF &&
  657. // pDividend->m_length <= divisor.m_length );
  658. // If the dividend is smaller than the divisor, the quotient is zero and the divisor is already
  659. // the remainder.
  660. int length = divisor.m_length;
  661. if (pDividend.m_length < divisor.m_length)
  662. return 0;
  663. fixed (uint* pDivisorCur1 = divisor.m_blocks)
  664. fixed (uint* pDividendCur1 = pDividend.m_blocks)
  665. {
  666. uint* pDivisorCur = pDivisorCur1;
  667. uint* pDividendCur = pDividendCur1;
  668. uint* pFinalDivisorBlock = pDivisorCur + length - 1;
  669. uint* pFinalDividendBlock = pDividendCur + length - 1;
  670. // Compute an estimated quotient based on the high block value. This will either match the actual quotient or
  671. // undershoot by one.
  672. uint quotient = *pFinalDividendBlock / (*pFinalDivisorBlock + 1);
  673. //RJ_ASSERT(quotient <= 9);
  674. // Divide out the estimated quotient
  675. if (quotient != 0)
  676. {
  677. // dividend = dividend - divisor*quotient
  678. ulong borrow = 0;
  679. ulong carry = 0;
  680. do
  681. {
  682. ulong product = (ulong) *pDivisorCur * (ulong) quotient + carry;
  683. carry = product >> 32;
  684. ulong difference = (ulong) *pDividendCur - (product & 0xFFFFFFFF) - borrow;
  685. borrow = (difference >> 32) & 1;
  686. *pDividendCur = (uint) (difference & 0xFFFFFFFF);
  687. ++pDivisorCur;
  688. ++pDividendCur;
  689. } while (pDivisorCur <= pFinalDivisorBlock);
  690. // remove all leading zero blocks from dividend
  691. while (length > 0 && pDividend.m_blocks[length - 1] == 0)
  692. --length;
  693. pDividend.m_length = length;
  694. }
  695. // If the dividend is still larger than the divisor, we overshot our estimate quotient. To correct,
  696. // we increment the quotient and subtract one more divisor from the dividend.
  697. if (BigInt_Compare(pDividend, divisor) >= 0)
  698. {
  699. ++quotient;
  700. // dividend = dividend - divisor
  701. pDivisorCur = pDivisorCur1;
  702. pDividendCur = pDividendCur1;
  703. ulong borrow = 0;
  704. do
  705. {
  706. ulong difference = (ulong) *pDividendCur - (ulong) *pDivisorCur - borrow;
  707. borrow = (difference >> 32) & 1;
  708. *pDividendCur = (uint)(difference & 0xFFFFFFFF);
  709. ++pDivisorCur;
  710. ++pDividendCur;
  711. } while (pDivisorCur <= pFinalDivisorBlock);
  712. // remove all leading zero blocks from dividend
  713. while (length > 0 && pDividend.m_blocks[length - 1] == 0)
  714. --length;
  715. pDividend.m_length = length;
  716. }
  717. return quotient;
  718. }
  719. }
  720. //******************************************************************************
  721. // result = result << shift
  722. //******************************************************************************
  723. private static unsafe void BigInt_ShiftLeft(ref tBigInt pResult, uint shift)
  724. {
  725. // RJ_ASSERT( shift != 0 );
  726. int shiftBlocks = (int)shift / 32;
  727. int shiftBits = (int)shift % 32;
  728. int inLength = pResult.m_length;
  729. // RJ_ASSERT( inLength + shiftBlocks <= c_BigInt_MaxBlocks );
  730. // check if the shift is block aligned
  731. if (shiftBits == 0)
  732. {
  733. // process blocks high to low so that we can safely process in place
  734. fixed (uint* pInBlocks1 = pResult.m_blocks)
  735. {
  736. uint* pInBlocks = pInBlocks1;
  737. uint* pInCur = pInBlocks + inLength - 1;
  738. uint* pOutCur = pInCur + shiftBlocks;
  739. // copy blocks from high to low
  740. for (; pInCur >= pInBlocks; --pInCur, --pOutCur)
  741. {
  742. *pOutCur = *pInCur;
  743. }
  744. }
  745. // zero the remaining low blocks
  746. for ( uint i = 0; i < shiftBlocks; ++i)
  747. pResult.m_blocks[i] = 0;
  748. pResult.m_length += shiftBlocks;
  749. }
  750. // else we need to shift partial blocks
  751. else
  752. {
  753. int inBlockIdx = inLength - 1;
  754. int outBlockIdx = inLength + shiftBlocks;
  755. // set the length to hold the shifted blocks
  756. //RJ_ASSERT( outBlockIdx < c_BigInt_MaxBlocks );
  757. pResult.m_length = outBlockIdx + 1;
  758. // output the initial blocks
  759. int lowBitsShift = (32 - shiftBits);
  760. uint highBits = 0;
  761. uint block = pResult.m_blocks[inBlockIdx];
  762. uint lowBits = block >> lowBitsShift;
  763. while ( inBlockIdx > 0 )
  764. {
  765. pResult.m_blocks[outBlockIdx] = highBits | lowBits;
  766. highBits = block << shiftBits;
  767. --inBlockIdx;
  768. --outBlockIdx;
  769. block = pResult.m_blocks[inBlockIdx];
  770. lowBits = block >> lowBitsShift;
  771. }
  772. // output the final blocks
  773. // RJ_ASSERT( outBlockIdx == shiftBlocks + 1 );
  774. pResult.m_blocks[outBlockIdx] = highBits | lowBits;
  775. pResult.m_blocks[outBlockIdx-1] = block << shiftBits;
  776. // zero the remaining low blocks
  777. for ( uint i = 0; i < shiftBlocks; ++i)
  778. pResult.m_blocks[i] = 0;
  779. // check if the terminating block has no set bits
  780. if (pResult.m_blocks[pResult.m_length - 1] == 0)
  781. --pResult.m_length;
  782. }
  783. }
  784. //******************************************************************************
  785. // Different modes for terminating digit output
  786. //******************************************************************************
  787. public enum CutoffMode
  788. {
  789. Unique, // as many digits as necessary to print a uniquely identifiable number
  790. TotalLength, // up to cutoffNumber significant digits
  791. FractionLength, // up to cutoffNumber significant digits past the decimal point
  792. };
  793. //******************************************************************************
  794. // This is an implementation the Dragon4 algorithm to convert a binary number
  795. // in floating point format to a decimal number in string format. The function
  796. // returns the number of digits written to the output buffer and the output is
  797. // not NUL terminated.
  798. //
  799. // The floating point input value is (mantissa * 2^exponent).
  800. //
  801. // See the following papers for more information on the algorithm:
  802. // "How to Print Floating-Point Numbers Accurately"
  803. // Steele and White
  804. // http://kurtstephens.com/files/p372-steele.pdf
  805. // "Printing Floating-Point Numbers Quickly and Accurately"
  806. // Burger and Dybvig
  807. // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.4656&rep=rep1&type=pdf
  808. //******************************************************************************
  809. private static unsafe uint Dragon4
  810. (
  811. ulong mantissa, // value significand
  812. int exponent, // value exponent in base 2
  813. uint mantissaHighBitIdx, // index of the highest set mantissa bit
  814. bool hasUnequalMargins, // is the high margin twice as large as the low margin
  815. CutoffMode cutoffMode, // how to determine output length
  816. uint cutoffNumber, // parameter to the selected cutoffMode
  817. byte* pOutBuffer, // buffer to output into
  818. uint bufferSize, // maximum characters that can be printed to pOutBuffer
  819. out int pOutExponent // the base 10 exponent of the first digit
  820. )
  821. {
  822. byte* pCurDigit = pOutBuffer;
  823. // RJ_ASSERT( bufferSize > 0 );
  824. // if the mantissa is zero, the value is zero regardless of the exponent
  825. if (mantissa == 0)
  826. {
  827. *pCurDigit = (byte)'0';
  828. pOutExponent = 0;
  829. return 1;
  830. }
  831. // compute the initial state in integral form such that
  832. // value = scaledValue / scale
  833. // marginLow = scaledMarginLow / scale
  834. tBigInt scale = default; // positive scale applied to value and margin such that they can be
  835. // represented as whole numbers
  836. tBigInt scaledValue = default; // scale * mantissa
  837. tBigInt scaledMarginLow = default; // scale * 0.5 * (distance between this floating-point number and its
  838. // immediate lower value)
  839. // For normalized IEEE floating point values, each time the exponent is incremented the margin also
  840. // doubles. That creates a subset of transition numbers where the high margin is twice the size of
  841. // the low margin.
  842. tBigInt * pScaledMarginHigh;
  843. tBigInt optionalMarginHigh = default;
  844. if ( hasUnequalMargins )
  845. {
  846. // if we have no fractional component
  847. if (exponent > 0)
  848. {
  849. // 1) Expand the input value by multiplying out the mantissa and exponent. This represents
  850. // the input value in its whole number representation.
  851. // 2) Apply an additional scale of 2 such that later comparisons against the margin values
  852. // are simplified.
  853. // 3) Set the margin value to the lowest mantissa bit's scale.
  854. // scaledValue = 2 * 2 * mantissa*2^exponent
  855. scaledValue.SetU64( 4 * mantissa );
  856. BigInt_ShiftLeft(ref scaledValue, (uint)exponent);
  857. // scale = 2 * 2 * 1
  858. scale.SetU32( 4 );
  859. // scaledMarginLow = 2 * 2^(exponent-1)
  860. BigInt_Pow2( out scaledMarginLow, (uint)exponent );
  861. // scaledMarginHigh = 2 * 2 * 2^(exponent-1)
  862. BigInt_Pow2( out optionalMarginHigh, (uint)(exponent + 1));
  863. }
  864. // else we have a fractional exponent
  865. else
  866. {
  867. // In order to track the mantissa data as an integer, we store it as is with a large scale
  868. // scaledValue = 2 * 2 * mantissa
  869. scaledValue.SetU64( 4 * mantissa );
  870. // scale = 2 * 2 * 2^(-exponent)
  871. BigInt_Pow2(out scale, (uint)(-exponent + 2));
  872. // scaledMarginLow = 2 * 2^(-1)
  873. scaledMarginLow.SetU32( 1 );
  874. // scaledMarginHigh = 2 * 2 * 2^(-1)
  875. optionalMarginHigh.SetU32( 2 );
  876. }
  877. // the high and low margins are different
  878. pScaledMarginHigh = &optionalMarginHigh;
  879. }
  880. else
  881. {
  882. // if we have no fractional component
  883. if (exponent > 0)
  884. {
  885. // 1) Expand the input value by multiplying out the mantissa and exponent. This represents
  886. // the input value in its whole number representation.
  887. // 2) Apply an additional scale of 2 such that later comparisons against the margin values
  888. // are simplified.
  889. // 3) Set the margin value to the lowest mantissa bit's scale.
  890. // scaledValue = 2 * mantissa*2^exponent
  891. scaledValue.SetU64( 2 * mantissa );
  892. BigInt_ShiftLeft(ref scaledValue, (uint)exponent);
  893. // scale = 2 * 1
  894. scale.SetU32( 2 );
  895. // scaledMarginLow = 2 * 2^(exponent-1)
  896. BigInt_Pow2(out scaledMarginLow, (uint)exponent );
  897. }
  898. // else we have a fractional exponent
  899. else
  900. {
  901. // In order to track the mantissa data as an integer, we store it as is with a large scale
  902. // scaledValue = 2 * mantissa
  903. scaledValue.SetU64( 2 * mantissa );
  904. // scale = 2 * 2^(-exponent)
  905. BigInt_Pow2(out scale, (uint)(-exponent + 1));
  906. // scaledMarginLow = 2 * 2^(-1)
  907. scaledMarginLow.SetU32( 1 );
  908. }
  909. // the high and low margins are equal
  910. pScaledMarginHigh = &scaledMarginLow;
  911. }
  912. // Compute an estimate for digitExponent that will be correct or undershoot by one.
  913. // This optimization is based on the paper "Printing Floating-Point Numbers Quickly and Accurately"
  914. // by Burger and Dybvig http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.4656&rep=rep1&type=pdf
  915. // We perform an additional subtraction of 0.69 to increase the frequency of a failed estimate
  916. // because that lets us take a faster branch in the code. 0.69 is chosen because 0.69 + log10(2) is
  917. // less than one by a reasonable epsilon that will account for any floating point error.
  918. //
  919. // We want to set digitExponent to floor(log10(v)) + 1
  920. // v = mantissa*2^exponent
  921. // log2(v) = log2(mantissa) + exponent;
  922. // log10(v) = log2(v) * log10(2)
  923. // floor(log2(v)) = mantissaHighBitIdx + exponent;
  924. // log10(v) - log10(2) < (mantissaHighBitIdx + exponent) * log10(2) <= log10(v)
  925. // log10(v) < (mantissaHighBitIdx + exponent) * log10(2) + log10(2) <= log10(v) + log10(2)
  926. // floor( log10(v) ) < ceil( (mantissaHighBitIdx + exponent) * log10(2) ) <= floor( log10(v) ) + 1
  927. const double log10_2 = 0.30102999566398119521373889472449;
  928. var digitExponentDoubleValue = (double) ((int) mantissaHighBitIdx + exponent) * log10_2 - 0.69;
  929. digitExponentDoubleValue = Math.Ceiling(digitExponentDoubleValue);
  930. int digitExponent = (int)digitExponentDoubleValue;
  931. // if the digit exponent is smaller than the smallest desired digit for fractional cutoff,
  932. // pull the digit back into legal range at which point we will round to the appropriate value.
  933. // Note that while our value for digitExponent is still an estimate, this is safe because it
  934. // only increases the number. This will either correct digitExponent to an accurate value or it
  935. // will clamp it above the accurate value.
  936. if (cutoffMode == CutoffMode.FractionLength && digitExponent <= -(int)cutoffNumber)
  937. {
  938. digitExponent = -(int)cutoffNumber + 1;
  939. }
  940. // Divide value by 10^digitExponent.
  941. if (digitExponent > 0)
  942. {
  943. // The exponent is positive creating a division so we multiply up the scale.
  944. tBigInt temp;
  945. BigInt_MultiplyPow10( out temp, scale, (uint)digitExponent );
  946. scale = temp;
  947. }
  948. else if (digitExponent < 0)
  949. {
  950. // The exponent is negative creating a multiplication so we multiply up the scaledValue,
  951. // scaledMarginLow and scaledMarginHigh.
  952. tBigInt pow10;
  953. BigInt_Pow10(out pow10, (uint)(-digitExponent));
  954. tBigInt temp;
  955. BigInt_Multiply( out temp, scaledValue, pow10);
  956. scaledValue = temp;
  957. BigInt_Multiply( out temp, scaledMarginLow, pow10);
  958. scaledMarginLow = temp;
  959. if (pScaledMarginHigh != &scaledMarginLow)
  960. BigInt_Multiply2( out *pScaledMarginHigh, scaledMarginLow );
  961. }
  962. // If (value >= 1), our estimate for digitExponent was too low
  963. if( BigInt_Compare(scaledValue,scale) >= 0 )
  964. {
  965. // The exponent estimate was incorrect.
  966. // Increment the exponent and don't perform the premultiply needed
  967. // for the first loop iteration.
  968. digitExponent = digitExponent + 1;
  969. }
  970. else
  971. {
  972. // The exponent estimate was correct.
  973. // Multiply larger by the output base to prepare for the first loop iteration.
  974. BigInt_Multiply10( ref scaledValue );
  975. BigInt_Multiply10( ref scaledMarginLow );
  976. if (pScaledMarginHigh != &scaledMarginLow)
  977. BigInt_Multiply2( out *pScaledMarginHigh, scaledMarginLow );
  978. }
  979. // Compute the cutoff exponent (the exponent of the final digit to print).
  980. // Default to the maximum size of the output buffer.
  981. int cutoffExponent = digitExponent - (int)bufferSize;
  982. switch (cutoffMode)
  983. {
  984. // print digits until we pass the accuracy margin limits or buffer size
  985. case CutoffMode.Unique:
  986. break;
  987. // print cutoffNumber of digits or until we reach the buffer size
  988. case CutoffMode.TotalLength:
  989. {
  990. int desiredCutoffExponent = digitExponent - (int) cutoffNumber;
  991. if (desiredCutoffExponent > cutoffExponent)
  992. cutoffExponent = desiredCutoffExponent;
  993. }
  994. break;
  995. // print cutoffNumber digits past the decimal point or until we reach the buffer size
  996. case CutoffMode.FractionLength:
  997. {
  998. int desiredCutoffExponent = -(int) cutoffNumber;
  999. if (desiredCutoffExponent > cutoffExponent)
  1000. cutoffExponent = desiredCutoffExponent;
  1001. }
  1002. break;
  1003. }
  1004. // Output the exponent of the first digit we will print
  1005. pOutExponent = digitExponent-1;
  1006. // In preparation for calling BigInt_DivideWithRemainder_MaxQuotient9(),
  1007. // we need to scale up our values such that the highest block of the denominator
  1008. // is greater than or equal to 8. We also need to guarantee that the numerator
  1009. // can never have a length greater than the denominator after each loop iteration.
  1010. // This requires the highest block of the denominator to be less than or equal to
  1011. // 429496729 which is the highest number that can be multiplied by 10 without
  1012. // overflowing to a new block.
  1013. // RJ_ASSERT( scale.GetLength() > 0 );
  1014. uint hiBlock = scale.GetBlock( scale.GetLength() - 1 );
  1015. if (hiBlock < 8 || hiBlock > 429496729)
  1016. {
  1017. // Perform a bit shift on all values to get the highest block of the denominator into
  1018. // the range [8,429496729]. We are more likely to make accurate quotient estimations
  1019. // in BigInt_DivideWithRemainder_MaxQuotient9() with higher denominator values so
  1020. // we shift the denominator to place the highest bit at index 27 of the highest block.
  1021. // This is safe because (2^28 - 1) = 268435455 which is less than 429496729. This means
  1022. // that all values with a highest bit at index 27 are within range.
  1023. uint hiBlockLog2 = LogBase2(hiBlock);
  1024. // RJ_ASSERT(hiBlockLog2 < 3 || hiBlockLog2 > 27);
  1025. uint shift = (32 + 27 - hiBlockLog2) % 32;
  1026. BigInt_ShiftLeft( ref scale, shift );
  1027. BigInt_ShiftLeft( ref scaledValue, shift);
  1028. BigInt_ShiftLeft( ref scaledMarginLow, shift);
  1029. if (pScaledMarginHigh != &scaledMarginLow)
  1030. BigInt_Multiply2( out *pScaledMarginHigh, scaledMarginLow );
  1031. }
  1032. // These values are used to inspect why the print loop terminated so we can properly
  1033. // round the final digit.
  1034. bool low; // did the value get within marginLow distance from zero
  1035. bool high; // did the value get within marginHigh distance from one
  1036. uint outputDigit; // current digit being output
  1037. if (cutoffMode == CutoffMode.Unique)
  1038. {
  1039. // For the unique cutoff mode, we will try to print until we have reached a level of
  1040. // precision that uniquely distinguishes this value from its neighbors. If we run
  1041. // out of space in the output buffer, we terminate early.
  1042. for (;;)
  1043. {
  1044. digitExponent = digitExponent-1;
  1045. // divide out the scale to extract the digit
  1046. outputDigit = BigInt_DivideWithRemainder_MaxQuotient9(ref scaledValue, scale);
  1047. //RJ_ASSERT( outputDigit < 10 );
  1048. // update the high end of the value
  1049. tBigInt scaledValueHigh;
  1050. BigInt_Add( out scaledValueHigh, scaledValue, *pScaledMarginHigh );
  1051. // stop looping if we are far enough away from our neighboring values
  1052. // or if we have reached the cutoff digit
  1053. low = BigInt_Compare(scaledValue, scaledMarginLow) < 0;
  1054. high = BigInt_Compare(scaledValueHigh, scale) > 0;
  1055. if (low | high | (digitExponent == cutoffExponent))
  1056. break;
  1057. // store the output digit
  1058. *pCurDigit = (byte)('0' + outputDigit);
  1059. ++pCurDigit;
  1060. // multiply larger by the output base
  1061. BigInt_Multiply10( ref scaledValue );
  1062. BigInt_Multiply10( ref scaledMarginLow );
  1063. if (pScaledMarginHigh != &scaledMarginLow)
  1064. BigInt_Multiply2( out *pScaledMarginHigh, scaledMarginLow );
  1065. }
  1066. }
  1067. else
  1068. {
  1069. // For length based cutoff modes, we will try to print until we
  1070. // have exhausted all precision (i.e. all remaining digits are zeros) or
  1071. // until we reach the desired cutoff digit.
  1072. low = false;
  1073. high = false;
  1074. for (;;)
  1075. {
  1076. digitExponent = digitExponent-1;
  1077. // divide out the scale to extract the digit
  1078. outputDigit = BigInt_DivideWithRemainder_MaxQuotient9(ref scaledValue, scale);
  1079. //RJ_ASSERT( outputDigit < 10 );
  1080. if ( scaledValue.IsZero() | (digitExponent == cutoffExponent) )
  1081. break;
  1082. // store the output digit
  1083. *pCurDigit = (byte)('0' + outputDigit);
  1084. ++pCurDigit;
  1085. // multiply larger by the output base
  1086. BigInt_Multiply10(ref scaledValue);
  1087. }
  1088. }
  1089. // round off the final digit
  1090. // default to rounding down if value got too close to 0
  1091. bool roundDown = low;
  1092. // if it is legal to round up and down
  1093. if (low == high)
  1094. {
  1095. // round to the closest digit by comparing value with 0.5. To do this we need to convert
  1096. // the inequality to large integer values.
  1097. // compare( value, 0.5 )
  1098. // compare( scale * value, scale * 0.5 )
  1099. // compare( 2 * scale * value, scale )
  1100. BigInt_Multiply2(ref scaledValue);
  1101. int compare = BigInt_Compare(scaledValue, scale);
  1102. roundDown = compare < 0;
  1103. // if we are directly in the middle, round towards the even digit (i.e. IEEE rouding rules)
  1104. if (compare == 0)
  1105. roundDown = (outputDigit & 1) == 0;
  1106. }
  1107. // print the rounded digit
  1108. if (roundDown)
  1109. {
  1110. *pCurDigit = (byte)('0' + outputDigit);
  1111. ++pCurDigit;
  1112. }
  1113. else
  1114. {
  1115. // handle rounding up
  1116. if (outputDigit == 9)
  1117. {
  1118. // find the first non-nine prior digit
  1119. for (;;)
  1120. {
  1121. // if we are at the first digit
  1122. if (pCurDigit == pOutBuffer)
  1123. {
  1124. // output 1 at the next highest exponent
  1125. *pCurDigit = (byte)'1';
  1126. ++pCurDigit;
  1127. pOutExponent += 1;
  1128. break;
  1129. }
  1130. --pCurDigit;
  1131. if (*pCurDigit != (byte)'9')
  1132. {
  1133. // increment the digit
  1134. *pCurDigit += 1;
  1135. ++pCurDigit;
  1136. break;
  1137. }
  1138. }
  1139. }
  1140. else
  1141. {
  1142. // values in the range [0,8] can perform a simple round up
  1143. *pCurDigit = (byte)((byte)'0' + outputDigit + 1);
  1144. ++pCurDigit;
  1145. }
  1146. }
  1147. // return the number of digits output
  1148. uint outputLen = (uint)(pCurDigit - pOutBuffer);
  1149. // RJ_ASSERT(outputLen <= bufferSize);
  1150. return outputLen;
  1151. }
  1152. //******************************************************************************
  1153. //******************************************************************************
  1154. public enum PrintFloatFormat
  1155. {
  1156. Positional, // [-]ddddd.dddd
  1157. Scientific, // [-]d.dddde[sign]ddd
  1158. }
  1159. //******************************************************************************\
  1160. // Helper union to decompose a 32-bit IEEE float.
  1161. // sign: 1 bit
  1162. // exponent: 8 bits
  1163. // mantissa: 23 bits
  1164. //******************************************************************************
  1165. [StructLayout(LayoutKind.Explicit)]
  1166. public struct tFloatUnion32
  1167. {
  1168. public bool IsNegative() { return (m_integer >> 31) != 0; }
  1169. public uint GetExponent() { return (m_integer >> 23) & 0xFF; }
  1170. public uint GetMantissa() { return m_integer & 0x7FFFFF; }
  1171. [FieldOffset(0)]
  1172. public float m_floatingPoint;
  1173. [FieldOffset(0)]
  1174. public uint m_integer;
  1175. };
  1176. //******************************************************************************
  1177. // Helper union to decompose a 64-bit IEEE float.
  1178. // sign: 1 bit
  1179. // exponent: 11 bits
  1180. // mantissa: 52 bits
  1181. //******************************************************************************
  1182. [StructLayout(LayoutKind.Explicit)]
  1183. public struct tFloatUnion64
  1184. {
  1185. public bool IsNegative() { return (m_integer >> 63) != 0; }
  1186. public uint GetExponent() { return (uint)((m_integer >> 52) & 0x7FF); }
  1187. public ulong GetMantissa() { return m_integer & 0xFFFFFFFFFFFFFUL; }
  1188. [FieldOffset(0)]
  1189. public double m_floatingPoint;
  1190. [FieldOffset(0)]
  1191. public ulong m_integer;
  1192. };
  1193. //******************************************************************************
  1194. // Outputs the positive number with positional notation: ddddd.dddd
  1195. // The output is always NUL terminated and the output length (not including the
  1196. // NUL) is returned.
  1197. //******************************************************************************
  1198. private static unsafe int FormatPositional
  1199. (
  1200. byte* pOutBuffer, // buffer to output into
  1201. uint bufferSize, // maximum characters that can be printed to pOutBuffer
  1202. ulong mantissa, // value significand
  1203. int exponent, // value exponent in base 2
  1204. uint mantissaHighBitIdx, // index of the highest set mantissa bit
  1205. bool hasUnequalMargins, // is the high margin twice as large as the low margin
  1206. int precision // Negative prints as many digits as are needed for a unique
  1207. // number. Positive specifies the maximum number of
  1208. // significant digits to print past the decimal point.
  1209. )
  1210. {
  1211. //RJ_ASSERT(bufferSize > 0);
  1212. int printExponent;
  1213. uint numPrintDigits;
  1214. uint maxPrintLen = bufferSize - 1;
  1215. if (precision < 0)
  1216. {
  1217. numPrintDigits = Dragon4(mantissa,
  1218. exponent,
  1219. mantissaHighBitIdx,
  1220. hasUnequalMargins,
  1221. CutoffMode.Unique,
  1222. 0,
  1223. pOutBuffer,
  1224. maxPrintLen,
  1225. out printExponent);
  1226. }
  1227. else
  1228. {
  1229. numPrintDigits = Dragon4(mantissa,
  1230. exponent,
  1231. mantissaHighBitIdx,
  1232. hasUnequalMargins,
  1233. CutoffMode.FractionLength,
  1234. (uint)precision,
  1235. pOutBuffer,
  1236. maxPrintLen,
  1237. out printExponent);
  1238. }
  1239. //RJ_ASSERT(numPrintDigits > 0);
  1240. //RJ_ASSERT(numPrintDigits <= bufferSize);
  1241. // track the number of digits past the decimal point that have been printed
  1242. uint numFractionDigits = 0;
  1243. // if output has a whole number
  1244. if (printExponent >= 0)
  1245. {
  1246. // leave the whole number at the start of the buffer
  1247. uint numWholeDigits = (uint)(printExponent + 1);
  1248. if (numPrintDigits < numWholeDigits)
  1249. {
  1250. // don't overflow the buffer
  1251. if (numWholeDigits > maxPrintLen)
  1252. numWholeDigits = maxPrintLen;
  1253. // add trailing zeros up to the decimal point
  1254. for (; numPrintDigits < numWholeDigits; ++numPrintDigits)
  1255. pOutBuffer[numPrintDigits] = (byte)'0';
  1256. }
  1257. // insert the decimal point prior to the fraction
  1258. else if (numPrintDigits > (uint)numWholeDigits)
  1259. {
  1260. numFractionDigits = numPrintDigits - numWholeDigits;
  1261. uint maxFractionDigits = maxPrintLen - numWholeDigits - 1;
  1262. if (numFractionDigits > maxFractionDigits)
  1263. numFractionDigits = maxFractionDigits;
  1264. #if !UNITY_DOTSRUNTIME && !NET_DOTS
  1265. Unsafe.CopyBlock(pOutBuffer + numWholeDigits + 1, pOutBuffer + numWholeDigits, numFractionDigits);
  1266. #else
  1267. UnsafeUtility.MemCpy(pOutBuffer + numWholeDigits + 1, pOutBuffer + numWholeDigits, numFractionDigits);
  1268. #endif
  1269. pOutBuffer[numWholeDigits] = (byte)'.';
  1270. numPrintDigits = numWholeDigits + 1 + numFractionDigits;
  1271. }
  1272. }
  1273. else
  1274. {
  1275. // shift out the fraction to make room for the leading zeros
  1276. if (maxPrintLen > 2)
  1277. {
  1278. uint numFractionZeros = (uint)( - printExponent - 1);
  1279. uint maxFractionZeros = maxPrintLen - 2;
  1280. if (numFractionZeros > maxFractionZeros)
  1281. numFractionZeros = maxFractionZeros;
  1282. uint digitsStartIdx = 2 + numFractionZeros;
  1283. // shift the significant digits right such that there is room for leading zeros
  1284. numFractionDigits = numPrintDigits;
  1285. uint maxFractionDigits = maxPrintLen - digitsStartIdx;
  1286. if (numFractionDigits > maxFractionDigits)
  1287. numFractionDigits = maxFractionDigits;
  1288. #if !UNITY_DOTSRUNTIME && !NET_DOTS
  1289. Unsafe.CopyBlock(pOutBuffer + digitsStartIdx, pOutBuffer, numFractionDigits);
  1290. #else
  1291. UnsafeUtility.MemCpy(pOutBuffer + digitsStartIdx, pOutBuffer, numFractionDigits);
  1292. #endif
  1293. // insert the leading zeros
  1294. for (uint i = 2; i < digitsStartIdx; ++i)
  1295. pOutBuffer[i] = (byte)'0';
  1296. // update the counts
  1297. numFractionDigits += numFractionZeros;
  1298. numPrintDigits = numFractionDigits;
  1299. }
  1300. // add the decimal point
  1301. if (maxPrintLen > 1)
  1302. {
  1303. pOutBuffer[1] = (byte)'.';
  1304. numPrintDigits += 1;
  1305. }
  1306. // add the initial zero
  1307. if (maxPrintLen > 0)
  1308. {
  1309. pOutBuffer[0] = (byte)'0';
  1310. numPrintDigits += 1;
  1311. }
  1312. }
  1313. // add trailing zeros up to precision length
  1314. if (precision > (int)numFractionDigits && numPrintDigits < maxPrintLen)
  1315. {
  1316. // add a decimal point if this is the first fractional digit we are printing
  1317. if (numFractionDigits == 0)
  1318. {
  1319. pOutBuffer[numPrintDigits++] = (byte)'.';
  1320. }
  1321. // compute the number of trailing zeros needed
  1322. uint totalDigits = (uint)(numPrintDigits + (precision - (int)numFractionDigits));
  1323. if (totalDigits > maxPrintLen)
  1324. totalDigits = maxPrintLen;
  1325. for (; numPrintDigits < totalDigits; ++numPrintDigits)
  1326. pOutBuffer[numPrintDigits] = (byte)'0';
  1327. }
  1328. // terminate the buffer
  1329. //RJ_ASSERT(numPrintDigits <= maxPrintLen);
  1330. //pOutBuffer[numPrintDigits] = '\0';
  1331. return (int)numPrintDigits;
  1332. }
  1333. //******************************************************************************
  1334. // Outputs the positive number with scientific notation: d.dddde[sign]ddd
  1335. // The output is always NUL terminated and the output length (not including the
  1336. // NUL) is returned.
  1337. //******************************************************************************
  1338. private static unsafe int FormatScientific
  1339. (
  1340. byte* pOutBuffer, // buffer to output into
  1341. uint bufferSize, // maximum characters that can be printed to pOutBuffer
  1342. ulong mantissa, // value significand
  1343. int exponent, // value exponent in base 2
  1344. uint mantissaHighBitIdx, // index of the highest set mantissa bit
  1345. bool hasUnequalMargins, // is the high margin twice as large as the low margin
  1346. int precision // Negative prints as many digits as are needed for a unique
  1347. // number. Positive specifies the maximum number of
  1348. // significant digits to print past the decimal point.
  1349. )
  1350. {
  1351. //RJ_ASSERT(bufferSize > 0);
  1352. int printExponent;
  1353. uint numPrintDigits;
  1354. if (precision < 0)
  1355. {
  1356. numPrintDigits = Dragon4(mantissa,
  1357. exponent,
  1358. mantissaHighBitIdx,
  1359. hasUnequalMargins,
  1360. CutoffMode.Unique,
  1361. 0,
  1362. pOutBuffer,
  1363. bufferSize,
  1364. out printExponent);
  1365. }
  1366. else
  1367. {
  1368. numPrintDigits = Dragon4(mantissa,
  1369. exponent,
  1370. mantissaHighBitIdx,
  1371. hasUnequalMargins,
  1372. CutoffMode.TotalLength,
  1373. (uint)(precision + 1),
  1374. pOutBuffer,
  1375. bufferSize,
  1376. out printExponent);
  1377. }
  1378. //RJ_ASSERT(numPrintDigits > 0);
  1379. //RJ_ASSERT(numPrintDigits <= bufferSize);
  1380. byte* pCurOut = pOutBuffer;
  1381. // keep the whole number as the first digit
  1382. if (bufferSize > 1)
  1383. {
  1384. pCurOut += 1;
  1385. bufferSize -= 1;
  1386. }
  1387. // insert the decimal point prior to the fractional number
  1388. uint numFractionDigits = numPrintDigits - 1;
  1389. if (numFractionDigits > 0 && bufferSize > 1)
  1390. {
  1391. uint maxFractionDigits = bufferSize - 2;
  1392. if (numFractionDigits > maxFractionDigits)
  1393. numFractionDigits = maxFractionDigits;
  1394. #if !UNITY_DOTSRUNTIME && !NET_DOTS
  1395. Unsafe.CopyBlock(pCurOut + 1, pCurOut, numFractionDigits);
  1396. #else
  1397. UnsafeUtility.MemCpy(pCurOut + 1, pCurOut, numFractionDigits);
  1398. #endif
  1399. pCurOut[0] = (byte)'.';
  1400. pCurOut += (1 + numFractionDigits);
  1401. bufferSize -= (1 + numFractionDigits);
  1402. }
  1403. // add trailing zeros up to precision length
  1404. if (precision > (int)numFractionDigits && bufferSize > 1)
  1405. {
  1406. // add a decimal point if this is the first fractional digit we are printing
  1407. if (numFractionDigits == 0)
  1408. {
  1409. *pCurOut = (byte)'.';
  1410. ++pCurOut;
  1411. --bufferSize;
  1412. }
  1413. // compute the number of trailing zeros needed
  1414. uint numZeros = (uint)(precision - numFractionDigits);
  1415. if (numZeros > bufferSize - 1)
  1416. numZeros = bufferSize - 1;
  1417. for (byte* pEnd = pCurOut + numZeros; pCurOut < pEnd; ++pCurOut)
  1418. *pCurOut = (byte)'0';
  1419. }
  1420. // print the exponent into a local buffer and copy into output buffer
  1421. if (bufferSize > 1)
  1422. {
  1423. var exponentBuffer = stackalloc byte[5];
  1424. exponentBuffer[0] = (byte)'e';
  1425. if (printExponent >= 0)
  1426. {
  1427. exponentBuffer[1] = (byte)'+';
  1428. }
  1429. else
  1430. {
  1431. exponentBuffer[1] = (byte)'-';
  1432. printExponent = -printExponent;
  1433. }
  1434. //RJ_ASSERT(printExponent < 1000);
  1435. uint hundredsPlace = (uint)(printExponent / 100);
  1436. uint tensPlace = (uint)((printExponent - hundredsPlace * 100) / 10);
  1437. uint onesPlace = (uint)((printExponent - hundredsPlace * 100 - tensPlace * 10));
  1438. exponentBuffer[2] = (byte)('0' + hundredsPlace);
  1439. exponentBuffer[3] = (byte)('0' + tensPlace);
  1440. exponentBuffer[4] = (byte)('0' + onesPlace);
  1441. // copy the exponent buffer into the output
  1442. uint maxExponentSize = bufferSize - 1;
  1443. uint exponentSize = (5 < maxExponentSize) ? 5 : maxExponentSize;
  1444. #if !UNITY_DOTSRUNTIME && !NET_DOTS
  1445. Unsafe.CopyBlock(pCurOut, exponentBuffer, exponentSize);
  1446. #else
  1447. UnsafeUtility.MemCpy(pCurOut, exponentBuffer, exponentSize);
  1448. #endif
  1449. pCurOut += exponentSize;
  1450. bufferSize -= exponentSize;
  1451. }
  1452. //RJ_ASSERT(bufferSize > 0);
  1453. //pCurOut[0] = '\0';
  1454. return (int)(pCurOut - pOutBuffer);
  1455. }
  1456. //******************************************************************************
  1457. // Print special case values for infinities and NaNs.
  1458. // The output string is always NUL terminated and the string length (not
  1459. // including the NUL) is returned.
  1460. //******************************************************************************
  1461. private static readonly byte[] InfinityString = new byte[]
  1462. {
  1463. (byte) 'I',
  1464. (byte) 'n',
  1465. (byte) 'f',
  1466. (byte) 'i',
  1467. (byte) 'n',
  1468. (byte) 'i',
  1469. (byte) 't',
  1470. (byte) 'y',
  1471. };
  1472. private static readonly byte[] NanString = new byte[]
  1473. {
  1474. (byte) 'N',
  1475. (byte) 'a',
  1476. (byte) 'N',
  1477. };
  1478. private static unsafe void FormatInfinityNaN(byte* dest, ref int destIndex, int destLength, ulong mantissa, bool isNegative, FormatOptions formatOptions)
  1479. {
  1480. //RJ_ASSERT(bufferSize > 0);
  1481. int length = mantissa == 0 ? 8 + (isNegative ? 1 : 0) : 3;
  1482. int align = formatOptions.AlignAndSize;
  1483. // left align
  1484. if (AlignLeft(dest, ref destIndex, destLength, align, length)) return;
  1485. // Check for infinity
  1486. if (mantissa == 0)
  1487. {
  1488. if (isNegative)
  1489. {
  1490. if (destIndex >= destLength) return;
  1491. dest[destIndex++] = (byte)'-';
  1492. }
  1493. for (int i = 0; i < 8; i++)
  1494. {
  1495. if (destIndex >= destLength) return;
  1496. dest[destIndex++] = InfinityString[i];
  1497. }
  1498. }
  1499. else
  1500. {
  1501. for (int i = 0; i < 3; i++)
  1502. {
  1503. if (destIndex >= destLength) return;
  1504. dest[destIndex++] = NanString[i];
  1505. }
  1506. }
  1507. // right align
  1508. AlignRight(dest, ref destIndex, destLength, align, length);
  1509. }
  1510. // ------------------------------------------------------------------------------
  1511. // Part of the following code is taking some constants and code from
  1512. // https://github.com/dotnet/runtime/blob/75036ffec9473dd1d948c052c041fdedd7784ac9/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs
  1513. // Licensed to the .NET Foundation under one or more agreements.
  1514. // The .NET Foundation licenses this file to you under the MIT license.
  1515. // See the https://github.com/dotnet/runtime/blob/master/LICENSE.TXT file for more information.
  1516. // ------------------------------------------------------------------------------
  1517. // SinglePrecision and DoublePrecision represent the maximum number of digits required
  1518. // to guarantee that any given Single or Double can roundtrip. Some numbers may require
  1519. // less, but none will require more.
  1520. private const int SinglePrecision = 9;
  1521. private const int DoublePrecision = 17;
  1522. internal const int SingleNumberBufferLength = SinglePrecision + 1; // + zero
  1523. internal const int DoubleNumberBufferLength = DoublePrecision + 1; // + zero
  1524. // SinglePrecisionCustomFormat and DoublePrecisionCustomFormat are used to ensure that
  1525. // custom format strings return the same string as in previous releases when the format
  1526. // would return x digits or less (where x is the value of the corresponding constant).
  1527. // In order to support more digits, we would need to update ParseFormatSpecifier to pre-parse
  1528. // the format and determine exactly how many digits are being requested and whether they
  1529. // represent "significant digits" or "digits after the decimal point".
  1530. private const int SinglePrecisionCustomFormat = 7;
  1531. private const int DoublePrecisionCustomFormat = 15;
  1532. /// <summary>
  1533. /// Format a float 32-bit to a general format to the specified destination buffer.
  1534. /// </summary>
  1535. /// <param name="dest">Destination buffer.</param>
  1536. /// <param name="destIndex">Current index in destination buffer.</param>
  1537. /// <param name="destLength">Maximum length of destination buffer.</param>
  1538. /// <param name="value">The float 32 value to format.</param>
  1539. /// <param name="formatOptions">Formatting options.</param>
  1540. [MethodImpl(MethodImplOptions.NoInlining)]
  1541. private static unsafe void ConvertFloatToString(byte* dest, ref int destIndex, int destLength, float value, FormatOptions formatOptions)
  1542. {
  1543. // deconstruct the floating point value
  1544. tFloatUnion32 floatUnion = default;
  1545. floatUnion.m_floatingPoint = value;
  1546. uint floatExponent = floatUnion.GetExponent();
  1547. uint floatMantissa = floatUnion.GetMantissa();
  1548. // if this is a special value
  1549. if (floatExponent == 0xFF)
  1550. {
  1551. FormatInfinityNaN(dest, ref destIndex, destLength, floatMantissa, floatUnion.IsNegative(), formatOptions);
  1552. }
  1553. // else this is a number
  1554. else
  1555. {
  1556. // factor the value into its parts
  1557. uint mantissa;
  1558. int exponent;
  1559. uint mantissaHighBitIdx;
  1560. bool hasUnequalMargins;
  1561. if (floatExponent != 0)
  1562. {
  1563. // normalized
  1564. // The floating point equation is:
  1565. // value = (1 + mantissa/2^23) * 2 ^ (exponent-127)
  1566. // We convert the integer equation by factoring a 2^23 out of the exponent
  1567. // value = (1 + mantissa/2^23) * 2^23 * 2 ^ (exponent-127-23)
  1568. // value = (2^23 + mantissa) * 2 ^ (exponent-127-23)
  1569. // Because of the implied 1 in front of the mantissa we have 24 bits of precision.
  1570. // m = (2^23 + mantissa)
  1571. // e = (exponent-127-23)
  1572. mantissa = (uint)((1UL << 23) | floatMantissa);
  1573. exponent = (int)(floatExponent - 127 - 23);
  1574. mantissaHighBitIdx = 23;
  1575. hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0);
  1576. }
  1577. else
  1578. {
  1579. // denormalized
  1580. // The floating point equation is:
  1581. // value = (mantissa/2^23) * 2 ^ (1-127)
  1582. // We convert the integer equation by factoring a 2^23 out of the exponent
  1583. // value = (mantissa/2^23) * 2^23 * 2 ^ (1-127-23)
  1584. // value = mantissa * 2 ^ (1-127-23)
  1585. // We have up to 23 bits of precision.
  1586. // m = (mantissa)
  1587. // e = (1-127-23)
  1588. mantissa = floatMantissa;
  1589. exponent = 1 - 127 - 23;
  1590. mantissaHighBitIdx = LogBase2(mantissa);
  1591. hasUnequalMargins = false;
  1592. }
  1593. var precision = formatOptions.Specifier == 0 ? -1 : formatOptions.Specifier;
  1594. var bufferSize = Math.Max(SingleNumberBufferLength, precision + 1);
  1595. var pOutBuffer = stackalloc byte[bufferSize];
  1596. if (precision < 0)
  1597. {
  1598. precision = SinglePrecisionCustomFormat;
  1599. }
  1600. int printExponent;
  1601. uint numPrintDigits = Dragon4(mantissa,
  1602. exponent,
  1603. mantissaHighBitIdx,
  1604. hasUnequalMargins,
  1605. CutoffMode.TotalLength,
  1606. (uint)precision,
  1607. pOutBuffer,
  1608. (uint)(bufferSize - 1),
  1609. out printExponent);
  1610. pOutBuffer[numPrintDigits] = 0;
  1611. // Negative 0 are displayed as 0
  1612. bool isNegative = floatUnion.IsNegative();
  1613. if (floatUnion.m_integer == ((uint)1 << 31))
  1614. {
  1615. isNegative = false;
  1616. }
  1617. var number = new NumberBuffer(NumberBufferKind.Float, pOutBuffer, (int)numPrintDigits, printExponent + 1, isNegative);
  1618. FormatNumber(dest, ref destIndex, destLength, ref number, precision, formatOptions);
  1619. }
  1620. }
  1621. /// <summary>
  1622. /// Format a float 64-bit to a general format to the specified destination buffer.
  1623. /// </summary>
  1624. /// <param name="dest">Destination buffer.</param>
  1625. /// <param name="destIndex">Current index in destination buffer.</param>
  1626. /// <param name="destLength">Maximum length of destination buffer.</param>
  1627. /// <param name="value">The float 64 value to format.</param>
  1628. /// <param name="formatOptions">Formatting options.</param>
  1629. [MethodImpl(MethodImplOptions.NoInlining)]
  1630. private static unsafe void ConvertDoubleToString(byte* dest, ref int destIndex, int destLength, double value, FormatOptions formatOptions)
  1631. {
  1632. // deconstruct the floating point value
  1633. tFloatUnion64 floatUnion = default;
  1634. floatUnion.m_floatingPoint = value;
  1635. uint floatExponent = floatUnion.GetExponent();
  1636. ulong floatMantissa = floatUnion.GetMantissa();
  1637. // if this is a special value
  1638. if (floatExponent == 0x7FF)
  1639. {
  1640. FormatInfinityNaN(dest, ref destIndex, destLength, floatMantissa, floatUnion.IsNegative(), formatOptions);
  1641. }
  1642. // else this is a number
  1643. else
  1644. {
  1645. // factor the value into its parts
  1646. ulong mantissa;
  1647. int exponent;
  1648. uint mantissaHighBitIdx;
  1649. bool hasUnequalMargins;
  1650. if (floatExponent != 0)
  1651. {
  1652. // normal
  1653. // The floating point equation is:
  1654. // value = (1 + mantissa/2^52) * 2 ^ (exponent-1023)
  1655. // We convert the integer equation by factoring a 2^52 out of the exponent
  1656. // value = (1 + mantissa/2^52) * 2^52 * 2 ^ (exponent-1023-52)
  1657. // value = (2^52 + mantissa) * 2 ^ (exponent-1023-52)
  1658. // Because of the implied 1 in front of the mantissa we have 53 bits of precision.
  1659. // m = (2^52 + mantissa)
  1660. // e = (exponent-1023+1-53)
  1661. mantissa = (1UL << 52) | floatMantissa;
  1662. exponent = (int)(floatExponent - 1023 - 52);
  1663. mantissaHighBitIdx = 52;
  1664. hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0);
  1665. }
  1666. else
  1667. {
  1668. // subnormal
  1669. // The floating point equation is:
  1670. // value = (mantissa/2^52) * 2 ^ (1-1023)
  1671. // We convert the integer equation by factoring a 2^52 out of the exponent
  1672. // value = (mantissa/2^52) * 2^52 * 2 ^ (1-1023-52)
  1673. // value = mantissa * 2 ^ (1-1023-52)
  1674. // We have up to 52 bits of precision.
  1675. // m = (mantissa)
  1676. // e = (1-1023-52)
  1677. mantissa = floatMantissa;
  1678. exponent = 1 - 1023 - 52;
  1679. mantissaHighBitIdx = LogBase2((uint)mantissa);
  1680. hasUnequalMargins = false;
  1681. }
  1682. var precision = formatOptions.Specifier == 0 ? -1 : formatOptions.Specifier;
  1683. var bufferSize = Math.Max(DoubleNumberBufferLength, precision + 1);
  1684. var pOutBuffer = stackalloc byte[bufferSize];
  1685. if (precision < 0)
  1686. {
  1687. precision = DoublePrecisionCustomFormat;
  1688. }
  1689. int printExponent;
  1690. uint numPrintDigits = Dragon4(mantissa,
  1691. exponent,
  1692. mantissaHighBitIdx,
  1693. hasUnequalMargins,
  1694. CutoffMode.TotalLength,
  1695. (uint)precision,
  1696. pOutBuffer,
  1697. (uint)(bufferSize - 1),
  1698. out printExponent);
  1699. pOutBuffer[numPrintDigits] = 0;
  1700. // Negative 0 are displayed as 0
  1701. bool isNegative = floatUnion.IsNegative();
  1702. if (floatUnion.m_integer == ((ulong)1 << 63))
  1703. {
  1704. isNegative = false;
  1705. }
  1706. var number = new NumberBuffer(NumberBufferKind.Float, pOutBuffer, (int)numPrintDigits, printExponent + 1, isNegative);
  1707. FormatNumber(dest, ref destIndex, destLength, ref number, precision, formatOptions);
  1708. }
  1709. }
  1710. }
  1711. }