flt_core.inc 93 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751
  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: AnsiChar );
  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: AnsiChar ); {$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] := AnsiChar( 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] := AnsiChar( 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] := AnsiChar( 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] := AnsiChar( 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] := AnsiChar( 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] := AnsiChar( 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] := AnsiChar( 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. {$ifndef FPC_SYSTEM_HAS_U128_DIV_U64_TO_U64}
  1244. (*-------------------------------------------------------
  1245. | u128_div_u64_to_u64 [local]
  1246. |
  1247. | Divides unsigned 128-bit integer by unsigned 64-bit integer.
  1248. | Returns 64-bit quotient and reminder.
  1249. |
  1250. | This routine is used here only for splitting specially prepared unsigned
  1251. | 128-bit integer into two 64-bit ones before converting it to ASCII.
  1252. |
  1253. *-------------------------------------------------------*)
  1254. function u128_div_u64_to_u64( const xh, xl: qword; const y: qword; out quotient, remainder: qword ): boolean;
  1255. var
  1256. b, // Number base
  1257. v : qword; // Norm. divisor
  1258. un1, un0, // Norm. dividend LSD's
  1259. vn1, vn0 : dword; // Norm. divisor digits
  1260. q1, q0, // Quotient digits
  1261. un64, un21, un10, // Dividend digit pairs
  1262. rhat: qword; // A remainder
  1263. s: integer; // Shift amount for norm
  1264. begin
  1265. // Overflow check
  1266. if ( xh >= y ) then
  1267. begin
  1268. u128_div_u64_to_u64 := false;
  1269. exit;
  1270. end;
  1271. // Count leading zeros
  1272. s := 63 - BSRqword( y ); // 0 <= s <= 63
  1273. // Normalize divisor
  1274. v := y shl s;
  1275. // Break divisor up into two 32-bit digits
  1276. vn1 := hi(v);
  1277. vn0 := lo(v);
  1278. // Shift dividend left
  1279. un64 := xh shl s;
  1280. if ( s > 0 ) then
  1281. un64 := un64 or ( xl shr ( 64 - s ) );
  1282. un10 := xl shl s;
  1283. // Break right half of dividend into two digits
  1284. un1 := hi(un10);
  1285. un0 := lo(un10);
  1286. // Compute the first quotient digit, q1
  1287. q1 := un64 div vn1;
  1288. rhat := un64 - q1 * vn1;
  1289. b := qword(1) shl 32; // Number base
  1290. while ( hi(q1) <> 0 ) or ( q1 * vn0 > b * rhat + un1 ) do
  1291. begin
  1292. dec( q1 );
  1293. inc( rhat, vn1 );
  1294. if rhat >= b then
  1295. break;
  1296. end;
  1297. // Multiply and subtract
  1298. un21 := un64 * b + un1 - q1 * v;
  1299. // Compute the second quotient digit, q0
  1300. q0 := un21 div vn1;
  1301. rhat := un21 - q0 * vn1;
  1302. while ( hi(q0) <> 0 ) or ( q0 * vn0 > b * rhat + un0 ) do
  1303. begin
  1304. dec( q0 );
  1305. inc( rhat, vn1 );
  1306. if ( hi(rhat) <> 0 ) then
  1307. break;
  1308. end;
  1309. // Result
  1310. remainder := ( un21 * b + un0 - q0 * v ) shr s;
  1311. quotient := q1 * b + q0;
  1312. u128_div_u64_to_u64 := true;
  1313. end;
  1314. {$endif FPC_SYSTEM_HAS_U128_DIV_U64_TO_U64}
  1315. {$endif VALREAL_80 | VALREAL_128}
  1316. (*-------------------------------------------------------
  1317. | count_leading_zero [local]
  1318. |
  1319. | Counts number of 0-bits at most significant bit position.
  1320. |
  1321. *-------------------------------------------------------*)
  1322. {$ifdef VALREAL_32}
  1323. function count_leading_zero( const X: dword ): integer; {$ifdef grisu1_inline}inline;{$endif}
  1324. begin
  1325. count_leading_zero := 31 - BSRdword( X );
  1326. end;
  1327. {$else not VALREAL_32}
  1328. function count_leading_zero( const X: qword ): integer; {$ifdef grisu1_inline}inline;{$endif}
  1329. begin
  1330. count_leading_zero := 63 - BSRqword( X );
  1331. end;
  1332. {$endif VALREAL_*}
  1333. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  1334. (*-------------------------------------------------------
  1335. | make_frac_mask [local]
  1336. |
  1337. | Makes DIY_FP fractional part mask:
  1338. | result := ( 1 shl one.e ) - 1
  1339. |
  1340. *-------------------------------------------------------*)
  1341. {$ifdef VALREAL_80}
  1342. procedure make_frac_mask( out h: dword; out l: qword; one_e: integer ); {$ifdef grisu1_inline}inline;{$endif}
  1343. {$else VALREAL_128}
  1344. procedure make_frac_mask( out h, l: qword; one_e: integer ); {$ifdef grisu1_inline}inline;{$endif}
  1345. {$endif VALREAL_*}
  1346. begin
  1347. {$ifdef grisu1_debug}
  1348. assert( one_e <= 0 );
  1349. assert( one_e > - ( sizeof( l ) + sizeof( h ) ) * 8 );
  1350. {$endif grisu1_debug}
  1351. if ( one_e <= - 64 ) then
  1352. begin
  1353. l := qword( -1 );
  1354. h := ( {$ifdef VALREAL_128} qword {$else} dword {$endif} ( 1 ) shl ( - one_e - 64 ) ) - 1;
  1355. end
  1356. else
  1357. begin
  1358. l := ( qword( 1 ) shl ( - one_e ) ) - 1;
  1359. h := 0;
  1360. end;
  1361. end;
  1362. {$endif VALREAL_80 | VALREAL_128}
  1363. (*-------------------------------------------------------
  1364. | k_comp [local]
  1365. |
  1366. | Calculates the exp10 of a factor required to bring the binary exponent
  1367. | of the original number into selected [ alpha .. gamma ] range:
  1368. | result := ceiling[ ( alpha - e ) * log10(2) ]
  1369. |
  1370. *-------------------------------------------------------*)
  1371. function k_comp( e, alpha{, gamma}: integer ): integer;
  1372. {$ifdef fpc_softfpu_implementation}
  1373. ///////////////
  1374. //
  1375. // Assuming no HardFloat available.
  1376. // Note: using softfpu here significantly slows down overall
  1377. // conversion performance, so we use integers.
  1378. //
  1379. const
  1380. D_LOG10_2: TDIY_FP = // log10(2) = 0.301029995663981195213738894724493027
  1381. {$ifdef VALREAL_32}
  1382. ( f: dword($9A209A85); e: -33 );
  1383. {$endif}
  1384. {$ifdef VALREAL_64}
  1385. ( f: qword($9A209A84FBCFF799); e: -65 );
  1386. {$endif}
  1387. {$ifdef VALREAL_80}
  1388. ( f: qword($FBCFF7988F8959AC); fh: dword($9A209A84); e: -97 );
  1389. {$endif}
  1390. {$ifdef VALREAL_128}
  1391. ( fh: qword($9A209A84FBCFF798); f: qword($8F8959AC0B7C9178); e: -129 );
  1392. {$endif}
  1393. var
  1394. x, n: integer;
  1395. y, z: TDIY_FP;
  1396. {$ifdef VALREAL_32}
  1397. mask_one: dword;
  1398. {$else not VALREAL_32}
  1399. mask_one: qword;
  1400. {$endif}
  1401. {$ifdef VALREAL_80}
  1402. mask_oneh: dword;
  1403. {$endif}
  1404. {$ifdef VALREAL_128}
  1405. mask_oneh: qword;
  1406. {$endif}
  1407. plus, round_up: boolean;
  1408. begin
  1409. x := alpha - e;
  1410. if ( x = 0 ) then
  1411. begin
  1412. k_comp := 0;
  1413. exit;
  1414. end;
  1415. plus := ( x > 0 );
  1416. if plus then
  1417. y.f := x
  1418. else
  1419. y.f := - x;
  1420. round_up := plus;
  1421. n := C_DIY_FP_Q - 1 - BSRdword( y.f );
  1422. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1423. y.f := y.f shl n;
  1424. {$else VALREAL_80 | VALREAL_128}
  1425. y.fh := 0;
  1426. diy_util_shl( y.fh, y.f, n );
  1427. {$endif VALREAL_*}
  1428. y.e := - n;
  1429. z := diy_fp_multiply( y, D_LOG10_2, false );
  1430. if ( z.e <= - C_DIY_FP_Q ) then
  1431. begin
  1432. round_up := plus and ( 0 <>
  1433. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1434. z.f
  1435. {$else VALREAL_80 | VALREAL_128}
  1436. z.f or z.fh
  1437. {$endif}
  1438. );
  1439. n := 0;
  1440. end
  1441. else
  1442. begin
  1443. if plus then
  1444. begin
  1445. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1446. mask_one := ( {$ifdef VALREAL_64} qword {$else} dword {$endif} ( 1 ) shl ( - z.e ) ) - 1;
  1447. round_up := ( z.f and mask_one <> 0 );
  1448. {$else VALREAL_80 | VALREAL_128}
  1449. make_frac_mask( mask_oneh, mask_one, z.e );
  1450. round_up := ( z.f and mask_one <> 0 ) or ( z.fh and mask_oneh <> 0 );
  1451. {$endif VALREAL_*}
  1452. end;
  1453. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1454. n := z.f shr ( - z.e );
  1455. {$else VALREAL_80 | VALREAL_128}
  1456. diy_util_shr( z.fh, z.f, - z.e );
  1457. n := z.f;
  1458. {$endif VALREAL_*}
  1459. end;
  1460. if not plus then
  1461. n := - n;
  1462. if round_up then
  1463. k_comp := n + 1
  1464. else
  1465. k_comp := n;
  1466. end;
  1467. {$else not fpc_softfpu_implementation}
  1468. ///////////////
  1469. //
  1470. // HardFloat implementation
  1471. //
  1472. {$if defined(SUPPORT_SINGLE) and defined(VALREAL_32)}
  1473. // If available, use single math for VALREAL_32
  1474. var
  1475. dexp: single;
  1476. const
  1477. D_LOG10_2: single =
  1478. {$elseif defined(SUPPORT_DOUBLE) and not defined(VALREAL_32)}
  1479. // If available, use double math for all types >VALREAL_32
  1480. var
  1481. dexp: double;
  1482. const
  1483. D_LOG10_2: double =
  1484. {$else}
  1485. // Use native math
  1486. var
  1487. dexp: ValReal;
  1488. const
  1489. D_LOG10_2: ValReal =
  1490. {$endif}
  1491. 0.301029995663981195213738894724493027; // log10(2)
  1492. var
  1493. x, n: integer;
  1494. begin
  1495. x := alpha - e;
  1496. dexp := x * D_LOG10_2;
  1497. // ceil( dexp )
  1498. n := trunc( dexp );
  1499. if ( x > 0 ) then
  1500. if ( dexp <> n ) then
  1501. inc( n ); // round-up
  1502. k_comp := n;
  1503. end;
  1504. {$endif fpc_softfpu_implementation}
  1505. (****************************************************************************)
  1506. var
  1507. w, D: TDIY_FP;
  1508. c_mk: TDIY_FP_Power_of_10;
  1509. n, mk, dot_pos, n_digits_exp, n_digits_need, n_digits_have: integer;
  1510. n_digits_req, n_digits_sci: integer;
  1511. minus: boolean;
  1512. {$ifndef VALREAL_32}
  1513. fl, one_maskl: qword;
  1514. {$endif not VALREAL_32}
  1515. {$ifdef VALREAL_80}
  1516. templ: qword;
  1517. fh, one_maskh, temph: dword;
  1518. {$endif VALREAL_80}
  1519. {$ifdef VALREAL_128}
  1520. templ: qword;
  1521. fh, one_maskh, temph: qword;
  1522. {$endif VALREAL_128}
  1523. one_e: integer;
  1524. one_mask, f: dword;
  1525. buf: TAsciiDigits;
  1526. begin
  1527. // Limit parameters
  1528. if ( frac_digits > 216 ) then
  1529. frac_digits := 216; // Delphi compatible
  1530. if ( min_width <= C_NO_MIN_WIDTH ) then
  1531. min_width := -1 // no minimal width
  1532. else
  1533. if ( min_width < 0 ) then
  1534. min_width := 0 // minimal width is as short as possible
  1535. else
  1536. if ( min_width > C_MAX_WIDTH ) then
  1537. min_width := C_MAX_WIDTH;
  1538. // Format profile: select "n_digits_need" and "n_digits_exp"
  1539. n_digits_req := float_format[real_type].nDig_mantissa;
  1540. n_digits_exp := float_format[real_type].nDig_exp10;
  1541. // number of digits to be calculated by Grisu
  1542. n_digits_need := float_format[RT_NATIVE].nDig_mantissa;
  1543. if ( n_digits_req < n_digits_need ) then
  1544. n_digits_need := n_digits_req;
  1545. // number of mantissa digits to be printed in exponential notation
  1546. if ( min_width < 0 ) then
  1547. n_digits_sci := n_digits_req
  1548. else
  1549. begin
  1550. n_digits_sci := min_width - 1{sign} - 1{dot} - 1{E} - 1{E-sign} - n_digits_exp;
  1551. if ( n_digits_sci < 2 ) then
  1552. n_digits_sci := 2; // at least 2 digits
  1553. if ( n_digits_sci > n_digits_req ) then
  1554. n_digits_sci := n_digits_req; // at most requested by real_type
  1555. end;
  1556. // Float -> DIY_FP
  1557. w := unpack_float( v, minus );
  1558. // Handle Zero
  1559. if ( w.e = 0 ) and ( w.f {$ifdef VALREAL_128} or w.fh {$endif} = 0 ) then
  1560. begin
  1561. buf[0] := 0; // to avoid "warning: uninitialized"
  1562. if ( frac_digits >= 0 ) then
  1563. if try_return_fixed( str, minus, buf, 0, 1, min_width, frac_digits ) then
  1564. exit
  1565. {$ifdef grisu1_debug}
  1566. else
  1567. assert( FALSE ) // should never fail with these arguments
  1568. {$endif grisu1_debug};
  1569. return_exponential( str, minus, buf, 0, n_digits_sci, 0, n_digits_exp, min_width );
  1570. exit;
  1571. end;
  1572. {$ifdef VALREAL_80}
  1573. // Handle non-normals
  1574. if ( w.e <> 0 ) and ( w.e <> C_EXP2_SPECIAL ) then
  1575. if ( w.f and C_MANT2_INTEGER = 0 ) then
  1576. begin
  1577. // -> QNaN
  1578. w.f := qword(-1);
  1579. w.e := C_EXP2_SPECIAL;
  1580. end;
  1581. {$endif VALREAL_80}
  1582. // Handle specials
  1583. if ( w.e = C_EXP2_SPECIAL ) then
  1584. begin
  1585. if ( min_width < 0 ) then
  1586. // backward compat..
  1587. min_width := float_format[real_type].nDig_mantissa + float_format[real_type].nDig_exp10 + 4;
  1588. n := 1 - ord(minus) * 2; // default special sign [-1|+1]
  1589. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1590. if ( w.f = 0 ) then
  1591. {$endif VALREAL_32 | VALREAL_64}
  1592. {$ifdef VALREAL_80}
  1593. if ( w.f = qword(C_MANT2_INTEGER) ) then
  1594. {$endif VALREAL_80}
  1595. {$ifdef VALREAL_128}
  1596. if ( w.fh or w.f = 0 ) then
  1597. {$endif VALREAL_128}
  1598. begin
  1599. // Inf
  1600. return_special( str, n, C_STR_INF, min_width );
  1601. end
  1602. else
  1603. begin
  1604. // NaN [also pseudo-NaN, pseudo-Inf, non-normal for floatx80]
  1605. {$ifdef GRISU1_F2A_NAN_SIGNLESS}
  1606. n := 0;
  1607. {$endif}
  1608. {$ifndef GRISU1_F2A_NO_SNAN}
  1609. {$ifdef VALREAL_128}
  1610. if ( w.fh and ( C_MANT2_INTEGER_H shr 1 ) = 0 ) then
  1611. {$else}
  1612. if ( w.f and ( C_MANT2_INTEGER shr 1 ) = 0 ) then
  1613. {$endif}
  1614. return_special( str, n, C_STR_SNAN, min_width )
  1615. else
  1616. {$endif GRISU1_F2A_NO_SNAN}
  1617. return_special( str, n, C_STR_QNAN, min_width );
  1618. end;
  1619. exit;
  1620. end;
  1621. // Handle denormals
  1622. if ( w.e <> 0 ) then
  1623. begin
  1624. // normal
  1625. {$ifdef VALREAL_128}
  1626. w.fh := w.fh or C_MANT2_INTEGER_H;
  1627. {$else not VALREAL_128}
  1628. {$ifndef VALREAL_80}
  1629. w.f := w.f or C_MANT2_INTEGER;
  1630. {$endif not VALREAL_80}
  1631. {$endif VALREAL_*}
  1632. n := C_DIY_FP_Q - C_FRAC2_BITS - 1;
  1633. end
  1634. else
  1635. begin
  1636. // denormal
  1637. {$ifdef VALREAL_128}
  1638. if ( w.fh = 0 ) then
  1639. n := count_leading_zero( w.f ) + 64
  1640. else
  1641. n := count_leading_zero( w.fh );
  1642. {$else not VALREAL_128}
  1643. {$ifdef VALREAL_80}
  1644. // also handle pseudo-denormals
  1645. n := count_leading_zero( w.f ) + 32;
  1646. {$else VALREAL_32 | VALREAL_64}
  1647. n := count_leading_zero( w.f );
  1648. {$endif VALREAL_*}
  1649. {$endif VALREAL_*}
  1650. inc( w.e );
  1651. end;
  1652. // Final normalization
  1653. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  1654. w.f := w.f shl n;
  1655. {$else VALREAL_80 | VALREAL_128}
  1656. diy_util_shl( w.fh, w.f, n );
  1657. {$endif VALREAL_*}
  1658. dec( w.e, C_EXP2_BIAS + n + C_FRAC2_BITS );
  1659. //
  1660. // 1. Find the normalized "c_mk = f_c * 2^e_c" such that "alpha <= e_c + e_w + q <= gamma"
  1661. // 2. Define "V = D * 10^k": multiply the input number by "c_mk", do not normalize to land into [ alpha .. gamma ]
  1662. // 3. Generate digits ( n_digits_need + "round" )
  1663. //
  1664. if ( C_GRISU_ALPHA <= w.e ) and ( w.e <= C_GRISU_GAMMA ) then
  1665. begin
  1666. // no scaling required
  1667. D := w;
  1668. c_mk.e10 := 0;
  1669. end
  1670. else
  1671. begin
  1672. mk := k_comp( w.e, C_GRISU_ALPHA{, C_GRISU_GAMMA} );
  1673. diy_fp_cached_power10( mk, c_mk );
  1674. // Let "D = f_D * 2^e_D := w (*) c_mk"
  1675. if c_mk.e10 = 0 then
  1676. D := w
  1677. else
  1678. D := diy_fp_multiply( w, c_mk.c, FALSE );
  1679. end;
  1680. {$ifdef grisu1_debug}
  1681. assert( ( C_GRISU_ALPHA <= D.e ) and ( D.e <= C_GRISU_GAMMA ) );
  1682. {$endif grisu1_debug}
  1683. // Generate digits: integer part
  1684. {$ifdef grisu1_debug}
  1685. {$ifdef VALREAL_80}
  1686. assert( D.e <= 32 );
  1687. {$else not VALREAL_80}
  1688. assert( D.e <= 0 );
  1689. {$endif VALREAL_*}
  1690. {$endif grisu1_debug}
  1691. {$ifdef VALREAL_32}
  1692. n_digits_have := gen_digits_32( buf, 0, D.f shr ( - D.e ) );
  1693. {$endif VALREAL_32}
  1694. {$ifdef VALREAL_64}
  1695. n_digits_have := gen_digits_64( buf, 0, D.f shr ( - D.e ) );
  1696. {$endif VALREAL_64}
  1697. {$ifdef VALREAL_80}
  1698. fl := D.f;
  1699. fh := D.fh;
  1700. if ( D.e > 0 ) then
  1701. begin
  1702. templ := ( qword(fh) shl D.e ) and qword($FFFFFFFF00000000);
  1703. diy_util_shl( fh, fl, D.e );
  1704. inc( templ, fh );
  1705. end
  1706. else
  1707. begin
  1708. diy_util_shr( fh, fl, - D.e );
  1709. templ := fh;
  1710. end;
  1711. {$endif VALREAL_80}
  1712. {$ifdef VALREAL_128}
  1713. fl := D.f;
  1714. templ := D.fh;
  1715. diy_util_shr( templ, fl, - D.e );
  1716. {$endif VALREAL_128}
  1717. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  1718. if ( templ = 0 ) then
  1719. n_digits_have := gen_digits_64( buf, 0, fl )
  1720. else
  1721. begin
  1722. if not u128_div_u64_to_u64( templ, fl, qword(10000000000000000000), templ, fl ) then
  1723. {$ifdef grisu1_debug}
  1724. assert( FALSE ) // never overflows by design
  1725. {$endif grisu1_debug};
  1726. n_digits_have := gen_digits_64( buf, 0, templ );
  1727. inc( n_digits_have, gen_digits_64( buf, n_digits_have, fl, n_digits_have > 0 ) );
  1728. end;
  1729. {$endif VALREAL_80 | VALREAL_128}
  1730. dot_pos := n_digits_have;
  1731. // Generate digits: fractional part
  1732. f := 0; // "sticky" digit
  1733. if ( D.e < 0 ) then
  1734. repeat
  1735. // MOD by ONE
  1736. one_e := D.e;
  1737. {$ifdef VALREAL_32}
  1738. one_mask := dword( 1 ) shl ( - D.e ) - 1;
  1739. f := D.f and one_mask;
  1740. {$endif VALREAL_32}
  1741. {$ifdef VALREAL_64}
  1742. one_maskl := qword( 1 ) shl ( - D.e ) - 1;
  1743. fl := D.f and one_maskl;
  1744. {$endif VALREAL_64}
  1745. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  1746. make_frac_mask( one_maskh, one_maskl, D.e );
  1747. fl := D.f and one_maskl;
  1748. fh := D.fh and one_maskh;
  1749. // 128/96-bit loop
  1750. while ( one_e < -61 ) and ( n_digits_have < n_digits_need + 1 ) and ( fl or fh <> 0 ) do
  1751. begin
  1752. // f := f * 5;
  1753. templ := fl;
  1754. temph := fh;
  1755. diy_util_shl( fh, fl, 2 );
  1756. diy_util_add( fh, fl, temph, templ );
  1757. // one := one / 2
  1758. diy_util_shr( one_maskh, one_maskl, 1 );
  1759. inc( one_e );
  1760. // DIV by one
  1761. templ := fl;
  1762. temph := fh;
  1763. diy_util_shr( temph, templ, - one_e );
  1764. buf[ n_digits_have ] := lo(templ);
  1765. // MOD by one
  1766. fl := fl and one_maskl;
  1767. fh := fh and one_maskh;
  1768. // next
  1769. inc( n_digits_have );
  1770. end;
  1771. if ( n_digits_have >= n_digits_need + 1 ) then
  1772. begin
  1773. // only "sticky" digit remains
  1774. f := ord( fl or fh <> 0 );
  1775. break;
  1776. end;
  1777. {$endif VALREAL_80 | VALREAL_128}
  1778. {$ifndef VALREAL_32}
  1779. // 64-bit loop
  1780. while ( one_e < -29 ) and ( n_digits_have < n_digits_need + 1 ) and ( fl <> 0 ) do
  1781. begin
  1782. // f := f * 5;
  1783. inc( fl, fl shl 2 );
  1784. // one := one / 2
  1785. one_maskl := one_maskl shr 1;
  1786. inc( one_e );
  1787. // DIV by one
  1788. buf[ n_digits_have ] := fl shr ( - one_e );
  1789. // MOD by one
  1790. fl := fl and one_maskl;
  1791. // next
  1792. inc( n_digits_have );
  1793. end;
  1794. if ( n_digits_have >= n_digits_need + 1 ) then
  1795. begin
  1796. // only "sticky" digit remains
  1797. f := ord( fl <> 0 );
  1798. break;
  1799. end;
  1800. one_mask := lo(one_maskl);
  1801. f := lo(fl);
  1802. {$endif not VALREAL_32}
  1803. // 32-bit loop
  1804. while ( n_digits_have < n_digits_need + 1 ) and ( f <> 0 ) do
  1805. begin
  1806. // f := f * 5;
  1807. inc( f, f shl 2 );
  1808. // one := one / 2
  1809. one_mask := one_mask shr 1;
  1810. inc( one_e );
  1811. // DIV by one
  1812. buf[ n_digits_have ] := f shr ( - one_e );
  1813. // MOD by one
  1814. f := f and one_mask;
  1815. // next
  1816. inc( n_digits_have );
  1817. end;
  1818. until true;
  1819. // Append "sticky" digit if any
  1820. if ( f <> 0 ) and ( n_digits_have >= n_digits_need + 1 ) then
  1821. begin
  1822. // single "<>0" digit is enough
  1823. n_digits_have := n_digits_need + 2;
  1824. buf[ n_digits_need + 1 ] := 1;
  1825. end;
  1826. // Round to n_digits_need using "roundTiesToEven"
  1827. if ( n_digits_have > n_digits_need ) then
  1828. inc( dot_pos, round_digits( buf, n_digits_have, n_digits_need ) );
  1829. // Generate output
  1830. if ( frac_digits >= 0 ) then
  1831. if try_return_fixed( str, minus, buf, n_digits_have, dot_pos - c_mk.e10, min_width, frac_digits ) then
  1832. exit;
  1833. if ( n_digits_have > n_digits_sci ) then
  1834. inc( dot_pos, round_digits( buf, n_digits_have, n_digits_sci {$ifdef GRISU1_F2A_HALF_ROUNDUP}, false {$endif} ) );
  1835. return_exponential( str, minus, buf, n_digits_have, n_digits_sci, dot_pos - c_mk.e10 - 1, n_digits_exp, min_width );
  1836. end;
  1837. (****************************************************************************)
  1838. {$ifndef fpc_softfpu_implementation}
  1839. procedure str_real_iso( len, f: longint; d: ValReal; real_type: treal_type; out s:
  1840. shortstring );
  1841. var
  1842. i: integer;
  1843. begin
  1844. str_real( len, f, d, real_type, s );
  1845. for i := length( s ) downto 1 do
  1846. if ( s[i] ='E' ) then
  1847. begin
  1848. s[i] := 'e';
  1849. break; // only one "E" expected
  1850. end;
  1851. end;
  1852. {$endif not fpc_softfpu_implementation}
  1853. (*==========================================================================*
  1854. * *
  1855. * ASCII -> Float *
  1856. * *
  1857. *==========================================================================*)
  1858. function val_real( const src: shortstring; out err_pos: ValSInt ): ValReal;
  1859. {$define VALREAL_PACK}
  1860. {$i flt_pack.inc}
  1861. { NOTE: C_MAX_DIGITS_ACCEPTED should fit into unsigned integer which forms DIY_FP }
  1862. const
  1863. {$ifdef VALREAL_32}
  1864. C_MAX_DIGITS_ACCEPTED = 9;
  1865. C_EXP10_OVER = 100;
  1866. C_DIY_FP_Q = 32;
  1867. C_FRAC2_BITS = 23;
  1868. C_EXP2_BIAS = 127;
  1869. {$endif VALREAL_32}
  1870. {$ifdef VALREAL_64}
  1871. C_MAX_DIGITS_ACCEPTED = 19;
  1872. C_EXP10_OVER = 1000;
  1873. C_DIY_FP_Q = 64;
  1874. C_FRAC2_BITS = 52;
  1875. C_EXP2_BIAS = 1023;
  1876. {$endif VALREAL_64}
  1877. {$ifdef VALREAL_80}
  1878. C_MAX_DIGITS_ACCEPTED = 28;
  1879. C_EXP10_OVER = 10000;
  1880. C_DIY_FP_Q = 96;
  1881. C_FRAC2_BITS = 63;
  1882. C_EXP2_BIAS = 16383;
  1883. {$endif VALREAL_80}
  1884. {$ifdef VALREAL_128}
  1885. C_MAX_DIGITS_ACCEPTED = 38;
  1886. C_EXP10_OVER = 10000;
  1887. C_DIY_FP_Q = 128;
  1888. C_FRAC2_BITS = 112;
  1889. C_EXP2_BIAS = 16383;
  1890. {$endif VALREAL_128}
  1891. (****************************************************************************)
  1892. // handy const
  1893. C_EXP2_SPECIAL = C_EXP2_BIAS * 2 + 1;
  1894. C_DIY_SHR_TO_FLT = C_DIY_FP_Q - 1 - C_FRAC2_BITS;
  1895. C_DIY_EXP_TO_FLT = C_DIY_FP_Q - 1 + C_EXP2_BIAS;
  1896. C_DIY_ROUND_BIT = 1 shl ( C_DIY_SHR_TO_FLT - 1 );
  1897. C_DIY_ROUND_MASK = ( C_DIY_ROUND_BIT shl 2 ) - 1;
  1898. {$ifdef VALREAL_128}
  1899. C_FLT_INT_BITh = qword(1) shl ( C_FRAC2_BITS - 64 );
  1900. C_FLT_FRAC_MASKh = C_FLT_INT_BITh - 1;
  1901. {$else not VALREAL_128}
  1902. {$ifdef VALREAL_32}
  1903. C_FLT_INT_BIT = dword(1) shl C_FRAC2_BITS;
  1904. C_FLT_FRAC_MASK = C_FLT_INT_BIT - 1;
  1905. {$else VALREAL_64 | VALREAL_80}
  1906. C_FLT_INT_BIT = qword(1) shl C_FRAC2_BITS;
  1907. C_FLT_FRAC_MASK = qword(C_FLT_INT_BIT) - 1;
  1908. {$endif VALREAL_*}
  1909. {$endif VALREAL_*}
  1910. // specials
  1911. {$ifdef VALREAL_32}
  1912. C_FLT_MANT_INF = dword($00000000);
  1913. {$ifndef GRISU1_A2F_NO_SNAN}
  1914. C_FLT_MANT_SNAN = dword($00200000);
  1915. {$endif GRISU1_A2F_NO_SNAN}
  1916. C_FLT_MANT_QNAN = dword($00400000);
  1917. {$endif VALREAL_32}
  1918. {$ifdef VALREAL_64}
  1919. C_FLT_MANT_INF = qword($0000000000000000);
  1920. {$ifndef GRISU1_A2F_NO_SNAN}
  1921. C_FLT_MANT_SNAN = qword($0004000000000000);
  1922. {$endif GRISU1_A2F_NO_SNAN}
  1923. C_FLT_MANT_QNAN = qword($0008000000000000);
  1924. {$endif VALREAL_64}
  1925. {$ifdef VALREAL_80}
  1926. C_FLT_MANT_INF = qword($8000000000000000);
  1927. {$ifndef GRISU1_A2F_NO_SNAN}
  1928. C_FLT_MANT_SNAN = qword($A000000000000000);
  1929. {$endif GRISU1_A2F_NO_SNAN}
  1930. C_FLT_MANT_QNAN = qword($C000000000000000);
  1931. {$endif VALREAL_80}
  1932. {$ifdef VALREAL_128}
  1933. C_FLT_MANT_INFh = qword($0000000000000000);
  1934. C_FLT_MANT_INF = qword($0000000000000000);
  1935. {$ifndef GRISU1_A2F_NO_SNAN}
  1936. C_FLT_MANT_SNANh = qword($0000400000000000);
  1937. C_FLT_MANT_SNAN = qword($0000000000000000);
  1938. {$endif GRISU1_A2F_NO_SNAN}
  1939. C_FLT_MANT_QNANh = qword($0000800000000000);
  1940. C_FLT_MANT_QNAN = qword($0000000000000000);
  1941. {$endif VALREAL_128}
  1942. (*-------------------------------------------------------
  1943. | factor_10_inexact [local]
  1944. |
  1945. | Calculates an arbitrary normalized power of 10 required for final scaling.
  1946. | The result of this calculation may be off by several ulp's from exact.
  1947. |
  1948. | Returns an overflow/underflow status:
  1949. | "<0": underflow
  1950. | "=0": ok
  1951. | ">0": overflow
  1952. |
  1953. *-------------------------------------------------------*)
  1954. function factor_10_inexact( const exp10: integer; out C: TDIY_FP_Power_of_10 ): integer;
  1955. const
  1956. {$ifdef VALREAL_32}
  1957. factor: array [ 0 .. 7 ] of TDIY_FP_Power_of_10 = (
  1958. ( c: ( f: $80000000; e: -31); e10: 0 ),
  1959. ( c: ( f: $CCCCCCCD; e: -35); e10: -1 ),
  1960. ( c: ( f: $A3D70A3D; e: -38); e10: -2 ),
  1961. ( c: ( f: $83126E98; e: -41); e10: -3 ),
  1962. ( c: ( f: $D1B71759; e: -45); e10: -4 ),
  1963. ( c: ( f: $A7C5AC47; e: -48); e10: -5 ),
  1964. ( c: ( f: $8637BD06; e: -51); e10: -6 ),
  1965. ( c: ( f: $D6BF94D6; e: -55); e10: -7 )
  1966. );
  1967. {$endif VALREAL_32}
  1968. {$ifdef VALREAL_64}
  1969. factor: array [ 0 .. 17 ] of TDIY_FP_Power_of_10 = (
  1970. ( c: ( f: qword($8000000000000000); e: -63); e10: 0 ),
  1971. ( c: ( f: qword($CCCCCCCCCCCCCCCD); e: -67); e10: -1 ),
  1972. ( c: ( f: qword($A3D70A3D70A3D70A); e: -70); e10: -2 ),
  1973. ( c: ( f: qword($83126E978D4FDF3B); e: -73); e10: -3 ),
  1974. ( c: ( f: qword($D1B71758E219652C); e: -77); e10: -4 ),
  1975. ( c: ( f: qword($A7C5AC471B478423); e: -80); e10: -5 ),
  1976. ( c: ( f: qword($8637BD05AF6C69B6); e: -83); e10: -6 ),
  1977. ( c: ( f: qword($D6BF94D5E57A42BC); e: -87); e10: -7 ),
  1978. ( c: ( f: qword($ABCC77118461CEFD); e: -90); e10: -8 ),
  1979. ( c: ( f: qword($89705F4136B4A597); e: -93); e10: -9 ),
  1980. ( c: ( f: qword($DBE6FECEBDEDD5BF); e: -97); e10: -10 ),
  1981. ( c: ( f: qword($AFEBFF0BCB24AAFF); e: -100); e10: -11 ),
  1982. ( c: ( f: qword($8CBCCC096F5088CC); e: -103); e10: -12 ),
  1983. ( c: ( f: qword($E12E13424BB40E13); e: -107); e10: -13 ),
  1984. ( c: ( f: qword($B424DC35095CD80F); e: -110); e10: -14 ),
  1985. ( c: ( f: qword($901D7CF73AB0ACD9); e: -113); e10: -15 ),
  1986. ( c: ( f: qword($E69594BEC44DE15B); e: -117); e10: -16 ),
  1987. ( c: ( f: qword($B877AA3236A4B449); e: -120); e10: -17 )
  1988. );
  1989. {$endif VALREAL_64}
  1990. {$ifdef VALREAL_80}
  1991. factor: array [ 0 .. 36 ] of TDIY_FP_Power_of_10 = (
  1992. ( c: ( f: qword($0000000000000000); fh: dword($80000000); e: -95 ); e10: 0 ),
  1993. ( c: ( f: qword($CCCCCCCCCCCCCCCD); fh: dword($CCCCCCCC); e: -99 ); e10: -1 ),
  1994. ( c: ( f: qword($70A3D70A3D70A3D7); fh: dword($A3D70A3D); e: -102 ); e10: -2 ),
  1995. ( c: ( f: qword($8D4FDF3B645A1CAC); fh: dword($83126E97); e: -105 ); e10: -3 ),
  1996. ( c: ( f: qword($E219652BD3C36113); fh: dword($D1B71758); e: -109 ); e10: -4 ),
  1997. ( c: ( f: qword($1B4784230FCF80DC); fh: dword($A7C5AC47); e: -112 ); e10: -5 ),
  1998. ( c: ( f: qword($AF6C69B5A63F9A4A); fh: dword($8637BD05); e: -115 ); e10: -6 ),
  1999. ( c: ( f: qword($E57A42BC3D329076); fh: dword($D6BF94D5); e: -119 ); e10: -7 ),
  2000. ( c: ( f: qword($8461CEFCFDC20D2B); fh: dword($ABCC7711); e: -122 ); e10: -8 ),
  2001. ( c: ( f: qword($36B4A59731680A89); fh: dword($89705F41); e: -125 ); e10: -9 ),
  2002. ( c: ( f: qword($BDEDD5BEB573440E); fh: dword($DBE6FECE); e: -129 ); e10: -10 ),
  2003. ( c: ( f: qword($CB24AAFEF78F69A5); fh: dword($AFEBFF0B); e: -132 ); e10: -11 ),
  2004. ( c: ( f: qword($6F5088CBF93F87B7); fh: dword($8CBCCC09); e: -135 ); e10: -12 ),
  2005. ( c: ( f: qword($4BB40E132865A5F2); fh: dword($E12E1342); e: -139 ); e10: -13 ),
  2006. ( c: ( f: qword($095CD80F538484C2); fh: dword($B424DC35); e: -142 ); e10: -14 ),
  2007. ( c: ( f: qword($3AB0ACD90F9D3701); fh: dword($901D7CF7); e: -145 ); e10: -15 ),
  2008. ( c: ( f: qword($C44DE15B4C2EBE68); fh: dword($E69594BE); e: -149 ); e10: -16 ),
  2009. ( c: ( f: qword($36A4B44909BEFEBA); fh: dword($B877AA32); e: -152 ); e10: -17 ),
  2010. ( c: ( f: qword($921D5D073AFF322E); fh: dword($9392EE8E); e: -155 ); e10: -18 ),
  2011. ( c: ( f: qword($B69561A52B31E9E4); fh: dword($EC1E4A7D); e: -159 ); e10: -19 ),
  2012. ( c: ( f: qword($92111AEA88F4BB1D); fh: dword($BCE50864); e: -162 ); e10: -20 ),
  2013. ( c: ( f: qword($74DA7BEED3F6FC17); fh: dword($971DA050); e: -165 ); e10: -21 ),
  2014. ( c: ( f: qword($BAF72CB15324C68B); fh: dword($F1C90080); e: -169 ); e10: -22 ),
  2015. ( c: ( f: qword($95928A2775B7053C); fh: dword($C16D9A00); e: -172 ); e10: -23 ),
  2016. ( c: ( f: qword($44753B52C4926A96); fh: dword($9ABE14CD); e: -175 ); e10: -24 ),
  2017. ( c: ( f: qword($D3EEC5513A83DDBE); fh: dword($F79687AE); e: -179 ); e10: -25 ),
  2018. ( c: ( f: qword($76589DDA95364AFE); fh: dword($C6120625); e: -182 ); e10: -26 ),
  2019. ( c: ( f: qword($91E07E48775EA265); fh: dword($9E74D1B7); e: -185 ); e10: -27 ),
  2020. ( c: ( f: qword($8300CA0D8BCA9D6E); fh: dword($FD87B5F2); e: -189 ); e10: -28 ),
  2021. ( c: ( f: qword($359A3B3E096EE458); fh: dword($CAD2F7F5); e: -192 ); e10: -29 ),
  2022. ( c: ( f: qword($5E14FC31A125837A); fh: dword($A2425FF7); e: -195 ); e10: -30 ),
  2023. ( c: ( f: qword($4B43FCF480EACF95); fh: dword($81CEB32C); e: -198 ); e10: -31 ),
  2024. ( c: ( f: qword($453994BA67DE18EE); fh: dword($CFB11EAD); e: -202 ); e10: -32 ),
  2025. ( c: ( f: qword($D0FADD61ECB1AD8B); fh: dword($A6274BBD); e: -205 ); e10: -33 ),
  2026. ( c: ( f: qword($DA624AB4BD5AF13C); fh: dword($84EC3C97); e: -208 ); e10: -34 ),
  2027. ( c: ( f: qword($C3D07787955E4EC6); fh: dword($D4AD2DBF); e: -212 ); e10: -35 ),
  2028. ( c: ( f: qword($697392D2DDE50BD2); fh: dword($AA242499); e: -215 ); e10: -36 )
  2029. );
  2030. {$endif VALREAL_80}
  2031. {$ifdef VALREAL_128}
  2032. factor: array [ 0 .. 36 ] of TDIY_FP_Power_of_10 = (
  2033. ( c: ( fh: qword($8000000000000000); f: qword($0000000000000000); e: -127 ); e10: 0 ),
  2034. ( c: ( fh: qword($CCCCCCCCCCCCCCCC); f: qword($CCCCCCCCCCCCCCCD); e: -131 ); e10: -1 ),
  2035. ( c: ( fh: qword($A3D70A3D70A3D70A); f: qword($3D70A3D70A3D70A4); e: -134 ); e10: -2 ),
  2036. ( c: ( fh: qword($83126E978D4FDF3B); f: qword($645A1CAC083126E9); e: -137 ); e10: -3 ),
  2037. ( c: ( fh: qword($D1B71758E219652B); f: qword($D3C36113404EA4A9); e: -141 ); e10: -4 ),
  2038. ( c: ( fh: qword($A7C5AC471B478423); f: qword($0FCF80DC33721D54); e: -144 ); e10: -5 ),
  2039. ( c: ( fh: qword($8637BD05AF6C69B5); f: qword($A63F9A49C2C1B110); e: -147 ); e10: -6 ),
  2040. ( c: ( fh: qword($D6BF94D5E57A42BC); f: qword($3D32907604691B4D); e: -151 ); e10: -7 ),
  2041. ( c: ( fh: qword($ABCC77118461CEFC); f: qword($FDC20D2B36BA7C3D); e: -154 ); e10: -8 ),
  2042. ( c: ( fh: qword($89705F4136B4A597); f: qword($31680A88F8953031); e: -157 ); e10: -9 ),
  2043. ( c: ( fh: qword($DBE6FECEBDEDD5BE); f: qword($B573440E5A884D1B); e: -161 ); e10: -10 ),
  2044. ( c: ( fh: qword($AFEBFF0BCB24AAFE); f: qword($F78F69A51539D749); e: -164 ); e10: -11 ),
  2045. ( c: ( fh: qword($8CBCCC096F5088CB); f: qword($F93F87B7442E45D4); e: -167 ); e10: -12 ),
  2046. ( c: ( fh: qword($E12E13424BB40E13); f: qword($2865A5F206B06FBA); e: -171 ); e10: -13 ),
  2047. ( c: ( fh: qword($B424DC35095CD80F); f: qword($538484C19EF38C94); e: -174 ); e10: -14 ),
  2048. ( c: ( fh: qword($901D7CF73AB0ACD9); f: qword($0F9D37014BF60A10); e: -177 ); e10: -15 ),
  2049. ( c: ( fh: qword($E69594BEC44DE15B); f: qword($4C2EBE687989A9B4); e: -181 ); e10: -16 ),
  2050. ( c: ( fh: qword($B877AA3236A4B449); f: qword($09BEFEB9FAD487C3); e: -184 ); e10: -17 ),
  2051. ( c: ( fh: qword($9392EE8E921D5D07); f: qword($3AFF322E62439FCF); e: -187 ); e10: -18 ),
  2052. ( c: ( fh: qword($EC1E4A7DB69561A5); f: qword($2B31E9E3D06C32E5); e: -191 ); e10: -19 ),
  2053. ( c: ( fh: qword($BCE5086492111AEA); f: qword($88F4BB1CA6BCF584); e: -194 ); e10: -20 ),
  2054. ( c: ( fh: qword($971DA05074DA7BEE); f: qword($D3F6FC16EBCA5E03); e: -197 ); e10: -21 ),
  2055. ( c: ( fh: qword($F1C90080BAF72CB1); f: qword($5324C68B12DD6338); e: -201 ); e10: -22 ),
  2056. ( c: ( fh: qword($C16D9A0095928A27); f: qword($75B7053C0F178294); e: -204 ); e10: -23 ),
  2057. ( c: ( fh: qword($9ABE14CD44753B52); f: qword($C4926A9672793543); e: -207 ); e10: -24 ),
  2058. ( c: ( fh: qword($F79687AED3EEC551); f: qword($3A83DDBD83F52205); e: -211 ); e10: -25 ),
  2059. ( c: ( fh: qword($C612062576589DDA); f: qword($95364AFE032A819D); e: -214 ); e10: -26 ),
  2060. ( c: ( fh: qword($9E74D1B791E07E48); f: qword($775EA264CF55347E); e: -217 ); e10: -27 ),
  2061. ( c: ( fh: qword($FD87B5F28300CA0D); f: qword($8BCA9D6E188853FC); e: -221 ); e10: -28 ),
  2062. ( c: ( fh: qword($CAD2F7F5359A3B3E); f: qword($096EE45813A04330); e: -224 ); e10: -29 ),
  2063. ( c: ( fh: qword($A2425FF75E14FC31); f: qword($A1258379A94D028D); e: -227 ); e10: -30 ),
  2064. ( c: ( fh: qword($81CEB32C4B43FCF4); f: qword($80EACF948770CED7); e: -230 ); e10: -31 ),
  2065. ( c: ( fh: qword($CFB11EAD453994BA); f: qword($67DE18EDA5814AF2); e: -234 ); e10: -32 ),
  2066. ( c: ( fh: qword($A6274BBDD0FADD61); f: qword($ECB1AD8AEACDD58E); e: -237 ); e10: -33 ),
  2067. ( c: ( fh: qword($84EC3C97DA624AB4); f: qword($BD5AF13BEF0B113F); e: -240 ); e10: -34 ),
  2068. ( c: ( fh: qword($D4AD2DBFC3D07787); f: qword($955E4EC64B44E864); e: -244 ); e10: -35 ),
  2069. ( c: ( fh: qword($AA242499697392D2); f: qword($DDE50BD1D5D0B9EA); e: -247 ); e10: -36 )
  2070. );
  2071. {$endif VALREAL_128}
  2072. var
  2073. i: integer;
  2074. a, b: TDIY_FP_Power_of_10;
  2075. begin
  2076. diy_fp_cached_power10( exp10, a );
  2077. i := a.e10 - exp10;
  2078. if ( i < 0 ) then
  2079. begin
  2080. factor_10_inexact := 1; // overflow
  2081. exit;
  2082. end;
  2083. if ( i > high( factor ) ) then
  2084. begin
  2085. factor_10_inexact := -1; // underflow
  2086. exit;
  2087. end;
  2088. b := factor[i];
  2089. {$ifdef grisu1_debug}
  2090. assert( exp10 = a.e10 + b.e10 );
  2091. {$endif grisu1_debug}
  2092. if ( b.e10 = 0 ) then
  2093. C := a
  2094. else
  2095. if ( a.e10 = 0 ) then
  2096. C := b
  2097. else
  2098. begin
  2099. C.c := diy_fp_multiply( a.c, b.c, TRUE );
  2100. c.e10 := exp10;
  2101. end;
  2102. factor_10_inexact := 0; // no error
  2103. end;
  2104. (*-------------------------------------------------------
  2105. | add_digit [local]
  2106. |
  2107. | This helper routine performs next digit addition:
  2108. | X := X * 10 + digit
  2109. |
  2110. *-------------------------------------------------------*)
  2111. {$ifdef VALREAL_80}
  2112. procedure add_digit( var h: dword; var l: qword; digit: byte ); {$ifdef grisu1_inline}inline;{$endif}
  2113. var
  2114. temp1, temp2: qword;
  2115. begin
  2116. //
  2117. temp1 := lo(l);
  2118. inc( temp1, ( temp1 shl 3 ) + temp1 + digit );
  2119. //
  2120. temp2 := h;
  2121. temp2 := ( temp2 shl 32 ) + hi(l);
  2122. inc( temp2, ( temp2 shl 3 ) + temp2 + hi(temp1) );
  2123. //
  2124. h := hi(temp2);
  2125. l := ( temp2 shl 32 ) + lo(temp1);
  2126. //
  2127. end;
  2128. {$endif VALREAL_80}
  2129. {$ifdef VALREAL_128}
  2130. procedure add_digit( var h, l: qword; digit: byte ); {$ifdef grisu1_inline}inline;{$endif}
  2131. var
  2132. templ, temph, temp1, temp2: qword;
  2133. begin
  2134. templ := l;
  2135. temph := h;
  2136. diy_util_shl( temph, templ, 3 );
  2137. //
  2138. temp1 := lo(l);
  2139. inc( temp1, lo(templ) + temp1 + digit );
  2140. //
  2141. temp2 := hi(l);
  2142. inc( temp2, hi(templ) + temp2 + hi(temp1) );
  2143. //
  2144. inc( h, temph + h + hi(temp2) );
  2145. l := ( temp2 shl 32 ) + lo(temp1);
  2146. //
  2147. end;
  2148. {$endif VALREAL_128}
  2149. (*-------------------------------------------------------
  2150. | count_leading_zero [local] <<<duplicate>>>
  2151. |
  2152. | Counts number of 0-bits at most significant bit position.
  2153. |
  2154. *-------------------------------------------------------*)
  2155. {$if defined(VALREAL_32) or defined(VALREAL_80)}
  2156. function count_leading_zero( const X: dword ): integer; {$ifdef grisu1_inline}inline;{$endif}
  2157. begin
  2158. count_leading_zero := 31 - BSRdword( X );
  2159. end;
  2160. {$endif VALREAL_32 | VALREAL_80}
  2161. {$ifndef VALREAL_32}
  2162. function count_leading_zero( const X: qword ): integer; {$ifdef grisu1_inline}inline;{$endif}
  2163. begin
  2164. count_leading_zero := 63 - BSRqword( X );
  2165. end;
  2166. {$endif not VALREAL_32}
  2167. (*-------------------------------------------------------
  2168. | match_special [local]
  2169. |
  2170. | Routine compares source string tail with the string representing
  2171. | one of special values: Inf | QNaN | SNaN
  2172. |
  2173. *-------------------------------------------------------*)
  2174. function match_special( src_pos: integer; const src, spec: shortstring ): boolean;
  2175. var
  2176. sl, xl: integer;
  2177. begin
  2178. match_special := false;
  2179. xl := length( src );
  2180. sl := length( spec );
  2181. if ( sl <> xl - src_pos + 1 ) then
  2182. exit;
  2183. {$ifdef grisu1_debug}
  2184. assert( sl > 0 );
  2185. {$endif grisu1_debug}
  2186. repeat
  2187. if ( UpCase( src[xl] ) <> UpCase( spec[sl] ) ) then
  2188. exit;
  2189. dec( xl );
  2190. dec( sl );
  2191. until sl <= 0;
  2192. match_special := true;
  2193. end;
  2194. (****************************************************************************)
  2195. var
  2196. a: AnsiChar;
  2197. mantissa, bit_round, bit_round_mask: {$ifdef VALREAL_32} dword {$else} qword {$endif};
  2198. {$ifdef VALREAL_80}
  2199. mantissa_h: dword;
  2200. {$endif}
  2201. {$ifdef VALREAL_128}
  2202. mantissa_h, bit_round_h, bit_round_mask_h: qword;
  2203. {$endif}
  2204. dig_num, exp10, overflow, n, src_pos, src_len: integer;
  2205. exp_read, exp_temp: longint;
  2206. b, dig_round, dig_sticky: byte;
  2207. minus, exp_minus, special: boolean;
  2208. C: TDIY_FP_Power_of_10;
  2209. D: TDIY_FP;
  2210. begin
  2211. err_pos := 1;
  2212. src_pos := 1;
  2213. src_len := length(src);
  2214. // Pre-initialize result
  2215. {$ifdef GRISU1_A2F_ERROR_RET0}
  2216. pack_float( val_real, false, 0, {$ifdef VALREAL_128} 0, {$endif} 0 );
  2217. {$else}
  2218. {-ifdef GRISU1_A2F_NO_SNAN}
  2219. // "real indefinite"
  2220. pack_float( val_real, true, C_EXP2_SPECIAL, {$ifdef VALREAL_128} C_FLT_MANT_QNANh, {$endif} C_FLT_MANT_QNAN );
  2221. (*{-else}
  2222. // SNaN is preferable for catching uninitialized variables access, but may cause troubles with implicit float type conversions
  2223. pack_float( val_real, false, C_EXP2_SPECIAL, {$ifdef VALREAL_128} C_FLT_MANT_SNANh, {$endif} C_FLT_MANT_SNAN );
  2224. {-endif}*)
  2225. {$endif}
  2226. // search for a sign skipping leading spaces
  2227. minus := false;
  2228. while ( src_pos <= src_len ) do
  2229. begin
  2230. a := src[src_pos];
  2231. case a of
  2232. '+':
  2233. begin
  2234. inc( src_pos );
  2235. break;
  2236. end;
  2237. '-':
  2238. begin
  2239. minus := true;
  2240. inc( src_pos );
  2241. break;
  2242. end;
  2243. else
  2244. if a <> ' ' then
  2245. break;
  2246. end;
  2247. inc( src_pos );
  2248. end;
  2249. if ( src_pos > src_len ) then
  2250. begin
  2251. // syntax: nothing to evaluate
  2252. err_pos := src_pos;
  2253. exit;
  2254. end;
  2255. // handle specials
  2256. case src[src_pos] of
  2257. '0' .. '9', '.', 'E', 'e': special := false;
  2258. else
  2259. special := true;
  2260. end;
  2261. if special then
  2262. begin
  2263. mantissa := C_FLT_MANT_INF;
  2264. {$ifdef VALREAL_128}
  2265. mantissa_h := C_FLT_MANT_INFh;
  2266. {$endif}
  2267. if not match_special( src_pos, src, C_STR_INF ) then
  2268. begin
  2269. {$ifndef GRISU1_A2F_NO_SNAN}
  2270. if match_special( src_pos, src, C_STR_SNAN ) then
  2271. begin
  2272. mantissa := C_FLT_MANT_SNAN;
  2273. {$ifdef VALREAL_128}
  2274. mantissa_h := C_FLT_MANT_SNANh;
  2275. {$endif}
  2276. end
  2277. else
  2278. {$endif GRISU1_A2F_NO_SNAN}
  2279. if match_special( src_pos, src, C_STR_QNAN ) then
  2280. begin
  2281. {$ifdef GRISU1_A2F_QNAN_REAL_INDEFINITE}
  2282. minus := TRUE;
  2283. {$endif}
  2284. mantissa := C_FLT_MANT_QNAN;
  2285. {$ifdef VALREAL_128}
  2286. mantissa_h := C_FLT_MANT_QNANh;
  2287. {$endif}
  2288. end
  2289. else
  2290. special := false;
  2291. end;
  2292. if special then
  2293. begin
  2294. pack_float( val_real, minus, C_EXP2_SPECIAL, {$ifdef VALREAL_128} mantissa_h, {$endif} mantissa );
  2295. src_pos := 0;
  2296. end;
  2297. err_pos := src_pos;
  2298. exit;
  2299. end;
  2300. // consume mantissa digits skipping leading zeroes
  2301. // empty mantissa ("0.E#", ".0E#", ".E#", "E#") is allowed at least in D5
  2302. mantissa := 0;
  2303. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  2304. mantissa_h := 0;
  2305. {$endif VALREAL_80 | VALREAL_128}
  2306. dig_num := 0;
  2307. exp10 := 0;
  2308. dig_round := 0;
  2309. dig_sticky := 0;
  2310. // leading zero loop
  2311. while ( src_pos <= src_len ) and ( src[src_pos] = '0' ) do
  2312. inc( src_pos );
  2313. // integer part loop
  2314. while ( src_pos <= src_len ) do
  2315. begin
  2316. a := src[src_pos];
  2317. if ( a < '0' ) or ( a > '9' ) then
  2318. break;
  2319. b := ord(a) - ord('0');
  2320. if ( dig_num < C_MAX_DIGITS_ACCEPTED ) then
  2321. // normal digit
  2322. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  2323. inc( mantissa, ( mantissa shl 3 ) + mantissa + b )
  2324. {$else VALREAL_80 | VALREAL_128}
  2325. add_digit( mantissa_h, mantissa, b )
  2326. {$endif VALREAL_*}
  2327. else
  2328. begin
  2329. // over-required digits: use them for rounding later
  2330. if ( dig_num = C_MAX_DIGITS_ACCEPTED ) then
  2331. dig_round := b // main digit for rounding
  2332. else
  2333. dig_sticky := dig_sticky or b; // just "<>0" to judge "round to even" case later
  2334. inc( exp10 ); // move [yet virtual] dot to the right
  2335. end;
  2336. inc( dig_num );
  2337. inc( src_pos );
  2338. end;
  2339. // fraction part
  2340. if ( src_pos <= src_len ) and ( src[src_pos] = '.' ) then
  2341. begin
  2342. // skip dot
  2343. inc( src_pos );
  2344. // leading zero loop, if integer part was 0
  2345. if dig_num = 0 then
  2346. while ( src_pos <= src_len ) and ( src[src_pos] = '0' ) do
  2347. begin
  2348. dec( exp10 ); // move the dot to the left
  2349. inc( src_pos );
  2350. end;
  2351. // fraction part loop
  2352. while ( src_pos <= src_len ) do
  2353. begin
  2354. a := src[src_pos];
  2355. if ( a < '0' ) or ( a > '9' ) then
  2356. break;
  2357. b := ord(a) - ord('0');
  2358. if ( dig_num < C_MAX_DIGITS_ACCEPTED ) then
  2359. begin
  2360. // normal digit
  2361. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  2362. inc( mantissa, ( mantissa shl 3 ) + mantissa + b );
  2363. {$else VALREAL_80 | VALREAL_128}
  2364. add_digit( mantissa_h, mantissa, b );
  2365. {$endif VALREAL_*}
  2366. dec( exp10 ); // move the dot to the left
  2367. end
  2368. else
  2369. begin
  2370. // over-required digits: use them for rounding later
  2371. if ( dig_num = C_MAX_DIGITS_ACCEPTED ) then
  2372. dig_round := b // main digit for rounding
  2373. else
  2374. dig_sticky := dig_sticky or b; // just "<>0" to judge "round to even" case later
  2375. end;
  2376. inc( dig_num );
  2377. inc( src_pos );
  2378. end;
  2379. end;
  2380. // round digits
  2381. {$ifndef GRISU1_A2F_HALF_ROUNDUP}
  2382. if ( dig_round = 5 ) and ( dig_sticky = 0 ) and ( mantissa and 1 = 0 ) then
  2383. // need to "round to even", and already even..
  2384. dec( dig_round ); // ..so force no round-up
  2385. {$endif not GRISU1_A2F_HALF_ROUNDUP}
  2386. if ( dig_round >= 5 ) then
  2387. begin
  2388. // round-up
  2389. inc( mantissa );
  2390. {$if defined(VALREAL_80) or defined(VALREAL_128)}
  2391. if ( mantissa = 0 ) then
  2392. inc( mantissa_h );
  2393. {$endif VALREAL_*}
  2394. end;
  2395. // consume exponent digits
  2396. exp_read := 0;
  2397. if ( src_pos <= src_len ) then
  2398. begin
  2399. exp_minus := false;
  2400. case src[src_pos] of
  2401. 'e', 'E':;
  2402. else
  2403. // syntax: "E" expected
  2404. err_pos := src_pos;
  2405. exit;
  2406. end;
  2407. inc( src_pos );
  2408. if ( src_pos > src_len ) then
  2409. begin
  2410. // syntax: empty exponent
  2411. err_pos := src_pos;
  2412. exit;
  2413. end;
  2414. case src[src_pos] of
  2415. '+':
  2416. inc( src_pos );
  2417. '-':
  2418. begin
  2419. exp_minus := true;
  2420. inc( src_pos );
  2421. end;
  2422. end;
  2423. while ( src_pos <= src_len ) do
  2424. begin
  2425. a := src[src_pos];
  2426. if ( a < '0' ) or ( a > '9' ) then
  2427. begin
  2428. // syntax: bad digit
  2429. err_pos := src_pos;
  2430. exit;
  2431. end;
  2432. if ( exp_read < 100000 ) then
  2433. inc( exp_read, ( exp_read shl 3 ) + exp_read + ord(a) - ord('0') );
  2434. // else just syntax check
  2435. inc( src_pos );
  2436. end;
  2437. if exp_minus then
  2438. exp_read := - exp_read;
  2439. end;
  2440. exp_temp := exp_read + exp10;
  2441. if ( exp_read >= 100000 ) or ( exp_temp >= C_EXP10_OVER ) then
  2442. exp10 := C_EXP10_OVER
  2443. else
  2444. if ( exp_read <= - 100000 ) or ( exp_temp <= - C_EXP10_OVER ) then
  2445. exp10 := - C_EXP10_OVER
  2446. else
  2447. exp10 := exp_temp;
  2448. // nothing should remain in the "src" here
  2449. if ( src_pos <= src_len ) then
  2450. begin
  2451. err_pos := src_pos;
  2452. exit;
  2453. end;
  2454. // zero [or negative exponent overflow]
  2455. if ( mantissa {$if defined(VALREAL_80) or defined(VALREAL_128)} or mantissa_h {$endif} = 0 )
  2456. or ( exp10 <= - C_EXP10_OVER ) then
  2457. begin
  2458. pack_float( val_real, minus, 0, {$ifdef VALREAL_128} 0, {$endif} 0 ); // +0|-0
  2459. err_pos := 0;
  2460. exit;
  2461. end;
  2462. if ( exp10 >= C_EXP10_OVER ) then
  2463. // exponent overflowed -> return Inf
  2464. overflow := 1
  2465. else
  2466. begin
  2467. // make DIY_FP
  2468. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  2469. n := count_leading_zero( mantissa );
  2470. D.f := mantissa shl n;
  2471. {$else VALREAL_80 | VALREAL_128}
  2472. if ( mantissa_h = 0 ) then
  2473. n := count_leading_zero( mantissa ) + sizeof( mantissa_h ) * 8
  2474. else
  2475. n := count_leading_zero( mantissa_h );
  2476. D.f := mantissa;
  2477. D.fh := mantissa_h;
  2478. diy_util_shl( D.fh, D.f, n );
  2479. {$endif VALREAL_*}
  2480. D.e := - n;
  2481. // get factor
  2482. overflow := factor_10_inexact( exp10, C ); // <>0 -> over/underflow
  2483. end;
  2484. if ( overflow = 0 ) then
  2485. begin
  2486. // multiply
  2487. if ( C.e10 <> 0 ) then
  2488. // C <> 1
  2489. D := diy_fp_multiply( D, C.c, TRUE );
  2490. // calculate round increment
  2491. if ( D.f and C_DIY_ROUND_MASK = C_DIY_ROUND_BIT ) then
  2492. // round to even and already even
  2493. b := 0
  2494. else
  2495. b := ord( D.f and C_DIY_ROUND_BIT <> 0 );
  2496. // shift and round
  2497. {$if defined(VALREAL_32) or defined(VALREAL_64)}
  2498. D.f := ( D.f shr C_DIY_SHR_TO_FLT ) + b;
  2499. // handle round overflow
  2500. if ( D.f and ( C_FLT_INT_BIT shl 1 ) <> 0 ) then
  2501. begin
  2502. D.f := D.f shr 1;
  2503. inc( D.e );
  2504. end;
  2505. {$else VALREAL_80 or VALREAL_128}
  2506. diy_util_shr( D.fh, D.f, C_DIY_SHR_TO_FLT );
  2507. if ( b <> 0 ) then
  2508. diy_util_add( D.fh, D.f, 0, b );
  2509. // handle round overflow
  2510. if ( D.fh {$ifdef VALREAL_128} and ( C_FLT_INT_BITh shl 1 ) {$endif} <> 0 ) then
  2511. begin
  2512. diy_util_shr( D.fh, D.f, 1 );
  2513. inc( D.e );
  2514. end;
  2515. {$if defined(grisu1_debug) and defined(VALREAL_80)}
  2516. assert( D.fh = 0 );
  2517. {$endif grisu1_debug}
  2518. {$endif VALREAL_*}
  2519. // calculate exponent
  2520. D.e := D.e + C_DIY_EXP_TO_FLT;
  2521. if ( D.e >= C_EXP2_SPECIAL ) then
  2522. ///////////////////
  2523. //
  2524. // overflow
  2525. //
  2526. ///////////////////
  2527. overflow := 1
  2528. else
  2529. if ( D.e < - C_FRAC2_BITS ) then
  2530. ///////////////////
  2531. //
  2532. // underflow
  2533. //
  2534. ///////////////////
  2535. overflow := -1
  2536. else
  2537. if ( D.e <= 0 ) then
  2538. begin
  2539. ///////////////////
  2540. //
  2541. // denormal (and also an extreme case of "D.e=-C_FRAC2_BITS", where
  2542. // rounding may produce either the lowest denormal or underflow)
  2543. //
  2544. ///////////////////
  2545. n := 1 - D.e; // SHR amount
  2546. // round bit
  2547. {$ifdef VALREAL_32}
  2548. bit_round := dword(1) shl ( n - 1 );
  2549. {$endif VALREAL_32}
  2550. {$if defined(VALREAL_64) or defined(VALREAL_80)}
  2551. bit_round := qword(1) shl ( n - 1 );
  2552. {$endif VALREAL_64 | VALREAL_80}
  2553. {$ifdef VALREAL_128}
  2554. bit_round := 1;
  2555. bit_round_h := 0;
  2556. diy_util_shl( bit_round_h, bit_round, n - 1 );
  2557. // mask for ulp and all least bits including the round one
  2558. bit_round_mask := bit_round;
  2559. bit_round_mask_h := bit_round_h;
  2560. diy_util_shl( bit_round_mask_h, bit_round_mask, 2 );
  2561. if ( bit_round_mask = 0 ) then
  2562. dec( bit_round_mask_h );
  2563. dec( bit_round_mask );
  2564. {$else not VALREAL_128}
  2565. // mask for ulp and all least bits including the round one
  2566. bit_round_mask := ( bit_round shl 2 ) - 1;
  2567. // Note[floatx80]: works correctly despite the overflow is ignored in extreme case "D.e=-C_FRAC2_BITS"
  2568. {$endif VALREAL_*}
  2569. // round increment
  2570. 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
  2571. // round to even and already even -> no round-up
  2572. b := 0
  2573. else
  2574. b := ord( ( D.f and bit_round ) {$ifdef VALREAL_128} or ( D.fh and bit_round_h ) {$endif} <> 0 );
  2575. // shift and round
  2576. if ( D.e = - C_FRAC2_BITS ) then
  2577. begin
  2578. // extreme case: rounding may result in either lowest denormal or zero
  2579. {$ifdef VALREAL_128}
  2580. D.fh := 0;
  2581. {$endif VALREAL_128}
  2582. D.f := b;
  2583. if ( b = 0 ) then
  2584. overflow := -1; // underflow
  2585. end
  2586. else
  2587. {$ifdef VALREAL_128}
  2588. begin
  2589. diy_util_shr( D.fh, D.f, n );
  2590. if ( b <> 0 ) then
  2591. diy_util_add( D.fh, D.f, 0, b );
  2592. end;
  2593. {$else not VALREAL_128}
  2594. D.f := ( D.f shr n ) + b;
  2595. {$endif VALREAL_*}
  2596. D.e := 0;
  2597. {$ifdef grisu1_debug}
  2598. {$ifdef VALREAL_128}
  2599. assert( ( D.f or D.fh <> 0 ) or ( overflow = -1 ) );
  2600. assert( D.fh and not C_FLT_FRAC_MASKh = 0 );
  2601. {$else not VALREAL_128}
  2602. assert( ( D.f <> 0 ) or ( overflow = -1 ) );
  2603. assert( D.f and not C_FLT_FRAC_MASK = 0 );
  2604. {$endif VALREAL_*}
  2605. {$endif grisu1_debug}
  2606. end
  2607. else
  2608. begin
  2609. ///////////////////
  2610. //
  2611. // normal: 0 < D.e < C_EXP2_SPECIAL
  2612. //
  2613. ///////////////////
  2614. {$ifdef grisu1_debug}
  2615. {$ifdef VALREAL_32}
  2616. assert( D.f and not C_FLT_FRAC_MASK = C_FLT_INT_BIT );
  2617. {$endif VALREAL_32}
  2618. {$if defined(VALREAL_64) or defined(VALREAL_80)}
  2619. assert( D.f and not qword(C_FLT_FRAC_MASK) = qword(C_FLT_INT_BIT) );
  2620. {$endif VALREAL_64 | VALREAL_80}
  2621. {$ifdef VALREAL_128}
  2622. assert( D.fh and not C_FLT_FRAC_MASKh = C_FLT_INT_BITh );
  2623. {$endif VALREAL_128}
  2624. {$endif grisu1_debug}
  2625. {$ifndef VALREAL_80}
  2626. // clear the implicit integer bit
  2627. {$ifdef VALREAL_128}
  2628. D.fh := D.fh and C_FLT_FRAC_MASKh;
  2629. {$else not VALREAL_128}
  2630. D.f := D.f and C_FLT_FRAC_MASK;
  2631. {$endif VALREAL_*}
  2632. {$endif not VALREAL_80}
  2633. end;
  2634. end;
  2635. // final result
  2636. if ( overflow < 0 ) then
  2637. begin
  2638. // underflow [+0|-0]
  2639. pack_float( val_real, minus, 0, {$ifdef VALREAL_128} 0, {$endif} 0 );
  2640. end
  2641. else
  2642. if ( overflow > 0 ) then
  2643. begin
  2644. // overflow [+Inf|-Inf]
  2645. pack_float( val_real, minus, C_EXP2_SPECIAL, {$ifdef VALREAL_128} C_FLT_MANT_INFh, {$endif} C_FLT_MANT_INF );
  2646. end
  2647. else
  2648. begin
  2649. // no error
  2650. pack_float( val_real, minus, D.e, {$ifdef VALREAL_128} D.fh, {$endif} D.f );
  2651. end;
  2652. err_pos := 0;
  2653. end;