fmtbcd.pp 107 KB

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