fmtbcd.pp 107 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2005-2006 by the Free Pascal development team
  4. and Gehard Scholz
  5. It contains the Free Pascal BCD implementation
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS for A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. { "Programming is the time between two bugs" }
  13. { (last words of the unknown programmer) }
  14. (* this program was a good test for the compiler: some bugs have been found.
  15. 1. WITH in inline funcs produces a compiler error AFTER producing an .exe file
  16. (was already known; I didn't see it in the bug list)
  17. 2. macro names were checked for being a keyword, even when starting with
  18. an '_' (produces range check when compiler is compiled with { $r+ }-mode
  19. fixed.
  20. 3. { $define program } was not possible in { $macro on } mode
  21. (keywords not allowed: doesn't make sense here)
  22. fixed.
  23. 4. the Inc/Dec ( unsigned, signed ) problem (has been similar in the
  24. bug list already)
  25. 5. when the result of an overloaded (inline) operator is ABSOLUTEd:
  26. compiler error 200110205
  27. happens only when operator is defined in a unit.
  28. 6. two range check errors in scanner.pas
  29. a) array subscripting
  30. b) value out ouf range
  31. *)
  32. { $define debug_version}
  33. {$r+,q+,s+}
  34. { $r-,q-,s-}
  35. {$mode objfpc}
  36. {$h-}
  37. {$inline on}
  38. {$macro on}
  39. {$define BCDMaxDigits := 64 } { should be even }
  40. { the next defines must be defined by hand,
  41. unless someone shows me a way how to to it with macros }
  42. {$define BCDgr4} { define this if MCDMaxDigits is greater 4, else undefine! }
  43. {$define BCDgr9} { define this if MCDMaxDigits is greater 9, else undefine! }
  44. {$define BCDgr18} { define this if MCDMaxDigits is greater 18, else undefine! }
  45. { $define BCDgr64} { define this if MCDMaxDigits is greater 64, else undefine! }
  46. { $define BCDgr180} { define this if MCDMaxDigits is greater 180, else undefine! }
  47. {$ifdef BCDgr4}
  48. {$hint BCD Digits > 4}
  49. {$endif}
  50. {$ifdef BCDgr9}
  51. {$hint BCD Digits > 9}
  52. {$endif}
  53. {$ifdef BCDgr18}
  54. {$hint BCD Digits > 18}
  55. {$endif}
  56. {$ifdef BCDgr64}
  57. {$hint BCD Digits > 64}
  58. {$endif}
  59. {$ifdef BCDgr180}
  60. {$hint BCD Digits > 180}
  61. {$endif}
  62. {$ifndef NO_SMART_LINK}
  63. { $smartlink on}
  64. {$endif}
  65. {$define some_packed} { enable this to keep some local structures PACKED }
  66. { $define as_object} { to define the tBCD record as object instead;
  67. fields then are private }
  68. { not done yet! }
  69. {$define additional_routines} { to create additional routines and operators }
  70. (* only define one of them! *)
  71. { $define integ32}
  72. {$define integ64}
  73. (* only define one of them! *)
  74. { $define real8}
  75. {$define real10}
  76. {check}
  77. {$ifndef integ32}
  78. {$ifndef integ64}
  79. {$define integ64}
  80. {$endif}
  81. {$endif}
  82. {$ifdef integ32}
  83. {$ifdef integ64}
  84. {$undef integ32}
  85. {$endif}
  86. {$endif}
  87. {check}
  88. {$ifndef real8}
  89. {$ifndef real10}
  90. {$define real8}
  91. {$endif}
  92. {$endif}
  93. {$ifdef real8}
  94. {$ifdef real10}
  95. {$undef real10}
  96. {$endif}
  97. {$endif}
  98. {$ifdef some_packed}
  99. {$define maybe_packed := packed}
  100. {$else}
  101. {$define maybe_packed := (**)}
  102. {$endif}
  103. UNIT FmtBCD;
  104. INTERFACE
  105. USES
  106. SysUtils,
  107. { dateutils,}
  108. Variants;
  109. const
  110. MaxStringDigits = 100; { not used ! }
  111. _NoDecimal = -255; { not used ! }
  112. _DefaultDecimals = 10; { not used ! }
  113. { From DB.pas }
  114. { Max supported by Midas } { must be EVEN }
  115. MaxFmtBCDFractionSize = BCDMaxDigits + Ord ( Odd ( BCDMaxDigits ) );
  116. { Max supported by Midas }
  117. MaxFmtBCDDigits = 32; { not used ! }
  118. DefaultFmtBCDScale = 6; { not used ! }
  119. MaxBCDPrecision = 18; { not used ! }
  120. MaxBCDScale = 4; { not used ! }
  121. {$ifdef BCDgr64}
  122. { $fatal big 1}
  123. {$define bigger_BCD} { must be defined
  124. if MaxFmtBCDFractionSize > 64 }
  125. { not usable in the moment }
  126. {$endif}
  127. {$ifdef BCDgr180}
  128. { $fatal big 2}
  129. type
  130. FmtBCDStringtype = AnsiString;
  131. {$define use_Ansistring}
  132. {$else}
  133. type
  134. FmtBCDStringtype = string [ 255 ];
  135. {$undef use_Ansistring}
  136. {$endif}
  137. {$ifdef use_ansistring}
  138. {$hint ansi}
  139. {$else}
  140. {$hint -ansi}
  141. {$endif}
  142. {$ifdef integ32}
  143. {$define myInttype := LongInt}
  144. {$endif}
  145. {$ifdef integ64}
  146. {$define myInttype := int64}
  147. {$endif}
  148. {$ifndef FPUNONE}
  149. {$ifdef real8}
  150. {$define myRealtype := double}
  151. {$endif}
  152. {$ifdef real10}
  153. {$define myRealtype := extended}
  154. {$endif}
  155. {$endif}
  156. {$ifdef SUPPORT_COMP}
  157. {$define comproutines}
  158. {$endif SUPPORT_COMP}
  159. {$define __low_Fraction := 0 }
  160. {$define __high_Fraction := ( ( MaxFmtBCDFractionSize DIV 2 ) - 1 ) }
  161. type
  162. pBCD = ^ tBCD;
  163. tBCD = packed {$ifdef as_object} OBJECT {$else} record {$endif}
  164. {$ifdef as_object} PRIVATE {$endif}
  165. Precision : 0..maxfmtbcdfractionsize; { 1 (joke?)..64 }
  166. {$ifndef bigger_BCD}
  167. SignSpecialPlaces : Byte; { Sign:1, Special:1, Places:6 }
  168. {$else}
  169. Negativ : Boolean;
  170. {
  171. Special : Boolean;
  172. }
  173. Places : 0..maxfmtbcdfractionsize - 1;
  174. {$endif}
  175. Fraction : packed array [ __low_Fraction..__high_Fraction ] of Byte;
  176. { BCD Nibbles, 00..99 per Byte, high Nibble 1st }
  177. end;
  178. type
  179. tDecimalPoint = ( DecimalPoint_is_Point, DecimalPoint_is_Comma, DecimalPoint_is_System );
  180. { Exception classes }
  181. type
  182. eBCDException = CLASS ( Exception );
  183. eBCDOverflowException = CLASS ( eBCDException );
  184. eBCDNotImplementedException = CLASS ( eBCDException );
  185. var
  186. DecimalPoint : tDecimalPoint = DecimalPoint_is_Point;
  187. { Utility functions for TBCD access }
  188. function BCDPrecision ( const BCD : tBCD ) : Word; Inline;
  189. function BCDScale ( const BCD : tBCD ) : Word; Inline;
  190. function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline;
  191. { BCD Arithmetic}
  192. procedure BCDNegate ( var BCD : tBCD ); Inline;
  193. { !!!!!!!!!! most routines are intentionally NOT inline !!!!!!!!!! }
  194. { Returns True if successful, False if Int Digits needed to be truncated }
  195. function NormalizeBCD ( const InBCD : tBCD;
  196. var OutBCD : tBCD;
  197. const Prec,
  198. Scale : Word ) : Boolean;
  199. procedure BCDAdd ( const BCDin1,
  200. BCDin2 : tBCD;
  201. var BCDout : tBCD );
  202. procedure BCDSubtract ( const BCDin1,
  203. BCDin2 : tBCD;
  204. var BCDout : tBCD );
  205. procedure BCDMultiply ( const BCDin1,
  206. BCDin2 : tBCD;
  207. var BCDout : tBCD );
  208. {$ifndef FPUNONE}
  209. procedure BCDMultiply ( const BCDIn : tBCD;
  210. const DoubleIn : myRealtype;
  211. var BCDout : tBCD ); Inline;
  212. {$endif}
  213. procedure BCDMultiply ( const BCDIn : tBCD;
  214. const StringIn : FmtBCDStringtype;
  215. var BCDout : tBCD ); Inline;
  216. { !!! params changed to const, shouldn't give a problem }
  217. procedure BCDMultiply ( const StringIn1,
  218. StringIn2 : FmtBCDStringtype;
  219. var BCDout : tBCD ); Inline;
  220. procedure BCDDivide ( const Dividend,
  221. Divisor : tBCD;
  222. var BCDout : tBCD );
  223. {$ifndef FPUNONE}
  224. procedure BCDDivide ( const Dividend : tBCD;
  225. const Divisor : myRealtype;
  226. var BCDout : tBCD ); Inline;
  227. {$endif}
  228. procedure BCDDivide ( const Dividend : tBCD;
  229. const Divisor : FmtBCDStringtype;
  230. var BCDout : tBCD ); Inline;
  231. { !!! params changed to const, shouldn't give a problem }
  232. procedure BCDDivide ( const Dividend,
  233. Divisor : FmtBCDStringtype;
  234. var BCDout : tBCD ); Inline;
  235. { TBCD variant creation utils }
  236. procedure VarFmtBCDCreate ( var aDest : Variant;
  237. const aBCD : tBCD );
  238. function VarFmtBCDCreate : Variant;
  239. function VarFmtBCDCreate ( const aValue : FmtBCDStringtype;
  240. Precision,
  241. Scale : Word ) : Variant;
  242. {$ifndef FPUNONE}
  243. function VarFmtBCDCreate ( const aValue : myRealtype;
  244. Precision : Word = 18;
  245. Scale : Word = 4 ) : Variant;
  246. {$endif}
  247. function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant;
  248. function VarIsFmtBCD ( const aValue : Variant ) : Boolean;
  249. function VarFmtBCD : TVartype;
  250. { Convert string/Double/Integer to BCD struct }
  251. function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD;
  252. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  253. var BCD : tBCD ) : Boolean;
  254. {$ifndef FPUNONE}
  255. function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline;
  256. procedure DoubleToBCD ( const aValue : myRealtype;
  257. var BCD : tBCD );
  258. {$endif}
  259. function IntegerToBCD ( const aValue : myInttype ) : tBCD;
  260. function VarToBCD ( const aValue : Variant ) : tBCD;
  261. { From DB.pas }
  262. function CurrToBCD ( const Curr : currency;
  263. var BCD : tBCD;
  264. Precision : Integer = 32;
  265. Decimals : Integer = 4 ) : Boolean;
  266. { Convert BCD struct to string/Double/Integer }
  267. function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype;
  268. {$ifndef FPUNONE}
  269. function BCDToDouble ( const BCD : tBCD ) : myRealtype;
  270. {$endif}
  271. function BCDToInteger ( const BCD : tBCD;
  272. Truncate : Boolean = False ) : myInttype;
  273. { From DB.pas }
  274. function BCDToCurr ( const BCD : tBCD;
  275. var Curr : currency ) : Boolean;
  276. { Formatting BCD as string }
  277. function BCDToStrF ( const BCD : tBCD;
  278. Format : TFloatFormat;
  279. const Precision,
  280. Digits : Integer ) : FmtBCDStringtype;
  281. function FormatBCD ( const Format : string;
  282. BCD : tBCD ) : FmtBCDStringtype;
  283. { returns -1 if BCD1 < BCD2, 0 if BCD1 = BCD2, 1 if BCD1 > BCD2 }
  284. function BCDCompare ( const BCD1,
  285. BCD2 : tBCD ) : Integer;
  286. {$ifdef additional_routines}
  287. function CurrToBCD ( const Curr : currency ) : tBCD; Inline;
  288. {$ifdef comproutines}
  289. function CompToBCD ( const Curr : Comp ) : tBCD; Inline;
  290. function BCDToComp ( const BCD : tBCD ) : Comp; Inline;
  291. {$endif}
  292. procedure BCDAdd ( const BCDIn : tBCD;
  293. const IntIn : myInttype;
  294. var BCDout : tBCD );
  295. procedure BCDAdd ( const IntIn : myInttype;
  296. const BCDIn : tBCD;
  297. var BCDout : tBCD ); Inline;
  298. {$ifndef FPUNONE}
  299. procedure BCDAdd ( const BCDIn : tBCD;
  300. const DoubleIn : myRealtype;
  301. var BCDout : tBCD ); Inline;
  302. procedure BCDAdd ( const DoubleIn : myRealtype;
  303. const BCDIn : tBCD;
  304. var BCDout : tBCD ); Inline;
  305. {$endif}
  306. procedure BCDAdd ( const BCDIn : tBCD;
  307. const Currin : currency;
  308. var BCDout : tBCD ); Inline;
  309. procedure BCDAdd ( const Currin : currency;
  310. const BCDIn : tBCD;
  311. var BCDout : tBCD ); Inline;
  312. {$ifdef comproutines}
  313. procedure BCDAdd ( const BCDIn : tBCD;
  314. const Compin : Comp;
  315. var BCDout : tBCD ); Inline;
  316. procedure BCDAdd ( const Compin : Comp;
  317. const BCDIn : tBCD;
  318. var BCDout : tBCD ); Inline;
  319. {$endif}
  320. procedure BCDAdd ( const BCDIn : tBCD;
  321. const StringIn : FmtBCDStringtype;
  322. var BCDout : tBCD ); Inline;
  323. procedure BCDAdd ( const StringIn : FmtBCDStringtype;
  324. const BCDIn : tBCD;
  325. var BCDout : tBCD ); Inline;
  326. procedure BCDAdd ( const StringIn1,
  327. StringIn2 : FmtBCDStringtype;
  328. var BCDout : tBCD ); Inline;
  329. procedure BCDSubtract ( const BCDIn : tBCD;
  330. const IntIn : myInttype;
  331. var BCDout : tBCD );
  332. procedure BCDSubtract ( const IntIn : myInttype;
  333. const BCDIn : tBCD;
  334. var BCDout : tBCD ); Inline;
  335. {$ifndef FPUNONE}
  336. procedure BCDSubtract ( const BCDIn : tBCD;
  337. const DoubleIn : myRealtype;
  338. var BCDout : tBCD ); Inline;
  339. procedure BCDSubtract ( const DoubleIn : myRealtype;
  340. const BCDIn : tBCD;
  341. var BCDout : tBCD ); Inline;
  342. {$endif}
  343. procedure BCDSubtract ( const BCDIn : tBCD;
  344. const Currin : currency;
  345. var BCDout : tBCD ); Inline;
  346. procedure BCDSubtract ( const Currin : currency;
  347. const BCDIn : tBCD;
  348. var BCDout : tBCD ); Inline;
  349. {$ifdef comproutines}
  350. procedure BCDSubtract ( const BCDIn : tBCD;
  351. const Compin : Comp;
  352. var BCDout : tBCD ); Inline;
  353. procedure BCDSubtract ( const Compin : Comp;
  354. const BCDIn : tBCD;
  355. var BCDout : tBCD ); Inline;
  356. {$endif}
  357. procedure BCDSubtract ( const BCDIn : tBCD;
  358. const StringIn : FmtBCDStringtype;
  359. var BCDout : tBCD ); Inline;
  360. procedure BCDSubtract ( const StringIn : FmtBCDStringtype;
  361. const BCDIn : tBCD;
  362. var BCDout : tBCD ); Inline;
  363. procedure BCDSubtract ( const StringIn1,
  364. StringIn2 : FmtBCDStringtype;
  365. var BCDout : tBCD ); Inline;
  366. procedure BCDMultiply ( const BCDIn : tBCD;
  367. const IntIn : myInttype;
  368. var BCDout : tBCD );
  369. procedure BCDMultiply ( const IntIn : myInttype;
  370. const BCDIn : tBCD;
  371. var BCDout : tBCD ); Inline;
  372. {$ifndef FPUNONE}
  373. procedure BCDMultiply ( const DoubleIn : myRealtype;
  374. const BCDIn : tBCD;
  375. var BCDout : tBCD ); Inline;
  376. {$endif}
  377. procedure BCDMultiply ( const BCDIn : tBCD;
  378. const Currin : currency;
  379. var BCDout : tBCD ); Inline;
  380. procedure BCDMultiply ( const Currin : currency;
  381. const BCDIn : tBCD;
  382. var BCDout : tBCD ); Inline;
  383. {$ifdef comproutines}
  384. procedure BCDMultiply ( const BCDIn : tBCD;
  385. const Compin : Comp;
  386. var BCDout : tBCD ); Inline;
  387. procedure BCDMultiply ( const Compin : Comp;
  388. const BCDIn : tBCD;
  389. var BCDout : tBCD ); Inline;
  390. {$endif}
  391. procedure BCDMultiply ( const StringIn : FmtBCDStringtype;
  392. const BCDIn : tBCD;
  393. var BCDout : tBCD ); Inline;
  394. procedure BCDDivide ( const Dividend : tBCD;
  395. const Divisor : myInttype;
  396. var BCDout : tBCD ); Inline;
  397. procedure BCDDivide ( const Dividend : myInttype;
  398. const Divisor : tBCD;
  399. var BCDout : tBCD ); Inline;
  400. {$ifndef FPUNONE}
  401. procedure BCDDivide ( const Dividend : myRealtype;
  402. const Divisor : tBCD;
  403. var BCDout : tBCD ); Inline;
  404. {$endif}
  405. procedure BCDDivide ( const BCDIn : tBCD;
  406. const Currin : currency;
  407. var BCDout : tBCD ); Inline;
  408. procedure BCDDivide ( const Currin : currency;
  409. const BCDIn : tBCD;
  410. var BCDout : tBCD ); Inline;
  411. {$ifdef comproutines}
  412. procedure BCDDivide ( const BCDIn : tBCD;
  413. const Compin : Comp;
  414. var BCDout : tBCD ); Inline;
  415. procedure BCDDivide ( const Compin : Comp;
  416. const BCDIn : tBCD;
  417. var BCDout : tBCD ); Inline;
  418. {$endif}
  419. procedure BCDDivide ( const Dividend : FmtBCDStringtype;
  420. const Divisor : tBCD;
  421. var BCDout : tBCD ); Inline;
  422. operator = ( const BCD1,
  423. BCD2 : tBCD ) z : Boolean; Inline;
  424. operator < ( const BCD1,
  425. BCD2 : tBCD ) z : Boolean; Inline;
  426. operator > ( const BCD1,
  427. BCD2 : tBCD ) z : Boolean; Inline;
  428. operator <= ( const BCD1,
  429. BCD2 : tBCD ) z : Boolean; Inline;
  430. operator >= ( const BCD1,
  431. BCD2 : tBCD ) z : Boolean; Inline;
  432. (* ######################## not allowed: why?
  433. operator + ( const BCD : tBCD ) z : tBCD; make_Inline
  434. ##################################################### *)
  435. operator - ( const BCD : tBCD ) z : tBCD; Inline;
  436. operator + ( const BCD1,
  437. BCD2 : tBCD ) z : tBCD; Inline;
  438. operator + ( const BCD : tBCD;
  439. const i : myInttype ) z : tBCD; Inline;
  440. operator + ( const i : myInttype;
  441. const BCD : tBCD ) z : tBCD; Inline;
  442. {$ifndef FPUNONE}
  443. operator + ( const BCD : tBCD;
  444. const r : myRealtype ) z : tBCD; Inline;
  445. operator + ( const r : myRealtype;
  446. const BCD : tBCD ) z : tBCD; Inline;
  447. {$endif}
  448. operator + ( const BCD : tBCD;
  449. const c : currency ) z : tBCD; Inline;
  450. operator + ( const c : currency;
  451. const BCD : tBCD ) z : tBCD; Inline;
  452. {$ifdef comproutines}
  453. operator + ( const BCD : tBCD;
  454. const c : Comp ) z : tBCD; Inline;
  455. operator + ( const c : Comp;
  456. const BCD : tBCD ) z : tBCD; Inline;
  457. {$endif}
  458. operator + ( const BCD : tBCD;
  459. const s : FmtBCDStringtype ) z : tBCD; Inline;
  460. operator + ( const s : FmtBCDStringtype;
  461. const BCD : tBCD ) z : tBCD; Inline;
  462. operator - ( const BCD1,
  463. BCD2 : tBCD ) z : tBCD; Inline;
  464. operator - ( const BCD : tBCD;
  465. const i : myInttype ) z : tBCD; Inline;
  466. operator - ( const i : myInttype;
  467. const BCD : tBCD ) z : tBCD; Inline;
  468. {$ifndef FPUNONE}
  469. operator - ( const BCD : tBCD;
  470. const r : myRealtype ) z : tBCD; Inline;
  471. operator - ( const r : myRealtype;
  472. const BCD : tBCD ) z : tBCD; Inline;
  473. {$endif}
  474. operator - ( const BCD : tBCD;
  475. const c : currency ) z : tBCD; Inline;
  476. operator - ( const c : currency;
  477. const BCD : tBCD ) z : tBCD; Inline;
  478. {$ifdef comproutines}
  479. operator - ( const BCD : tBCD;
  480. const c : Comp ) z : tBCD; Inline;
  481. operator - ( const c : Comp;
  482. const BCD : tBCD ) z : tBCD; Inline;
  483. {$endif}
  484. operator - ( const BCD : tBCD;
  485. const s : FmtBCDStringtype ) z : tBCD; Inline;
  486. operator - ( const s : FmtBCDStringtype;
  487. const BCD : tBCD ) z : tBCD; Inline;
  488. operator * ( const BCD1,
  489. BCD2 : tBCD ) z : tBCD; Inline;
  490. operator * ( const BCD : tBCD;
  491. const i : myInttype ) z : tBCD; Inline;
  492. operator * ( const i : myInttype;
  493. const BCD : tBCD ) z : tBCD; Inline;
  494. {$ifndef FPUNONE}
  495. operator * ( const BCD : tBCD;
  496. const r : myRealtype ) z : tBCD; Inline;
  497. operator * ( const r : myRealtype;
  498. const BCD : tBCD ) z : tBCD; Inline;
  499. {$endif}
  500. operator * ( const BCD : tBCD;
  501. const c : currency ) z : tBCD; Inline;
  502. operator * ( const c : currency;
  503. const BCD : tBCD ) z : tBCD; Inline;
  504. {$ifdef comproutines}
  505. operator * ( const BCD : tBCD;
  506. const c : Comp ) z : tBCD; Inline;
  507. operator * ( const c : Comp;
  508. const BCD : tBCD ) z : tBCD; Inline;
  509. {$endif}
  510. operator * ( const BCD : tBCD;
  511. const s : FmtBCDStringtype ) z : tBCD; Inline;
  512. operator * ( const s : FmtBCDStringtype;
  513. const BCD : tBCD ) z : tBCD; Inline;
  514. operator / ( const BCD1,
  515. BCD2 : tBCD ) z : tBCD; Inline;
  516. operator / ( const BCD : tBCD;
  517. const i : myInttype ) z : tBCD; Inline;
  518. operator / ( const i : myInttype;
  519. const BCD : tBCD ) z : tBCD; Inline;
  520. {$ifndef FPUNONE}
  521. operator / ( const BCD : tBCD;
  522. const r : myRealtype ) z : tBCD; Inline;
  523. operator / ( const r : myRealtype;
  524. const BCD : tBCD ) z : tBCD; Inline;
  525. {$endif}
  526. operator / ( const BCD : tBCD;
  527. const c : currency ) z : tBCD; Inline;
  528. operator / ( const c : currency;
  529. const BCD : tBCD ) z : tBCD; Inline;
  530. {$ifdef comproutines}
  531. operator / ( const BCD : tBCD;
  532. const c : Comp ) z : tBCD; Inline;
  533. operator / ( const c : Comp;
  534. const BCD : tBCD ) z : tBCD; Inline;
  535. {$endif}
  536. operator / ( const BCD : tBCD;
  537. const s : FmtBCDStringtype ) z : tBCD; Inline;
  538. operator / ( const s : FmtBCDStringtype;
  539. const BCD : tBCD ) z : tBCD; Inline;
  540. operator := ( const i : Byte ) z : tBCD; Inline;
  541. operator := ( const BCD : tBCD ) z : Byte; Inline;
  542. operator := ( const i : Word ) z : tBCD; Inline;
  543. operator := ( const BCD : tBCD ) z : Word; Inline;
  544. operator := ( const i : longword ) z : tBCD; Inline;
  545. operator := ( const BCD : tBCD ) z : longword; Inline;
  546. {$if declared ( qword ) }
  547. operator := ( const i : qword ) z : tBCD; Inline;
  548. operator := ( const BCD : tBCD ) z : qword; Inline;
  549. {$endif}
  550. operator := ( const i : ShortInt ) z : tBCD; Inline;
  551. operator := ( const BCD : tBCD ) z : ShortInt; Inline;
  552. operator := ( const i : smallint ) z : tBCD; Inline;
  553. operator := ( const BCD : tBCD ) z : smallint; Inline;
  554. operator := ( const i : LongInt ) z : tBCD; Inline;
  555. operator := ( const BCD : tBCD ) z : LongInt; Inline;
  556. {$if declared ( int64 ) }
  557. operator := ( const i : int64 ) z : tBCD; Inline;
  558. operator := ( const BCD : tBCD ) z : int64; Inline;
  559. {$endif}
  560. {$ifndef FPUNONE}
  561. operator := ( const r : Single ) z : tBCD; Inline;
  562. operator := ( const BCD : tBCD ) z : Single; Inline;
  563. operator := ( const r : Double ) z : tBCD; Inline;
  564. operator := ( const BCD : tBCD ) z : Double; Inline;
  565. {$if sizeof ( extended ) <> sizeof ( double )}
  566. operator := ( const r : Extended ) z : tBCD; Inline;
  567. operator := ( const BCD : tBCD ) z : Extended; Inline;
  568. {$endif}
  569. {$endif}
  570. operator := ( const c : currency ) z : tBCD; Inline;
  571. operator := ( const BCD : tBCD ) z : currency; Inline;
  572. {$ifdef comproutines}
  573. operator := ( const c : Comp ) z : tBCD; Inline;
  574. operator := ( const BCD : tBCD ) z : Comp; Inline;
  575. {$endif}
  576. operator := ( const s : string ) z : tBCD; Inline;
  577. operator := ( const BCD : tBCD ) z : string; Inline;
  578. operator := ( const s : AnsiString ) z : tBCD; Inline;
  579. operator := ( const BCD : tBCD ) z : AnsiString; Inline;
  580. {$endif}
  581. function __get_null : tBCD; Inline;
  582. function __get_one : tBCD; Inline;
  583. PROPERTY
  584. NullBCD : tBCD Read __get_null;
  585. OneBCD : tBCD Read __get_one;
  586. //{$define __lo_bh := 1 * ( -( MaxFmtBCDFractionSize * 1 + 2 ) ) }
  587. //{$define __hi_bh := 1 * ( MaxFmtBCDFractionSize * 1 + 1 ) }
  588. {$define helper_declarations :=
  589. const
  590. __lo_bh = -( MaxFmtBCDFractionSize + 2 );
  591. __hi_bh = ( MaxFmtBCDFractionSize + 1 );
  592. type
  593. tBCD_helper = Maybe_Packed record
  594. Prec : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif};
  595. Plac : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif};
  596. FDig,
  597. LDig : {$ifopt r+} __lo_bh..__hi_bh {$else} Integer {$endif};
  598. Singles : Maybe_packed array [ __lo_bh..__hi_bh ]
  599. of {$ifopt r+} 0..9 {$else} Byte {$endif};
  600. Neg : Boolean;
  601. end;
  602. { in the tBCD_helper the bcd is stored for computations,
  603. shifted to the right position }
  604. // {$define __lo_bhb := 1 * ( __lo_bh + __lo_bh ) }
  605. // {$define __hi_bhb := 1 * ( __hi_bh + __hi_bh + 1 ) }
  606. const
  607. __lo_bhb = __lo_bh + __lo_bh - 1;
  608. __hi_bhb = __hi_bh + __hi_bh;
  609. type
  610. tBCD_helper_big = Maybe_Packed record
  611. Prec : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif};
  612. Plac : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif};
  613. FDig,
  614. LDig : {$ifopt r+} __lo_bhb..__hi_bhb {$else} Integer {$endif};
  615. Singles : Maybe_packed array [ __lo_bhb..__hi_bhb ]
  616. of {$ifopt r+} 0 * 0..9 * 9 * Pred ( MaxFmtBCDDigits ) {$else} Integer {$endif};
  617. Neg : Boolean;
  618. end;
  619. }
  620. {$ifdef debug_version}
  621. helper_declarations
  622. procedure unpack_BCD ( const BCD : tBCD;
  623. var bh : tBCD_helper );
  624. function pack_BCD ( var bh : tBCD_helper;
  625. var BCD : tBCD ) : Boolean;
  626. procedure dumpBCD ( const v : tBCD );
  627. {$endif}
  628. IMPLEMENTATION
  629. USES
  630. classes {$ifopt r+}, sysconst {$endif};
  631. type
  632. TFMTBcdFactory = CLASS(TPublishableVarianttype)
  633. PROTECTED
  634. function GetInstance(const v : TVarData): tObject; OVERRIDE;
  635. PUBLIC
  636. procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp); override;
  637. procedure Clear(var V: TVarData); override;
  638. procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
  639. end;
  640. TFMTBcdVarData = CLASS(TPersistent)
  641. PRIVATE
  642. FBcd : tBCD;
  643. PUBLIC
  644. constructor create;
  645. constructor create(const BCD : tBCD);
  646. PROPERTY BCD : tBCD Read FBcd Write FBcd;
  647. end;
  648. var
  649. NullBCD_ : tBCD;
  650. OneBCD_ : tBCD;
  651. function __get_null : tBCD; Inline;
  652. begin
  653. __get_null := NullBCD_;
  654. end;
  655. function __get_one : tBCD; Inline;
  656. begin
  657. __get_one := OneBCD_;
  658. end;
  659. type
  660. range_digits = 1..maxfmtbcdfractionsize;
  661. range_digits0 = 0..maxfmtbcdfractionsize;
  662. range_fracdigits = 0..pred ( MaxFmtBCDFractionSize );
  663. {$ifopt r+}
  664. procedure RangeError;
  665. begin
  666. raise ERangeError.Create(SRangeError);
  667. end;
  668. {$endif}
  669. {$ifndef debug_version}
  670. helper_declarations
  671. {$endif}
  672. var
  673. null_ : record
  674. case Boolean of
  675. False: ( bh : tBCD_helper );
  676. True: ( bhb : tBCD_helper_big );
  677. end;
  678. FMTBcdFactory : TFMTBcdFactory = NIL;
  679. {$ifndef bigger_BCD}
  680. const
  681. NegBit = 1 SHL 7;
  682. SpecialBit = 1 SHL 6;
  683. PlacesMask = $ff XOR ( NegBit OR SpecialBit );
  684. {$endif}
  685. {$define _select := {$define _when := if {$define _when := end else if } }
  686. {$define _then := then begin }
  687. {$define _whenother := end else begin }
  688. {$define _endselect := end } }
  689. {$ifdef debug_version}
  690. procedure dumpBCD ( const v : tBCD );
  691. var
  692. i,
  693. j : Integer;
  694. const
  695. ft : ARRAY [ Boolean ] of Char = ( 'f', 't' );
  696. begin
  697. {$ifndef bigger_BCD}
  698. Write ( 'Prec:', v.Precision, ' ',
  699. 'Neg:', ft[( v.SignSpecialPlaces AND NegBit ) <> 0], ' ',
  700. 'Special:', ft[( v.SignSpecialPlaces AND SpecialBit ) <> 0], ' ',
  701. 'Places:', v.SignSpecialPlaces AND PlacesMask, ' ' );
  702. {$else}
  703. Write ( 'Prec:', v.Precision, ' ',
  704. 'Neg:', ft[v.Negativ], ' ',
  705. 'Places:', v.Places, ' ' );
  706. {$endif}
  707. j := 0;
  708. for i := 1 TO v.Precision do
  709. if Odd ( i )
  710. then Write ( ( v.Fraction[j] AND $f0 ) SHR 4 )
  711. else begin
  712. Write ( v.Fraction[j] AND $0f );
  713. Inc ( j );
  714. end;
  715. WriteLn;
  716. end;
  717. procedure dumpbh ( const v : tBCD_helper );
  718. var
  719. i : Integer;
  720. const
  721. ft : ARRAY [ Boolean ] of Char = ( 'f', 't' );
  722. begin
  723. Write ( 'Prec:', v.Prec, ' ',
  724. 'Neg:', ft[v.Neg], ' ',
  725. 'Places:', v.Plac, ' ',
  726. 'FDig:', v.FDig, ' ',
  727. 'LDig:', v.LDig, ' ',
  728. 'Digits:', v.LDig - v.FDig + 1, ' ' );
  729. for i := v.FDig TO v.LDig do
  730. Write ( v.Singles[i] );
  731. WriteLn;
  732. end;
  733. {$endif}
  734. {$if sizeof ( integer ) = 2 }
  735. {$ifdef BCDgr4 }
  736. var
  737. myMinIntBCD : tBCD;
  738. {$endif}
  739. {$else}
  740. {$if sizeof ( integer ) = 4 }
  741. {$ifdef BCDgr9 }
  742. var
  743. myMinIntBCD : tBCD;
  744. {$endif}
  745. {$else}
  746. {$if sizeof ( integer ) = 8 }
  747. {$ifdef BCDgr18 }
  748. var
  749. myMinIntBCD : tBCD;
  750. {$endif}
  751. {$else}
  752. {$fatal You have an interesting integer type! Sorry, not supported}
  753. {$endif}
  754. {$endif}
  755. {$endif}
  756. procedure not_implemented;
  757. begin
  758. RAISE eBCDNotImplementedException.create ( 'not implemented' );
  759. end;
  760. procedure unpack_BCD ( const BCD : tBCD;
  761. var bh : tBCD_helper );
  762. var
  763. i : {$ifopt r+} __lo_bh + 1 ..__hi_bh {$else} Integer {$endif};
  764. j : {$ifopt r+} -1..__high_fraction {$else} Integer {$endif};
  765. vv : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  766. begin
  767. bh := null_.bh;
  768. WITH bh,
  769. BCD do
  770. begin
  771. Prec := Precision;
  772. if Prec > 0
  773. then begin
  774. {$ifndef bigger_BCD}
  775. Plac := SignSpecialPlaces AND PlacesMask;
  776. Neg := ( SignSpecialPlaces AND NegBit ) <> 0;
  777. {$else}
  778. Plac := Places;
  779. Neg := Negativ;
  780. {$endif}
  781. LDig := Plac;
  782. FDig := LDig - Prec + 1;
  783. j := -1;
  784. i := FDig;
  785. while i <= LDig do
  786. begin
  787. Inc ( j );
  788. vv := Fraction[j];
  789. Singles[i] := ( vv {AND $f0} ) SHR 4;
  790. if i < LDig
  791. then Singles[i+1] := vv AND $0f;
  792. Inc ( i, 2 );
  793. end;
  794. end;
  795. end;
  796. end;
  797. function pack_BCD ( var bh : tBCD_helper;
  798. var BCD : tBCD ) : Boolean;
  799. { return TRUE if successful (BCD valid) }
  800. var
  801. pre : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 {$else} Integer {$endif};
  802. fra : {$ifopt r+} -1 * ( __hi_bh - __lo_bh + 1 )..__hi_bh - __lo_bh + 1 {$else} Integer {$endif};
  803. tm : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 - Pred ( MaxFmtBCDFractionSize ) {$else} Integer {$endif};
  804. i : {$ifopt r+} low ( bh.FDig ) - 1..high ( bh.LDig ) {$else} Integer {$endif};
  805. rp : {$ifopt r+} low ( BCD.Fraction )..high ( BCD.Fraction ) + 1 {$else} Integer {$endif};
  806. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  807. v : {$ifopt r+} 0..10 {$else} Integer {$endif};
  808. lnz : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  809. doround,
  810. lnzf : Boolean;
  811. begin
  812. pack_BCD := False;
  813. BCD := NullBCD;
  814. WITH BCD,
  815. bh do
  816. begin
  817. lnzf := FDig < 0;
  818. while lnzf do
  819. if Singles[FDig] = 0
  820. then begin
  821. Inc ( FDig );
  822. if FDig = 0
  823. then lnzf := False;
  824. end
  825. else lnzf := False;
  826. pre := LDig - FDig + 1;
  827. fra := Plac;
  828. doround := False;
  829. if fra >= MaxFmtBCDFractionSize
  830. then begin
  831. doround := True;
  832. tm := fra - Pred ( MaxFmtBCDFractionSize );
  833. { dec ( pre, tm ); Dec/Inc error? }
  834. pre := pre - tm;
  835. { Dec ( fra, tm ); Dec/Inc error? }
  836. fra := fra - tm;
  837. { Dec ( LDig, tm ); Dec/Inc error? }
  838. LDig := LDig - tm;
  839. end;
  840. if pre > MaxFmtBCDFractionSize
  841. then begin
  842. doround := True;
  843. tm := pre - MaxFmtBCDFractionSize;
  844. { Dec ( pre, tm ); Dec/Inc error? }
  845. pre := pre - tm;
  846. { Dec ( fra, tm ); Dec/Inc error? }
  847. fra := fra - tm;
  848. { Dec ( LDig, tm ); Dec/Inc error? }
  849. LDig := LDig - tm;
  850. end;
  851. if fra < 0
  852. then EXIT;
  853. if doround
  854. then begin
  855. v := Singles[fra + 1];
  856. if v > 4
  857. then begin
  858. ue := 1;
  859. i := LDig;
  860. while ( i >= FDig ) AND ( ue <> 0 ) do
  861. begin
  862. v := Singles[i] + ue;
  863. ue := v DIV 10;
  864. Singles[i] := v MOD 10;
  865. Dec ( i );
  866. end;
  867. if ue <> 0
  868. then begin
  869. Dec ( FDig );
  870. Singles[FDig] := ue;
  871. Dec ( LDig );
  872. Dec ( fra );
  873. if fra < 0
  874. then EXIT;
  875. end;
  876. end;
  877. end;
  878. lnzf := False;
  879. i := LDig;
  880. while ( i >= FDig ) AND ( NOT lnzf ) do
  881. begin
  882. if Singles[i] <> 0
  883. then begin
  884. lnz := i;
  885. lnzf := True;
  886. end;
  887. Dec ( i );
  888. end;
  889. if lnzf
  890. then begin
  891. tm := LDig - lnz;
  892. if tm <> 0
  893. then begin
  894. { Dec ( pre, tm ); Dec/Inc error? }
  895. pre := pre - tm;
  896. { Dec ( fra, tm ); Dec/Inc error? }
  897. fra := fra - tm;
  898. { Dec ( LDig, tm ); Dec/Inc error? }
  899. LDig := LDig - tm;
  900. if fra < 0
  901. then begin
  902. { Dec ( pre, fra ); Dec/Inc error? }
  903. pre := pre - fra;
  904. { Dec ( LDig, fra ); Dec/Inc error? }
  905. LDig := LDig - fra;
  906. fra := 0;
  907. end;
  908. end;
  909. end
  910. else begin
  911. LDig := FDig;
  912. fra := 0;
  913. pre := 0;
  914. Neg := False;
  915. end;
  916. if pre <> 0
  917. then begin
  918. Precision := pre;
  919. rp := 0;
  920. i := FDig;
  921. while i <= LDig do
  922. begin
  923. if i < LDig
  924. then Fraction[rp] := ( Singles[i] SHL 4 ) OR Singles[i + 1]
  925. else Fraction[rp] := Singles[i] SHL 4;
  926. Inc ( rp );
  927. Inc ( i, 2 );
  928. end;
  929. {$ifndef bigger_BCD}
  930. if Neg
  931. then SignSpecialPlaces := NegBit;
  932. SignSpecialPlaces := SignSpecialPlaces OR fra;
  933. {$else}
  934. Negativ := Neg;
  935. Places := fra;
  936. {$endif}
  937. end;
  938. end;
  939. pack_BCD := True;
  940. end;
  941. procedure SetDecimals ( var dp,
  942. dc : Char );
  943. begin
  944. case DecimalPoint of
  945. DecimalPoint_is_Point: begin
  946. dp := '.';
  947. dc := ',';
  948. end;
  949. DecimalPoint_is_Comma: begin
  950. dp := ',';
  951. dc := '.';
  952. end;
  953. { find out language-specific ? }
  954. DecimalPoint_is_System: begin
  955. dp := DecimalSeparator;
  956. dc := ThousandSeparator;
  957. end;
  958. end;
  959. end;
  960. function BCDPrecision ( const BCD : tBCD ) : Word; Inline;
  961. begin
  962. BCDPrecision := BCD.Precision;
  963. end;
  964. function BCDScale ( const BCD : tBCD ) : Word; Inline;
  965. begin
  966. {$ifndef bigger_BCD}
  967. BCDScale := BCD.SignSpecialPlaces AND PlacesMask;
  968. {$else}
  969. BCDScale := BCD.Places;
  970. {$endif}
  971. end;
  972. function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline;
  973. begin
  974. {$ifndef bigger_BCD}
  975. IsBCDNegative := ( BCD.SignSpecialPlaces AND NegBit ) <> 0;
  976. {$else}
  977. IsBCDNegative := BCD.Negativ;
  978. {$endif}
  979. end;
  980. { BCD Arithmetic}
  981. procedure BCDNegate ( var BCD : tBCD ); Inline;
  982. begin
  983. { with-statement geht nicht !!
  984. with bcd do
  985. if precision <> 0
  986. then signspecialplaces := signspecialplaces xor negbit;
  987. }
  988. if BCD.Precision <> 0
  989. then
  990. {$ifndef bigger_BCD}
  991. BCD.SignSpecialPlaces := BCD.SignSpecialPlaces XOR NegBit;
  992. {$else}
  993. BCD.Negativ := NOT BCD.Negativ;
  994. {$endif}
  995. end;
  996. { returns -1 if BCD1 < BCD2, 0 if BCD1 = BCD2, 1 if BCD1 > BCD2 }
  997. function BCDCompare ( const BCD1,
  998. BCD2 : tBCD ) : Integer;
  999. var
  1000. pl1 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  1001. pl2 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  1002. pr1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1003. pr2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1004. pr : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1005. idig1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1006. idig2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1007. i : {$ifopt r+} __low_Fraction..__high_Fraction + 1 {$else} Integer {$endif};
  1008. f1 : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  1009. f2 : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  1010. res : {$ifopt r+} -1..1 {$else} Integer {$endif};
  1011. neg1,
  1012. neg2 : Boolean;
  1013. begin
  1014. {$ifndef bigger_BCD}
  1015. neg1 := ( BCD1.SignSpecialPlaces AND NegBit ) <> 0;
  1016. neg2 := ( BCD2.SignSpecialPlaces AND NegBit ) <> 0;
  1017. {$else}
  1018. neg1 := BCD1.Negativ;
  1019. neg2 := BCD2.Negativ;
  1020. {$endif}
  1021. _SELECT
  1022. _WHEN neg1 AND ( NOT neg2 )
  1023. _THEN result := -1;
  1024. _WHEN ( NOT neg1 ) AND neg2
  1025. _THEN result := +1;
  1026. _WHENOTHER
  1027. pr1 := BCD1.Precision;
  1028. pr2 := BCD2.Precision;
  1029. {$ifndef bigger_BCD}
  1030. pl1 := BCD1.SignSpecialPlaces AND PlacesMask;
  1031. pl2 := BCD2.SignSpecialPlaces AND PlacesMask;
  1032. {$else}
  1033. pl1 := BCD1.Places;
  1034. pl2 := BCD2.Places;
  1035. {$endif}
  1036. idig1 := pr1 - pl1;
  1037. idig2 := pr2 - pl2;
  1038. if idig1 <> idig2
  1039. then begin
  1040. if ( idig1 > idig2 ) = neg1
  1041. then result := -1
  1042. else result := +1;
  1043. end
  1044. else begin
  1045. if pr1 < pr2
  1046. then pr := pr1
  1047. else pr := pr2;
  1048. res := 0;
  1049. i := __low_Fraction;
  1050. while ( res = 0 ) AND ( i < ( __low_Fraction + ( pr DIV 2 ) ) ) do
  1051. begin
  1052. {
  1053. if BCD1.Fraction[i] < BCD2.Fraction[i]
  1054. then res := -1
  1055. else
  1056. if BCD1.Fraction[i] > BCD2.Fraction[i]
  1057. then res := +1;
  1058. }
  1059. _SELECT
  1060. _WHEN BCD1.Fraction[i] < BCD2.Fraction[i]
  1061. _THEN res := -1
  1062. _WHEN BCD1.Fraction[i] > BCD2.Fraction[i]
  1063. _THEN res := +1;
  1064. _WHENOTHER
  1065. _endSELECT;
  1066. Inc ( i );
  1067. end;
  1068. if res = 0
  1069. then begin
  1070. if Odd ( pr )
  1071. then begin
  1072. f1 := BCD1.Fraction[i] AND $f0;
  1073. f2 := BCD2.Fraction[i] AND $f0;
  1074. {
  1075. if f1 < f2
  1076. then res := -1
  1077. else
  1078. if f1 > f2
  1079. then res := +1;
  1080. }
  1081. _SELECT
  1082. _WHEN f1 < f2
  1083. _THEN res := -1
  1084. _WHEN f1 > f2
  1085. _THEN res := +1;
  1086. _endSELECT;
  1087. end;
  1088. end;
  1089. if neg1
  1090. then result := 0 - res
  1091. else result := res;
  1092. end;
  1093. _endSELECT
  1094. end;
  1095. { Convert string/Double/Integer to BCD struct }
  1096. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  1097. var BCD : tBCD ) : Boolean;
  1098. { shall this return TRUE when error and FALSE when o.k. or the other way round ? }
  1099. var
  1100. {$ifndef use_ansistring}
  1101. lav : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1102. i : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1103. {$else}
  1104. lav : {$ifopt r+} longword {$else} longword {$endif};
  1105. i : {$ifopt r+} longword {$else} longword {$endif};
  1106. {$endif}
  1107. ch : Char;
  1108. dp,
  1109. dc : Char;
  1110. type
  1111. ife = ( inint, infrac, inexp );
  1112. {$define max_exp_scanned := 9999 }
  1113. var
  1114. inife : ife;
  1115. lvars : record
  1116. fp,
  1117. lp : ARRAY [ ife ]
  1118. {$ifndef use_ansistring}
  1119. of {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1120. pfnb : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1121. ps : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1122. pse : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1123. errp : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1124. {$else}
  1125. of {$ifopt r+} longword {$else} longword {$endif};
  1126. pfnb : {$ifopt r+} longword {$else} longword {$endif};
  1127. ps : {$ifopt r+} longword {$else} longword {$endif};
  1128. pse : {$ifopt r+} longword {$else} longword {$endif};
  1129. errp : {$ifopt r+} longword {$else} longword {$endif};
  1130. {$endif}
  1131. exp : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1132. p : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1133. bh : tBCD_helper;
  1134. nbf : Boolean;
  1135. end;
  1136. begin
  1137. result := False;
  1138. FillChar ( lvars, SizeOf ( lvars ), #0 );
  1139. BCD := NullBCD;
  1140. lav := Length ( aValue );
  1141. if lav <> 0
  1142. then
  1143. WITH lvars,
  1144. bh do
  1145. begin
  1146. SetDecimals ( dp, dc );
  1147. while ( pfnb < lav ) AND ( NOT nbf ) do
  1148. begin
  1149. Inc ( pfnb );
  1150. nbf := aValue[pfnb] <> ' ';
  1151. end;
  1152. if nbf
  1153. then begin
  1154. if aValue[pfnb] IN [ '+', '-' ]
  1155. then begin
  1156. ps := pfnb;
  1157. Inc ( pfnb );
  1158. end;
  1159. inife := low ( inife );
  1160. for i := pfnb TO lav do
  1161. begin
  1162. ch := aValue[i];
  1163. case ch of
  1164. '0'..'9': begin
  1165. case inife of
  1166. inint,
  1167. inexp: if fp[inife] = 0
  1168. then begin
  1169. if ch <> '0'
  1170. then begin
  1171. fp[inife] := i;
  1172. lp[inife] := i;
  1173. end;
  1174. end
  1175. else lp[inife] := i;
  1176. infrac: begin
  1177. if fp[infrac] = 0
  1178. then fp[infrac] := i;
  1179. if ch <> '0'
  1180. then lp[infrac] := i;
  1181. end;
  1182. end;
  1183. end;
  1184. ',',
  1185. '.': if ch = dp
  1186. then begin
  1187. if inife <> inint
  1188. then result := True
  1189. else inife := infrac;
  1190. end;
  1191. 'e',
  1192. 'E': if inife = inexp
  1193. then result := True
  1194. else inife := inexp;
  1195. '+',
  1196. '-': if ( inife = inexp ) AND ( fp[inexp] = 0 )
  1197. then pse := i
  1198. else result := True;
  1199. else begin
  1200. result := True;
  1201. errp := i;
  1202. end;
  1203. end;
  1204. end;
  1205. if result
  1206. then begin
  1207. result := False;
  1208. for i := errp TO lav do
  1209. if aValue[i] <> ' '
  1210. then result := True;
  1211. end;
  1212. if result
  1213. then EXIT;
  1214. if ps <> 0
  1215. then Neg := aValue[ps] = '-';
  1216. if lp[infrac] = 0
  1217. then fp[infrac] := 0;
  1218. if fp[inexp] <> 0
  1219. then begin
  1220. exp := 0;
  1221. for i := fp[inexp] TO lp[inexp] do
  1222. if NOT result
  1223. then
  1224. if aValue[i] <> dc
  1225. then begin
  1226. exp := exp * 10 + ( Ord ( aValue[i] ) - Ord ( '0' ) );
  1227. if exp > 999
  1228. then result := True;
  1229. end;
  1230. if result
  1231. then EXIT;
  1232. if pse <> 0
  1233. then
  1234. if aValue[pse] = '-'
  1235. then exp := -exp;
  1236. end;
  1237. p := -exp;
  1238. if fp[infrac] <> 0
  1239. then begin
  1240. for i := fp[infrac] TO lp[infrac] do
  1241. if aValue[i] <> dc
  1242. then begin
  1243. if p < ( MaxFmtBCDFractionSize + 2 )
  1244. then begin
  1245. Inc ( p );
  1246. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1247. end;
  1248. end;
  1249. end;
  1250. LDig := p;
  1251. p := 1 - exp;
  1252. if fp[inint] <> 0
  1253. then
  1254. for i := lp[inint] DOWNTO fp[inint] do
  1255. if aValue[i] <> dc
  1256. then begin
  1257. if p > - ( MaxFmtBCDFractionSize + 2 )
  1258. then begin
  1259. Dec ( p );
  1260. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1261. end
  1262. else result := True;
  1263. end;
  1264. if result
  1265. then EXIT;
  1266. FDig := p;
  1267. if LDig < 0
  1268. then LDig := 0;
  1269. Plac := LDig;
  1270. result := NOT pack_BCD ( bh, BCD );
  1271. end;
  1272. end;
  1273. end;
  1274. function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD;
  1275. var
  1276. BCD : tBCD;
  1277. begin
  1278. if TryStrToBCD ( aValue, BCD )
  1279. then begin
  1280. RAISE eBCDOverflowException.create ( 'in StrToBCD' );
  1281. end
  1282. else StrToBCD := BCD;
  1283. end;
  1284. {$ifndef FPUNONE}
  1285. procedure DoubleToBCD ( const aValue : myRealtype;
  1286. var BCD : tBCD );
  1287. var
  1288. s : string [ 30 ];
  1289. dp : tDecimalPoint;
  1290. begin
  1291. Str ( aValue : 25, s );
  1292. dp := DecimalPoint;
  1293. DecimalPoint := DecimalPoint_is_Point;
  1294. BCD := StrToBCD ( s );
  1295. DecimalPoint := dp;
  1296. end;
  1297. function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline;
  1298. begin
  1299. DoubleToBCD ( aValue, result );
  1300. end;
  1301. {$endif}
  1302. function IntegerToBCD ( const aValue : myInttype ) : tBCD;
  1303. var
  1304. bh : tBCD_helper;
  1305. v : {$ifopt r+} 0..high ( myInttype ) {$else} Integer {$endif};
  1306. p : {$ifopt r+} low ( bh.Singles ) - 1..0 {$else} Integer {$endif};
  1307. exitloop : Boolean;
  1308. begin
  1309. _SELECT
  1310. _WHEN aValue = 0
  1311. _THEN result := NullBCD;
  1312. _WHEN aValue = 1
  1313. _THEN result := OneBCD;
  1314. _WHEN aValue = low ( myInttype )
  1315. _THEN
  1316. {$if declared ( myMinIntBCD ) }
  1317. result := myMinIntBCD;
  1318. {$else}
  1319. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1320. {$endif}
  1321. _WHENOTHER
  1322. bh := null_.bh;
  1323. WITH bh do
  1324. begin
  1325. Neg := aValue < 0;
  1326. if Neg
  1327. then v := -aValue
  1328. else v := +aValue;
  1329. LDig := 0;
  1330. p := 0;
  1331. REPEAT
  1332. Singles[p] := v MOD 10;
  1333. v := v DIV 10;
  1334. exitloop := v = 0;
  1335. Dec ( p );
  1336. if p < low ( Singles )
  1337. then begin
  1338. exitloop := True;
  1339. (* what to do if error occured? *)
  1340. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1341. end;
  1342. UNTIL exitloop;
  1343. FDig := p + 1;
  1344. end;
  1345. pack_BCD ( bh, result );
  1346. _endSELECT;
  1347. end;
  1348. {$warnings off}
  1349. function VarToBCD ( const aValue : Variant ) : tBCD;
  1350. begin
  1351. not_implemented;
  1352. end;
  1353. {$warnings on}
  1354. function CurrToBCD ( const Curr : currency;
  1355. var BCD : tBCD;
  1356. Precision : Integer = 32;
  1357. Decimals : Integer = 4 ) : Boolean;
  1358. {
  1359. this works under the assumption that a currency is an int64,
  1360. except for scale of 10000
  1361. }
  1362. var
  1363. i : int64 absolute Curr;
  1364. begin
  1365. BCD := IntegerToBCD ( i );
  1366. {$ifndef bigger_BCD}
  1367. BCD.SignSpecialPlaces := 4 OR ( BCD.SignSpecialPlaces AND NegBit );
  1368. {$else}
  1369. BCD.Places := 4;
  1370. {$endif}
  1371. if Decimals <> 4 then
  1372. Result := NormalizeBCD ( BCD, BCD, Precision, Decimals )
  1373. else
  1374. CurrToBCD := True;
  1375. end;
  1376. {$ifdef comproutines}
  1377. function CompToBCD ( const Curr : Comp ) : tBCD; Inline;
  1378. var
  1379. cc : int64 absolute Curr;
  1380. begin
  1381. result := IntegerToBCD ( cc );
  1382. end;
  1383. function BCDToComp ( const BCD : tBCD ) : Comp; Inline;
  1384. var
  1385. zz : record
  1386. case Boolean of
  1387. False: ( i : int64 );
  1388. True: ( c : Comp );
  1389. end;
  1390. begin
  1391. zz.i := BCDToInteger ( BCD );
  1392. BCDToComp := zz.c;
  1393. end;
  1394. {$endif}
  1395. { Convert BCD struct to string/Double/Integer }
  1396. function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype;
  1397. var
  1398. bh : tBCD_helper;
  1399. l : {$ifopt r+} 0..maxfmtbcdfractionsize + 1 + 1 {$else} Integer {$endif};
  1400. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1401. pp : {$ifopt r+} low ( bh.FDig ) - 1..1 {$else} Integer {$endif};
  1402. begin
  1403. {$ifdef use_ansistring}
  1404. result := '';
  1405. {$endif}
  1406. unpack_BCD ( BCD, bh );
  1407. WITH bh do
  1408. begin
  1409. l := 0;
  1410. if Neg
  1411. then begin
  1412. {$ifndef use_ansistring}
  1413. Inc ( l );
  1414. result[1] := '-';
  1415. {$else}
  1416. result := result + '-';
  1417. {$endif}
  1418. end;
  1419. if Prec = Plac
  1420. then begin
  1421. {$ifndef use_ansistring}
  1422. Inc ( l );
  1423. result[1] := '0';
  1424. {$else}
  1425. result := result + '0';
  1426. {$endif}
  1427. end;
  1428. if Prec > 0
  1429. then begin
  1430. pp := low ( bh.FDig ) - 1;
  1431. if Plac > 0
  1432. then pp := 1;
  1433. for i := FDig TO LDig do
  1434. begin
  1435. if i = pp
  1436. then begin
  1437. {$ifndef use_ansistring}
  1438. Inc ( l );
  1439. result[l] := '.';
  1440. {$else}
  1441. result := result + '.';
  1442. {$endif}
  1443. end;
  1444. {$ifndef use_ansistring}
  1445. Inc ( l );
  1446. result[l] := Chr ( Singles[i] + Ord ( '0' ) );
  1447. {$else}
  1448. result := result + Chr ( Singles[i] + Ord ( '0' ) );
  1449. {$endif}
  1450. end;
  1451. end;
  1452. end;
  1453. {$ifndef use_ansistring}
  1454. result[0] := Chr ( l );
  1455. {$endif}
  1456. end;
  1457. {$ifndef FPUNONE}
  1458. function BCDToDouble ( const BCD : tBCD ) : myRealtype;
  1459. var
  1460. bh : tBCD_helper;
  1461. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1462. r,
  1463. e : myRealtype;
  1464. begin
  1465. unpack_BCD ( BCD, bh );
  1466. WITH bh do
  1467. begin
  1468. r := 0;
  1469. e := 1;
  1470. for i := 0 DOWNTO FDig do
  1471. begin
  1472. r := r + Singles[i] * e;
  1473. e := e * 10;
  1474. end;
  1475. e := 1;
  1476. for i := 1 TO LDig do
  1477. begin
  1478. e := e / 10;
  1479. r := r + Singles[i] * e;
  1480. end;
  1481. if Neg
  1482. then BCDToDouble := -r
  1483. else BCDToDouble := +r;
  1484. end;
  1485. end;
  1486. {$endif}
  1487. function BCDToInteger ( const BCD : tBCD;
  1488. Truncate : Boolean = False ) : myInttype;
  1489. var
  1490. bh : tBCD_helper;
  1491. res : myInttype;
  1492. i : {$ifopt r+} low ( bh.FDig )..0 {$else} Integer {$endif};
  1493. {
  1494. unclear: behaviour if overflow: abort? return 0? return something?
  1495. so: checks are missing yet
  1496. }
  1497. begin
  1498. unpack_BCD ( BCD, bh );
  1499. res := 0;
  1500. WITH bh do
  1501. begin
  1502. for i := FDig TO 0 do
  1503. res := res * 10 - Singles[i];
  1504. if NOT Truncate
  1505. then
  1506. if Plac > 0
  1507. then
  1508. if Singles[1] > 4
  1509. then Dec ( res );
  1510. if Neg
  1511. then BCDToInteger := +res
  1512. else BCDToInteger := -res;
  1513. end;
  1514. end;
  1515. { From DB.pas }
  1516. function BCDToCurr ( const BCD : tBCD;
  1517. var Curr : currency ) : Boolean;
  1518. var
  1519. bh : tBCD_helper;
  1520. res : int64;
  1521. c : currency absolute res;
  1522. i : {$ifopt r+} low ( bh.FDig )..4 {$else} Integer {$endif};
  1523. {
  1524. unclear: behaviour if overflow: abort? return 0? return something?
  1525. }
  1526. begin
  1527. BCDToCurr := True;
  1528. unpack_BCD ( BCD, bh );
  1529. res := 0;
  1530. WITH bh do
  1531. begin
  1532. for i := FDig TO 4 do
  1533. res := res * 10 + Singles[i];
  1534. if Plac > 4
  1535. then
  1536. if Singles[5] > 4
  1537. then Inc ( res );
  1538. if Neg
  1539. then Curr := -c
  1540. else Curr := +c;
  1541. end;
  1542. end;
  1543. procedure BCDAdd ( const BCDin1,
  1544. BCDin2 : tBCD;
  1545. var BCDout : tBCD );
  1546. var
  1547. bhr,
  1548. bh1,
  1549. bh2 : tBCD_helper;
  1550. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1551. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1552. v : {$ifopt r+} 0..9 + 9 + 1 {$else} Integer {$endif};
  1553. BCD : tBCD;
  1554. negate : Boolean;
  1555. begin
  1556. negate := IsBCDNegative ( BCDin1 );
  1557. if negate <> IsBCDNegative ( BCDin2 )
  1558. then begin
  1559. if negate
  1560. then begin
  1561. BCD := BCDin1;
  1562. BCDNegate ( BCD );
  1563. BCDSubtract ( BCDin2, BCD, BCDout );
  1564. EXIT;
  1565. end;
  1566. BCD := BCDin2;
  1567. BCDNegate ( BCD );
  1568. BCDSubtract ( BCDin1, BCD, BCDout );
  1569. EXIT;
  1570. end;
  1571. bhr := null_.bh;
  1572. WITH bhr do
  1573. begin
  1574. unpack_BCD ( BCDin1, bh1 );
  1575. unpack_BCD ( BCDin2, bh2 );
  1576. if bh1.FDig < bh2.FDig
  1577. then FDig := bh1.FDig
  1578. else FDig := bh2.FDig;
  1579. if bh1.LDig > bh2.LDig
  1580. then LDig := bh1.LDig
  1581. else LDig := bh2.LDig;
  1582. Plac := LDig;
  1583. ue := 0;
  1584. for i := LDig DOWNTO FDig do
  1585. begin
  1586. v := bh1.Singles[i] + bh2.Singles[i] + ue;
  1587. ue := v DIV 10;
  1588. Singles[i] := v MOD 10;
  1589. end;
  1590. if ue <> 0
  1591. then begin
  1592. Dec ( FDig );
  1593. Singles[FDig] := ue;
  1594. end;
  1595. Neg := negate;
  1596. end;
  1597. if NOT pack_BCD ( bhr, BCDout )
  1598. then begin
  1599. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  1600. end;
  1601. end;
  1602. procedure BCDSubtract ( const BCDin1,
  1603. BCDin2 : tBCD;
  1604. var BCDout : tBCD );
  1605. var
  1606. bhr,
  1607. bh1,
  1608. bh2 : tBCD_helper;
  1609. cmp : {$ifopt r+} -1..1 {$else} Integer {$endif};
  1610. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1611. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1612. v : {$ifopt r+} 0 - 9 - 1..9 - 0 - 0 {$else} Integer {$endif};
  1613. negate : Boolean;
  1614. BCD : tBCD;
  1615. begin
  1616. negate := IsBCDNegative ( BCDin1 );
  1617. if negate <> IsBCDNegative ( BCDin2 )
  1618. then begin
  1619. if negate
  1620. then begin
  1621. BCD := BCDin1;
  1622. BCDNegate ( BCD );
  1623. BCDAdd ( BCDin2, BCD, BCDout );
  1624. BCDNegate ( BCDout );
  1625. EXIT;
  1626. end;
  1627. BCD := BCDin2;
  1628. BCDNegate ( BCD );
  1629. BCDAdd ( BCDin1, BCD, BCDout );
  1630. EXIT;
  1631. end;
  1632. cmp := BCDCompare ( BCDin1, BCDin2 );
  1633. if cmp = 0
  1634. then begin
  1635. BCDout := NullBCD;
  1636. EXIT;
  1637. end;
  1638. bhr := null_.bh; { n n }
  1639. WITH bhr do { > < > < }
  1640. begin { }
  1641. if ( cmp > 0 ) = negate { +123 +12 -12 -123 }
  1642. then begin { - +12 - +123 - -123 - -12 }
  1643. unpack_BCD ( BCDin1, bh2 ); { x x }
  1644. unpack_BCD ( BCDin2, bh1 ); { s s s s }
  1645. negate := NOT negate; { nn n nn n }
  1646. end
  1647. else begin
  1648. unpack_BCD ( BCDin1, bh1 );
  1649. unpack_BCD ( BCDin2, bh2 );
  1650. end;
  1651. if bh1.FDig < bh2.FDig
  1652. then FDig := bh1.FDig
  1653. else FDig := bh2.FDig;
  1654. if bh1.LDig > bh2.LDig
  1655. then LDig := bh1.LDig
  1656. else LDig := bh2.LDig;
  1657. Plac := LDig;
  1658. ue := 0;
  1659. for i := LDig DOWNTO FDig do
  1660. begin
  1661. v := Integer ( bh1.Singles[i] ) - bh2.Singles[i] - ue;
  1662. ue := 0;
  1663. if v < 0
  1664. then begin
  1665. ue := 1;
  1666. Inc ( v, 10 );
  1667. end;
  1668. Singles[i] := v;
  1669. end;
  1670. Neg := negate;
  1671. if NOT pack_BCD ( bhr, BCDout )
  1672. then begin
  1673. {should never occur!}
  1674. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  1675. end;
  1676. end;
  1677. end;
  1678. { Returns True if successful, False if Int Digits needed to be truncated }
  1679. function NormalizeBCD ( const InBCD : tBCD;
  1680. var OutBCD : tBCD;
  1681. const Prec,
  1682. Scale : Word ) : Boolean;
  1683. var
  1684. bh : tBCD_helper;
  1685. tm : {$ifopt r+} 1..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  1686. begin
  1687. NormalizeBCD := True;
  1688. {$ifopt r+}
  1689. if ( Prec < 0 ) OR ( Prec > MaxFmtBCDFractionSize ) then RangeError;
  1690. if ( Scale < 0 ) OR ( Prec >= MaxFmtBCDFractionSize ) then RangeError;
  1691. {$endif}
  1692. if BCDScale ( InBCD ) > Scale
  1693. then begin
  1694. unpack_BCD ( InBCD, bh );
  1695. WITH bh do
  1696. begin
  1697. tm := Plac - Scale;
  1698. Plac := Scale;
  1699. { dec ( prec, tm ); Dec/Inc error? }
  1700. Prec := Prec - tm;
  1701. { dec ( ldig, tm ); Dec/Inc error? }
  1702. LDig := LDig - tm;
  1703. NormalizeBCD := False;
  1704. end;
  1705. if NOT pack_BCD ( bh, OutBCD )
  1706. then begin
  1707. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  1708. end;
  1709. end;
  1710. end;
  1711. procedure BCDMultiply ( const BCDin1,
  1712. BCDin2 : tBCD;
  1713. var BCDout : tBCD );
  1714. var
  1715. bh1,
  1716. bh2,
  1717. bhr : tBCD_helper;
  1718. bhrr : tBCD_helper_big;
  1719. i1 : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1720. i2 : {$ifopt r+} low ( bh2.FDig )..high ( bh2.LDig ) {$else} Integer {$endif};
  1721. i3 : {$ifopt r+} low ( bhrr.FDig )..high ( bhrr.LDig ) {$else} Integer {$endif};
  1722. v : {$ifopt r+} low ( bhrr.Singles[0] )..high ( bhrr.Singles[0] ) {$else} Integer {$endif};
  1723. ue : {$ifopt r+} low ( bhrr.Singles[0] ) DIV 10..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  1724. begin
  1725. unpack_BCD ( BCDin1, bh1 );
  1726. unpack_BCD ( BCDin2, bh2 );
  1727. if ( bh1.Prec = 0 ) OR ( bh2.Prec = 0 )
  1728. then begin
  1729. BCDout := NullBCD;
  1730. EXIT;
  1731. end;
  1732. bhr := null_.bh;
  1733. bhrr := null_.bhb;
  1734. WITH bhrr do
  1735. begin
  1736. Neg := bh1.Neg XOR bh2.Neg;
  1737. {
  1738. writeln ( __lo_bhb, ' ', __hi_bhb, ' ', bh1.fdig, ' ', bh2.fdig, ' ', low ( fdig ), ' ', low ( ldig ) );
  1739. }
  1740. FDig := bh1.FDig + bh2.FDig;
  1741. LDig := bh1.LDig + bh2.LDig;
  1742. for i1 := bh1.FDig TO bh1.LDig do
  1743. for i2 := bh2.FDig TO bh2.LDig do
  1744. begin
  1745. Inc ( Singles[i1 + i2],
  1746. bh1.Singles[i1]
  1747. * bh2.Singles[i2] );
  1748. {
  1749. write ( Singles[i1 + i2], ' ', bh1.Singles[i1], ' ', bh2.Singles[i2], ' : ' );
  1750. writeln ( Singles[i1 + i2] + bh1.Singles[i1] + bh2.Singles[i2] );
  1751. }
  1752. {
  1753. Singles[i1 + i2] := Singles[i1 + i2]
  1754. + bh1.Singles[i1]
  1755. * bh2.Singles[i2];
  1756. }
  1757. end;
  1758. {
  1759. for i3 := fdig to ldig do
  1760. write ( ' ', singles[i3] );
  1761. writeln;
  1762. }
  1763. if FDig < low ( bhr.Singles )
  1764. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1765. ue := 0;
  1766. for i3 := LDig DOWNTO FDig do
  1767. begin
  1768. v := Singles[i3] + ue;
  1769. ue := v DIV 10;
  1770. v := v MOD 10;
  1771. bhr.Singles[i3] := v;
  1772. end;
  1773. while ue <> 0 do
  1774. begin
  1775. Dec ( FDig );
  1776. if FDig < low ( bhr.Singles )
  1777. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1778. bhr.Singles[FDig] := ue MOD 10;
  1779. ue := ue DIV 10;
  1780. end;
  1781. bhr.Plac := LDig;
  1782. bhr.FDig := FDig;
  1783. if LDig > high ( bhr.Singles )
  1784. then bhr.LDig := high ( bhr.Singles )
  1785. else bhr.LDig := LDig;
  1786. end;
  1787. if NOT pack_BCD ( bhr, BCDout )
  1788. then begin
  1789. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1790. end;
  1791. end;
  1792. {$ifndef FPUNONE}
  1793. procedure BCDMultiply ( const BCDIn : tBCD;
  1794. const DoubleIn : myRealtype;
  1795. var BCDout : tBCD ); Inline;
  1796. begin
  1797. BCDMultiply ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  1798. end;
  1799. {$endif}
  1800. procedure BCDMultiply ( const BCDIn : tBCD;
  1801. const StringIn : FmtBCDStringtype;
  1802. var BCDout : tBCD ); Inline;
  1803. begin
  1804. BCDMultiply ( BCDIn, StrToBCD ( StringIn ), BCDout );
  1805. end;
  1806. procedure BCDMultiply ( const StringIn1,
  1807. StringIn2 : FmtBCDStringtype;
  1808. var BCDout : tBCD ); Inline;
  1809. begin
  1810. BCDMultiply ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  1811. end;
  1812. procedure BCDDivide ( const Dividend,
  1813. Divisor : tBCD;
  1814. var BCDout : tBCD );
  1815. var
  1816. bh1 : ARRAY [ Boolean ] of tBCD_helper;
  1817. bh2,
  1818. bh : tBCD_helper;
  1819. p : {$ifopt r+} low ( bh.FDig ) - high ( bh.FDig )..high ( bh.FDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1820. v1 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1821. v2 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1822. lFDig : {$ifopt r+} low ( bh.FDig )..high ( bh.FDig ) {$else} Integer {$endif};
  1823. d1 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1824. d2 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1825. d : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1826. lLdig : {$ifopt r+} low ( lFDig ) + low ( d )..high ( lFDig ) + high ( d ) {$else} Integer {$endif};
  1827. tm : {$ifopt r+} low ( lLdig ) - high ( bh2.Singles )..high ( lLdig ) - high ( bh2.Singles ) {$else} Integer {$endif};
  1828. i2 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1829. i3 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1830. ie : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1831. i4 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1832. nFDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1833. nLDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1834. dd : {$ifopt r+} 0..9 {$else} Integer {$endif};
  1835. Add : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1836. ue : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1837. v3 : {$ifopt r+} low ( bh.Singles[0] ) - high ( bh2.singles[9] ) * high ( dd ) - high ( ue )..high ( bh.Singles[0] ) - low ( bh2.singles[9] ) * low ( dd ) - low ( ue ) {$else} Integer {$endif};
  1838. v4 : {$ifopt r+} low ( bh.Singles[0] ) + low ( add )..high ( bh.Singles[0] ) + high ( add ) {$else} Integer {$endif};
  1839. FlipFlop,
  1840. nz,
  1841. sf,
  1842. sh,
  1843. fdset : Boolean;
  1844. {
  1845. bh1p : ARRAY [ Boolean ] of ^ tBCD_helper;
  1846. }
  1847. begin
  1848. { test:
  1849. bh1p[false] := @ bh1[false];
  1850. bh1p[true] := @ bh1[true];
  1851. v := bh1[false].singles[0];
  1852. v := bh1[true].singles[0];
  1853. v := bh1p[false]^.singles[0];
  1854. v := bh1p[true]^.singles[0];
  1855. v := bh1[nz].singles[0];
  1856. v := bh1p[nz]^.singles[0];
  1857. }
  1858. unpack_BCD ( Divisor, bh2 );
  1859. unpack_BCD ( Dividend, bh1[False] );
  1860. p := bh1[False].FDig - bh2.FDig;
  1861. _SELECT
  1862. _WHEN bh2.Prec = 0
  1863. _THEN RAISE eBCDException.create ( 'Division by zero' );
  1864. _WHEN bh1[False].Prec = 0
  1865. _THEN BCDout := NullBCD;
  1866. _WHEN p < low ( bh2.Singles )
  1867. _THEN RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  1868. _WHENOTHER
  1869. bh := null_.bh;
  1870. bh.Neg := bh1[False].Neg XOR bh2.Neg;
  1871. if p <= high ( bh.Singles )
  1872. then begin
  1873. bh1[True] := null_.bh;
  1874. FlipFlop := False;
  1875. fdset := p > 0;
  1876. if fdset
  1877. then bh.FDig := 0;
  1878. add := 0;
  1879. nz := True;
  1880. while nz do
  1881. WITH bh1[FlipFlop] do
  1882. begin
  1883. {
  1884. WriteLn('#####');
  1885. dumpbh ( bh1[flipflop] );
  1886. dumpbh ( bh2 );
  1887. dumpbh ( bh );
  1888. }
  1889. if ( Singles[FDig] + bh2.Singles[bh2.FDig] ) = 0
  1890. then begin
  1891. if ( FDig >= LDig )
  1892. OR ( bh2.FDig >= bh2.LDig )
  1893. then nz := False
  1894. else begin
  1895. Inc ( FDig );
  1896. Inc ( bh2.FDig );
  1897. end;
  1898. end
  1899. else begin
  1900. v1 := Singles[FDig];
  1901. v2 := bh2.Singles[bh2.FDig];
  1902. sh := v1 < v2;
  1903. if ( v1 = v2 )
  1904. then begin
  1905. nz := False;
  1906. i3 := Succ ( FDig );
  1907. ie := LDig;
  1908. while ( i3 <= ie ) AND ( NOT nz ) AND ( NOT sh ) do
  1909. begin
  1910. v1 := Singles[i3];
  1911. v2 := bh2.Singles[i3 - p];
  1912. if v1 <> v2
  1913. then begin
  1914. nz := True;
  1915. if v1 < v2
  1916. then sh := True;
  1917. end;
  1918. Inc ( i3 );
  1919. end;
  1920. end;
  1921. if NOT nz
  1922. then Add := 1
  1923. else begin
  1924. if sh
  1925. then begin
  1926. Inc ( p );
  1927. {
  1928. if p > 3 then halt;
  1929. }
  1930. if p > high ( bh.Singles )
  1931. then nz := False
  1932. else Dec ( bh2.FDig );
  1933. end
  1934. else begin
  1935. lFDig := FDig;
  1936. d1 := LDig - FDig;
  1937. d2 := bh2.LDig - bh2.FDig;
  1938. if d1 > d2
  1939. then d := d1
  1940. else d := d2;
  1941. lLdig := lFDig + d;
  1942. if lLdig > high ( bh2.Singles )
  1943. then begin
  1944. tm := ( lLdig ) - high ( bh2.Singles );
  1945. d := d - tm;
  1946. lLdig := lLdig - tm;
  1947. {runden?}
  1948. end;
  1949. sf := True;
  1950. Add := 0;
  1951. nFDig := 0;
  1952. nLDig := 0;
  1953. ue := 0;
  1954. dd := Singles[lFDig] DIV ( bh2.Singles[lFDig - p] + 1 );
  1955. {
  1956. dd := 1;
  1957. }
  1958. if dd < 1
  1959. then dd := 1;
  1960. {
  1961. writeln ( 'p=', p, ' dd=', dd, ' lFdig=', lfdig, ' lldig=', lldig );
  1962. }
  1963. for i2 := lLdig DOWNTO lFDig do
  1964. begin
  1965. v3 := Singles[i2] - bh2.Singles[i2 - p] * dd - ue;
  1966. ue := 0;
  1967. while v3 < 0 do
  1968. begin
  1969. Inc ( ue );;
  1970. v3 := v3 + 10;
  1971. end;
  1972. {
  1973. if v3 <> 0
  1974. then begin
  1975. }
  1976. bh1[NOT FlipFlop].Singles[i2] := v3;
  1977. {
  1978. nFDig := i2;
  1979. if sf
  1980. then begin
  1981. nLDig := i2;
  1982. sf := False;
  1983. end;
  1984. end;
  1985. }
  1986. end;
  1987. sf := False;
  1988. nfdig := lfdig;
  1989. nldig := lldig;
  1990. Inc ( Add, dd );
  1991. if NOT fdset
  1992. then begin
  1993. bh.FDig := p;
  1994. fdset := True;
  1995. end;
  1996. if bh.LDig < p
  1997. then begin
  1998. bh.LDig := p;
  1999. if ( bh.LDig - bh.FDig ) > Succ ( MaxFmtBCDFractionSize )
  2000. then nz := False;
  2001. end;
  2002. if sf
  2003. then nz := False
  2004. else begin
  2005. FillChar ( bh1[FlipFlop], SizeOf ( bh1[FlipFlop] ), #0 );
  2006. FlipFlop := NOT FlipFlop;
  2007. WITH bh1[FlipFlop] do
  2008. begin
  2009. FDig := nFDig;
  2010. LDig := nLDig;
  2011. end;
  2012. end;
  2013. end;
  2014. end;
  2015. if Add <> 0
  2016. then begin
  2017. i4 := p;
  2018. while ( Add <> 0 ) AND ( i4 >= bh.FDig ) do
  2019. begin
  2020. {
  2021. writeln ( '> ', i4, ' ', bh.Singles[i4], ' ', Add );
  2022. }
  2023. v4 := bh.Singles[i4] + Add;
  2024. Add := v4 DIV 10;
  2025. bh.Singles[i4] := v4 MOD 10;
  2026. Dec ( i4 );
  2027. end;
  2028. if Add <> 0
  2029. then begin
  2030. Dec ( bh.FDig );
  2031. bh.Singles[bh.FDig] := Add;
  2032. Add := 0;
  2033. end;
  2034. end;
  2035. end;
  2036. end;
  2037. end;
  2038. WITH bh do
  2039. begin
  2040. if LDig < 0
  2041. then LDig := 0;
  2042. if LDig > 0
  2043. then Plac := LDig
  2044. else Plac := 0;
  2045. end;
  2046. if NOT pack_BCD ( bh, BCDout )
  2047. then begin
  2048. RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  2049. end;
  2050. _endSELECT
  2051. end;
  2052. procedure BCDDivide ( const Dividend,
  2053. Divisor : FmtBCDStringtype;
  2054. var BCDout : tBCD ); Inline;
  2055. begin
  2056. BCDDivide ( StrToBCD ( Dividend ), StrToBCD ( Divisor ), BCDout );
  2057. end;
  2058. {$ifndef FPUNONE}
  2059. procedure BCDDivide ( const Dividend : tBCD;
  2060. const Divisor : myRealtype;
  2061. var BCDout : tBCD ); Inline;
  2062. begin
  2063. BCDDivide ( Dividend, DoubleToBCD ( Divisor ), BCDout );
  2064. end;
  2065. {$endif}
  2066. procedure BCDDivide ( const Dividend : tBCD;
  2067. const Divisor : FmtBCDStringtype;
  2068. var BCDout : tBCD ); Inline;
  2069. begin
  2070. BCDDivide ( Dividend, StrToBCD ( Divisor ), BCDout );
  2071. end;
  2072. { TBCD variant creation utils }
  2073. procedure VarFmtBCDCreate ( var aDest : Variant;
  2074. const aBCD : tBCD );
  2075. begin
  2076. VarClear(aDest);
  2077. TVarData(aDest).Vtype:=FMTBcdFactory.Vartype;
  2078. TVarData(aDest).VPointer:=TFMTBcdVarData.create(aBCD);
  2079. end;
  2080. function VarFmtBCDCreate : Variant;
  2081. begin
  2082. VarFmtBCDCreate ( result, NullBCD );
  2083. end;
  2084. function VarFmtBCDCreate ( const aValue : FmtBCDStringtype;
  2085. Precision,
  2086. Scale : Word ) : Variant;
  2087. begin
  2088. VarFmtBCDCreate ( result, StrToBCD ( aValue ) );
  2089. end;
  2090. {$ifndef FPUNONE}
  2091. function VarFmtBCDCreate ( const aValue : myRealtype;
  2092. Precision : Word = 18;
  2093. Scale : Word = 4 ) : Variant;
  2094. begin
  2095. VarFmtBCDCreate ( result, DoubleToBCD ( aValue ) );
  2096. end;
  2097. {$endif}
  2098. function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant;
  2099. begin
  2100. VarFmtBCDCreate ( result, aBCD );
  2101. end;
  2102. function VarIsFmtBCD ( const aValue : Variant ) : Boolean;
  2103. begin
  2104. result:=false;
  2105. not_implemented;
  2106. end;
  2107. function VarFmtBCD : TVartype;
  2108. begin
  2109. result:=0;
  2110. not_implemented;
  2111. end;
  2112. { Formatting BCD as string }
  2113. function BCDToStrF ( const BCD : tBCD;
  2114. Format : TFloatFormat;
  2115. const Precision,
  2116. Digits : Integer ) : FmtBCDStringtype;
  2117. begin
  2118. not_implemented;
  2119. result:='';
  2120. end;
  2121. function FormatBCD ( const Format : string;
  2122. BCD : tBCD ) : FmtBCDStringtype;
  2123. begin
  2124. not_implemented;
  2125. result:='';
  2126. end;
  2127. {$ifdef additional_routines}
  2128. function CurrToBCD ( const Curr : currency ) : tBCD; Inline;
  2129. begin
  2130. CurrToBCD ( Curr, result );
  2131. end;
  2132. procedure BCDAdd ( const BCDIn : tBCD;
  2133. const IntIn : myInttype;
  2134. var BCDout : tBCD );
  2135. var
  2136. BCD : tBCD;
  2137. bhr : tBCD_helper;
  2138. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2139. ue : {$ifopt r+} 0..high ( IntIn ) - 9 {$else} Integer {$endif};
  2140. v : {$ifopt r+} 0..{high ( ue ) + 9} high ( IntIn ) {$else} Integer {$endif};
  2141. nz : Boolean;
  2142. begin
  2143. if IntIn = 0
  2144. then begin
  2145. BCDout := BCDIn;
  2146. EXIT;
  2147. end;
  2148. if IntIn = low ( myInttype )
  2149. then begin
  2150. {$if declared ( myMinIntBCD ) }
  2151. BCDAdd ( BCDIn, myMinIntBCD, BCDout );
  2152. EXIT;
  2153. {$else}
  2154. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2155. {$endif}
  2156. end;
  2157. if IsBCDNegative ( BCDIn )
  2158. then begin
  2159. BCD := BCDIn;
  2160. BCDNegate ( BCD );
  2161. if IntIn < 0
  2162. then BCDAdd ( BCD, -IntIn, BCDout )
  2163. else BCDSubtract ( BCD, IntIn, BCDout );
  2164. BCDNegate ( BCDout );
  2165. EXIT;
  2166. end;
  2167. if IntIn < 0
  2168. then begin
  2169. BCDSubtract ( BCDIn, -IntIn, BCDout );
  2170. EXIT;
  2171. end;
  2172. if IntIn > ( high ( IntIn ) - 9 )
  2173. then begin
  2174. BCDAdd ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2175. EXIT;
  2176. end;
  2177. unpack_BCD ( BCDIn, bhr );
  2178. p := 0;
  2179. nz := True;
  2180. ue := IntIn;
  2181. while nz do
  2182. begin
  2183. v := bhr.Singles[p] + ue;
  2184. bhr.Singles[p] := v MOD 10;
  2185. ue := v DIV 10;
  2186. if ue = 0
  2187. then nz := False
  2188. else Dec ( p );
  2189. end;
  2190. if p < bhr.FDig
  2191. then begin
  2192. bhr.FDig := p;
  2193. bhr.Prec := bhr.Prec + ( bhr.FDig - p );
  2194. end;
  2195. if NOT pack_BCD ( bhr, BCDout )
  2196. then begin
  2197. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2198. end;
  2199. end;
  2200. procedure BCDSubtract ( const BCDIn : tBCD;
  2201. const IntIn : myInttype;
  2202. var BCDout : tBCD );
  2203. {}
  2204. var
  2205. BCD : tBCD;
  2206. bhr : tBCD_helper;
  2207. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2208. ue : {$ifopt r+} 0..pred ( 100000000 ) {$else} Integer {$endif};
  2209. v : {$ifopt r+} -9..9 {$else} Integer {$endif};
  2210. direct : Boolean;
  2211. {}
  2212. begin
  2213. if IntIn = 0
  2214. then begin
  2215. BCDout := BCDIn;
  2216. EXIT;
  2217. end;
  2218. if IntIn = low ( myInttype )
  2219. then begin
  2220. {$if declared ( myMinIntBCD ) }
  2221. BCDSubtract ( BCDIn, myMinIntBCD, BCDout );
  2222. EXIT;
  2223. {$else}
  2224. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2225. {$endif}
  2226. end;
  2227. if IsBCDNegative ( BCDIn )
  2228. then begin
  2229. BCD := BCDIn;
  2230. BCDNegate ( BCD );
  2231. if IntIn < 0
  2232. then BCDSubtract ( BCD, -IntIn, BCDout )
  2233. else BCDAdd ( BCD, IntIn, BCDout );
  2234. BCDNegate ( BCDout );
  2235. EXIT;
  2236. end;
  2237. if IntIn < 0
  2238. then begin
  2239. BCDAdd ( BCDIn, -IntIn, BCDout );
  2240. EXIT;
  2241. end;
  2242. direct := False;
  2243. case BCDIn.Precision
  2244. -
  2245. {$ifndef bigger_BCD}
  2246. ( BCDIn.SignSpecialPlaces AND PlacesMask )
  2247. {$else}
  2248. BCDIn.Places
  2249. {$endif}
  2250. of
  2251. 2: direct := IntIn < 10;
  2252. 3: direct := IntIn < 100;
  2253. 4: direct := IntIn < 1000;
  2254. 5: direct := IntIn < 10000;
  2255. 6: direct := IntIn < 100000;
  2256. 7: direct := IntIn < 1000000;
  2257. 8: direct := IntIn < 10000000;
  2258. 9: direct := IntIn < 100000000;
  2259. end;
  2260. {
  2261. write(direct);dumpbcd(bcdin);write('[',intin,']');
  2262. }
  2263. if direct
  2264. then begin
  2265. unpack_BCD ( BCDIn, bhr );
  2266. WITH bhr do
  2267. begin
  2268. p := 0;
  2269. ue := IntIn;
  2270. while p >= FDig do
  2271. begin
  2272. v := Singles[p] - ue MOD 10;
  2273. ue := ue DIV 10;
  2274. if v < 0
  2275. then begin
  2276. v := v + 10;
  2277. ue := ue + 1;
  2278. end;
  2279. Singles[p] := v;
  2280. Dec ( p );
  2281. end;
  2282. end;
  2283. if NOT pack_BCD ( bhr, BCDout )
  2284. then begin
  2285. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2286. end;
  2287. end
  2288. else
  2289. {}
  2290. BCDSubtract ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2291. end;
  2292. procedure BCDAdd ( const IntIn : myInttype;
  2293. const BCDIn : tBCD;
  2294. var BCDout : tBCD ); Inline;
  2295. begin
  2296. BCDAdd ( BCDIn, IntIn, BCDout );
  2297. end;
  2298. {$ifndef FPUNONE}
  2299. procedure BCDAdd ( const BCDIn : tBCD;
  2300. const DoubleIn : myRealtype;
  2301. var BCDout : tBCD ); Inline;
  2302. begin
  2303. BCDAdd ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2304. end;
  2305. procedure BCDAdd ( const DoubleIn : myRealtype;
  2306. const BCDIn : tBCD;
  2307. var BCDout : tBCD ); Inline;
  2308. begin
  2309. BCDAdd ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2310. end;
  2311. {$endif}
  2312. procedure BCDAdd ( const BCDIn : tBCD;
  2313. const Currin : currency;
  2314. var BCDout : tBCD ); Inline;
  2315. begin
  2316. BCDAdd ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2317. end;
  2318. procedure BCDAdd ( const Currin : currency;
  2319. const BCDIn : tBCD;
  2320. var BCDout : tBCD ); Inline;
  2321. begin
  2322. BCDAdd ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2323. end;
  2324. {$ifdef comproutines}
  2325. procedure BCDAdd ( const BCDIn : tBCD;
  2326. const Compin : Comp;
  2327. var BCDout : tBCD ); Inline;
  2328. begin
  2329. BCDAdd ( BCDIn, CompToBCD ( Compin ), BCDout );
  2330. end;
  2331. procedure BCDAdd ( const Compin : Comp;
  2332. const BCDIn : tBCD;
  2333. var BCDout : tBCD ); Inline;
  2334. begin
  2335. BCDAdd ( CompToBCD ( Compin ), BCDIn, BCDout );
  2336. end;
  2337. {$endif}
  2338. procedure BCDAdd ( const BCDIn : tBCD;
  2339. const StringIn : FmtBCDStringtype;
  2340. var BCDout : tBCD ); Inline;
  2341. begin
  2342. BCDAdd ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2343. end;
  2344. procedure BCDAdd ( const StringIn : FmtBCDStringtype;
  2345. const BCDIn : tBCD;
  2346. var BCDout : tBCD ); Inline;
  2347. begin
  2348. BCDAdd ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2349. end;
  2350. procedure BCDAdd ( const StringIn1,
  2351. StringIn2 : FmtBCDStringtype;
  2352. var BCDout : tBCD ); Inline;
  2353. begin
  2354. BCDAdd ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2355. end;
  2356. procedure BCDSubtract ( const IntIn : myInttype;
  2357. const BCDIn : tBCD;
  2358. var BCDout : tBCD ); Inline;
  2359. begin
  2360. BCDSubtract ( BCDIn, IntIn, BCDout );
  2361. BCDNegate ( BCDout );
  2362. end;
  2363. {$ifndef FPUNONE}
  2364. procedure BCDSubtract ( const BCDIn : tBCD;
  2365. const DoubleIn : myRealtype;
  2366. var BCDout : tBCD ); Inline;
  2367. begin
  2368. BCDSubtract ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2369. end;
  2370. procedure BCDSubtract ( const DoubleIn : myRealtype;
  2371. const BCDIn : tBCD;
  2372. var BCDout : tBCD ); Inline;
  2373. begin
  2374. BCDSubtract ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2375. end;
  2376. {$endif}
  2377. procedure BCDSubtract ( const BCDIn : tBCD;
  2378. const Currin : currency;
  2379. var BCDout : tBCD ); Inline;
  2380. begin
  2381. BCDSubtract ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2382. end;
  2383. procedure BCDSubtract ( const Currin : currency;
  2384. const BCDIn : tBCD;
  2385. var BCDout : tBCD ); Inline;
  2386. begin
  2387. BCDSubtract ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2388. end;
  2389. {$ifdef comproutines}
  2390. procedure BCDSubtract ( const BCDIn : tBCD;
  2391. const Compin : Comp;
  2392. var BCDout : tBCD ); Inline;
  2393. begin
  2394. BCDSubtract ( BCDIn, CompToBCD ( Compin ), BCDout );
  2395. end;
  2396. procedure BCDSubtract ( const Compin : Comp;
  2397. const BCDIn : tBCD;
  2398. var BCDout : tBCD ); Inline;
  2399. begin
  2400. BCDSubtract ( CompToBCD ( Compin ), BCDIn, BCDout );
  2401. end;
  2402. {$endif}
  2403. procedure BCDSubtract ( const BCDIn : tBCD;
  2404. const StringIn : FmtBCDStringtype;
  2405. var BCDout : tBCD ); Inline;
  2406. begin
  2407. BCDSubtract ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2408. end;
  2409. procedure BCDSubtract ( const StringIn : FmtBCDStringtype;
  2410. const BCDIn : tBCD;
  2411. var BCDout : tBCD ); Inline;
  2412. begin
  2413. BCDSubtract ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2414. end;
  2415. procedure BCDSubtract ( const StringIn1,
  2416. StringIn2 : FmtBCDStringtype;
  2417. var BCDout : tBCD ); Inline;
  2418. begin
  2419. BCDSubtract ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2420. end;
  2421. procedure BCDMultiply ( const BCDIn : tBCD;
  2422. const IntIn : myInttype;
  2423. var BCDout : tBCD );
  2424. var
  2425. bh : tBCD_helper;
  2426. bhr : tBCD_helper;
  2427. bhrr : tBCD_helper_big;
  2428. int : {$ifopt r+} 0..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  2429. i1 : {$ifopt r+} low ( bh.Singles )..high ( bh.Singles ) {$else} Integer {$endif};
  2430. i3 : {$ifopt r+} low ( bhr.Singles )..high ( bhr.Singles ) {$else} Integer {$endif};
  2431. v : {$ifopt r+} low ( bhrr.Singles[0] ) + low ( bhrr.Singles[0] ) DIV 10..high ( bhrr.Singles[0] ) + high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  2432. ue : {$ifopt r+} 1 * ( low ( bhrr.Singles[0] ) + low ( bhrr.Singles[0] ) DIV 10 ) DIV 10
  2433. ..( high ( bhrr.Singles[0] ) + high ( bhrr.Singles[0] ) DIV 10 ) DIV 10 {$else} Integer {$endif};
  2434. begin
  2435. if IntIn = 0
  2436. then begin
  2437. BCDout := NullBCD;
  2438. EXIT;
  2439. end;
  2440. if IntIn = 1
  2441. then begin
  2442. BCDout := BCDIn;
  2443. EXIT;
  2444. end;
  2445. if IntIn = -1
  2446. then begin
  2447. BCDout := BCDIn;
  2448. BCDNegate ( BCDout );
  2449. EXIT;
  2450. end;
  2451. if IntIn = low ( myInttype )
  2452. then begin
  2453. {$if declared ( myMinIntBCD ) }
  2454. BCDMultiply ( BCDIn, myMinIntBCD, BCDout );
  2455. EXIT;
  2456. {$else}
  2457. RAISE eBCDOverflowException.create ( 'in BCDmultiply' );
  2458. {$endif}
  2459. end;
  2460. if Abs ( IntIn ) > low ( bhrr.Singles[0] ) DIV 10
  2461. then begin
  2462. BCDMultiply ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2463. EXIT;
  2464. end;
  2465. unpack_BCD ( BCDIn, bh );
  2466. if bh.Prec = 0
  2467. then begin
  2468. BCDout := NullBCD;
  2469. EXIT;
  2470. end;
  2471. bhr := null_.bh;
  2472. bhrr := null_.bhb;
  2473. int := Abs ( IntIn );
  2474. WITH bhrr do
  2475. begin
  2476. Neg := bh.Neg XOR ( IntIn < 0 );
  2477. FDig := bh.FDig;
  2478. LDig := bh.LDig;
  2479. for i1 := bh.FDig TO bh.LDig do
  2480. Singles[i1] := bh.Singles[i1] * int;
  2481. {
  2482. for i3 := fdig to ldig do
  2483. write ( ' ', singles[i3] );
  2484. writeln;
  2485. }
  2486. ue := 0;
  2487. for i3 := LDig DOWNTO FDig do
  2488. begin
  2489. v := Singles[i3] + ue;
  2490. ue := v DIV 10;
  2491. v := v MOD 10;
  2492. bhr.Singles[i3] := v;
  2493. end;
  2494. while ue <> 0 do
  2495. begin
  2496. Dec ( FDig );
  2497. if FDig < low ( bhr.Singles )
  2498. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2499. bhr.Singles[FDig] := ue MOD 10;
  2500. ue := ue DIV 10;
  2501. end;
  2502. bhr.Plac := LDig;
  2503. bhr.FDig := FDig;
  2504. if LDig > high ( bhr.Singles )
  2505. then bhr.LDig := high ( bhr.Singles )
  2506. else bhr.LDig := LDig;
  2507. end;
  2508. if NOT pack_BCD ( bhr, BCDout )
  2509. then begin
  2510. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2511. end;
  2512. end;
  2513. procedure BCDMultiply ( const IntIn : myInttype;
  2514. const BCDIn : tBCD;
  2515. var BCDout : tBCD ); Inline;
  2516. begin
  2517. BCDMultiply ( BCDIn, IntIn, BCDout );
  2518. end;
  2519. {$ifndef FPUNONE}
  2520. procedure BCDMultiply ( const DoubleIn : myRealtype;
  2521. const BCDIn : tBCD;
  2522. var BCDout : tBCD ); Inline;
  2523. begin
  2524. BCDMultiply ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2525. end;
  2526. {$endif}
  2527. procedure BCDMultiply ( const BCDIn : tBCD;
  2528. const Currin : currency;
  2529. var BCDout : tBCD ); Inline;
  2530. begin
  2531. BCDMultiply ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2532. end;
  2533. procedure BCDMultiply ( const Currin : currency;
  2534. const BCDIn : tBCD;
  2535. var BCDout : tBCD ); Inline;
  2536. begin
  2537. BCDMultiply ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2538. end;
  2539. {$ifdef comproutines}
  2540. procedure BCDMultiply ( const BCDIn : tBCD;
  2541. const Compin : Comp;
  2542. var BCDout : tBCD ); Inline;
  2543. begin
  2544. BCDMultiply ( BCDIn, CompToBCD ( Compin ), BCDout );
  2545. end;
  2546. procedure BCDMultiply ( const Compin : Comp;
  2547. const BCDIn : tBCD;
  2548. var BCDout : tBCD ); Inline;
  2549. begin
  2550. BCDMultiply ( CompToBCD ( Compin ), BCDIn, BCDout );
  2551. end;
  2552. {$endif}
  2553. procedure BCDMultiply ( const StringIn : FmtBCDStringtype;
  2554. const BCDIn : tBCD;
  2555. var BCDout : tBCD ); Inline;
  2556. begin
  2557. BCDMultiply ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2558. end;
  2559. procedure BCDDivide ( const Dividend : tBCD;
  2560. const Divisor : myInttype;
  2561. var BCDout : tBCD ); Inline;
  2562. begin
  2563. BCDDivide ( Dividend, IntegerToBCD ( Divisor ), BCDout );
  2564. end;
  2565. procedure BCDDivide ( const Dividend : myInttype;
  2566. const Divisor : tBCD;
  2567. var BCDout : tBCD ); Inline;
  2568. begin
  2569. BCDDivide ( IntegerToBCD ( Dividend ), Divisor, BCDout );
  2570. end;
  2571. {$ifndef FPUNONE}
  2572. procedure BCDDivide ( const Dividend : myRealtype;
  2573. const Divisor : tBCD;
  2574. var BCDout : tBCD ); Inline;
  2575. begin
  2576. BCDDivide ( DoubleToBCD ( Dividend ), Divisor, BCDout );
  2577. end;
  2578. {$endif}
  2579. procedure BCDDivide ( const BCDIn : tBCD;
  2580. const Currin : currency;
  2581. var BCDout : tBCD ); Inline;
  2582. begin
  2583. BCDDivide ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2584. end;
  2585. procedure BCDDivide ( const Currin : currency;
  2586. const BCDIn : tBCD;
  2587. var BCDout : tBCD ); Inline;
  2588. begin
  2589. BCDDivide ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2590. end;
  2591. {$ifdef comproutines}
  2592. procedure BCDDivide ( const BCDIn : tBCD;
  2593. const Compin : Comp;
  2594. var BCDout : tBCD ); Inline;
  2595. begin
  2596. BCDDivide ( BCDIn, CompToBCD ( Compin ), BCDout );
  2597. end;
  2598. procedure BCDDivide ( const Compin : Comp;
  2599. const BCDIn : tBCD;
  2600. var BCDout : tBCD ); Inline;
  2601. begin
  2602. BCDDivide ( CompToBCD ( Compin ), BCDIn, BCDout );
  2603. end;
  2604. {$endif}
  2605. procedure BCDDivide ( const Dividend : FmtBCDStringtype;
  2606. const Divisor : tBCD;
  2607. var BCDout : tBCD ); Inline;
  2608. begin
  2609. BCDDivide ( StrToBCD ( Dividend ), Divisor, BCDout );
  2610. end;
  2611. operator = ( const BCD1,
  2612. BCD2 : tBCD ) z : Boolean; Inline;
  2613. begin
  2614. z := BCDCompare ( BCD1, BCD2 ) = 0;
  2615. end;
  2616. operator < ( const BCD1,
  2617. BCD2 : tBCD ) z : Boolean; Inline;
  2618. begin
  2619. z := BCDCompare ( BCD1, BCD2 ) < 0;
  2620. end;
  2621. operator > ( const BCD1,
  2622. BCD2 : tBCD ) z : Boolean; Inline;
  2623. begin
  2624. z := BCDCompare ( BCD1, BCD2 ) > 0;
  2625. end;
  2626. operator <= ( const BCD1,
  2627. BCD2 : tBCD ) z : Boolean; Inline;
  2628. begin
  2629. z := BCDCompare ( BCD1, BCD2 ) <= 0;
  2630. end;
  2631. operator >= ( const BCD1,
  2632. BCD2 : tBCD ) z : Boolean; Inline;
  2633. begin
  2634. z := BCDCompare ( BCD1, BCD2 ) >= 0;
  2635. end;
  2636. (* ######################## not allowed: why?
  2637. operator + ( const BCD : tBCD ) z : tBCD; Inline;
  2638. begin
  2639. z := bcd;
  2640. end;
  2641. ##################################################### *)
  2642. operator - ( const BCD : tBCD ) z : tBCD; Inline;
  2643. begin
  2644. z := BCD;
  2645. BCDNegate ( z );
  2646. end;
  2647. operator + ( const BCD1,
  2648. BCD2 : tBCD ) z : tBCD; Inline;
  2649. begin
  2650. BCDAdd ( BCD1, BCD2, z );
  2651. end;
  2652. operator + ( const BCD : tBCD;
  2653. const i : myInttype ) z : tBCD; Inline;
  2654. begin
  2655. BCDAdd ( BCD, i, z );
  2656. end;
  2657. operator + ( const i : myInttype;
  2658. const BCD : tBCD ) z : tBCD; Inline;
  2659. begin
  2660. BCDAdd ( i, BCD, z );
  2661. end;
  2662. {$ifndef FPUNONE}
  2663. operator + ( const BCD : tBCD;
  2664. const r : myRealtype ) z : tBCD; Inline;
  2665. begin
  2666. BCDAdd ( BCD, DoubleToBCD ( r ), z );
  2667. end;
  2668. operator + ( const r : myRealtype;
  2669. const BCD : tBCD ) z : tBCD; Inline;
  2670. begin
  2671. BCDAdd ( DoubleToBCD ( r ), BCD, z );
  2672. end;
  2673. {$endif}
  2674. operator + ( const BCD : tBCD;
  2675. const c : currency ) z : tBCD; Inline;
  2676. begin
  2677. BCDAdd ( BCD, CurrToBCD ( c ), z );
  2678. end;
  2679. operator + ( const c : currency;
  2680. const BCD : tBCD ) z : tBCD; Inline;
  2681. begin
  2682. BCDAdd ( CurrToBCD ( c ), BCD, z );
  2683. end;
  2684. {$ifdef comproutines}
  2685. operator + ( const BCD : tBCD;
  2686. const c : Comp ) z : tBCD; Inline;
  2687. begin
  2688. BCDAdd ( BCD, CompToBCD ( c ), z );
  2689. end;
  2690. operator + ( const c : Comp;
  2691. const BCD : tBCD ) z : tBCD; Inline;
  2692. begin
  2693. BCDAdd ( CompToBCD ( c ), BCD, z );
  2694. end;
  2695. {$endif}
  2696. operator + ( const BCD : tBCD;
  2697. const s : FmtBCDStringtype ) z : tBCD; Inline;
  2698. begin
  2699. BCDAdd ( BCD, StrToBCD ( s ), z );
  2700. end;
  2701. operator + ( const s : FmtBCDStringtype;
  2702. const BCD : tBCD ) z : tBCD; Inline;
  2703. begin
  2704. BCDAdd ( StrToBCD ( s ), BCD, z );
  2705. end;
  2706. operator - ( const BCD1,
  2707. BCD2 : tBCD ) z : tBCD; Inline;
  2708. begin
  2709. BCDSubtract ( BCD1, BCD2, z );
  2710. end;
  2711. operator - ( const BCD : tBCD;
  2712. const i : myInttype ) z : tBCD; Inline;
  2713. begin
  2714. BCDSubtract ( BCD, i, z );
  2715. end;
  2716. operator - ( const i : myInttype;
  2717. const BCD : tBCD ) z : tBCD; Inline;
  2718. begin
  2719. BCDSubtract ( BCD, i, z );
  2720. BCDNegate ( z );
  2721. end;
  2722. {$ifndef FPUNONE}
  2723. operator - ( const BCD : tBCD;
  2724. const r : myRealtype ) z : tBCD; Inline;
  2725. begin
  2726. BCDSubtract ( BCD, DoubleToBCD ( r ), z );
  2727. end;
  2728. operator - ( const r : myRealtype;
  2729. const BCD : tBCD ) z : tBCD; Inline;
  2730. begin
  2731. BCDSubtract ( DoubleToBCD ( r ), BCD, z );
  2732. end;
  2733. {$endif}
  2734. operator - ( const BCD : tBCD;
  2735. const c : currency ) z : tBCD; Inline;
  2736. begin
  2737. BCDSubtract ( BCD, CurrToBCD ( c ), z );
  2738. end;
  2739. operator - ( const c : currency;
  2740. const BCD : tBCD ) z : tBCD; Inline;
  2741. begin
  2742. BCDSubtract ( CurrToBCD ( c ), BCD, z );
  2743. end;
  2744. {$ifdef comproutines}
  2745. operator - ( const BCD : tBCD;
  2746. const c : Comp ) z : tBCD; Inline;
  2747. begin
  2748. BCDSubtract ( BCD, CompToBCD ( c ), z );
  2749. end;
  2750. operator - ( const c : Comp;
  2751. const BCD : tBCD ) z : tBCD; Inline;
  2752. begin
  2753. BCDSubtract ( CompToBCD ( c ), BCD, z );
  2754. end;
  2755. {$endif}
  2756. operator - ( const BCD : tBCD;
  2757. const s : FmtBCDStringtype ) z : tBCD; Inline;
  2758. begin
  2759. BCDSubtract ( BCD, StrToBCD ( s ), z );
  2760. end;
  2761. operator - ( const s : FmtBCDStringtype;
  2762. const BCD : tBCD ) z : tBCD; Inline;
  2763. begin
  2764. BCDSubtract ( StrToBCD ( s ), BCD, z );
  2765. end;
  2766. operator * ( const BCD1,
  2767. BCD2 : tBCD ) z : tBCD; Inline;
  2768. begin
  2769. BCDMultiply ( BCD1, BCD2, z );
  2770. end;
  2771. operator * ( const BCD : tBCD;
  2772. const i : myInttype ) z : tBCD; Inline;
  2773. begin
  2774. BCDMultiply ( BCD, i, z );
  2775. end;
  2776. operator * ( const i : myInttype;
  2777. const BCD : tBCD ) z : tBCD; Inline;
  2778. begin
  2779. BCDMultiply ( BCD, i, z );
  2780. end;
  2781. {$ifndef FPUNONE}
  2782. operator * ( const BCD : tBCD;
  2783. const r : myRealtype ) z : tBCD; Inline;
  2784. begin
  2785. BCDMultiply ( BCD, DoubleToBCD ( r ), z );
  2786. end;
  2787. operator * ( const r : myRealtype;
  2788. const BCD : tBCD ) z : tBCD; Inline;
  2789. begin
  2790. BCDMultiply ( DoubleToBCD ( r ), BCD, z );
  2791. end;
  2792. {$endif}
  2793. operator * ( const BCD : tBCD;
  2794. const c : currency ) z : tBCD; Inline;
  2795. begin
  2796. BCDMultiply ( BCD, CurrToBCD ( c ), z );
  2797. end;
  2798. operator * ( const c : currency;
  2799. const BCD : tBCD ) z : tBCD; Inline;
  2800. begin
  2801. BCDMultiply ( CurrToBCD ( c ), BCD, z );
  2802. end;
  2803. {$ifdef comproutines}
  2804. operator * ( const BCD : tBCD;
  2805. const c : Comp ) z : tBCD; Inline;
  2806. begin
  2807. BCDMultiply ( BCD, CompToBCD ( c ), z );
  2808. end;
  2809. operator * ( const c : Comp;
  2810. const BCD : tBCD ) z : tBCD; Inline;
  2811. begin
  2812. BCDMultiply ( CompToBCD ( c ), BCD, z );
  2813. end;
  2814. {$endif}
  2815. operator * ( const BCD : tBCD;
  2816. const s : FmtBCDStringtype ) z : tBCD; Inline;
  2817. begin
  2818. BCDMultiply ( BCD, StrToBCD ( s ), z );
  2819. end;
  2820. operator * ( const s : FmtBCDStringtype;
  2821. const BCD : tBCD ) z : tBCD; Inline;
  2822. begin
  2823. BCDMultiply ( StrToBCD ( s ), BCD, z );
  2824. end;
  2825. operator / ( const BCD1,
  2826. BCD2 : tBCD ) z : tBCD; Inline;
  2827. begin
  2828. BCDDivide ( BCD1, BCD2, z );
  2829. end;
  2830. operator / ( const BCD : tBCD;
  2831. const i : myInttype ) z : tBCD; Inline;
  2832. begin
  2833. BCDDivide ( BCD, i, z );
  2834. end;
  2835. operator / ( const i : myInttype;
  2836. const BCD : tBCD ) z : tBCD; Inline;
  2837. begin
  2838. BCDDivide ( IntegerToBCD ( i ), BCD, z );
  2839. end;
  2840. {$ifndef FPUNONE}
  2841. operator / ( const BCD : tBCD;
  2842. const r : myRealtype ) z : tBCD; Inline;
  2843. begin
  2844. BCDDivide ( BCD, DoubleToBCD ( r ), z );
  2845. end;
  2846. operator / ( const r : myRealtype;
  2847. const BCD : tBCD ) z : tBCD; Inline;
  2848. begin
  2849. BCDDivide ( DoubleToBCD ( r ), BCD, z );
  2850. end;
  2851. {$endif}
  2852. operator / ( const BCD : tBCD;
  2853. const c : currency ) z : tBCD; Inline;
  2854. begin
  2855. BCDDivide ( BCD, CurrToBCD ( c ), z );
  2856. end;
  2857. operator / ( const c : currency;
  2858. const BCD : tBCD ) z : tBCD; Inline;
  2859. begin
  2860. BCDDivide ( CurrToBCD ( c ), BCD, z );
  2861. end;
  2862. {$ifdef comproutines}
  2863. operator / ( const BCD : tBCD;
  2864. const c : Comp ) z : tBCD; Inline;
  2865. begin
  2866. BCDDivide ( BCD, CompToBCD ( c ), z );
  2867. end;
  2868. operator / ( const c : Comp;
  2869. const BCD : tBCD ) z : tBCD; Inline;
  2870. begin
  2871. BCDDivide ( CompToBCD ( c ), BCD, z );
  2872. end;
  2873. {$endif}
  2874. operator / ( const BCD : tBCD;
  2875. const s : FmtBCDStringtype ) z : tBCD; Inline;
  2876. begin
  2877. BCDDivide ( BCD, StrToBCD ( s ), z );
  2878. end;
  2879. operator / ( const s : FmtBCDStringtype;
  2880. const BCD : tBCD ) z : tBCD; Inline;
  2881. begin
  2882. BCDDivide ( StrToBCD ( s ), BCD, z );
  2883. end;
  2884. operator := ( const i : Byte ) z : tBCD; Inline;
  2885. begin
  2886. z := IntegerToBCD ( myInttype ( i ) );
  2887. end;
  2888. operator := ( const BCD : tBCD ) z : Byte; Inline;
  2889. begin
  2890. z := BCDToInteger ( BCD );
  2891. end;
  2892. operator := ( const i : Word ) z : tBCD; Inline;
  2893. begin
  2894. z := IntegerToBCD ( myInttype ( i ) );
  2895. end;
  2896. operator := ( const BCD : tBCD ) z : Word; Inline;
  2897. begin
  2898. z := BCDToInteger ( BCD );
  2899. end;
  2900. operator := ( const i : longword ) z : tBCD; Inline;
  2901. begin
  2902. z := IntegerToBCD ( myInttype ( i ) );
  2903. end;
  2904. operator := ( const BCD : tBCD ) z : longword; Inline;
  2905. begin
  2906. z := BCDToInteger ( BCD );
  2907. end;
  2908. {$if declared ( qword ) }
  2909. operator := ( const i : qword ) z : tBCD; Inline;
  2910. begin
  2911. z := IntegerToBCD ( myInttype ( i ) );
  2912. end;
  2913. operator := ( const BCD : tBCD ) z : qword; Inline;
  2914. begin
  2915. z := BCDToInteger ( BCD );
  2916. end;
  2917. {$endif}
  2918. operator := ( const i : ShortInt ) z : tBCD; Inline;
  2919. begin
  2920. z := IntegerToBCD ( myInttype ( i ) );
  2921. end;
  2922. operator := ( const BCD : tBCD ) z : ShortInt; Inline;
  2923. begin
  2924. z := BCDToInteger ( BCD );
  2925. end;
  2926. operator := ( const i : smallint ) z : tBCD; Inline;
  2927. begin
  2928. z := IntegerToBCD ( myInttype ( i ) );
  2929. end;
  2930. operator := ( const BCD : tBCD ) z : smallint; Inline;
  2931. begin
  2932. z := BCDToInteger ( BCD );
  2933. end;
  2934. operator := ( const i : LongInt ) z : tBCD; Inline;
  2935. begin
  2936. z := IntegerToBCD ( myInttype ( i ) );
  2937. end;
  2938. operator := ( const BCD : tBCD ) z : LongInt; Inline;
  2939. begin
  2940. z := BCDToInteger ( BCD );
  2941. end;
  2942. {$if declared ( int64 ) }
  2943. operator := ( const i : int64 ) z : tBCD; Inline;
  2944. begin
  2945. z := IntegerToBCD ( myInttype ( i ) );
  2946. end;
  2947. operator := ( const BCD : tBCD ) z : int64; Inline;
  2948. begin
  2949. z := BCDToInteger ( BCD );
  2950. end;
  2951. {$endif}
  2952. {$ifndef FPUNONE}
  2953. operator := ( const r : Single ) z : tBCD; Inline;
  2954. begin
  2955. z := DoubleToBCD ( myRealtype ( r ) );
  2956. end;
  2957. operator := ( const BCD : tBCD ) z : Single; Inline;
  2958. begin
  2959. z := BCDToDouble ( BCD );
  2960. end;
  2961. operator := ( const r : Double ) z : tBCD; Inline;
  2962. begin
  2963. z := DoubleToBCD ( myRealtype ( r ) );
  2964. end;
  2965. operator := ( const BCD : tBCD ) z : Double; Inline;
  2966. begin
  2967. z := BCDToDouble ( BCD );
  2968. end;
  2969. {$if sizeof ( extended ) <> sizeof ( double )}
  2970. operator := ( const r : Extended ) z : tBCD; Inline;
  2971. begin
  2972. z := DoubleToBCD ( {myRealtype (} r {)} );
  2973. end;
  2974. operator := ( const BCD : tBCD ) z : Extended; Inline;
  2975. begin
  2976. z := BCDToDouble ( BCD );
  2977. end;
  2978. {$endif}
  2979. {$endif}
  2980. operator := ( const c : currency ) z : tBCD; Inline;
  2981. begin
  2982. CurrToBCD ( c, z );
  2983. end;
  2984. operator := ( const BCD : tBCD ) z : currency; Inline;
  2985. begin
  2986. BCDToCurr ( BCD, z );
  2987. end;
  2988. {$ifdef comproutines}
  2989. {$undef makedirect}
  2990. {$ifdef makedirect}
  2991. operator := ( const c : Comp ) z : tBCD; Inline;
  2992. var
  2993. cc : int64 absolute c;
  2994. begin
  2995. z := IntegerToBCD ( cc );
  2996. end;
  2997. { $define version1} { only one of these may be defined! }
  2998. { $define version2} { version 1 produces a compiler error (with INLINE only!)}
  2999. {$define version3} { I wasn't able to reduce the problem, sorry }
  3000. {$ifdef version1}
  3001. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3002. var
  3003. zz : Comp absolute z;
  3004. begin
  3005. zz := BCDToInteger ( BCD );
  3006. end;
  3007. {$endif}
  3008. {$ifdef version2}
  3009. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3010. var
  3011. zz : int64;
  3012. zzz : Comp absolute zz;
  3013. begin
  3014. zz := BCDToInteger ( BCD );
  3015. z := zzz;
  3016. end;
  3017. {$endif}
  3018. {$ifdef version3}
  3019. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3020. var
  3021. zz : record
  3022. case Boolean of
  3023. False: ( i : int64 );
  3024. True: ( c : Comp );
  3025. end;
  3026. begin
  3027. zz.i := BCDToInteger ( BCD );
  3028. z := zz.c;
  3029. end;
  3030. {$endif}
  3031. {$else}
  3032. operator := ( const c : Comp ) z : tBCD; Inline;
  3033. begin
  3034. z := CompToBCD ( c );
  3035. end;
  3036. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3037. begin
  3038. z := BCDToComp ( BCD );
  3039. end;
  3040. {$endif}
  3041. {$endif}
  3042. operator := ( const s : string ) z : tBCD; Inline;
  3043. begin
  3044. z := StrToBCD ( s );
  3045. end;
  3046. operator := ( const BCD : tBCD ) z : string; Inline;
  3047. begin
  3048. z := BCDToStr ( BCD );
  3049. end;
  3050. operator := ( const s : AnsiString ) z : tBCD; Inline;
  3051. begin
  3052. z := StrToBCD ( s );
  3053. end;
  3054. operator := ( const BCD : tBCD ) z : AnsiString; Inline;
  3055. begin
  3056. z := BCDToStr ( BCD );
  3057. end;
  3058. {$endif}
  3059. constructor TFMTBcdVarData.create;
  3060. begin
  3061. inherited create;
  3062. FBcd:=NullBCD;
  3063. end;
  3064. constructor TFMTBcdVarData.create(const BCD : tBCD);
  3065. begin
  3066. inherited create;
  3067. FBcd:=BCD;
  3068. end;
  3069. function TFMTBcdFactory.GetInstance(const v : TVarData): tObject;
  3070. begin
  3071. result:=tObject(v.VPointer);
  3072. end;
  3073. procedure TFMTBcdFactory.BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp);
  3074. begin
  3075. case Operation of
  3076. opAdd:
  3077. TFMTBcdVarData(Left.VPointer).BCD:=TFMTBcdVarData(Left.VPointer).BCD+TFMTBcdVarData(Right.VPointer).BCD;
  3078. opSubtract:
  3079. TFMTBcdVarData(Left.VPointer).BCD:=TFMTBcdVarData(Left.VPointer).BCD-TFMTBcdVarData(Right.VPointer).BCD;
  3080. opMultiply:
  3081. TFMTBcdVarData(Left.VPointer).BCD:=TFMTBcdVarData(Left.VPointer).BCD*TFMTBcdVarData(Right.VPointer).BCD;
  3082. opDivide:
  3083. TFMTBcdVarData(Left.VPointer).BCD:=TFMTBcdVarData(Left.VPointer).BCD/TFMTBcdVarData(Right.VPointer).BCD;
  3084. else
  3085. RaiseInvalidOp;
  3086. end;
  3087. end;
  3088. procedure TFMTBcdFactory.Clear(var V: TVarData);
  3089. begin
  3090. FreeAndNil(tObject(V.VPointer));
  3091. V.VType:=varEmpty;
  3092. end;
  3093. procedure TFMTBcdFactory.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
  3094. begin
  3095. if Indirect then
  3096. Dest.VPointer:=Source.VPointer
  3097. else
  3098. Dest.VPointer:=TFMTBcdVarData.Create(TFMTBcdVarData(Source.VPointer).BCD);
  3099. Dest.VType:=Vartype;
  3100. end;
  3101. {$if declared ( myMinIntBCD ) }
  3102. (*
  3103. {$if sizeof ( integer ) = 2 }
  3104. {$ifdef BCDgr4 }
  3105. const
  3106. myMinIntBCDValue : packed array [ 1..3 ] of Char = #$32#$76#$80;
  3107. {$endif}
  3108. {$else}
  3109. {$if sizeof ( integer ) = 4 }
  3110. *)
  3111. {$ifdef BCDgr9 }
  3112. const
  3113. myMinIntBCDValue : packed array [ 1..10 ] of Char = #$21#$47#$48#$36#$48;
  3114. {$endif}
  3115. (*
  3116. {$else}
  3117. {$if sizeof ( integer ) = 8 }
  3118. {$ifdef BCDgr18 }
  3119. const
  3120. myMinIntBCDValue : packed array [ 1..19 ] of Char = #$92#$23#$37#$20#$36#$85#$47#$75#$80#$80;
  3121. {$endif}
  3122. {$else}
  3123. {$fatal You have an interesting integer type! Sorry, not supported}
  3124. {$endif}
  3125. {$endif}
  3126. {$endif}
  3127. *)
  3128. {$endif}
  3129. initialization
  3130. FillChar ( null_, SizeOf ( null_ ), #0 );
  3131. FillChar ( NullBCD_, SizeOf ( NullBCD_ ), #0 );
  3132. FillChar ( OneBCD_, SizeOf ( OneBCD_ ), #0 );
  3133. OneBCD_.Precision := 1;
  3134. OneBCD_.Fraction[low ( OneBCD_.Fraction )] := $10;
  3135. {$if declared ( myMinIntBCD ) }
  3136. FillChar ( myMinIntBCD, SizeOf ( myMinIntBCD ), #0 );
  3137. {$ifndef bigger_BCD}
  3138. myMinIntBCD.SignSpecialPlaces := NegBit;
  3139. {$else}
  3140. myMinIntBCD.Negativ := True;
  3141. {$endif}
  3142. {$if sizeof ( integer ) = 2 }
  3143. {$ifdef BCDgr4 }
  3144. myMinIntBCD.Precision := 5;
  3145. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3146. {$endif}
  3147. {$else}
  3148. {$if sizeof ( integer ) = 4 }
  3149. {$ifdef BCDgr9 }
  3150. myMinIntBCD.Precision := 10;
  3151. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3152. {$endif}
  3153. {$else}
  3154. {$if sizeof ( integer ) = 8 }
  3155. {$ifdef BCDgr18 }
  3156. myMinIntBCD.Precision := 19;
  3157. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3158. {$endif}
  3159. {$else}
  3160. {$fatal You have an interesting integer type! Sorry, not supported}
  3161. {$endif}
  3162. {$endif}
  3163. {$endif}
  3164. {$endif}
  3165. FMTBcdFactory:=TFMTBcdFactory.create;
  3166. finalization
  3167. FreeAndNil(FMTBcdFactory)
  3168. end.