flt_core.inc 93 KB

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