flt_core.inc 93 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748
  1. {
  2. Copyright (C) 2013 by Max Nazhalov
  3. This file contains generalized floating point<->ASCII conversion routines.
  4. It is included by the FLT_CONV.INC after setting-up correct conditional
  5. definitions, therefore it sholud not be used directly.
  6. Refer to FLT_CONV.INC for further explanation.
  7. This library is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU Library General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at your
  10. option) any later version with the following modification:
  11. As a special exception, the copyright holders of this library give you
  12. permission to link this library with independent modules to produce an
  13. executable, regardless of the license terms of these independent modules,
  14. and to copy and distribute the resulting executable under terms of your
  15. choice, provided that you also meet, for each linked independent module,
  16. the terms and conditions of the license of that module. An independent
  17. module is a module which is not derived from or based on this library.
  18. If you modify this library, you may extend this exception to your version
  19. of the library, but you are not obligated to do so. If you do not wish to
  20. do so, delete this exception statement from your version.
  21. This program is distributed in the hope that it will be useful,
  22. but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  24. See the GNU Library General Public License for more details.
  25. You should have received a copy of the GNU Library General Public License
  26. along with this library; if not, write to the Free Software Foundation,
  27. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  28. ****************************************************************************
  29. }
  30. type
  31. // "Do-It-Yourself Floating Point" structure
  32. TDIY_FP = record
  33. {$ifdef VALREAL_128}
  34. fh : qword;
  35. {$endif}
  36. {$ifdef VALREAL_32}
  37. f : dword;
  38. {$else}
  39. f : qword;
  40. {$endif}
  41. {$ifdef VALREAL_80}
  42. fh : dword;
  43. {$endif}
  44. e : integer;
  45. end;
  46. TDIY_FP_Power_of_10 = record
  47. c : TDIY_FP;
  48. e10 : integer;
  49. end;
  50. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  51. (****************************************************************************
  52. * diy_util_add
  53. *
  54. * Helper routine: summ of multiword unsigned integers
  55. *
  56. * Used by:
  57. * [80,128] diy_fp_cached_power10
  58. * [80,128] diy_fp_multiply
  59. * [80,128] float<->ASCII
  60. *
  61. ****************************************************************************)
  62. {$ifdef VALREAL_80}
  63. procedure diy_util_add( var xh: dword; var xl: qword; const yh: dword; const yl: qword ); {$ifdef grisu1_inline}inline;{$endif}
  64. {$else VALREAL_128}
  65. procedure diy_util_add( var xh, xl: qword; const yh, yl: qword ); {$ifdef grisu1_inline}inline;{$endif}
  66. {$endif VALREAL_*}
  67. var
  68. temp: qword;
  69. begin
  70. temp := xl + yl;
  71. xh := xh + yh + ord( temp < xl );
  72. xl := temp;
  73. end;
  74. (****************************************************************************
  75. * diy_util_shl
  76. *
  77. * Helper routine: left shift of multiword unsigned integer
  78. *
  79. * Used by:
  80. * [80,128] float<->ASCII
  81. *
  82. ****************************************************************************)
  83. {$ifdef VALREAL_80}
  84. procedure diy_util_shl( var h: dword; var l: qword; const count: integer );
  85. {$else VALREAL_128}
  86. procedure diy_util_shl( var h, l: qword; const count: integer );
  87. {$endif VALREAL_*}
  88. begin
  89. if ( count = 0 ) then
  90. exit;
  91. {$ifdef grisu1_debug}
  92. assert( count > 0 );
  93. {$ifdef VALREAL_80}
  94. assert( count < 96 );
  95. {$else VALREAL_128}
  96. assert( count < 128 );
  97. {$endif VALREAL_*}
  98. {$endif grisu1_debug}
  99. if ( count = 1 ) then
  100. begin
  101. diy_util_add( h, l, h, l );
  102. exit;
  103. end;
  104. if ( count >= 64 ) then
  105. begin
  106. if ( count > 64 ) then
  107. h := ( l shl ( count - 64 ) )
  108. else
  109. h := l;
  110. l := 0;
  111. exit;
  112. end;
  113. {$ifdef VALREAL_80}
  114. if ( count = 32 ) then
  115. h := hi( l )
  116. else
  117. {$endif VALREAL_80}
  118. if ( count < 32 ) then
  119. h := ( h shl count ) + ( hi( l ) shr ( 32 - count ) )
  120. else
  121. {$ifdef VALREAL_80}
  122. h := ( l shr ( 64 - count ) );
  123. {$else VALREAL_128}
  124. h := ( h shl count ) + ( l shr ( 64 - count ) );
  125. {$endif VALREAL_*}
  126. l := ( l shl count );
  127. end;
  128. (****************************************************************************
  129. * diy_util_shr
  130. *
  131. * Helper routine: right shift of multiword unsigned integer
  132. *
  133. * Used by:
  134. * [80,128] float<->ASCII
  135. *
  136. ****************************************************************************)
  137. {$ifdef VALREAL_80}
  138. procedure diy_util_shr( var h: dword; var l: qword; const count: integer );
  139. {$else VALREAL_128}
  140. procedure diy_util_shr( var h, l: qword; const count: integer );
  141. {$endif VALREAL_*}
  142. begin
  143. if ( count = 0 ) then
  144. exit;
  145. {$ifdef grisu1_debug}
  146. assert( count > 0 );
  147. {$endif grisu1_debug}
  148. if ( count = 1 ) then
  149. begin
  150. l := l shr 1;
  151. if ( lo(h) and 1 <> 0 ) then
  152. l := l or qword($8000000000000000);
  153. h := h shr 1;
  154. exit;
  155. end;
  156. if ( count < 64 ) then
  157. begin
  158. l := ( qword( h ) shl ( ( - count ) and 63 ) ) or ( l shr count );
  159. {$ifdef VALREAL_80}
  160. if ( count >= 32 ) then
  161. h := 0
  162. else
  163. {$endif VALREAL_80}
  164. h := h shr count;
  165. exit;
  166. end;
  167. {$ifdef VALREAL_80}
  168. if ( count < 96 ) then
  169. {$else VALREAL_128}
  170. if ( count < 128 ) then
  171. {$endif VALREAL_*}
  172. l := h shr ( count and 63 )
  173. else
  174. l := 0;
  175. h := 0;
  176. end;
  177. {$endif VALREAL_80 | VALREAL_128}
  178. (****************************************************************************
  179. * diy_fp_multiply
  180. *
  181. * "Do-It-Yourself Floating Point" multiplication routine
  182. *
  183. * Simplified implementation:
  184. * > restricted input:
  185. * - both operands should be normalized
  186. * > relaxed output:
  187. * - rounding is simple [half is rounded-up]
  188. * - normalization is optional and performed at the very end if requested
  189. * [at most 1 shift required since both multipliers are normalized]
  190. *
  191. * Used by:
  192. * [all] float<->ASCII
  193. * [>32] diy_fp_cached_power10
  194. *
  195. ****************************************************************************)
  196. function diy_fp_multiply( const x, y: TDIY_FP; normalize: boolean ): TDIY_FP;
  197. const
  198. C_1_SHL_31 = dword($80000000);
  199. {$ifdef VALREAL_32}
  200. //***************** 32-bit *********************
  201. var
  202. a, b, c, d, ac, bc, ad, bd, t1: dword;
  203. begin
  204. a := ( x.f shr 16 );
  205. b := ( x.f and $0000FFFF );
  206. c := ( y.f shr 16 );
  207. d := ( y.f and $0000FFFF );
  208. ac := a * c;
  209. bc := b * c;
  210. ad := a * d;
  211. bd := b * d;
  212. t1 := ( bc and $0000FFFF )
  213. + ( bd shr 16 )
  214. + ( ad and $0000FFFF )
  215. + ( 1 shl 15 ); // round
  216. diy_fp_multiply.f := ac
  217. + ( ad shr 16 )
  218. + ( bc shr 16 )
  219. + ( t1 shr 16 );
  220. diy_fp_multiply.e := x.e + y.e + 32;
  221. if normalize then with diy_fp_multiply do
  222. begin
  223. if ( f and C_1_SHL_31 = 0 ) then
  224. begin
  225. inc( f, f );
  226. dec( e );
  227. end;
  228. {$ifdef grisu1_debug}
  229. assert( f and C_1_SHL_31 <> 0 );
  230. {$endif grisu1_debug}
  231. end;
  232. end;
  233. {$else not VALREAL_32}
  234. (*-------------------------------------------------------
  235. | u32_mul_u32_to_u64 [local]
  236. |
  237. | Local routine of the "diy_fp_multiply"; common to float64..float128:
  238. | uint32 * uint32 -> uint64
  239. |
  240. *-------------------------------------------------------*)
  241. function u32_mul_u32_to_u64( const a, b: dword ): qword; {$ifdef grisu1_inline}inline;{$endif}
  242. begin
  243. // it seems this pattern is very tightly optimized by FPC at least for i386
  244. u32_mul_u32_to_u64 := qword( a ) * b;
  245. end;
  246. {$endif VALREAL_*}
  247. {$ifdef VALREAL_64}
  248. //***************** 64-bit *********************
  249. var
  250. a, b, c, d: dword;
  251. ac, bc, ad, bd, t1: qword;
  252. begin
  253. a := hi( x.f ); b := x.f;
  254. c := hi( y.f ); d := y.f;
  255. ac := u32_mul_u32_to_u64( a, c );
  256. bc := u32_mul_u32_to_u64( b, c );
  257. ad := u32_mul_u32_to_u64( a, d );
  258. bd := u32_mul_u32_to_u64( b, d );
  259. t1 := qword( C_1_SHL_31 ) // round
  260. + hi( bd ) + lo( bc ) + lo( ad );
  261. diy_fp_multiply.f := ac + hi( ad ) + hi( bc ) + hi( t1 );
  262. diy_fp_multiply.e := x.e + y.e + 64;
  263. if normalize then with diy_fp_multiply do
  264. begin
  265. if ( hi( f ) and C_1_SHL_31 = 0 ) then
  266. begin
  267. inc( f, f );
  268. dec( e );
  269. end;
  270. {$ifdef grisu1_debug}
  271. assert( hi( f ) and C_1_SHL_31 <> 0 );
  272. {$endif grisu1_debug}
  273. end;
  274. end;
  275. {$endif VALREAL_64}
  276. {$ifdef VALREAL_80}
  277. //***************** 96-bit *********************
  278. var
  279. a, b, c, u, v, w: dword;
  280. au, av, aw, bu, bv, bw, cu, cv, cw, t1, t2: qword;
  281. begin
  282. a := x.fh; b := hi( x.f ); c := x.f;
  283. u := y.fh; v := hi( y.f ); w := y.f;
  284. au := u32_mul_u32_to_u64( a, u );
  285. bu := u32_mul_u32_to_u64( b, u );
  286. cu := u32_mul_u32_to_u64( c, u );
  287. av := u32_mul_u32_to_u64( a, v );
  288. bv := u32_mul_u32_to_u64( b, v );
  289. cv := u32_mul_u32_to_u64( c, v );
  290. aw := u32_mul_u32_to_u64( a, w );
  291. bw := u32_mul_u32_to_u64( b, w );
  292. cw := u32_mul_u32_to_u64( c, w );
  293. t1 := ( cw shr 32 ) + lo( bw ) + lo( cv );
  294. t1 := qword( C_1_SHL_31 ) // round
  295. + hi( t1 ) + hi( bw ) + hi( cv ) + lo( aw ) + lo( bv ) + lo( cu );
  296. t1 := ( t1 shr 32 ) + hi( aw ) + hi( bv ) + hi( cu ) + lo( av ) + lo( bu );
  297. t2 := au + hi( av ) + hi( bu ) + hi( t1 );
  298. diy_fp_multiply.f := ( t2 shl 32 ) + lo( t1 );
  299. diy_fp_multiply.fh := hi( t2 );
  300. diy_fp_multiply.e := x.e + y.e + 96;
  301. if normalize then with diy_fp_multiply do
  302. begin
  303. if ( fh and C_1_SHL_31 = 0 ) then
  304. begin
  305. diy_util_add( fh, f, fh, f );
  306. dec( e );
  307. end;
  308. {$ifdef grisu1_debug}
  309. assert( fh and C_1_SHL_31 <> 0 );
  310. {$endif grisu1_debug}
  311. end;
  312. end;
  313. {$endif VALREAL_80}
  314. {$ifdef VALREAL_128}
  315. //***************** 128-bit ********************
  316. var
  317. a, b, c, d, u, v, w, z: dword;
  318. au, av, aw, az, bu, bv, bw, bz, cu, cv, cw, cz, du, dv, dw, dz, t1, t2: qword;
  319. begin
  320. a := hi( x.fh ); b := x.fh; c := hi( x.f ); d := x.f;
  321. u := hi( y.fh ); v := y.fh; w := hi( y.f ); z := y.f;
  322. au := u32_mul_u32_to_u64( a, u );
  323. bu := u32_mul_u32_to_u64( b, u );
  324. cu := u32_mul_u32_to_u64( c, u );
  325. du := u32_mul_u32_to_u64( d, u );
  326. av := u32_mul_u32_to_u64( a, v );
  327. bv := u32_mul_u32_to_u64( b, v );
  328. cv := u32_mul_u32_to_u64( c, v );
  329. dv := u32_mul_u32_to_u64( d, v );
  330. aw := u32_mul_u32_to_u64( a, w );
  331. bw := u32_mul_u32_to_u64( b, w );
  332. cw := u32_mul_u32_to_u64( c, w );
  333. dw := u32_mul_u32_to_u64( d, w );
  334. az := u32_mul_u32_to_u64( a, z );
  335. bz := u32_mul_u32_to_u64( b, z );
  336. cz := u32_mul_u32_to_u64( c, z );
  337. dz := u32_mul_u32_to_u64( d, z );
  338. t1 := ( dz shr 32 ) + lo( cz ) + lo( dw );
  339. t1 := ( t1 shr 32 ) + hi( cz ) + hi( dw ) + lo( bz ) + lo( cw ) + lo( dv );
  340. t1 := qword( C_1_SHL_31 ) // round
  341. + hi( t1 ) + hi( bz ) + hi( cw ) + hi( dv ) + lo( az ) + lo( bw ) + lo( cv ) + lo( du );
  342. t2 := ( t1 shr 32 ) + hi( az ) + hi( bw ) + hi( cv ) + hi( du ) + lo( aw ) + lo( bv ) + lo( cu );
  343. t1 := ( t2 shr 32 ) + hi( aw ) + hi( bv ) + hi( cu ) + lo( av ) + lo( bu );
  344. diy_fp_multiply.f := ( t1 shl 32 ) + lo( t2 );
  345. diy_fp_multiply.fh := au + hi( av ) + hi( bu ) + hi( t1 );
  346. diy_fp_multiply.e := x.e + y.e + 128;
  347. if normalize then with diy_fp_multiply do
  348. begin
  349. if ( hi( fh ) and C_1_SHL_31 = 0 ) then
  350. begin
  351. diy_util_add( fh, f, fh, f );
  352. dec( e );
  353. end;
  354. {$ifdef grisu1_debug}
  355. assert( hi( fh ) and C_1_SHL_31 <> 0 );
  356. {$endif grisu1_debug}
  357. end;
  358. end;
  359. {$endif VALREAL_128}
  360. (****************************************************************************
  361. * diy_fp_cached_power10
  362. *
  363. * The main purpose of this routine is to return normalized correctly rounded
  364. * DIY-floating-point approximation of the power of 10, which has to be used
  365. * by the Grisu1 as a scaling factor, intended to shift a binary exponent of
  366. * the original number into selected [ alpha .. gamma ] range.
  367. *
  368. * This routine is also usable as a helper during ASCII -> float conversion,
  369. * so the range of cached powers is slightly extended beyond the requirements
  370. * of the Grisu1.
  371. *
  372. * Used by:
  373. * [all] float<->ASCII
  374. *
  375. ****************************************************************************)
  376. procedure diy_fp_cached_power10( exp10: integer; out factor: TDIY_FP_Power_of_10 );
  377. {$ifdef VALREAL_32}
  378. const
  379. // alpha =-29; gamma = 0; step = 1E+8
  380. cache: array [ 0 .. 13 ] of TDIY_FP_Power_of_10 = (
  381. ( c: ( f: dword($FB158593); e: -218 ); e10: -56 ),
  382. ( c: ( f: dword($BB127C54); e: -191 ); e10: -48 ),
  383. ( c: ( f: dword($8B61313C); e: -164 ); e10: -40 ),
  384. ( c: ( f: dword($CFB11EAD); e: -138 ); e10: -32 ),
  385. ( c: ( f: dword($9ABE14CD); e: -111 ); e10: -24 ),
  386. ( c: ( f: dword($E69594BF); e: -85 ); e10: -16 ),
  387. ( c: ( f: dword($ABCC7712); e: -58 ); e10: -8 ),
  388. ( c: ( f: dword($80000000); e: -31 ); e10: 0 ),
  389. ( c: ( f: dword($BEBC2000); e: -5 ); e10: 8 ),
  390. ( c: ( f: dword($8E1BC9BF); e: 22 ); e10: 16 ),
  391. ( c: ( f: dword($D3C21BCF); e: 48 ); e10: 24 ),
  392. ( c: ( f: dword($9DC5ADA8); e: 75 ); e10: 32 ),
  393. ( c: ( f: dword($EB194F8E); e: 101 ); e10: 40 ),
  394. ( c: ( f: dword($AF298D05); e: 128 ); e10: 48 )
  395. );
  396. var
  397. i, min10: integer;
  398. begin
  399. // find index
  400. min10 := cache[ low( cache ) ].e10;
  401. if ( exp10 <= min10 ) then
  402. i := 0
  403. else
  404. begin
  405. i := ( exp10 - min10 ) div 8;
  406. if ( i >= high(cache) ) then
  407. i := high(cache)
  408. else
  409. if ( cache[ i ].e10 <> exp10 ) then
  410. inc( i ); // round-up
  411. end;
  412. // generate result
  413. factor := cache[ i ];
  414. end;
  415. {$endif VALREAL_32}
  416. //**************************************
  417. {$ifdef VALREAL_64}
  418. const
  419. // alpha =-61; gamma = 0
  420. // full cache: 1E-450 .. 1E+432, step = 1E+18
  421. // sparse = 1/10
  422. C_PWR10_DELTA = 18;
  423. C_PWR10_COUNT = 50;
  424. base: array [ 0 .. 9 ] of TDIY_FP_Power_of_10 = (
  425. ( c: ( f: qword($825ECC24C8737830); e: -362 ); e10: -90 ),
  426. ( c: ( f: qword($E2280B6C20DD5232); e: -303 ); e10: -72 ),
  427. ( c: ( f: qword($C428D05AA4751E4D); e: -243 ); e10: -54 ),
  428. ( c: ( f: qword($AA242499697392D3); e: -183 ); e10: -36 ),
  429. ( c: ( f: qword($9392EE8E921D5D07); e: -123 ); e10: -18 ),
  430. ( c: ( f: qword($8000000000000000); e: -63 ); e10: 0 ),
  431. ( c: ( f: qword($DE0B6B3A76400000); e: -4 ); e10: 18 ),
  432. ( c: ( f: qword($C097CE7BC90715B3); e: 56 ); e10: 36 ),
  433. ( c: ( f: qword($A70C3C40A64E6C52); e: 116 ); e10: 54 ),
  434. ( c: ( f: qword($90E40FBEEA1D3A4B); e: 176 ); e10: 72 )
  435. );
  436. factor_plus: array [ 0 .. 1 ] of TDIY_FP_Power_of_10 = (
  437. ( c: ( f: qword($F6C69A72A3989F5C); e: 534 ); e10: 180 ),
  438. ( c: ( f: qword($EDE24AE798EC8284); e: 1132 ); e10: 360 )
  439. );
  440. factor_minus: array [ 0 .. 1 ] of TDIY_FP_Power_of_10 = (
  441. ( c: ( f: qword($84C8D4DFD2C63F3B); e: -661 ); e10: -180 ),
  442. ( c: ( f: qword($89BF722840327F82); e: -1259 ); e10: -360 )
  443. );
  444. corrector: array [ 0 .. C_PWR10_COUNT - 1 ] of shortint = (
  445. // extra mantissa correction [ulp; signed]
  446. 0, 0, 0, 0, 1, 0, 0, 0, 1, -1,
  447. 0, 1, 1, 1, -1, 0, 0, 1, 0, -1,
  448. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  449. -1, 0, 0, -1, 0, 0, 0, 0, 0, -1,
  450. 0, 0, 0, 0, 1, 0, 0, 0, -1, 0
  451. );
  452. {$endif VALREAL_64}
  453. //**************************************
  454. {$ifdef VALREAL_80}
  455. const
  456. // alpha =-93; gamma =+30
  457. // full cache: 1E-5032 .. 1E+4995, step = 1E+37
  458. // sparse = 1/16
  459. C_PWR10_DELTA = 37;
  460. C_PWR10_COUNT = 272;
  461. base: array [ 0 .. 15 ] of TDIY_FP_Power_of_10 = (
  462. ( c: ( f: qword($07286FAA1AF5AF66); fh: dword($D1476E2C); e: -1079 ); e10: -296 ),
  463. ( c: ( f: qword($99107C22CB550FB4); fh: dword($C4CE17B3); e: -956 ); e10: -259 ),
  464. ( c: ( f: qword($99F6858428E2557B); fh: dword($B9131798); e: -833 ); e10: -222 ),
  465. ( c: ( f: qword($4738705E9624AB51); fh: dword($AE0B158B); e: -710 ); e10: -185 ),
  466. ( c: ( f: qword($0D5FDAF5C13E60D1); fh: dword($A3AB6658); e: -587 ); e10: -148 ),
  467. ( c: ( f: qword($163FA42E504BCED2); fh: dword($99EA0196); e: -464 ); e10: -111 ),
  468. ( c: ( f: qword($483BB9B9B1C6F22B); fh: dword($90BD77F3); e: -341 ); e10: -74 ),
  469. ( c: ( f: qword($545C75757E50D641); fh: dword($881CEA14); e: -218 ); e10: -37 ),
  470. ( c: ( f: qword($0000000000000000); fh: dword($80000000); e: -95 ); e10: 0 ),
  471. ( c: ( f: qword($BB48DB201E86D400); fh: dword($F0BDC21A); e: 27 ); e10: 37 ),
  472. ( c: ( f: qword($4DCDAB14C696963C); fh: dword($E264589A); e: 150 ); e10: 74 ),
  473. ( c: ( f: qword($C1D1EA966C9E18AC); fh: dword($D4E5E2CD); e: 273 ); e10: 111 ),
  474. ( c: ( f: qword($C8965D3D6F928295); fh: dword($C83553C5); e: 396 ); e10: 148 ),
  475. ( c: ( f: qword($96706114873D5D9F); fh: dword($BC4665B5); e: 519 ); e10: 185 ),
  476. ( c: ( f: qword($56105DAD7425A83F); fh: dword($B10D8E14); e: 642 ); e10: 222 ),
  477. ( c: ( f: qword($B84603568A892ABB); fh: dword($A67FF273); e: 765 ); e10: 259 )
  478. );
  479. factor_plus: array [ 0 .. 7 ] of TDIY_FP_Power_of_10 = (
  480. ( c: ( f: qword($3576D3D149738BA0); fh: dword($BF87DECC); e: 1871 ); e10: 592 ),
  481. ( c: ( f: qword($750E83050A40DE03); fh: dword($8F4C0691); e: 3838 ); e10: 1184 ),
  482. ( c: ( f: qword($727E5D9756BC4BF8); fh: dword($D66B8D68); e: 5804 ); e10: 1776 ),
  483. ( c: ( f: qword($CE9DB63FD51AF6A3); fh: dword($A06C0BD4); e: 7771 ); e10: 2368 ),
  484. ( c: ( f: qword($5A7ADBC5B8787D89); fh: dword($F00B82D7); e: 9737 ); e10: 2960 ),
  485. ( c: ( f: qword($22D732D7AE7EDAA7); fh: dword($B397FD9A); e: 11704 ); e10: 3552 ),
  486. ( c: ( f: qword($CCD2839E0367500B); fh: dword($865DB7A9); e: 13671 ); e10: 4144 ),
  487. ( c: ( f: qword($FCBEE713F3BE171A); fh: dword($C90E78C7); e: 15637 ); e10: 4736 )
  488. );
  489. factor_minus: array [ 0 .. 7 ] of TDIY_FP_Power_of_10 = (
  490. ( c: ( f: qword($2F85DC7AE66FEACF); fh: dword($AB15B5D2); e: -2062 ); e10: -592 ),
  491. ( c: ( f: qword($4237088F4C7284FA); fh: dword($E4AC057C); e: -4029 ); e10: -1184 ),
  492. ( c: ( f: qword($D2DCB34CEC42875C); fh: dword($98D24C2F); e: -5995 ); e10: -1776 ),
  493. ( c: ( f: qword($B50918191D8106CD); fh: dword($CC42DD5C); e: -7962 ); e10: -2368 ),
  494. ( c: ( f: qword($10CF24303CA163B8); fh: dword($8881FC6C); e: -9928 ); e10: -2960 ),
  495. ( c: ( f: qword($BF10EA474FE1E9B1); fh: dword($B674CE73); e: -11895 ); e10: -3552 ),
  496. ( c: ( f: qword($478E074A0E85FC7F); fh: dword($F3DEFE25); e: -13862 ); e10: -4144 ),
  497. ( c: ( f: qword($A3BD093CC62364C2); fh: dword($A2FAA242); e: -15828 ); e10: -4736 )
  498. );
  499. corrector: array [ 0 .. C_PWR10_COUNT - 1 ] of shortint = (
  500. // extra mantissa correction [ulp; signed]
  501. 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, -1, 1, 0, 0,
  502. 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
  503. 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 1, 1, 0, 0, -2, 0,
  504. 2, 0, 1, 1, 1, 1, 1, 2, 0, 0, 2, 1, 0, 1, 0, 0,
  505. 0, 0, 1, -1, 0, 0, 1, 1, 0, 0, 1, 0, -1, 0, -1, 0,
  506. 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, -1, 0, -1, 1,
  507. 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0,
  508. -1, 0, 0, -1, 0, -1, 1, 1, 0, -1, 0, 0, -1, -1, -1, 0,
  509. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  510. -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0,
  511. 2, 2, 1, 1, 0, 0, 0, 2, 0, 0, 1, 1, 0, 0, 1, 1,
  512. 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0, -1, 0,
  513. 0, 0, 2, 0, 0, 0, 1, 1, 0, 0, 0, 1, -1, 1, 0, 1,
  514. 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0,
  515. 0, 0, 1, 1, -1, 0, 0, 2, 0, 0, 1, 1, 0, 1, 1, 1,
  516. -1, -1, 1, -2, 0, 0, 0, -1, 1, -1, 1, -1, -1, -1, 0, 0,
  517. 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
  518. );
  519. {$endif VALREAL_80}
  520. //**************************************
  521. {$ifdef VALREAL_128}
  522. const
  523. // alpha =-125; gamma = -2
  524. // full cache: 1E-5032 .. 1E+4995, step = 1E+37
  525. // sparse = 1/16
  526. C_PWR10_DELTA = 37;
  527. C_PWR10_COUNT = 272;
  528. base: array [ 0 .. 15 ] of TDIY_FP_Power_of_10 = (
  529. ( c: ( fh: qword($D1476E2C07286FAA); f: qword($1AF5AF660DB4AEE2); e: -1111 ); e10: -296 ),
  530. ( c: ( fh: qword($C4CE17B399107C22); f: qword($CB550FB4384D21D4); e: -988 ); e10: -259 ),
  531. ( c: ( fh: qword($B913179899F68584); f: qword($28E2557B59846E3F); e: -865 ); e10: -222 ),
  532. ( c: ( fh: qword($AE0B158B4738705E); f: qword($9624AB50B148D446); e: -742 ); e10: -185 ),
  533. ( c: ( fh: qword($A3AB66580D5FDAF5); f: qword($C13E60D0D2E0EBBA); e: -619 ); e10: -148 ),
  534. ( c: ( fh: qword($99EA0196163FA42E); f: qword($504BCED1BF8E4E46); e: -496 ); e10: -111 ),
  535. ( c: ( fh: qword($90BD77F3483BB9B9); f: qword($B1C6F22B5E6F48C3); e: -373 ); e10: -74 ),
  536. ( c: ( fh: qword($881CEA14545C7575); f: qword($7E50D64177DA2E55); e: -250 ); e10: -37 ),
  537. ( c: ( fh: qword($8000000000000000); f: qword($0000000000000000); e: -127 ); e10: 0 ),
  538. ( c: ( fh: qword($F0BDC21ABB48DB20); f: qword($1E86D40000000000); e: -5 ); e10: 37 ),
  539. ( c: ( fh: qword($E264589A4DCDAB14); f: qword($C696963C7EED2DD2); e: 118 ); e10: 74 ),
  540. ( c: ( fh: qword($D4E5E2CDC1D1EA96); f: qword($6C9E18AC7007C91A); e: 241 ); e10: 111 ),
  541. ( c: ( fh: qword($C83553C5C8965D3D); f: qword($6F92829494E5ACC7); e: 364 ); e10: 148 ),
  542. ( c: ( fh: qword($BC4665B596706114); f: qword($873D5D9F0DDE1FEF); e: 487 ); e10: 185 ),
  543. ( c: ( fh: qword($B10D8E1456105DAD); f: qword($7425A83E872C5F47); e: 610 ); e10: 222 ),
  544. ( c: ( fh: qword($A67FF273B8460356); f: qword($8A892ABAF368F137); e: 733 ); e10: 259 )
  545. );
  546. factor_plus: array [ 0 .. 7 ] of TDIY_FP_Power_of_10 = (
  547. ( c: ( fh: qword($BF87DECC3576D3D1); f: qword($49738B9F99B4642D); e: 1839 ); e10: 592 ),
  548. ( c: ( fh: qword($8F4C0691750E8305); f: qword($0A40DE037C9AD730); e: 3806 ); e10: 1184 ),
  549. ( c: ( fh: qword($D66B8D68727E5D97); f: qword($56BC4BF837B34968); e: 5772 ); e10: 1776 ),
  550. ( c: ( fh: qword($A06C0BD4CE9DB63F); f: qword($D51AF6A3244A6983); e: 7739 ); e10: 2368 ),
  551. ( c: ( fh: qword($F00B82D75A7ADBC5); f: qword($B8787D891AB45D5B); e: 9705 ); e10: 2960 ),
  552. ( c: ( fh: qword($B397FD9A22D732D7); f: qword($AE7EDAA76FBBD923); e: 11672 ); e10: 3552 ),
  553. ( c: ( fh: qword($865DB7A9CCD2839E); f: qword($0367500A8E9A1790); e: 13639 ); e10: 4144 ),
  554. ( c: ( fh: qword($C90E78C7FCBEE713); f: qword($F3BE171A27BF81DB); e: 15605 ); e10: 4736 )
  555. );
  556. factor_minus: array [ 0 .. 7 ] of TDIY_FP_Power_of_10 = (
  557. ( c: ( fh: qword($AB15B5D22F85DC7A); f: qword($E66FEACEB7836F69); e: -2094 ); e10: -592 ),
  558. ( c: ( fh: qword($E4AC057C4237088F); f: qword($4C7284F9EDDA793D); e: -4061 ); e10: -1184 ),
  559. ( c: ( fh: qword($98D24C2FD2DCB34C); f: qword($EC42875C0B22B986); e: -6027 ); e10: -1776 ),
  560. ( c: ( fh: qword($CC42DD5CB5091819); f: qword($1D8106CCF8EE85B4); e: -7994 ); e10: -2368 ),
  561. ( c: ( fh: qword($8881FC6C10CF2430); f: qword($3CA163B873AA88A6); e: -9960 ); e10: -2960 ),
  562. ( c: ( fh: qword($B674CE73BF10EA47); f: qword($4FE1E9B0FCDF7B3D); e: -11927 ); e10: -3552 ),
  563. ( c: ( fh: qword($F3DEFE25478E074A); f: qword($0E85FC7F4EDBD3CB); e: -13894 ); e10: -4144 ),
  564. ( c: ( fh: qword($A2FAA242A3BD093C); f: qword($C62364C260A887E2); e: -15860 ); e10: -4736 )
  565. );
  566. corrector: array [ 0 .. C_PWR10_COUNT - 1 ] of shortint = (
  567. // extra mantissa correction [ulp; signed]
  568. 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0,
  569. -1, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0,
  570. 1, 0, 0, 0, 1, -1, 0, -1, -1, 1, 0, 1, 0, 0, 1, 1,
  571. 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0,
  572. 0, -1, 1, 0, 1, 0, 0, -1, 0, 1, 0, 0, 1, 0, 1, 1,
  573. 1, -1, 0, 0, 1, -1, 0, 0, 0, 1, 0, 1, 1, -1, 1, 1,
  574. 0, 0, 1, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 1,
  575. 0, 0, 2, 1, 0, -1, -1, -1, -1, 0, -1, 1, 0, -1, 0, 0,
  576. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  577. 0, 0, 0, -1, 1, -1, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0,
  578. 1, -1, 2, 1, 2, 0, -1, 1, 0, 0, 0, 1, 2, 0, 1, 1,
  579. 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1,
  580. 0, 0, 0, 1, 0, -1, -1, 0, -1, 0, 0, 0, 0, 0, 0, 1,
  581. -1, -1, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 1, 0, 0, 0,
  582. 0, 0, 1, 0, -1, 0, 0, 0, -1, 0, -1, 0, 1, 0, 0, -1,
  583. 0, -1, 1, -1, 1, -1, 0, -1, 0, 1, -1, 0, 1, 1, 1, 1,
  584. 0, -1, 1, -1, 0, -2, 0, -1, -1, 0, -1, 0, 0, -1, 0, 0
  585. );
  586. {$endif VALREAL_128}
  587. //**************************************
  588. {$ifndef VALREAL_32} // common for float64..float128
  589. var
  590. i, xmul, inod, min10: integer;
  591. A: TDIY_FP_Power_of_10;
  592. {$ifdef VALREAL_80}
  593. ch: dword;
  594. {$endif}
  595. {$ifdef VALREAL_128}
  596. ch: qword;
  597. {$endif}
  598. cx: shortint;
  599. begin
  600. // find non-sparse index
  601. min10 := base [ low( base ) ].e10 + factor_minus[ high( factor_minus ) ].e10;
  602. if ( exp10 <= min10 ) then
  603. i := 0
  604. else
  605. begin
  606. i := ( exp10 - min10 ) div C_PWR10_DELTA;
  607. if ( i * C_PWR10_DELTA + min10 <> exp10 ) then
  608. inc( i ); // round-up
  609. if ( i > C_PWR10_COUNT - 1 ) then
  610. i := C_PWR10_COUNT - 1;
  611. end;
  612. // generate result
  613. inod := i mod length( base );
  614. xmul := ( i div length( base ) ) - length( factor_minus );
  615. if ( xmul = 0 ) then
  616. begin
  617. // base
  618. factor := base[ inod ];
  619. exit;
  620. end;
  621. // surrogate
  622. A := base[ inod ];
  623. if ( xmul > 0 ) then
  624. begin
  625. dec( xmul );
  626. factor.e10 := A.e10 + factor_plus[ xmul ].e10;
  627. if ( A.e10 <> 0 ) then
  628. factor.c := diy_fp_multiply( A.c, factor_plus[ xmul ].c, TRUE )
  629. else
  630. begin
  631. // exact
  632. factor.c := factor_plus[ xmul ].c;
  633. exit;
  634. end;
  635. end
  636. else
  637. begin
  638. xmul := - ( xmul + 1 );
  639. factor.e10 := A.e10 + factor_minus[ xmul ].e10;
  640. if ( A.e10 <> 0 ) then
  641. factor.c := diy_fp_multiply( A.c, factor_minus[ xmul ].c, TRUE )
  642. else
  643. begin
  644. // exact
  645. factor.c := factor_minus[ xmul ].c;
  646. exit;
  647. end;
  648. end;
  649. // adjust mantissa
  650. cx := corrector[ i ];
  651. if ( cx <> 0 ) then
  652. {$ifdef VALREAL_64}
  653. inc( factor.c.f, int64( cx ) );
  654. {$else VALREAL_80 | VALREAL_128}
  655. begin
  656. ch := 0;
  657. if ( cx < 0 ) then
  658. dec( ch );
  659. diy_util_add( factor.c.fh, factor.c.f, ch, int64( cx ) );
  660. end;
  661. {$endif VALREAL_*}
  662. //
  663. end;
  664. {$endif VALREAL_64..VALREAL_128}
  665. (*==========================================================================*
  666. * *
  667. * Float -> ASCII *
  668. * *
  669. *==========================================================================*)
  670. procedure str_real( min_width, frac_digits: integer; const v: ValReal; real_type: TReal_Type; out str: shortstring );
  671. {$undef VALREAL_PACK}
  672. {$i flt_pack.inc}
  673. const
  674. {$ifdef VALREAL_32}
  675. C_FRAC2_BITS = 23;
  676. C_EXP2_BIAS = 127;
  677. C_DIY_FP_Q = 32;
  678. C_GRISU_ALPHA =-29;
  679. C_GRISU_GAMMA = 0;
  680. RT_NATIVE = RT_S32REAL;
  681. {$endif VALREAL_32}
  682. {$ifdef VALREAL_64}
  683. C_FRAC2_BITS = 52;
  684. C_EXP2_BIAS = 1023;
  685. C_DIY_FP_Q = 64;
  686. C_GRISU_ALPHA =-61;
  687. C_GRISU_GAMMA = 0;
  688. RT_NATIVE = RT_S64REAL;
  689. {$endif VALREAL_64}
  690. {$ifdef VALREAL_80}
  691. C_FRAC2_BITS = 63;
  692. C_EXP2_BIAS = 16383;
  693. C_DIY_FP_Q = 96;
  694. C_GRISU_ALPHA =-93;
  695. C_GRISU_GAMMA = 30;
  696. RT_NATIVE = RT_S80REAL;
  697. {$endif VALREAL_80}
  698. {$ifdef VALREAL_128}
  699. C_FRAC2_BITS = 112;
  700. C_EXP2_BIAS = 16383;
  701. C_DIY_FP_Q = 128;
  702. C_GRISU_ALPHA =-125;
  703. C_GRISU_GAMMA =-2;
  704. RT_NATIVE = RT_S128REAL;
  705. {$endif VALREAL_128}
  706. (****************************************************************************)
  707. // handy const
  708. C_EXP2_SPECIAL = C_EXP2_BIAS * 2 + 1;
  709. {$ifdef VALREAL_32}
  710. C_MANT2_INTEGER = dword(1) shl C_FRAC2_BITS;
  711. {$endif VALREAL_32}
  712. {$if defined(VALREAL_64) or defined(VALREAL_80)}
  713. C_MANT2_INTEGER = qword(1) shl C_FRAC2_BITS;
  714. {$endif VALREAL_64 | VALREAL_80}
  715. {$ifdef VALREAL_128}
  716. C_MANT2_INTEGER_H = qword(1) shl ( C_FRAC2_BITS - 64 );
  717. {$endif VALREAL_128}
  718. C_MAX_WIDTH = 255; // shortstring
  719. {$ifdef fpc_softfpu_implementation}
  720. C_NO_MIN_WIDTH = -1; // just for convenience
  721. {$else}
  722. C_NO_MIN_WIDTH = -32767; // this value is the one used internally by FPC
  723. {$endif}
  724. type
  725. TAsciiDigits = array [ 0 .. 39 ] of byte;
  726. (*-------------------------------------------------------
  727. | gen_digits_32 [local]
  728. | gen_digits_64 [local] (used only for float64..float128 -> ASCII)
  729. |
  730. | These routines perform conversion of 32-bit/64-bit unsigned integer
  731. | to the sequence of byte-sized decimal digits.
  732. |
  733. *-------------------------------------------------------*)
  734. function gen_digits_32( var buf: TAsciiDigits; pos: integer; x: dword; pad_9zero: boolean = false ): integer;
  735. const
  736. digits: array [ 0 .. 9 ] of dword = (
  737. 0,
  738. 10,
  739. 100,
  740. 1000,
  741. 10000,
  742. 100000,
  743. 1000000,
  744. 10000000,
  745. 100000000,
  746. 1000000000
  747. );
  748. var
  749. n: integer;
  750. m, z: dword;
  751. begin
  752. // Calculate amount of digits
  753. if ( x = 0 ) then
  754. // emit nothing if padding is not required
  755. n := 0
  756. else
  757. begin
  758. n :=( ( BSRdword( x ) + 1 ) * 1233 ) shr 12;
  759. if ( x >= digits[ n ] ) then
  760. inc( n );
  761. end;
  762. if pad_9zero and ( n < 9 ) then
  763. n := 9;
  764. gen_digits_32 := n;
  765. // Emit digits
  766. m := x;
  767. while ( n > 0 ) do
  768. begin
  769. dec( n );
  770. if ( m <> 0 ) then
  771. begin
  772. z := m div 10;
  773. buf[ pos + n ] := m - z * 10;
  774. m := z;
  775. end
  776. else
  777. buf[ pos + n ] := 0;
  778. end;
  779. end;
  780. {$ifndef VALREAL_32}
  781. function gen_digits_64( var buf: TAsciiDigits; pos: integer; const x: qword; pad_19zero: boolean = false ): integer;
  782. var
  783. n_digits: integer;
  784. temp: qword;
  785. splitl, splitm, splith: dword;
  786. begin
  787. // Split X into 3 unsigned 32-bit integers; lower two should be less than 10 digits long
  788. if ( x < 1000000000 ) then
  789. begin
  790. splith := 0;
  791. splitm := 0;
  792. splitl := x;
  793. end
  794. else
  795. begin
  796. temp := x div 1000000000;
  797. splitl := x - temp * 1000000000;
  798. if ( temp < 1000000000 ) then
  799. begin
  800. splith := 0;
  801. splitm := temp;
  802. end
  803. else
  804. begin
  805. splith := temp div 1000000000;
  806. splitm := lo( temp ) - splith * 1000000000;
  807. end;
  808. end;
  809. // Generate digits
  810. n_digits := gen_digits_32( buf, pos, splith, false );
  811. if pad_19zero and ( n_digits = 0 ) then
  812. begin
  813. // at most 18 digits expected from splitm and splitl, so add one more
  814. buf[ pos ] := 0;
  815. n_digits := 1;
  816. end;
  817. inc( n_digits, gen_digits_32( buf, pos + n_digits, splitm, n_digits <> 0 ) );
  818. inc( n_digits, gen_digits_32( buf, pos + n_digits, splitl, n_digits <> 0 ) );
  819. gen_digits_64 := n_digits;
  820. end;
  821. {$endif VALREAL_64..VALREAL_128}
  822. (*-------------------------------------------------------
  823. | round_digits [local]
  824. |
  825. | Performs digit sequence rounding, returns decimal point correction.
  826. |
  827. *-------------------------------------------------------*)
  828. function round_digits( var buf: TAsciiDigits; var n_current: integer; n_max: integer; half_round_to_even: boolean = true ): integer;
  829. var
  830. n: integer;
  831. dig_round, dig_sticky: byte;
  832. {$ifdef GRISU1_F2A_AGRESSIVE_ROUNDUP}
  833. i: integer;
  834. {$endif}
  835. begin
  836. round_digits := 0;
  837. n := n_current;
  838. {$ifdef grisu1_debug}
  839. assert( n_max >= 0 );
  840. assert( n_max < n );
  841. {$endif grisu1_debug}
  842. n_current := n_max;
  843. // Get round digit
  844. dig_round := buf[n_max];
  845. {$ifdef GRISU1_F2A_AGRESSIVE_ROUNDUP}
  846. // Detect if rounding-up the second last digit turns the "dig_round"
  847. // into "5"; also make sure we have at least 1 digit between "dig_round"
  848. // and the second last.
  849. if not half_round_to_even then
  850. if ( dig_round = 4 ) and ( n_max < n - 3 ) then
  851. if ( buf[ n - 2 ] >= 8 ) then // somewhat arbitrary..
  852. begin
  853. // check for only "9" are in between
  854. i := n - 2;
  855. repeat
  856. dec( i );
  857. until ( i = n_max ) or ( buf[i] <> 9 );
  858. if ( i = n_max ) then
  859. // force round-up
  860. dig_round := 9; // any value ">=5"
  861. end;
  862. {$endif}
  863. if ( dig_round < 5 ) then
  864. exit;
  865. // Handle "round half to even" case
  866. if ( dig_round = 5 ) and half_round_to_even and ( ( n_max = 0 ) or ( buf[ n_max - 1 ] and 1 = 0 ) ) then
  867. begin
  868. // even and a half: check if exactly the half
  869. dig_sticky := 0;
  870. while ( n > n_max + 1 ) and ( dig_sticky = 0 ) do
  871. begin
  872. dec( n );
  873. dig_sticky := buf[n];
  874. end;
  875. if ( dig_sticky = 0 ) then
  876. exit; // exactly a half -> no rounding is required
  877. end;
  878. // Round-up
  879. while ( n_max > 0 ) do
  880. begin
  881. dec( n_max );
  882. inc( buf[n_max] );
  883. if ( buf[n_max] < 10 ) then
  884. begin
  885. // no more overflow: stop now
  886. n_current := n_max + 1;
  887. exit;
  888. end;
  889. // continue rounding
  890. end;
  891. // Overflow out of the 1st digit, all n_max digits became 0
  892. buf[0] := 1;
  893. n_current := 1;
  894. round_digits := 1;
  895. end;
  896. (*-------------------------------------------------------
  897. | do_fillchar [local]
  898. |
  899. | Fills string region with certain character.
  900. |
  901. *-------------------------------------------------------*)
  902. {$ifdef cpujvm}
  903. procedure do_fillchar( var str: shortstring; pos, count: integer; c: char );
  904. begin
  905. while count>0 do
  906. begin
  907. str[pos]:=c;
  908. inc(pos);
  909. dec(count);
  910. end;
  911. end;
  912. {$else not cpujvm}
  913. procedure do_fillchar( var str: shortstring; pos, count: integer; c: char ); {$ifdef grisu1_inline}inline;{$endif}
  914. begin
  915. fillchar( str[pos], count, c );
  916. end;
  917. {$endif cpujvm}
  918. (*-------------------------------------------------------
  919. | try_return_fixed [local]
  920. |
  921. | This routine tries to format the number in the fixed-point representation.
  922. | If the resulting string is estimated to be too long to fit into shortstring,
  923. | routine returns FALSE giving the caller a chance to return the exponential
  924. | representation.
  925. | Otherwise, it returns TRUE.
  926. |
  927. | Not implemented [and why to do it at all?]:
  928. | Here also a good place to limit the fixed point formatting by exponent
  929. | range, falling back to exponential notation (just return FALSE).
  930. |
  931. *-------------------------------------------------------*)
  932. function try_return_fixed( out str: shortstring; minus: boolean; const digits: TAsciiDigits; n_digits_have, fixed_dot_pos, min_width, frac_digits: integer ): boolean;
  933. var
  934. rounded: boolean;
  935. temp_round: TAsciiDigits;
  936. i, j, len, cut_digits_at: integer;
  937. n_spaces, n_spaces_max, n_before_dot, n_before_dot_pad0, n_after_dot_pad0, n_after_dot, n_tail_pad0: integer;
  938. begin
  939. try_return_fixed := false;
  940. {$ifdef grisu1_debug}
  941. assert( n_digits_have >= 0 );
  942. assert( min_width <= C_MAX_WIDTH );
  943. assert( frac_digits >= 0 );
  944. assert( frac_digits <= C_MAX_WIDTH - 3 );
  945. {$endif grisu1_debug}
  946. // Round digits if necessary
  947. rounded := false;
  948. cut_digits_at := fixed_dot_pos + frac_digits;
  949. if ( cut_digits_at < 0 ) then
  950. // zero
  951. n_digits_have := 0
  952. else
  953. if ( cut_digits_at < n_digits_have ) then
  954. begin
  955. // round digits
  956. {$ifdef cpujvm}
  957. temp_round := digits;
  958. {$else not cpujvm}
  959. if ( n_digits_have > 0 ) then
  960. move( digits, temp_round, n_digits_have * sizeof( digits[0] ) );
  961. {$endif cpujvm}
  962. inc( fixed_dot_pos, round_digits( temp_round, n_digits_have, cut_digits_at {$ifdef GRISU1_F2A_HALF_ROUNDUP}, false {$endif} ) );
  963. rounded := true;
  964. end;
  965. // Before dot: digits, pad0
  966. if ( fixed_dot_pos <= 0 ) or ( n_digits_have = 0 ) then
  967. begin
  968. n_before_dot := 0;
  969. n_before_dot_pad0 := 1;
  970. end
  971. else
  972. if ( fixed_dot_pos > n_digits_have ) then
  973. begin
  974. n_before_dot := n_digits_have;
  975. n_before_dot_pad0 := fixed_dot_pos - n_digits_have;
  976. end
  977. else
  978. begin
  979. n_before_dot := fixed_dot_pos;
  980. n_before_dot_pad0 := 0;
  981. end;
  982. // After dot: pad0, digits, pad0
  983. if ( fixed_dot_pos < 0 ) then
  984. n_after_dot_pad0 := - fixed_dot_pos
  985. else
  986. n_after_dot_pad0 := 0;
  987. if ( n_after_dot_pad0 > frac_digits ) then
  988. n_after_dot_pad0 := frac_digits;
  989. n_after_dot := n_digits_have - n_before_dot;
  990. n_tail_pad0 := frac_digits - n_after_dot - n_after_dot_pad0;
  991. {$ifdef grisu1_debug}
  992. assert( n_tail_pad0 >= 0 );
  993. {$endif grisu1_debug}
  994. // Estimate string length
  995. len := ord( minus ) + n_before_dot + n_before_dot_pad0;
  996. if ( frac_digits > 0 ) then
  997. inc( len, n_after_dot_pad0 + n_after_dot + n_tail_pad0 + 1 );
  998. n_spaces_max := C_MAX_WIDTH - len;
  999. if ( n_spaces_max < 0 ) then
  1000. exit;
  1001. // Calculate space-padding length
  1002. n_spaces := min_width - len;
  1003. if ( n_spaces > n_spaces_max ) then
  1004. n_spaces := n_spaces_max;
  1005. if ( n_spaces > 0 ) then
  1006. inc( len, n_spaces );
  1007. // Allocate storage
  1008. SetLength( str, len );
  1009. i := 1;
  1010. // Leading spaces
  1011. if ( n_spaces > 0 ) then
  1012. begin
  1013. do_fillchar( str, i, n_spaces, ' ' );
  1014. inc( i, n_spaces );
  1015. end;
  1016. // Sign
  1017. if minus then
  1018. begin
  1019. str[i] := '-';
  1020. inc( i );
  1021. end;
  1022. // Integer significant digits
  1023. j := 0;
  1024. if rounded then
  1025. while ( n_before_dot > 0 ) do
  1026. begin
  1027. str[i] := char( temp_round[j] + ord('0') );
  1028. inc( i );
  1029. inc( j );
  1030. dec( n_before_dot );
  1031. end
  1032. else
  1033. while ( n_before_dot > 0 ) do
  1034. begin
  1035. str[i] := char( digits[j] + ord('0') );
  1036. inc( i );
  1037. inc( j );
  1038. dec( n_before_dot );
  1039. end;
  1040. // Integer 0-padding
  1041. if ( n_before_dot_pad0 > 0 ) then
  1042. begin
  1043. do_fillchar( str, i, n_before_dot_pad0, '0' );
  1044. inc( i, n_before_dot_pad0 );
  1045. end;
  1046. //
  1047. if ( frac_digits <> 0 ) then
  1048. begin
  1049. // Dot
  1050. str[i] := '.';
  1051. inc( i );
  1052. // Pre-fraction 0-padding
  1053. if ( n_after_dot_pad0 > 0 ) then
  1054. begin
  1055. do_fillchar( str, i, n_after_dot_pad0, '0' );
  1056. inc( i, n_after_dot_pad0 );
  1057. end;
  1058. // Fraction significant digits
  1059. if rounded then
  1060. while ( n_after_dot > 0 ) do
  1061. begin
  1062. str[i] := char( temp_round[j] + ord('0') );
  1063. inc( i );
  1064. inc( j );
  1065. dec( n_after_dot );
  1066. end
  1067. else
  1068. while ( n_after_dot > 0 ) do
  1069. begin
  1070. str[i] := char( digits[j] + ord('0') );
  1071. inc( i );
  1072. inc( j );
  1073. dec( n_after_dot );
  1074. end;
  1075. // Tail 0-padding
  1076. if ( n_tail_pad0 > 0 ) then
  1077. begin
  1078. do_fillchar( str, i, n_tail_pad0, '0' );
  1079. {$ifdef grisu1_debug}
  1080. inc( i, n_tail_pad0 );
  1081. {$endif grisu1_debug}
  1082. end;
  1083. end;
  1084. //
  1085. {$ifdef grisu1_debug}
  1086. assert( i = len + 1 );
  1087. {$endif grisu1_debug}
  1088. try_return_fixed := true
  1089. end;
  1090. (*-------------------------------------------------------
  1091. | return_exponential [local]
  1092. |
  1093. | Formats the number in the exponential representation.
  1094. |
  1095. *-------------------------------------------------------*)
  1096. procedure return_exponential( out str: shortstring; minus: boolean; const digits: TAsciiDigits; n_digits_have, n_digits_req, d_exp, n_digits_exp, min_width: integer );
  1097. var
  1098. e_minus: boolean;
  1099. i, j, len, n_exp, n_spaces, n_spaces_max: integer;
  1100. buf_exp: TAsciiDigits;
  1101. begin
  1102. {$ifdef grisu1_debug}
  1103. assert( n_digits_have >= 0 );
  1104. assert( n_digits_have <= n_digits_req );
  1105. assert( min_width <= C_MAX_WIDTH );
  1106. {$endif grisu1_debug}
  1107. // Prepare exponent
  1108. e_minus := ( d_exp < 0 );
  1109. if e_minus then
  1110. d_exp := - d_exp;
  1111. n_exp := gen_digits_32( buf_exp, 0, d_exp, false );
  1112. if ( n_exp <= n_digits_exp ) then
  1113. len := n_digits_exp
  1114. else
  1115. len := n_exp;
  1116. // Estimate string length
  1117. inc( len, 1{sign} + n_digits_req + 1{E} + 1{E-sign} );
  1118. if ( n_digits_req > 1 ) then
  1119. inc( len ); // dot
  1120. // Calculate space-padding length
  1121. n_spaces_max := C_MAX_WIDTH - len;
  1122. n_spaces := min_width - len;
  1123. if ( n_spaces > n_spaces_max ) then
  1124. n_spaces := n_spaces_max;
  1125. if ( n_spaces > 0 ) then
  1126. inc( len, n_spaces );
  1127. // Allocate storage
  1128. SetLength( str, len );
  1129. i := 1;
  1130. // Leading spaces
  1131. if ( n_spaces > 0 ) then
  1132. begin
  1133. do_fillchar( str, i, n_spaces, ' ' );
  1134. inc( i, n_spaces );
  1135. end;
  1136. // Sign
  1137. if minus then
  1138. str[i] := '-'
  1139. else
  1140. str[i] := ' ';
  1141. inc( i );
  1142. // Integer part
  1143. if ( n_digits_have > 0 ) then
  1144. str[i] := char( digits[0] + ord('0') )
  1145. else
  1146. str[i] := '0';
  1147. inc( i );
  1148. // Dot
  1149. if ( n_digits_req > 1 ) then
  1150. begin
  1151. str[i] := '.';
  1152. inc( i );
  1153. end;
  1154. // Fraction significant digits
  1155. j := 1;
  1156. while ( j < n_digits_have ) and ( j < n_digits_req ) do
  1157. begin
  1158. str[i] := char( digits[j] + ord('0') );
  1159. inc( i );
  1160. inc( j );
  1161. end;
  1162. // Fraction 0-padding
  1163. j := n_digits_req - j;
  1164. if ( j > 0 ) then
  1165. begin
  1166. do_fillchar( str, i, j, '0' );
  1167. inc( i, j );
  1168. end;
  1169. // Exponent designator
  1170. str[i] := 'E';
  1171. inc( i );
  1172. // Exponent sign
  1173. if e_minus then
  1174. str[i] := '-'
  1175. else
  1176. str[i] := '+';
  1177. inc( i );
  1178. // Exponent 0-padding
  1179. j := n_digits_exp - n_exp;
  1180. if ( j > 0 ) then
  1181. begin
  1182. do_fillchar( str, i, j, '0' );
  1183. inc( i, j );
  1184. end;
  1185. // Exponent digits
  1186. for j := 0 to n_exp - 1 do
  1187. begin
  1188. str[i] := char( buf_exp[j] + ord('0') );
  1189. inc( i );
  1190. end;
  1191. {$ifdef grisu1_debug}
  1192. assert( i = len + 1 );
  1193. {$endif grisu1_debug}
  1194. end;
  1195. (*-------------------------------------------------------
  1196. | return_special [local]
  1197. |
  1198. | This routine formats one of special results.
  1199. |
  1200. *-------------------------------------------------------*)
  1201. procedure return_special( out str: shortstring; sign: integer; const spec: shortstring; min_width: integer );
  1202. var
  1203. i, slen, len, n_spaces, n_spaces_max: integer;
  1204. begin
  1205. slen := length(spec);
  1206. if ( sign = 0 ) then
  1207. len := slen
  1208. else
  1209. len := slen + 1;
  1210. n_spaces_max := C_MAX_WIDTH - len;
  1211. // Calculate space-padding length
  1212. n_spaces := min_width - len;
  1213. if ( n_spaces > n_spaces_max ) then
  1214. n_spaces := n_spaces_max;
  1215. if ( n_spaces > 0 ) then
  1216. inc( len, n_spaces );
  1217. // Allocate storage
  1218. SetLength( str, len );
  1219. i := 1;
  1220. // Leading spaces
  1221. if ( n_spaces > 0 ) then
  1222. begin
  1223. do_fillchar( str, i, n_spaces, ' ' );
  1224. inc( i, n_spaces );
  1225. end;
  1226. // Sign
  1227. if ( sign <> 0 ) then
  1228. begin
  1229. if ( sign > 0 ) then
  1230. str[i] := '+'
  1231. else
  1232. str[i] := '-';
  1233. inc( i );
  1234. end;
  1235. // Special
  1236. while slen>0 do
  1237. begin
  1238. str[i+slen-1] := spec[slen];
  1239. dec(slen);
  1240. end;
  1241. end;
  1242. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  1243. (*-------------------------------------------------------
  1244. | u128_div_u64_to_u64 [local]
  1245. |
  1246. | Divides unsigned 128-bit integer by unsigned 64-bit integer.
  1247. | Returns 64-bit quotient and reminder.
  1248. |
  1249. | This routine is used here only for splitting specially prepared unsigned
  1250. | 128-bit integer into two 64-bit ones before converting it to ASCII.
  1251. |
  1252. *-------------------------------------------------------*)
  1253. function u128_div_u64_to_u64( const xh, xl: qword; const y: qword; out quotient, reminder: qword ): boolean;
  1254. var
  1255. b, // Number base
  1256. v, // Norm. divisor
  1257. un1, un0, // Norm. dividend LSD's
  1258. vn1, vn0, // Norm. divisor digits
  1259. q1, q0, // Quotient digits
  1260. un64, un21, un10, // Dividend digit pairs
  1261. rhat: qword; // A remainder
  1262. s: integer; // Shift amount for norm
  1263. begin
  1264. // Overflow check
  1265. if ( xh >= y ) then
  1266. begin
  1267. u128_div_u64_to_u64 := false;
  1268. exit;
  1269. end;
  1270. // Count leading zeros
  1271. s := 63 - BSRqword( y ); // 0 <= s <= 63
  1272. // Normalize divisor
  1273. v := y shl s;
  1274. // Break divisor up into two 32-bit digits
  1275. vn1 := hi(v);
  1276. vn0 := lo(v);
  1277. // Shift dividend left
  1278. un64 := xh shl s;
  1279. if ( s > 0 ) then
  1280. un64 := un64 or ( xl shr ( 64 - s ) );
  1281. un10 := xl shl s;
  1282. // Break right half of dividend into two digits
  1283. un1 := hi(un10);
  1284. un0 := lo(un10);
  1285. // Compute the first quotient digit, q1
  1286. q1 := un64 div vn1;
  1287. rhat := un64 - q1 * vn1;
  1288. b := qword(1) shl 32; // Number base
  1289. while ( q1 >= b ) or ( q1 * vn0 > b * rhat + un1 ) do
  1290. begin
  1291. dec( q1 );
  1292. inc( rhat, vn1 );
  1293. if rhat >= b then
  1294. break;
  1295. end;
  1296. // Multiply and subtract
  1297. un21 := un64 * b + un1 - q1 * v;
  1298. // Compute the second quotient digit, q0
  1299. q0 := un21 div vn1;
  1300. rhat := un21 - q0 * vn1;
  1301. while ( q0 >= b ) or ( q0 * vn0 > b * rhat + un0 ) do
  1302. begin
  1303. dec( q0 );
  1304. inc( rhat, vn1 );
  1305. if ( rhat >= b ) then
  1306. break;
  1307. end;
  1308. // Result
  1309. reminder := ( un21 * b + un0 - q0 * v ) shr s;
  1310. quotient := q1 * b + q0;
  1311. u128_div_u64_to_u64 := true;
  1312. end;
  1313. {$endif VALREAL_80 | VALREAL_128}
  1314. (*-------------------------------------------------------
  1315. | count_leading_zero [local]
  1316. |
  1317. | Counts number of 0-bits at most significant bit position.
  1318. |
  1319. *-------------------------------------------------------*)
  1320. {$ifdef VALREAL_32}
  1321. function count_leading_zero( const X: dword ): integer; {$ifdef grisu1_inline}inline;{$endif}
  1322. begin
  1323. count_leading_zero := 31 - BSRdword( X );
  1324. end;
  1325. {$else not VALREAL_32}
  1326. function count_leading_zero( const X: qword ): integer; {$ifdef grisu1_inline}inline;{$endif}
  1327. begin
  1328. count_leading_zero := 63 - BSRqword( X );
  1329. end;
  1330. {$endif VALREAL_*}
  1331. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  1332. (*-------------------------------------------------------
  1333. | make_frac_mask [local]
  1334. |
  1335. | Makes DIY_FP fractional part mask:
  1336. | result := ( 1 shl one.e ) - 1
  1337. |
  1338. *-------------------------------------------------------*)
  1339. {$ifdef VALREAL_80}
  1340. procedure make_frac_mask( out h: dword; out l: qword; one_e: integer ); {$ifdef grisu1_inline}inline;{$endif}
  1341. {$else VALREAL_128}
  1342. procedure make_frac_mask( out h, l: qword; one_e: integer ); {$ifdef grisu1_inline}inline;{$endif}
  1343. {$endif VALREAL_*}
  1344. begin
  1345. {$ifdef grisu1_debug}
  1346. assert( one_e <= 0 );
  1347. assert( one_e > - ( sizeof( l ) + sizeof( h ) ) * 8 );
  1348. {$endif grisu1_debug}
  1349. if ( one_e <= - 64 ) then
  1350. begin
  1351. l := qword( -1 );
  1352. h := ( {$ifdef VALREAL_128} qword {$else} dword {$endif} ( 1 ) shl ( - one_e - 64 ) ) - 1;
  1353. end
  1354. else
  1355. begin
  1356. l := ( qword( 1 ) shl ( - one_e ) ) - 1;
  1357. h := 0;
  1358. end;
  1359. end;
  1360. {$endif VALREAL_80 | VALREAL_128}
  1361. (*-------------------------------------------------------
  1362. | k_comp [local]
  1363. |
  1364. | Calculates the exp10 of a factor required to bring the binary exponent
  1365. | of the original number into selected [ alpha .. gamma ] range:
  1366. | result := ceiling[ ( alpha - e ) * log10(2) ]
  1367. |
  1368. *-------------------------------------------------------*)
  1369. function k_comp( e, alpha{, gamma}: integer ): integer;
  1370. {$ifdef fpc_softfpu_implementation}
  1371. ///////////////
  1372. //
  1373. // Assuming no HardFloat available.
  1374. // Note: using softfpu here significantly slows down overall
  1375. // conversion performance, so we use integers.
  1376. //
  1377. const
  1378. D_LOG10_2: TDIY_FP = // log10(2) = 0.301029995663981195213738894724493027
  1379. {$ifdef VALREAL_32}
  1380. ( f: dword($9A209A85); e: -33 );
  1381. {$endif}
  1382. {$ifdef VALREAL_64}
  1383. ( f: qword($9A209A84FBCFF799); e: -65 );
  1384. {$endif}
  1385. {$ifdef VALREAL_80}
  1386. ( f: qword($FBCFF7988F8959AC); fh: dword($9A209A84); e: -97 );
  1387. {$endif}
  1388. {$ifdef VALREAL_128}
  1389. ( fh: qword($9A209A84FBCFF798); f: qword($8F8959AC0B7C9178); e: -129 );
  1390. {$endif}
  1391. var
  1392. x, n: integer;
  1393. y, z: TDIY_FP;
  1394. {$ifdef VALREAL_32}
  1395. mask_one: dword;
  1396. {$else not VALREAL_32}
  1397. mask_one: qword;
  1398. {$endif}
  1399. {$ifdef VALREAL_80}
  1400. mask_oneh: dword;
  1401. {$endif}
  1402. {$ifdef VALREAL_128}
  1403. mask_oneh: qword;
  1404. {$endif}
  1405. plus, round_up: boolean;
  1406. begin
  1407. x := alpha - e;
  1408. if ( x = 0 ) then
  1409. begin
  1410. k_comp := 0;
  1411. exit;
  1412. end;
  1413. plus := ( x > 0 );
  1414. if plus then
  1415. y.f := x
  1416. else
  1417. y.f := - x;
  1418. round_up := plus;
  1419. n := C_DIY_FP_Q - 1 - BSRdword( y.f );
  1420. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1421. y.f := y.f shl n;
  1422. {$else VALREAL_80 | VALREAL_128}
  1423. y.fh := 0;
  1424. diy_util_shl( y.fh, y.f, n );
  1425. {$endif VALREAL_*}
  1426. y.e := - n;
  1427. z := diy_fp_multiply( y, D_LOG10_2, false );
  1428. if ( z.e <= - C_DIY_FP_Q ) then
  1429. begin
  1430. round_up := plus and ( 0 <>
  1431. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1432. z.f
  1433. {$else VALREAL_80 | VALREAL_128}
  1434. z.f or z.fh
  1435. {$endif}
  1436. );
  1437. n := 0;
  1438. end
  1439. else
  1440. begin
  1441. if plus then
  1442. begin
  1443. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1444. mask_one := ( {$ifdef VALREAL_64} qword {$else} dword {$endif} ( 1 ) shl ( - z.e ) ) - 1;
  1445. round_up := ( z.f and mask_one <> 0 );
  1446. {$else VALREAL_80 | VALREAL_128}
  1447. make_frac_mask( mask_oneh, mask_one, z.e );
  1448. round_up := ( z.f and mask_one <> 0 ) or ( z.fh and mask_oneh <> 0 );
  1449. {$endif VALREAL_*}
  1450. end;
  1451. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1452. n := z.f shr ( - z.e );
  1453. {$else VALREAL_80 | VALREAL_128}
  1454. diy_util_shr( z.fh, z.f, - z.e );
  1455. n := z.f;
  1456. {$endif VALREAL_*}
  1457. end;
  1458. if not plus then
  1459. n := - n;
  1460. if round_up then
  1461. k_comp := n + 1
  1462. else
  1463. k_comp := n;
  1464. end;
  1465. {$else not fpc_softfpu_implementation}
  1466. ///////////////
  1467. //
  1468. // HardFloat implementation
  1469. //
  1470. {$if defined(SUPPORT_SINGLE) and defined(VALREAL_32)}
  1471. // If available, use single math for VALREAL_32
  1472. var
  1473. dexp: single;
  1474. const
  1475. D_LOG10_2: single =
  1476. {$elseif defined(SUPPORT_DOUBLE) and not defined(VALREAL_32)}
  1477. // If available, use double math for all types >VALREAL_32
  1478. var
  1479. dexp: double;
  1480. const
  1481. D_LOG10_2: double =
  1482. {$else}
  1483. // Use native math
  1484. var
  1485. dexp: ValReal;
  1486. const
  1487. D_LOG10_2: ValReal =
  1488. {$endif}
  1489. 0.301029995663981195213738894724493027; // log10(2)
  1490. var
  1491. x, n: integer;
  1492. begin
  1493. x := alpha - e;
  1494. dexp := x * D_LOG10_2;
  1495. // ceil( dexp )
  1496. n := trunc( dexp );
  1497. if ( x > 0 ) then
  1498. if ( dexp <> n ) then
  1499. inc( n ); // round-up
  1500. k_comp := n;
  1501. end;
  1502. {$endif fpc_softfpu_implementation}
  1503. (****************************************************************************)
  1504. var
  1505. w, D: TDIY_FP;
  1506. c_mk: TDIY_FP_Power_of_10;
  1507. n, mk, dot_pos, n_digits_exp, n_digits_need, n_digits_have: integer;
  1508. n_digits_req, n_digits_sci: integer;
  1509. minus: boolean;
  1510. {$ifndef VALREAL_32}
  1511. fl, one_maskl: qword;
  1512. {$endif not VALREAL_32}
  1513. {$ifdef VALREAL_80}
  1514. templ: qword;
  1515. fh, one_maskh, temph: dword;
  1516. {$endif VALREAL_80}
  1517. {$ifdef VALREAL_128}
  1518. templ: qword;
  1519. fh, one_maskh, temph: qword;
  1520. {$endif VALREAL_128}
  1521. one_e: integer;
  1522. one_mask, f: dword;
  1523. buf: TAsciiDigits;
  1524. begin
  1525. // Limit parameters
  1526. if ( frac_digits > 216 ) then
  1527. frac_digits := 216; // Delphi compatible
  1528. if ( min_width <= C_NO_MIN_WIDTH ) then
  1529. min_width := -1 // no minimal width
  1530. else
  1531. if ( min_width < 0 ) then
  1532. min_width := 0 // minimal width is as short as possible
  1533. else
  1534. if ( min_width > C_MAX_WIDTH ) then
  1535. min_width := C_MAX_WIDTH;
  1536. // Format profile: select "n_digits_need" and "n_digits_exp"
  1537. n_digits_req := float_format[real_type].nDig_mantissa;
  1538. n_digits_exp := float_format[real_type].nDig_exp10;
  1539. // number of digits to be calculated by Grisu
  1540. n_digits_need := float_format[RT_NATIVE].nDig_mantissa;
  1541. if ( n_digits_req < n_digits_need ) then
  1542. n_digits_need := n_digits_req;
  1543. // number of mantissa digits to be printed in exponential notation
  1544. if ( min_width < 0 ) then
  1545. n_digits_sci := n_digits_req
  1546. else
  1547. begin
  1548. n_digits_sci := min_width - 1{sign} - 1{dot} - 1{E} - 1{E-sign} - n_digits_exp;
  1549. if ( n_digits_sci < 2 ) then
  1550. n_digits_sci := 2; // at least 2 digits
  1551. if ( n_digits_sci > n_digits_req ) then
  1552. n_digits_sci := n_digits_req; // at most requested by real_type
  1553. end;
  1554. // Float -> DIY_FP
  1555. w := unpack_float( v, minus );
  1556. // Handle Zero
  1557. if ( w.e = 0 ) and ( w.f {$ifdef VALREAL_128} or w.fh {$endif} = 0 ) then
  1558. begin
  1559. buf[0] := 0; // to avoid "warning: uninitialized"
  1560. if ( frac_digits >= 0 ) then
  1561. if try_return_fixed( str, minus, buf, 0, 1, min_width, frac_digits ) then
  1562. exit
  1563. {$ifdef grisu1_debug}
  1564. else
  1565. assert( FALSE ) // should never fail with these arguments
  1566. {$endif grisu1_debug};
  1567. return_exponential( str, minus, buf, 0, n_digits_sci, 0, n_digits_exp, min_width );
  1568. exit;
  1569. end;
  1570. {$ifdef VALREAL_80}
  1571. // Handle non-normals
  1572. if ( w.e <> 0 ) and ( w.e <> C_EXP2_SPECIAL ) then
  1573. if ( w.f and C_MANT2_INTEGER = 0 ) then
  1574. begin
  1575. // -> QNaN
  1576. w.f := qword(-1);
  1577. w.e := C_EXP2_SPECIAL;
  1578. end;
  1579. {$endif VALREAL_80}
  1580. // Handle specials
  1581. if ( w.e = C_EXP2_SPECIAL ) then
  1582. begin
  1583. if ( min_width < 0 ) then
  1584. // backward compat..
  1585. min_width := float_format[real_type].nDig_mantissa + float_format[real_type].nDig_exp10 + 4;
  1586. n := 1 - ord(minus) * 2; // default special sign [-1|+1]
  1587. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1588. if ( w.f = 0 ) then
  1589. {$endif VALREAL_32 | VALREAL_64}
  1590. {$ifdef VALREAL_80}
  1591. if ( w.f = qword(C_MANT2_INTEGER) ) then
  1592. {$endif VALREAL_80}
  1593. {$ifdef VALREAL_128}
  1594. if ( w.fh or w.f = 0 ) then
  1595. {$endif VALREAL_128}
  1596. begin
  1597. // Inf
  1598. return_special( str, n, C_STR_INF, min_width );
  1599. end
  1600. else
  1601. begin
  1602. // NaN [also pseudo-NaN, pseudo-Inf, non-normal for floatx80]
  1603. {$ifdef GRISU1_F2A_NAN_SIGNLESS}
  1604. n := 0;
  1605. {$endif}
  1606. {$ifndef GRISU1_F2A_NO_SNAN}
  1607. {$ifdef VALREAL_128}
  1608. if ( w.fh and ( C_MANT2_INTEGER_H shr 1 ) = 0 ) then
  1609. {$else}
  1610. if ( w.f and ( C_MANT2_INTEGER shr 1 ) = 0 ) then
  1611. {$endif}
  1612. return_special( str, n, C_STR_SNAN, min_width )
  1613. else
  1614. {$endif GRISU1_F2A_NO_SNAN}
  1615. return_special( str, n, C_STR_QNAN, min_width );
  1616. end;
  1617. exit;
  1618. end;
  1619. // Handle denormals
  1620. if ( w.e <> 0 ) then
  1621. begin
  1622. // normal
  1623. {$ifdef VALREAL_128}
  1624. w.fh := w.fh or C_MANT2_INTEGER_H;
  1625. {$else not VALREAL_128}
  1626. {$ifndef VALREAL_80}
  1627. w.f := w.f or C_MANT2_INTEGER;
  1628. {$endif not VALREAL_80}
  1629. {$endif VALREAL_*}
  1630. n := C_DIY_FP_Q - C_FRAC2_BITS - 1;
  1631. end
  1632. else
  1633. begin
  1634. // denormal
  1635. {$ifdef VALREAL_128}
  1636. if ( w.fh = 0 ) then
  1637. n := count_leading_zero( w.f ) + 64
  1638. else
  1639. n := count_leading_zero( w.fh );
  1640. {$else not VALREAL_128}
  1641. {$ifdef VALREAL_80}
  1642. // also handle pseudo-denormals
  1643. n := count_leading_zero( w.f ) + 32;
  1644. {$else VALREAL_32 | VALREAL_64}
  1645. n := count_leading_zero( w.f );
  1646. {$endif VALREAL_*}
  1647. {$endif VALREAL_*}
  1648. inc( w.e );
  1649. end;
  1650. // Final normalization
  1651. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1652. w.f := w.f shl n;
  1653. {$else VALREAL_80 | VALREAL_128}
  1654. diy_util_shl( w.fh, w.f, n );
  1655. {$endif VALREAL_*}
  1656. dec( w.e, C_EXP2_BIAS + n + C_FRAC2_BITS );
  1657. //
  1658. // 1. Find the normalized "c_mk = f_c * 2^e_c" such that "alpha <= e_c + e_w + q <= gamma"
  1659. // 2. Define "V = D * 10^k": multiply the input number by "c_mk", do not normalize to land into [ alpha .. gamma ]
  1660. // 3. Generate digits ( n_digits_need + "round" )
  1661. //
  1662. if ( C_GRISU_ALPHA <= w.e ) and ( w.e <= C_GRISU_GAMMA ) then
  1663. begin
  1664. // no scaling required
  1665. D := w;
  1666. c_mk.e10 := 0;
  1667. end
  1668. else
  1669. begin
  1670. mk := k_comp( w.e, C_GRISU_ALPHA{, C_GRISU_GAMMA} );
  1671. diy_fp_cached_power10( mk, c_mk );
  1672. // Let "D = f_D * 2^e_D := w (*) c_mk"
  1673. if c_mk.e10 = 0 then
  1674. D := w
  1675. else
  1676. D := diy_fp_multiply( w, c_mk.c, FALSE );
  1677. end;
  1678. {$ifdef grisu1_debug}
  1679. assert( ( C_GRISU_ALPHA <= D.e ) and ( D.e <= C_GRISU_GAMMA ) );
  1680. {$endif grisu1_debug}
  1681. // Generate digits: integer part
  1682. {$ifdef grisu1_debug}
  1683. {$ifdef VALREAL_80}
  1684. assert( D.e <= 32 );
  1685. {$else not VALREAL_80}
  1686. assert( D.e <= 0 );
  1687. {$endif VALREAL_*}
  1688. {$endif grisu1_debug}
  1689. {$ifdef VALREAL_32}
  1690. n_digits_have := gen_digits_32( buf, 0, D.f shr ( - D.e ) );
  1691. {$endif VALREAL_32}
  1692. {$ifdef VALREAL_64}
  1693. n_digits_have := gen_digits_64( buf, 0, D.f shr ( - D.e ) );
  1694. {$endif VALREAL_64}
  1695. {$ifdef VALREAL_80}
  1696. fl := D.f;
  1697. fh := D.fh;
  1698. if ( D.e > 0 ) then
  1699. begin
  1700. templ := ( qword(fh) shl D.e ) and qword($FFFFFFFF00000000);
  1701. diy_util_shl( fh, fl, D.e );
  1702. inc( templ, fh );
  1703. end
  1704. else
  1705. begin
  1706. diy_util_shr( fh, fl, - D.e );
  1707. templ := fh;
  1708. end;
  1709. {$endif VALREAL_80}
  1710. {$ifdef VALREAL_128}
  1711. fl := D.f;
  1712. templ := D.fh;
  1713. diy_util_shr( templ, fl, - D.e );
  1714. {$endif VALREAL_128}
  1715. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  1716. if ( templ = 0 ) then
  1717. n_digits_have := gen_digits_64( buf, 0, fl )
  1718. else
  1719. begin
  1720. if not u128_div_u64_to_u64( templ, fl, qword(10000000000000000000), templ, fl ) then
  1721. {$ifdef grisu1_debug}
  1722. assert( FALSE ) // never overflows by design
  1723. {$endif grisu1_debug};
  1724. n_digits_have := gen_digits_64( buf, 0, templ );
  1725. inc( n_digits_have, gen_digits_64( buf, n_digits_have, fl, n_digits_have > 0 ) );
  1726. end;
  1727. {$endif VALREAL_80 | VALREAL_128}
  1728. dot_pos := n_digits_have;
  1729. // Generate digits: fractional part
  1730. f := 0; // "sticky" digit
  1731. if ( D.e < 0 ) then
  1732. repeat
  1733. // MOD by ONE
  1734. one_e := D.e;
  1735. {$ifdef VALREAL_32}
  1736. one_mask := dword( 1 ) shl ( - D.e ) - 1;
  1737. f := D.f and one_mask;
  1738. {$endif VALREAL_32}
  1739. {$ifdef VALREAL_64}
  1740. one_maskl := qword( 1 ) shl ( - D.e ) - 1;
  1741. fl := D.f and one_maskl;
  1742. {$endif VALREAL_64}
  1743. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  1744. make_frac_mask( one_maskh, one_maskl, D.e );
  1745. fl := D.f and one_maskl;
  1746. fh := D.fh and one_maskh;
  1747. // 128/96-bit loop
  1748. while ( one_e < -61 ) and ( n_digits_have < n_digits_need + 1 ) and ( fl or fh <> 0 ) do
  1749. begin
  1750. // f := f * 5;
  1751. templ := fl;
  1752. temph := fh;
  1753. diy_util_shl( fh, fl, 2 );
  1754. diy_util_add( fh, fl, temph, templ );
  1755. // one := one / 2
  1756. diy_util_shr( one_maskh, one_maskl, 1 );
  1757. inc( one_e );
  1758. // DIV by one
  1759. templ := fl;
  1760. temph := fh;
  1761. diy_util_shr( temph, templ, - one_e );
  1762. buf[ n_digits_have ] := lo(templ);
  1763. // MOD by one
  1764. fl := fl and one_maskl;
  1765. fh := fh and one_maskh;
  1766. // next
  1767. inc( n_digits_have );
  1768. end;
  1769. if ( n_digits_have >= n_digits_need + 1 ) then
  1770. begin
  1771. // only "sticky" digit remains
  1772. f := ord( fl or fh <> 0 );
  1773. break;
  1774. end;
  1775. {$endif VALREAL_80 | VALREAL_128}
  1776. {$ifndef VALREAL_32}
  1777. // 64-bit loop
  1778. while ( one_e < -29 ) and ( n_digits_have < n_digits_need + 1 ) and ( fl <> 0 ) do
  1779. begin
  1780. // f := f * 5;
  1781. inc( fl, fl shl 2 );
  1782. // one := one / 2
  1783. one_maskl := one_maskl shr 1;
  1784. inc( one_e );
  1785. // DIV by one
  1786. buf[ n_digits_have ] := fl shr ( - one_e );
  1787. // MOD by one
  1788. fl := fl and one_maskl;
  1789. // next
  1790. inc( n_digits_have );
  1791. end;
  1792. if ( n_digits_have >= n_digits_need + 1 ) then
  1793. begin
  1794. // only "sticky" digit remains
  1795. f := ord( fl <> 0 );
  1796. break;
  1797. end;
  1798. one_mask := lo(one_maskl);
  1799. f := lo(fl);
  1800. {$endif not VALREAL_32}
  1801. // 32-bit loop
  1802. while ( n_digits_have < n_digits_need + 1 ) and ( f <> 0 ) do
  1803. begin
  1804. // f := f * 5;
  1805. inc( f, f shl 2 );
  1806. // one := one / 2
  1807. one_mask := one_mask shr 1;
  1808. inc( one_e );
  1809. // DIV by one
  1810. buf[ n_digits_have ] := f shr ( - one_e );
  1811. // MOD by one
  1812. f := f and one_mask;
  1813. // next
  1814. inc( n_digits_have );
  1815. end;
  1816. until true;
  1817. // Append "sticky" digit if any
  1818. if ( f <> 0 ) and ( n_digits_have >= n_digits_need + 1 ) then
  1819. begin
  1820. // single "<>0" digit is enough
  1821. n_digits_have := n_digits_need + 2;
  1822. buf[ n_digits_need + 1 ] := 1;
  1823. end;
  1824. // Round to n_digits_need using "roundTiesToEven"
  1825. if ( n_digits_have > n_digits_need ) then
  1826. inc( dot_pos, round_digits( buf, n_digits_have, n_digits_need ) );
  1827. // Generate output
  1828. if ( frac_digits >= 0 ) then
  1829. if try_return_fixed( str, minus, buf, n_digits_have, dot_pos - c_mk.e10, min_width, frac_digits ) then
  1830. exit;
  1831. if ( n_digits_have > n_digits_sci ) then
  1832. inc( dot_pos, round_digits( buf, n_digits_have, n_digits_sci {$ifdef GRISU1_F2A_HALF_ROUNDUP}, false {$endif} ) );
  1833. return_exponential( str, minus, buf, n_digits_have, n_digits_sci, dot_pos - c_mk.e10 - 1, n_digits_exp, min_width );
  1834. end;
  1835. (****************************************************************************)
  1836. {$ifndef fpc_softfpu_implementation}
  1837. procedure str_real_iso( len, f: longint; d: ValReal; real_type: treal_type; out s: string );
  1838. var
  1839. i: integer;
  1840. begin
  1841. str_real( len, f, d, real_type, s );
  1842. for i := length( s ) downto 1 do
  1843. if ( s[i] ='E' ) then
  1844. begin
  1845. s[i] := 'e';
  1846. break; // only one "E" expected
  1847. end;
  1848. end;
  1849. {$endif not fpc_softfpu_implementation}
  1850. (*==========================================================================*
  1851. * *
  1852. * ASCII -> Float *
  1853. * *
  1854. *==========================================================================*)
  1855. function val_real( const src: shortstring; out err_pos: ValSInt ): ValReal;
  1856. {$define VALREAL_PACK}
  1857. {$i flt_pack.inc}
  1858. { NOTE: C_MAX_DIGITS_ACCEPTED should fit into unsigned integer which forms DIY_FP }
  1859. const
  1860. {$ifdef VALREAL_32}
  1861. C_MAX_DIGITS_ACCEPTED = 9;
  1862. C_EXP10_OVER = 100;
  1863. C_DIY_FP_Q = 32;
  1864. C_FRAC2_BITS = 23;
  1865. C_EXP2_BIAS = 127;
  1866. {$endif VALREAL_32}
  1867. {$ifdef VALREAL_64}
  1868. C_MAX_DIGITS_ACCEPTED = 19;
  1869. C_EXP10_OVER = 1000;
  1870. C_DIY_FP_Q = 64;
  1871. C_FRAC2_BITS = 52;
  1872. C_EXP2_BIAS = 1023;
  1873. {$endif VALREAL_64}
  1874. {$ifdef VALREAL_80}
  1875. C_MAX_DIGITS_ACCEPTED = 28;
  1876. C_EXP10_OVER = 10000;
  1877. C_DIY_FP_Q = 96;
  1878. C_FRAC2_BITS = 63;
  1879. C_EXP2_BIAS = 16383;
  1880. {$endif VALREAL_80}
  1881. {$ifdef VALREAL_128}
  1882. C_MAX_DIGITS_ACCEPTED = 38;
  1883. C_EXP10_OVER = 10000;
  1884. C_DIY_FP_Q = 128;
  1885. C_FRAC2_BITS = 112;
  1886. C_EXP2_BIAS = 16383;
  1887. {$endif VALREAL_128}
  1888. (****************************************************************************)
  1889. // handy const
  1890. C_EXP2_SPECIAL = C_EXP2_BIAS * 2 + 1;
  1891. C_DIY_SHR_TO_FLT = C_DIY_FP_Q - 1 - C_FRAC2_BITS;
  1892. C_DIY_EXP_TO_FLT = C_DIY_FP_Q - 1 + C_EXP2_BIAS;
  1893. C_DIY_ROUND_BIT = 1 shl ( C_DIY_SHR_TO_FLT - 1 );
  1894. C_DIY_ROUND_MASK = ( C_DIY_ROUND_BIT shl 2 ) - 1;
  1895. {$ifdef VALREAL_128}
  1896. C_FLT_INT_BITh = qword(1) shl ( C_FRAC2_BITS - 64 );
  1897. C_FLT_FRAC_MASKh = C_FLT_INT_BITh - 1;
  1898. {$else not VALREAL_128}
  1899. {$ifdef VALREAL_32}
  1900. C_FLT_INT_BIT = dword(1) shl C_FRAC2_BITS;
  1901. C_FLT_FRAC_MASK = C_FLT_INT_BIT - 1;
  1902. {$else VALREAL_64 | VALREAL_80}
  1903. C_FLT_INT_BIT = qword(1) shl C_FRAC2_BITS;
  1904. C_FLT_FRAC_MASK = qword(C_FLT_INT_BIT) - 1;
  1905. {$endif VALREAL_*}
  1906. {$endif VALREAL_*}
  1907. // specials
  1908. {$ifdef VALREAL_32}
  1909. C_FLT_MANT_INF = dword($00000000);
  1910. {$ifndef GRISU1_A2F_NO_SNAN}
  1911. C_FLT_MANT_SNAN = dword($00200000);
  1912. {$endif GRISU1_A2F_NO_SNAN}
  1913. C_FLT_MANT_QNAN = dword($00400000);
  1914. {$endif VALREAL_32}
  1915. {$ifdef VALREAL_64}
  1916. C_FLT_MANT_INF = qword($0000000000000000);
  1917. {$ifndef GRISU1_A2F_NO_SNAN}
  1918. C_FLT_MANT_SNAN = qword($0004000000000000);
  1919. {$endif GRISU1_A2F_NO_SNAN}
  1920. C_FLT_MANT_QNAN = qword($0008000000000000);
  1921. {$endif VALREAL_64}
  1922. {$ifdef VALREAL_80}
  1923. C_FLT_MANT_INF = qword($8000000000000000);
  1924. {$ifndef GRISU1_A2F_NO_SNAN}
  1925. C_FLT_MANT_SNAN = qword($A000000000000000);
  1926. {$endif GRISU1_A2F_NO_SNAN}
  1927. C_FLT_MANT_QNAN = qword($C000000000000000);
  1928. {$endif VALREAL_80}
  1929. {$ifdef VALREAL_128}
  1930. C_FLT_MANT_INFh = qword($0000000000000000);
  1931. C_FLT_MANT_INF = qword($0000000000000000);
  1932. {$ifndef GRISU1_A2F_NO_SNAN}
  1933. C_FLT_MANT_SNANh = qword($0000400000000000);
  1934. C_FLT_MANT_SNAN = qword($0000000000000000);
  1935. {$endif GRISU1_A2F_NO_SNAN}
  1936. C_FLT_MANT_QNANh = qword($0000800000000000);
  1937. C_FLT_MANT_QNAN = qword($0000000000000000);
  1938. {$endif VALREAL_128}
  1939. (*-------------------------------------------------------
  1940. | factor_10_inexact [local]
  1941. |
  1942. | Calculates an arbitrary normalized power of 10 required for final scaling.
  1943. | The result of this calculation may be off by several ulp's from exact.
  1944. |
  1945. | Returns an overflow/underflow status:
  1946. | "<0": underflow
  1947. | "=0": ok
  1948. | ">0": overflow
  1949. |
  1950. *-------------------------------------------------------*)
  1951. function factor_10_inexact( const exp10: integer; out C: TDIY_FP_Power_of_10 ): integer;
  1952. const
  1953. {$ifdef VALREAL_32}
  1954. factor: array [ 0 .. 7 ] of TDIY_FP_Power_of_10 = (
  1955. ( c: ( f: $80000000; e: -31); e10: 0 ),
  1956. ( c: ( f: $CCCCCCCD; e: -35); e10: -1 ),
  1957. ( c: ( f: $A3D70A3D; e: -38); e10: -2 ),
  1958. ( c: ( f: $83126E98; e: -41); e10: -3 ),
  1959. ( c: ( f: $D1B71759; e: -45); e10: -4 ),
  1960. ( c: ( f: $A7C5AC47; e: -48); e10: -5 ),
  1961. ( c: ( f: $8637BD06; e: -51); e10: -6 ),
  1962. ( c: ( f: $D6BF94D6; e: -55); e10: -7 )
  1963. );
  1964. {$endif VALREAL_32}
  1965. {$ifdef VALREAL_64}
  1966. factor: array [ 0 .. 17 ] of TDIY_FP_Power_of_10 = (
  1967. ( c: ( f: qword($8000000000000000); e: -63); e10: 0 ),
  1968. ( c: ( f: qword($CCCCCCCCCCCCCCCD); e: -67); e10: -1 ),
  1969. ( c: ( f: qword($A3D70A3D70A3D70A); e: -70); e10: -2 ),
  1970. ( c: ( f: qword($83126E978D4FDF3B); e: -73); e10: -3 ),
  1971. ( c: ( f: qword($D1B71758E219652C); e: -77); e10: -4 ),
  1972. ( c: ( f: qword($A7C5AC471B478423); e: -80); e10: -5 ),
  1973. ( c: ( f: qword($8637BD05AF6C69B6); e: -83); e10: -6 ),
  1974. ( c: ( f: qword($D6BF94D5E57A42BC); e: -87); e10: -7 ),
  1975. ( c: ( f: qword($ABCC77118461CEFD); e: -90); e10: -8 ),
  1976. ( c: ( f: qword($89705F4136B4A597); e: -93); e10: -9 ),
  1977. ( c: ( f: qword($DBE6FECEBDEDD5BF); e: -97); e10: -10 ),
  1978. ( c: ( f: qword($AFEBFF0BCB24AAFF); e: -100); e10: -11 ),
  1979. ( c: ( f: qword($8CBCCC096F5088CC); e: -103); e10: -12 ),
  1980. ( c: ( f: qword($E12E13424BB40E13); e: -107); e10: -13 ),
  1981. ( c: ( f: qword($B424DC35095CD80F); e: -110); e10: -14 ),
  1982. ( c: ( f: qword($901D7CF73AB0ACD9); e: -113); e10: -15 ),
  1983. ( c: ( f: qword($E69594BEC44DE15B); e: -117); e10: -16 ),
  1984. ( c: ( f: qword($B877AA3236A4B449); e: -120); e10: -17 )
  1985. );
  1986. {$endif VALREAL_64}
  1987. {$ifdef VALREAL_80}
  1988. factor: array [ 0 .. 36 ] of TDIY_FP_Power_of_10 = (
  1989. ( c: ( f: qword($0000000000000000); fh: dword($80000000); e: -95 ); e10: 0 ),
  1990. ( c: ( f: qword($CCCCCCCCCCCCCCCD); fh: dword($CCCCCCCC); e: -99 ); e10: -1 ),
  1991. ( c: ( f: qword($70A3D70A3D70A3D7); fh: dword($A3D70A3D); e: -102 ); e10: -2 ),
  1992. ( c: ( f: qword($8D4FDF3B645A1CAC); fh: dword($83126E97); e: -105 ); e10: -3 ),
  1993. ( c: ( f: qword($E219652BD3C36113); fh: dword($D1B71758); e: -109 ); e10: -4 ),
  1994. ( c: ( f: qword($1B4784230FCF80DC); fh: dword($A7C5AC47); e: -112 ); e10: -5 ),
  1995. ( c: ( f: qword($AF6C69B5A63F9A4A); fh: dword($8637BD05); e: -115 ); e10: -6 ),
  1996. ( c: ( f: qword($E57A42BC3D329076); fh: dword($D6BF94D5); e: -119 ); e10: -7 ),
  1997. ( c: ( f: qword($8461CEFCFDC20D2B); fh: dword($ABCC7711); e: -122 ); e10: -8 ),
  1998. ( c: ( f: qword($36B4A59731680A89); fh: dword($89705F41); e: -125 ); e10: -9 ),
  1999. ( c: ( f: qword($BDEDD5BEB573440E); fh: dword($DBE6FECE); e: -129 ); e10: -10 ),
  2000. ( c: ( f: qword($CB24AAFEF78F69A5); fh: dword($AFEBFF0B); e: -132 ); e10: -11 ),
  2001. ( c: ( f: qword($6F5088CBF93F87B7); fh: dword($8CBCCC09); e: -135 ); e10: -12 ),
  2002. ( c: ( f: qword($4BB40E132865A5F2); fh: dword($E12E1342); e: -139 ); e10: -13 ),
  2003. ( c: ( f: qword($095CD80F538484C2); fh: dword($B424DC35); e: -142 ); e10: -14 ),
  2004. ( c: ( f: qword($3AB0ACD90F9D3701); fh: dword($901D7CF7); e: -145 ); e10: -15 ),
  2005. ( c: ( f: qword($C44DE15B4C2EBE68); fh: dword($E69594BE); e: -149 ); e10: -16 ),
  2006. ( c: ( f: qword($36A4B44909BEFEBA); fh: dword($B877AA32); e: -152 ); e10: -17 ),
  2007. ( c: ( f: qword($921D5D073AFF322E); fh: dword($9392EE8E); e: -155 ); e10: -18 ),
  2008. ( c: ( f: qword($B69561A52B31E9E4); fh: dword($EC1E4A7D); e: -159 ); e10: -19 ),
  2009. ( c: ( f: qword($92111AEA88F4BB1D); fh: dword($BCE50864); e: -162 ); e10: -20 ),
  2010. ( c: ( f: qword($74DA7BEED3F6FC17); fh: dword($971DA050); e: -165 ); e10: -21 ),
  2011. ( c: ( f: qword($BAF72CB15324C68B); fh: dword($F1C90080); e: -169 ); e10: -22 ),
  2012. ( c: ( f: qword($95928A2775B7053C); fh: dword($C16D9A00); e: -172 ); e10: -23 ),
  2013. ( c: ( f: qword($44753B52C4926A96); fh: dword($9ABE14CD); e: -175 ); e10: -24 ),
  2014. ( c: ( f: qword($D3EEC5513A83DDBE); fh: dword($F79687AE); e: -179 ); e10: -25 ),
  2015. ( c: ( f: qword($76589DDA95364AFE); fh: dword($C6120625); e: -182 ); e10: -26 ),
  2016. ( c: ( f: qword($91E07E48775EA265); fh: dword($9E74D1B7); e: -185 ); e10: -27 ),
  2017. ( c: ( f: qword($8300CA0D8BCA9D6E); fh: dword($FD87B5F2); e: -189 ); e10: -28 ),
  2018. ( c: ( f: qword($359A3B3E096EE458); fh: dword($CAD2F7F5); e: -192 ); e10: -29 ),
  2019. ( c: ( f: qword($5E14FC31A125837A); fh: dword($A2425FF7); e: -195 ); e10: -30 ),
  2020. ( c: ( f: qword($4B43FCF480EACF95); fh: dword($81CEB32C); e: -198 ); e10: -31 ),
  2021. ( c: ( f: qword($453994BA67DE18EE); fh: dword($CFB11EAD); e: -202 ); e10: -32 ),
  2022. ( c: ( f: qword($D0FADD61ECB1AD8B); fh: dword($A6274BBD); e: -205 ); e10: -33 ),
  2023. ( c: ( f: qword($DA624AB4BD5AF13C); fh: dword($84EC3C97); e: -208 ); e10: -34 ),
  2024. ( c: ( f: qword($C3D07787955E4EC6); fh: dword($D4AD2DBF); e: -212 ); e10: -35 ),
  2025. ( c: ( f: qword($697392D2DDE50BD2); fh: dword($AA242499); e: -215 ); e10: -36 )
  2026. );
  2027. {$endif VALREAL_80}
  2028. {$ifdef VALREAL_128}
  2029. factor: array [ 0 .. 36 ] of TDIY_FP_Power_of_10 = (
  2030. ( c: ( fh: qword($8000000000000000); f: qword($0000000000000000); e: -127 ); e10: 0 ),
  2031. ( c: ( fh: qword($CCCCCCCCCCCCCCCC); f: qword($CCCCCCCCCCCCCCCD); e: -131 ); e10: -1 ),
  2032. ( c: ( fh: qword($A3D70A3D70A3D70A); f: qword($3D70A3D70A3D70A4); e: -134 ); e10: -2 ),
  2033. ( c: ( fh: qword($83126E978D4FDF3B); f: qword($645A1CAC083126E9); e: -137 ); e10: -3 ),
  2034. ( c: ( fh: qword($D1B71758E219652B); f: qword($D3C36113404EA4A9); e: -141 ); e10: -4 ),
  2035. ( c: ( fh: qword($A7C5AC471B478423); f: qword($0FCF80DC33721D54); e: -144 ); e10: -5 ),
  2036. ( c: ( fh: qword($8637BD05AF6C69B5); f: qword($A63F9A49C2C1B110); e: -147 ); e10: -6 ),
  2037. ( c: ( fh: qword($D6BF94D5E57A42BC); f: qword($3D32907604691B4D); e: -151 ); e10: -7 ),
  2038. ( c: ( fh: qword($ABCC77118461CEFC); f: qword($FDC20D2B36BA7C3D); e: -154 ); e10: -8 ),
  2039. ( c: ( fh: qword($89705F4136B4A597); f: qword($31680A88F8953031); e: -157 ); e10: -9 ),
  2040. ( c: ( fh: qword($DBE6FECEBDEDD5BE); f: qword($B573440E5A884D1B); e: -161 ); e10: -10 ),
  2041. ( c: ( fh: qword($AFEBFF0BCB24AAFE); f: qword($F78F69A51539D749); e: -164 ); e10: -11 ),
  2042. ( c: ( fh: qword($8CBCCC096F5088CB); f: qword($F93F87B7442E45D4); e: -167 ); e10: -12 ),
  2043. ( c: ( fh: qword($E12E13424BB40E13); f: qword($2865A5F206B06FBA); e: -171 ); e10: -13 ),
  2044. ( c: ( fh: qword($B424DC35095CD80F); f: qword($538484C19EF38C94); e: -174 ); e10: -14 ),
  2045. ( c: ( fh: qword($901D7CF73AB0ACD9); f: qword($0F9D37014BF60A10); e: -177 ); e10: -15 ),
  2046. ( c: ( fh: qword($E69594BEC44DE15B); f: qword($4C2EBE687989A9B4); e: -181 ); e10: -16 ),
  2047. ( c: ( fh: qword($B877AA3236A4B449); f: qword($09BEFEB9FAD487C3); e: -184 ); e10: -17 ),
  2048. ( c: ( fh: qword($9392EE8E921D5D07); f: qword($3AFF322E62439FCF); e: -187 ); e10: -18 ),
  2049. ( c: ( fh: qword($EC1E4A7DB69561A5); f: qword($2B31E9E3D06C32E5); e: -191 ); e10: -19 ),
  2050. ( c: ( fh: qword($BCE5086492111AEA); f: qword($88F4BB1CA6BCF584); e: -194 ); e10: -20 ),
  2051. ( c: ( fh: qword($971DA05074DA7BEE); f: qword($D3F6FC16EBCA5E03); e: -197 ); e10: -21 ),
  2052. ( c: ( fh: qword($F1C90080BAF72CB1); f: qword($5324C68B12DD6338); e: -201 ); e10: -22 ),
  2053. ( c: ( fh: qword($C16D9A0095928A27); f: qword($75B7053C0F178294); e: -204 ); e10: -23 ),
  2054. ( c: ( fh: qword($9ABE14CD44753B52); f: qword($C4926A9672793543); e: -207 ); e10: -24 ),
  2055. ( c: ( fh: qword($F79687AED3EEC551); f: qword($3A83DDBD83F52205); e: -211 ); e10: -25 ),
  2056. ( c: ( fh: qword($C612062576589DDA); f: qword($95364AFE032A819D); e: -214 ); e10: -26 ),
  2057. ( c: ( fh: qword($9E74D1B791E07E48); f: qword($775EA264CF55347E); e: -217 ); e10: -27 ),
  2058. ( c: ( fh: qword($FD87B5F28300CA0D); f: qword($8BCA9D6E188853FC); e: -221 ); e10: -28 ),
  2059. ( c: ( fh: qword($CAD2F7F5359A3B3E); f: qword($096EE45813A04330); e: -224 ); e10: -29 ),
  2060. ( c: ( fh: qword($A2425FF75E14FC31); f: qword($A1258379A94D028D); e: -227 ); e10: -30 ),
  2061. ( c: ( fh: qword($81CEB32C4B43FCF4); f: qword($80EACF948770CED7); e: -230 ); e10: -31 ),
  2062. ( c: ( fh: qword($CFB11EAD453994BA); f: qword($67DE18EDA5814AF2); e: -234 ); e10: -32 ),
  2063. ( c: ( fh: qword($A6274BBDD0FADD61); f: qword($ECB1AD8AEACDD58E); e: -237 ); e10: -33 ),
  2064. ( c: ( fh: qword($84EC3C97DA624AB4); f: qword($BD5AF13BEF0B113F); e: -240 ); e10: -34 ),
  2065. ( c: ( fh: qword($D4AD2DBFC3D07787); f: qword($955E4EC64B44E864); e: -244 ); e10: -35 ),
  2066. ( c: ( fh: qword($AA242499697392D2); f: qword($DDE50BD1D5D0B9EA); e: -247 ); e10: -36 )
  2067. );
  2068. {$endif VALREAL_128}
  2069. var
  2070. i: integer;
  2071. a, b: TDIY_FP_Power_of_10;
  2072. begin
  2073. diy_fp_cached_power10( exp10, a );
  2074. i := a.e10 - exp10;
  2075. if ( i < 0 ) then
  2076. begin
  2077. factor_10_inexact := 1; // overflow
  2078. exit;
  2079. end;
  2080. if ( i > high( factor ) ) then
  2081. begin
  2082. factor_10_inexact := -1; // underflow
  2083. exit;
  2084. end;
  2085. b := factor[i];
  2086. {$ifdef grisu1_debug}
  2087. assert( exp10 = a.e10 + b.e10 );
  2088. {$endif grisu1_debug}
  2089. if ( b.e10 = 0 ) then
  2090. C := a
  2091. else
  2092. if ( a.e10 = 0 ) then
  2093. C := b
  2094. else
  2095. begin
  2096. C.c := diy_fp_multiply( a.c, b.c, TRUE );
  2097. c.e10 := exp10;
  2098. end;
  2099. factor_10_inexact := 0; // no error
  2100. end;
  2101. (*-------------------------------------------------------
  2102. | add_digit [local]
  2103. |
  2104. | This helper routine performs next digit addition:
  2105. | X := X * 10 + digit
  2106. |
  2107. *-------------------------------------------------------*)
  2108. {$ifdef VALREAL_80}
  2109. procedure add_digit( var h: dword; var l: qword; digit: byte ); {$ifdef grisu1_inline}inline;{$endif}
  2110. var
  2111. temp1, temp2: qword;
  2112. begin
  2113. //
  2114. temp1 := lo(l);
  2115. inc( temp1, ( temp1 shl 3 ) + temp1 + digit );
  2116. //
  2117. temp2 := h;
  2118. temp2 := ( temp2 shl 32 ) + hi(l);
  2119. inc( temp2, ( temp2 shl 3 ) + temp2 + hi(temp1) );
  2120. //
  2121. h := hi(temp2);
  2122. l := ( temp2 shl 32 ) + lo(temp1);
  2123. //
  2124. end;
  2125. {$endif VALREAL_80}
  2126. {$ifdef VALREAL_128}
  2127. procedure add_digit( var h, l: qword; digit: byte ); {$ifdef grisu1_inline}inline;{$endif}
  2128. var
  2129. templ, temph, temp1, temp2: qword;
  2130. begin
  2131. templ := l;
  2132. temph := h;
  2133. diy_util_shl( temph, templ, 3 );
  2134. //
  2135. temp1 := lo(l);
  2136. inc( temp1, lo(templ) + temp1 + digit );
  2137. //
  2138. temp2 := hi(l);
  2139. inc( temp2, hi(templ) + temp2 + hi(temp1) );
  2140. //
  2141. inc( h, temph + h + hi(temp2) );
  2142. l := ( temp2 shl 32 ) + lo(temp1);
  2143. //
  2144. end;
  2145. {$endif VALREAL_128}
  2146. (*-------------------------------------------------------
  2147. | count_leading_zero [local] <<<duplicate>>>
  2148. |
  2149. | Counts number of 0-bits at most significant bit position.
  2150. |
  2151. *-------------------------------------------------------*)
  2152. {$if defined(VALREAL_32) or defined(VALREAL_80)}
  2153. function count_leading_zero( const X: dword ): integer; {$ifdef grisu1_inline}inline;{$endif}
  2154. begin
  2155. count_leading_zero := 31 - BSRdword( X );
  2156. end;
  2157. {$endif VALREAL_32 | VALREAL_80}
  2158. {$ifndef VALREAL_32}
  2159. function count_leading_zero( const X: qword ): integer; {$ifdef grisu1_inline}inline;{$endif}
  2160. begin
  2161. count_leading_zero := 63 - BSRqword( X );
  2162. end;
  2163. {$endif not VALREAL_32}
  2164. (*-------------------------------------------------------
  2165. | match_special [local]
  2166. |
  2167. | Routine compares source string tail with the string representing
  2168. | one of special values: Inf | QNaN | SNaN
  2169. |
  2170. *-------------------------------------------------------*)
  2171. function match_special( src_pos: integer; const src, spec: shortstring ): boolean;
  2172. var
  2173. sl, xl: integer;
  2174. begin
  2175. match_special := false;
  2176. xl := length( src );
  2177. sl := length( spec );
  2178. if ( sl <> xl - src_pos + 1 ) then
  2179. exit;
  2180. {$ifdef grisu1_debug}
  2181. assert( sl > 0 );
  2182. {$endif grisu1_debug}
  2183. repeat
  2184. if ( UpCase( src[xl] ) <> UpCase( spec[sl] ) ) then
  2185. exit;
  2186. dec( xl );
  2187. dec( sl );
  2188. until sl <= 0;
  2189. match_special := true;
  2190. end;
  2191. (****************************************************************************)
  2192. var
  2193. a: char;
  2194. mantissa, bit_round, bit_round_mask: {$ifdef VALREAL_32} dword {$else} qword {$endif};
  2195. {$ifdef VALREAL_80}
  2196. mantissa_h: dword;
  2197. {$endif}
  2198. {$ifdef VALREAL_128}
  2199. mantissa_h, bit_round_h, bit_round_mask_h: qword;
  2200. {$endif}
  2201. dig_num, exp10, overflow, n, src_pos, src_len: integer;
  2202. exp_read, exp_temp: longint;
  2203. b, dig_round, dig_sticky: byte;
  2204. minus, exp_minus, special: boolean;
  2205. C: TDIY_FP_Power_of_10;
  2206. D: TDIY_FP;
  2207. begin
  2208. err_pos := 1;
  2209. src_pos := 1;
  2210. src_len := length(src);
  2211. // Pre-initialize result
  2212. {$ifdef GRISU1_A2F_ERROR_RET0}
  2213. pack_float( val_real, false, 0, {$ifdef VALREAL_128} 0, {$endif} 0 );
  2214. {$else}
  2215. {-ifdef GRISU1_A2F_NO_SNAN}
  2216. // "real indefinite"
  2217. pack_float( val_real, true, C_EXP2_SPECIAL, {$ifdef VALREAL_128} C_FLT_MANT_QNANh, {$endif} C_FLT_MANT_QNAN );
  2218. (*{-else}
  2219. // SNaN is preferable for catching uninitialized variables access, but may cause troubles with implicit float type conversions
  2220. pack_float( val_real, false, C_EXP2_SPECIAL, {$ifdef VALREAL_128} C_FLT_MANT_SNANh, {$endif} C_FLT_MANT_SNAN );
  2221. {-endif}*)
  2222. {$endif}
  2223. // search for a sign skipping leading spaces
  2224. minus := false;
  2225. while ( src_pos <= src_len ) do
  2226. begin
  2227. a := src[src_pos];
  2228. case a of
  2229. '+':
  2230. begin
  2231. inc( src_pos );
  2232. break;
  2233. end;
  2234. '-':
  2235. begin
  2236. minus := true;
  2237. inc( src_pos );
  2238. break;
  2239. end;
  2240. else
  2241. if a <> ' ' then
  2242. break;
  2243. end;
  2244. inc( src_pos );
  2245. end;
  2246. if ( src_pos > src_len ) then
  2247. begin
  2248. // syntax: nothing to evaluate
  2249. err_pos := src_pos;
  2250. exit;
  2251. end;
  2252. // handle specials
  2253. case src[src_pos] of
  2254. '0' .. '9', '.', 'E', 'e': special := false;
  2255. else
  2256. special := true;
  2257. end;
  2258. if special then
  2259. begin
  2260. mantissa := C_FLT_MANT_INF;
  2261. {$ifdef VALREAL_128}
  2262. mantissa_h := C_FLT_MANT_INFh;
  2263. {$endif}
  2264. if not match_special( src_pos, src, C_STR_INF ) then
  2265. begin
  2266. {$ifndef GRISU1_A2F_NO_SNAN}
  2267. if match_special( src_pos, src, C_STR_SNAN ) then
  2268. begin
  2269. mantissa := C_FLT_MANT_SNAN;
  2270. {$ifdef VALREAL_128}
  2271. mantissa_h := C_FLT_MANT_SNANh;
  2272. {$endif}
  2273. end
  2274. else
  2275. {$endif GRISU1_A2F_NO_SNAN}
  2276. if match_special( src_pos, src, C_STR_QNAN ) then
  2277. begin
  2278. {$ifdef GRISU1_A2F_QNAN_REAL_INDEFINITE}
  2279. minus := TRUE;
  2280. {$endif}
  2281. mantissa := C_FLT_MANT_QNAN;
  2282. {$ifdef VALREAL_128}
  2283. mantissa_h := C_FLT_MANT_QNANh;
  2284. {$endif}
  2285. end
  2286. else
  2287. special := false;
  2288. end;
  2289. if special then
  2290. begin
  2291. pack_float( val_real, minus, C_EXP2_SPECIAL, {$ifdef VALREAL_128} mantissa_h, {$endif} mantissa );
  2292. src_pos := 0;
  2293. end;
  2294. err_pos := src_pos;
  2295. exit;
  2296. end;
  2297. // consume mantissa digits skipping leading zeroes
  2298. // empty mantissa ("0.E#", ".0E#", ".E#", "E#") is allowed at least in D5
  2299. mantissa := 0;
  2300. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  2301. mantissa_h := 0;
  2302. {$endif VALREAL_80 | VALREAL_128}
  2303. dig_num := 0;
  2304. exp10 := 0;
  2305. dig_round := 0;
  2306. dig_sticky := 0;
  2307. // leading zero loop
  2308. while ( src_pos <= src_len ) and ( src[src_pos] = '0' ) do
  2309. inc( src_pos );
  2310. // integer part loop
  2311. while ( src_pos <= src_len ) do
  2312. begin
  2313. a := src[src_pos];
  2314. if ( a < '0' ) or ( a > '9' ) then
  2315. break;
  2316. b := ord(a) - ord('0');
  2317. if ( dig_num < C_MAX_DIGITS_ACCEPTED ) then
  2318. // normal digit
  2319. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  2320. inc( mantissa, ( mantissa shl 3 ) + mantissa + b )
  2321. {$else VALREAL_80 | VALREAL_128}
  2322. add_digit( mantissa_h, mantissa, b )
  2323. {$endif VALREAL_*}
  2324. else
  2325. begin
  2326. // over-required digits: use them for rounding later
  2327. if ( dig_num = C_MAX_DIGITS_ACCEPTED ) then
  2328. dig_round := b // main digit for rounding
  2329. else
  2330. dig_sticky := dig_sticky or b; // just "<>0" to judge "round to even" case later
  2331. inc( exp10 ); // move [yet virtual] dot to the right
  2332. end;
  2333. inc( dig_num );
  2334. inc( src_pos );
  2335. end;
  2336. // fraction part
  2337. if ( src_pos <= src_len ) and ( src[src_pos] = '.' ) then
  2338. begin
  2339. // skip dot
  2340. inc( src_pos );
  2341. // leading zero loop, if integer part was 0
  2342. if dig_num = 0 then
  2343. while ( src_pos <= src_len ) and ( src[src_pos] = '0' ) do
  2344. begin
  2345. dec( exp10 ); // move the dot to the left
  2346. inc( src_pos );
  2347. end;
  2348. // fraction part loop
  2349. while ( src_pos <= src_len ) do
  2350. begin
  2351. a := src[src_pos];
  2352. if ( a < '0' ) or ( a > '9' ) then
  2353. break;
  2354. b := ord(a) - ord('0');
  2355. if ( dig_num < C_MAX_DIGITS_ACCEPTED ) then
  2356. begin
  2357. // normal digit
  2358. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  2359. inc( mantissa, ( mantissa shl 3 ) + mantissa + b );
  2360. {$else VALREAL_80 | VALREAL_128}
  2361. add_digit( mantissa_h, mantissa, b );
  2362. {$endif VALREAL_*}
  2363. dec( exp10 ); // move the dot to the left
  2364. end
  2365. else
  2366. begin
  2367. // over-required digits: use them for rounding later
  2368. if ( dig_num = C_MAX_DIGITS_ACCEPTED ) then
  2369. dig_round := b // main digit for rounding
  2370. else
  2371. dig_sticky := dig_sticky or b; // just "<>0" to judge "round to even" case later
  2372. end;
  2373. inc( dig_num );
  2374. inc( src_pos );
  2375. end;
  2376. end;
  2377. // round digits
  2378. {$ifndef GRISU1_A2F_HALF_ROUNDUP}
  2379. if ( dig_round = 5 ) and ( dig_sticky = 0 ) and ( mantissa and 1 = 0 ) then
  2380. // need to "round to even", and already even..
  2381. dec( dig_round ); // ..so force no round-up
  2382. {$endif not GRISU1_A2F_HALF_ROUNDUP}
  2383. if ( dig_round >= 5 ) then
  2384. begin
  2385. // round-up
  2386. inc( mantissa );
  2387. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  2388. if ( mantissa = 0 ) then
  2389. inc( mantissa_h );
  2390. {$endif VALREAL_*}
  2391. end;
  2392. // consume exponent digits
  2393. exp_read := 0;
  2394. if ( src_pos <= src_len ) then
  2395. begin
  2396. exp_minus := false;
  2397. case src[src_pos] of
  2398. 'e', 'E':;
  2399. else
  2400. // syntax: "E" expected
  2401. err_pos := src_pos;
  2402. exit;
  2403. end;
  2404. inc( src_pos );
  2405. if ( src_pos > src_len ) then
  2406. begin
  2407. // syntax: empty exponent
  2408. err_pos := src_pos;
  2409. exit;
  2410. end;
  2411. case src[src_pos] of
  2412. '+':
  2413. inc( src_pos );
  2414. '-':
  2415. begin
  2416. exp_minus := true;
  2417. inc( src_pos );
  2418. end;
  2419. end;
  2420. while ( src_pos <= src_len ) do
  2421. begin
  2422. a := src[src_pos];
  2423. if ( a < '0' ) or ( a > '9' ) then
  2424. begin
  2425. // syntax: bad digit
  2426. err_pos := src_pos;
  2427. exit;
  2428. end;
  2429. if ( exp_read < 100000 ) then
  2430. inc( exp_read, ( exp_read shl 3 ) + exp_read + ord(a) - ord('0') );
  2431. // else just syntax check
  2432. inc( src_pos );
  2433. end;
  2434. if exp_minus then
  2435. exp_read := - exp_read;
  2436. end;
  2437. exp_temp := exp_read + exp10;
  2438. if ( exp_read >= 100000 ) or ( exp_temp >= C_EXP10_OVER ) then
  2439. exp10 := C_EXP10_OVER
  2440. else
  2441. if ( exp_read <= - 100000 ) or ( exp_temp <= - C_EXP10_OVER ) then
  2442. exp10 := - C_EXP10_OVER
  2443. else
  2444. exp10 := exp_temp;
  2445. // nothing should remain in the "src" here
  2446. if ( src_pos <= src_len ) then
  2447. begin
  2448. err_pos := src_pos;
  2449. exit;
  2450. end;
  2451. // zero [or negative exponent overflow]
  2452. if ( mantissa {$if defined(VALREAL_80) or defined(VALREAL_128)} or mantissa_h {$endif} = 0 )
  2453. or ( exp10 <= - C_EXP10_OVER ) then
  2454. begin
  2455. pack_float( val_real, minus, 0, {$ifdef VALREAL_128} 0, {$endif} 0 ); // +0|-0
  2456. err_pos := 0;
  2457. exit;
  2458. end;
  2459. if ( exp10 >= C_EXP10_OVER ) then
  2460. // exponent overflowed -> return Inf
  2461. overflow := 1
  2462. else
  2463. begin
  2464. // make DIY_FP
  2465. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  2466. n := count_leading_zero( mantissa );
  2467. D.f := mantissa shl n;
  2468. {$else VALREAL_80 | VALREAL_128}
  2469. if ( mantissa_h = 0 ) then
  2470. n := count_leading_zero( mantissa ) + sizeof( mantissa_h ) * 8
  2471. else
  2472. n := count_leading_zero( mantissa_h );
  2473. D.f := mantissa;
  2474. D.fh := mantissa_h;
  2475. diy_util_shl( D.fh, D.f, n );
  2476. {$endif VALREAL_*}
  2477. D.e := - n;
  2478. // get factor
  2479. overflow := factor_10_inexact( exp10, C ); // <>0 -> over/underflow
  2480. end;
  2481. if ( overflow = 0 ) then
  2482. begin
  2483. // multiply
  2484. if ( C.e10 <> 0 ) then
  2485. // C <> 1
  2486. D := diy_fp_multiply( D, C.c, TRUE );
  2487. // calculate round increment
  2488. if ( D.f and C_DIY_ROUND_MASK = C_DIY_ROUND_BIT ) then
  2489. // round to even and already even
  2490. b := 0
  2491. else
  2492. b := ord( D.f and C_DIY_ROUND_BIT <> 0 );
  2493. // shift and round
  2494. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  2495. D.f := ( D.f shr C_DIY_SHR_TO_FLT ) + b;
  2496. // handle round overflow
  2497. if ( D.f and ( C_FLT_INT_BIT shl 1 ) <> 0 ) then
  2498. begin
  2499. D.f := D.f shr 1;
  2500. inc( D.e );
  2501. end;
  2502. {$else VALREAL_80 or VALREAL_128}
  2503. diy_util_shr( D.fh, D.f, C_DIY_SHR_TO_FLT );
  2504. if ( b <> 0 ) then
  2505. diy_util_add( D.fh, D.f, 0, b );
  2506. // handle round overflow
  2507. if ( D.fh {$ifdef VALREAL_128} and ( C_FLT_INT_BITh shl 1 ) {$endif} <> 0 ) then
  2508. begin
  2509. diy_util_shr( D.fh, D.f, 1 );
  2510. inc( D.e );
  2511. end;
  2512. {$if defined(grisu1_debug) and defined(VALREAL_80)}
  2513. assert( D.fh = 0 );
  2514. {$endif grisu1_debug}
  2515. {$endif VALREAL_*}
  2516. // calculate exponent
  2517. D.e := D.e + C_DIY_EXP_TO_FLT;
  2518. if ( D.e >= C_EXP2_SPECIAL ) then
  2519. ///////////////////
  2520. //
  2521. // overflow
  2522. //
  2523. ///////////////////
  2524. overflow := 1
  2525. else
  2526. if ( D.e < - C_FRAC2_BITS ) then
  2527. ///////////////////
  2528. //
  2529. // underflow
  2530. //
  2531. ///////////////////
  2532. overflow := -1
  2533. else
  2534. if ( D.e <= 0 ) then
  2535. begin
  2536. ///////////////////
  2537. //
  2538. // denormal (and also an extreme case of "D.e=-C_FRAC2_BITS", where
  2539. // rounding may produce either the lowest denormal or underflow)
  2540. //
  2541. ///////////////////
  2542. n := 1 - D.e; // SHR amount
  2543. // round bit
  2544. {$ifdef VALREAL_32}
  2545. bit_round := dword(1) shl ( n - 1 );
  2546. {$endif VALREAL_32}
  2547. {$if defined(VALREAL_64) or defined(VALREAL_80)}
  2548. bit_round := qword(1) shl ( n - 1 );
  2549. {$endif VALREAL_64 | VALREAL_80}
  2550. {$ifdef VALREAL_128}
  2551. bit_round := 1;
  2552. bit_round_h := 0;
  2553. diy_util_shl( bit_round_h, bit_round, n - 1 );
  2554. // mask for ulp and all least bits including the round one
  2555. bit_round_mask := bit_round;
  2556. bit_round_mask_h := bit_round_h;
  2557. diy_util_shl( bit_round_mask_h, bit_round_mask, 2 );
  2558. if ( bit_round_mask = 0 ) then
  2559. dec( bit_round_mask_h );
  2560. dec( bit_round_mask );
  2561. {$else not VALREAL_128}
  2562. // mask for ulp and all least bits including the round one
  2563. bit_round_mask := ( bit_round shl 2 ) - 1;
  2564. // Note[floatx80]: works correctly despite the overflow is ignored in extreme case "D.e=-C_FRAC2_BITS"
  2565. {$endif VALREAL_*}
  2566. // round increment
  2567. if ( D.f and bit_round_mask = bit_round ) {$ifdef VALREAL_128} and ( D.fh and bit_round_mask_h = bit_round_h ) {$endif} then
  2568. // round to even and already even -> no round-up
  2569. b := 0
  2570. else
  2571. b := ord( ( D.f and bit_round ) {$ifdef VALREAL_128} or ( D.fh and bit_round_h ) {$endif} <> 0 );
  2572. // shift and round
  2573. if ( D.e = - C_FRAC2_BITS ) then
  2574. begin
  2575. // extreme case: rounding may result in either lowest denormal or zero
  2576. {$ifdef VALREAL_128}
  2577. D.fh := 0;
  2578. {$endif VALREAL_128}
  2579. D.f := b;
  2580. if ( b = 0 ) then
  2581. overflow := -1; // underflow
  2582. end
  2583. else
  2584. {$ifdef VALREAL_128}
  2585. begin
  2586. diy_util_shr( D.fh, D.f, n );
  2587. if ( b <> 0 ) then
  2588. diy_util_add( D.fh, D.f, 0, b );
  2589. end;
  2590. {$else not VALREAL_128}
  2591. D.f := ( D.f shr n ) + b;
  2592. {$endif VALREAL_*}
  2593. D.e := 0;
  2594. {$ifdef grisu1_debug}
  2595. {$ifdef VALREAL_128}
  2596. assert( ( D.f or D.fh <> 0 ) or ( overflow = -1 ) );
  2597. assert( D.fh and not C_FLT_FRAC_MASKh = 0 );
  2598. {$else not VALREAL_128}
  2599. assert( ( D.f <> 0 ) or ( overflow = -1 ) );
  2600. assert( D.f and not C_FLT_FRAC_MASK = 0 );
  2601. {$endif VALREAL_*}
  2602. {$endif grisu1_debug}
  2603. end
  2604. else
  2605. begin
  2606. ///////////////////
  2607. //
  2608. // normal: 0 < D.e < C_EXP2_SPECIAL
  2609. //
  2610. ///////////////////
  2611. {$ifdef grisu1_debug}
  2612. {$ifdef VALREAL_32}
  2613. assert( D.f and not C_FLT_FRAC_MASK = C_FLT_INT_BIT );
  2614. {$endif VALREAL_32}
  2615. {$if defined(VALREAL_64) or defined(VALREAL_80)}
  2616. assert( D.f and not qword(C_FLT_FRAC_MASK) = qword(C_FLT_INT_BIT) );
  2617. {$endif VALREAL_64 | VALREAL_80}
  2618. {$ifdef VALREAL_128}
  2619. assert( D.fh and not C_FLT_FRAC_MASKh = C_FLT_INT_BITh );
  2620. {$endif VALREAL_128}
  2621. {$endif grisu1_debug}
  2622. {$ifndef VALREAL_80}
  2623. // clear the implicit integer bit
  2624. {$ifdef VALREAL_128}
  2625. D.fh := D.fh and C_FLT_FRAC_MASKh;
  2626. {$else not VALREAL_128}
  2627. D.f := D.f and C_FLT_FRAC_MASK;
  2628. {$endif VALREAL_*}
  2629. {$endif not VALREAL_80}
  2630. end;
  2631. end;
  2632. // final result
  2633. if ( overflow < 0 ) then
  2634. begin
  2635. // underflow [+0|-0]
  2636. pack_float( val_real, minus, 0, {$ifdef VALREAL_128} 0, {$endif} 0 );
  2637. end
  2638. else
  2639. if ( overflow > 0 ) then
  2640. begin
  2641. // overflow [+Inf|-Inf]
  2642. pack_float( val_real, minus, C_EXP2_SPECIAL, {$ifdef VALREAL_128} C_FLT_MANT_INFh, {$endif} C_FLT_MANT_INF );
  2643. end
  2644. else
  2645. begin
  2646. // no error
  2647. pack_float( val_real, minus, D.e, {$ifdef VALREAL_128} D.fh, {$endif} D.f );
  2648. end;
  2649. err_pos := 0;
  2650. end;