{ This file is part of the Free Pascal run time library. Copyright (c) 2005-2006 by the Free Pascal development team and Gehard Scholz It contains the Free Pascal BCD implementation See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS for A PARTICULAR PURPOSE. **********************************************************************} { "Programming is the time between two bugs" } { (last words of the unknown programmer) } (* this program was a good test for the compiler: some bugs have been found. 1. WITH in inline funcs produces a compiler error AFTER producing an .exe file (was already known; I didn't see it in the bug list) 2. macro names were checked for being a keyword, even when starting with an '_' (produces range check when compiler is compiled with { $r+ }-mode fixed. 3. { $define program } was not possible in { $macro on } mode (keywords not allowed: doesn't make sense here) fixed. 4. the Inc/Dec ( unsigned, signed ) problem (has been similar in the bug list already) 5. when the result of an overloaded (inline) operator is ABSOLUTEd: compiler error 200110205 happens only when operator is defined in a unit. 6. two range check errors in scanner.pas a) array subscripting b) value out ouf range *) { $define debug_version} {$r+,q+,s+} { $r-,q-,s-} {$mode objfpc} {$h-} {$inline on} {$macro on} {$define BCDMaxDigits := 64 } { should be even } { the next defines must be defined by hand, unless someone shows me a way how to to it with macros } {$define BCDgr4} { define this if MCDMaxDigits is greater 4, else undefine! } {$define BCDgr9} { define this if MCDMaxDigits is greater 9, else undefine! } {$define BCDgr18} { define this if MCDMaxDigits is greater 18, else undefine! } { $define BCDgr64} { define this if MCDMaxDigits is greater 64, else undefine! } { $define BCDgr180} { define this if MCDMaxDigits is greater 180, else undefine! } {$ifdef BCDgr4} {$hint BCD Digits > 4} {$endif} {$ifdef BCDgr9} {$hint BCD Digits > 9} {$endif} {$ifdef BCDgr18} {$hint BCD Digits > 18} {$endif} {$ifdef BCDgr64} {$hint BCD Digits > 64} {$endif} {$ifdef BCDgr180} {$hint BCD Digits > 180} {$endif} {$ifndef NO_SMART_LINK} { $smartlink on} {$endif} {$define some_packed} { enable this to keep some local structures PACKED } { $define as_object} { to define the tBCD record as object instead; fields then are private } { not done yet! } {$define additional_routines} { to create additional routines and operators } (* only define one of them! *) { $define integ32} {$define integ64} (* only define one of them! *) { $define real8} {$define real10} {check} {$ifndef integ32} {$ifndef integ64} {$define integ64} {$endif} {$endif} {$ifdef integ32} {$ifdef integ64} {$undef integ32} {$endif} {$endif} {check} {$ifndef real8} {$ifndef real10} {$define real8} {$endif} {$endif} {$ifdef real8} {$ifdef real10} {$undef real10} {$endif} {$endif} {$ifdef some_packed} {$define maybe_packed := packed} {$else} {$define maybe_packed := (**)} {$endif} UNIT FmtBCD; INTERFACE USES SysUtils, Variants; const MaxStringDigits = 100; { not used ! } _NoDecimal = -255; { not used ! } _DefaultDecimals = 10; { not used ! } { From DB.pas } { Max supported by Midas } { must be EVEN } MaxFmtBCDFractionSize = BCDMaxDigits + Ord ( Odd ( BCDMaxDigits ) ); { Max supported by Midas } MaxFmtBCDDigits = 32; { not used ! } DefaultFmtBCDScale = 6; { not used ! } MaxBCDPrecision = 18; { not used ! } MaxBCDScale = 4; { not used ! } {$ifdef BCDgr64} { $fatal big 1} {$define bigger_BCD} { must be defined if MaxFmtBCDFractionSize > 64 } { not usable in the moment } {$endif} {$ifdef BCDgr180} { $fatal big 2} type FmtBCDStringtype = AnsiString; {$define use_Ansistring} {$else} type FmtBCDStringtype = string [ 255 ]; {$undef use_Ansistring} {$endif} {$ifdef use_ansistring} {$hint ansi} {$else} {$hint -ansi} {$endif} {$ifdef integ32} {$define myInttype := LongInt} {$endif} {$ifdef integ64} {$define myInttype := int64} {$endif} {$ifndef FPUNONE} {$ifdef real8} {$define myRealtype := double} {$endif} {$ifdef real10} {$define myRealtype := extended} {$endif} {$endif} {$ifdef SUPPORT_COMP} {$define comproutines} {$endif SUPPORT_COMP} {$define __low_Fraction := 0 } {$define __high_Fraction := ( ( MaxFmtBCDFractionSize DIV 2 ) - 1 ) } type pBCD = ^ tBCD; tBCD = packed {$ifdef as_object} OBJECT {$else} record {$endif} {$ifdef as_object} PRIVATE {$endif} Precision : 0..maxfmtbcdfractionsize; { 1 (joke?)..64 } {$ifndef bigger_BCD} SignSpecialPlaces : Byte; { Sign:1, Special:1, Places:6 } {$else} Negativ : Boolean; { Special : Boolean; } Places : 0..maxfmtbcdfractionsize - 1; {$endif} Fraction : packed array [ __low_Fraction..__high_Fraction ] of Byte; { BCD Nibbles, 00..99 per Byte, high Nibble 1st } end; { Exception classes } type eBCDException = CLASS ( Exception ); eBCDOverflowException = CLASS ( eBCDException ); eBCDNotImplementedException = CLASS ( eBCDException ); { Utility functions for TBCD access } function BCDPrecision ( const BCD : tBCD ) : Word; Inline; function BCDScale ( const BCD : tBCD ) : Word; Inline; function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline; { BCD Arithmetic} procedure BCDNegate ( var BCD : tBCD ); Inline; { !!!!!!!!!! most routines are intentionally NOT inline !!!!!!!!!! } { Returns True if successful, False if Int Digits needed to be truncated } function NormalizeBCD ( const InBCD : tBCD; var OutBCD : tBCD; const Prec, Scale : Word ) : Boolean; procedure BCDAdd ( const BCDin1, BCDin2 : tBCD; var BCDout : tBCD ); procedure BCDSubtract ( const BCDin1, BCDin2 : tBCD; var BCDout : tBCD ); procedure BCDMultiply ( const BCDin1, BCDin2 : tBCD; var BCDout : tBCD ); {$ifndef FPUNONE} procedure BCDMultiply ( const BCDIn : tBCD; const DoubleIn : myRealtype; var BCDout : tBCD ); Inline; {$endif} procedure BCDMultiply ( const BCDIn : tBCD; const StringIn : FmtBCDStringtype; var BCDout : tBCD ); Inline; { !!! params changed to const, shouldn't give a problem } procedure BCDMultiply ( const StringIn1, StringIn2 : FmtBCDStringtype; var BCDout : tBCD ); Inline; procedure BCDDivide ( const Dividend, Divisor : tBCD; var BCDout : tBCD ); {$ifndef FPUNONE} procedure BCDDivide ( const Dividend : tBCD; const Divisor : myRealtype; var BCDout : tBCD ); Inline; {$endif} procedure BCDDivide ( const Dividend : tBCD; const Divisor : FmtBCDStringtype; var BCDout : tBCD ); Inline; { !!! params changed to const, shouldn't give a problem } procedure BCDDivide ( const Dividend, Divisor : FmtBCDStringtype; var BCDout : tBCD ); Inline; { TBCD variant creation utils } procedure VarFmtBCDCreate ( var aDest : Variant; const aBCD : tBCD ); function VarFmtBCDCreate : Variant; function VarFmtBCDCreate ( const aValue : FmtBCDStringtype; Precision, Scale : Word ) : Variant; {$ifndef FPUNONE} function VarFmtBCDCreate ( const aValue : myRealtype; Precision : Word = 18; Scale : Word = 4 ) : Variant; {$endif} function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant; function VarIsFmtBCD ( const aValue : Variant ) : Boolean; function VarFmtBCD : TVartype; { Convert string/Double/Integer to BCD struct } function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD; function StrToBCD ( const aValue : FmtBCDStringtype; const Format : TFormatSettings ) : tBCD; function TryStrToBCD ( const aValue : FmtBCDStringtype; var BCD : tBCD ) : Boolean; function TryStrToBCD ( const aValue : FmtBCDStringtype; var BCD : tBCD; const Format : TFormatSettings) : Boolean; {$ifndef FPUNONE} function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline; procedure DoubleToBCD ( const aValue : myRealtype; var BCD : tBCD ); {$endif} function IntegerToBCD ( const aValue : myInttype ) : tBCD; function VarToBCD ( const aValue : Variant ) : tBCD; { From DB.pas } function CurrToBCD ( const Curr : currency; var BCD : tBCD; Precision : Integer = 32; Decimals : Integer = 4 ) : Boolean; { Convert BCD struct to string/Double/Integer } function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype; function BCDToStr ( const BCD : tBCD; const Format : TFormatSettings ) : FmtBCDStringtype; {$ifndef FPUNONE} function BCDToDouble ( const BCD : tBCD ) : myRealtype; {$endif} function BCDToInteger ( const BCD : tBCD; Truncate : Boolean = False ) : myInttype; { From DB.pas } function BCDToCurr ( const BCD : tBCD; var Curr : currency ) : Boolean; { Formatting BCD as string } function BCDToStrF ( const BCD : tBCD; Format : TFloatFormat; const Precision, Digits : Integer ) : FmtBCDStringtype; function FormatBCD ( const Format : string; BCD : tBCD ) : FmtBCDStringtype; { returns -1 if BCD1 < BCD2, 0 if BCD1 = BCD2, 1 if BCD1 > BCD2 } function BCDCompare ( const BCD1, BCD2 : tBCD ) : Integer; {$ifdef additional_routines} function CurrToBCD ( const Curr : currency ) : tBCD; Inline; {$ifdef comproutines} function CompToBCD ( const Curr : Comp ) : tBCD; Inline; function BCDToComp ( const BCD : tBCD ) : Comp; Inline; {$endif} procedure BCDAdd ( const BCDIn : tBCD; const IntIn : myInttype; var BCDout : tBCD ); procedure BCDAdd ( const IntIn : myInttype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$ifndef FPUNONE} procedure BCDAdd ( const BCDIn : tBCD; const DoubleIn : myRealtype; var BCDout : tBCD ); Inline; procedure BCDAdd ( const DoubleIn : myRealtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$endif} procedure BCDAdd ( const BCDIn : tBCD; const Currin : currency; var BCDout : tBCD ); Inline; procedure BCDAdd ( const Currin : currency; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$ifdef comproutines} procedure BCDAdd ( const BCDIn : tBCD; const Compin : Comp; var BCDout : tBCD ); Inline; procedure BCDAdd ( const Compin : Comp; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$endif} procedure BCDAdd ( const BCDIn : tBCD; const StringIn : FmtBCDStringtype; var BCDout : tBCD ); Inline; procedure BCDAdd ( const StringIn : FmtBCDStringtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; procedure BCDAdd ( const StringIn1, StringIn2 : FmtBCDStringtype; var BCDout : tBCD ); Inline; procedure BCDSubtract ( const BCDIn : tBCD; const IntIn : myInttype; var BCDout : tBCD ); procedure BCDSubtract ( const IntIn : myInttype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$ifndef FPUNONE} procedure BCDSubtract ( const BCDIn : tBCD; const DoubleIn : myRealtype; var BCDout : tBCD ); Inline; procedure BCDSubtract ( const DoubleIn : myRealtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$endif} procedure BCDSubtract ( const BCDIn : tBCD; const Currin : currency; var BCDout : tBCD ); Inline; procedure BCDSubtract ( const Currin : currency; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$ifdef comproutines} procedure BCDSubtract ( const BCDIn : tBCD; const Compin : Comp; var BCDout : tBCD ); Inline; procedure BCDSubtract ( const Compin : Comp; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$endif} procedure BCDSubtract ( const BCDIn : tBCD; const StringIn : FmtBCDStringtype; var BCDout : tBCD ); Inline; procedure BCDSubtract ( const StringIn : FmtBCDStringtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; procedure BCDSubtract ( const StringIn1, StringIn2 : FmtBCDStringtype; var BCDout : tBCD ); Inline; procedure BCDMultiply ( const BCDIn : tBCD; const IntIn : myInttype; var BCDout : tBCD ); procedure BCDMultiply ( const IntIn : myInttype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$ifndef FPUNONE} procedure BCDMultiply ( const DoubleIn : myRealtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$endif} procedure BCDMultiply ( const BCDIn : tBCD; const Currin : currency; var BCDout : tBCD ); Inline; procedure BCDMultiply ( const Currin : currency; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$ifdef comproutines} procedure BCDMultiply ( const BCDIn : tBCD; const Compin : Comp; var BCDout : tBCD ); Inline; procedure BCDMultiply ( const Compin : Comp; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$endif} procedure BCDMultiply ( const StringIn : FmtBCDStringtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; procedure BCDDivide ( const Dividend : tBCD; const Divisor : myInttype; var BCDout : tBCD ); Inline; procedure BCDDivide ( const Dividend : myInttype; const Divisor : tBCD; var BCDout : tBCD ); Inline; {$ifndef FPUNONE} procedure BCDDivide ( const Dividend : myRealtype; const Divisor : tBCD; var BCDout : tBCD ); Inline; {$endif} procedure BCDDivide ( const BCDIn : tBCD; const Currin : currency; var BCDout : tBCD ); Inline; procedure BCDDivide ( const Currin : currency; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$ifdef comproutines} procedure BCDDivide ( const BCDIn : tBCD; const Compin : Comp; var BCDout : tBCD ); Inline; procedure BCDDivide ( const Compin : Comp; const BCDIn : tBCD; var BCDout : tBCD ); Inline; {$endif} procedure BCDDivide ( const Dividend : FmtBCDStringtype; const Divisor : tBCD; var BCDout : tBCD ); Inline; operator = ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; operator < ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; operator > ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; operator <= ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; operator >= ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; (* ######################## not allowed: why? operator + ( const BCD : tBCD ) z : tBCD; make_Inline ##################################################### *) operator - ( const BCD : tBCD ) z : tBCD; Inline; operator + ( const BCD1, BCD2 : tBCD ) z : tBCD; Inline; operator + ( const BCD : tBCD; const i : myInttype ) z : tBCD; Inline; operator + ( const i : myInttype; const BCD : tBCD ) z : tBCD; Inline; {$ifndef FPUNONE} operator + ( const BCD : tBCD; const r : myRealtype ) z : tBCD; Inline; operator + ( const r : myRealtype; const BCD : tBCD ) z : tBCD; Inline; {$endif} operator + ( const BCD : tBCD; const c : currency ) z : tBCD; Inline; operator + ( const c : currency; const BCD : tBCD ) z : tBCD; Inline; {$ifdef comproutines} operator + ( const BCD : tBCD; const c : Comp ) z : tBCD; Inline; operator + ( const c : Comp; const BCD : tBCD ) z : tBCD; Inline; {$endif} operator + ( const BCD : tBCD; const s : FmtBCDStringtype ) z : tBCD; Inline; operator + ( const s : FmtBCDStringtype; const BCD : tBCD ) z : tBCD; Inline; operator - ( const BCD1, BCD2 : tBCD ) z : tBCD; Inline; operator - ( const BCD : tBCD; const i : myInttype ) z : tBCD; Inline; operator - ( const i : myInttype; const BCD : tBCD ) z : tBCD; Inline; {$ifndef FPUNONE} operator - ( const BCD : tBCD; const r : myRealtype ) z : tBCD; Inline; operator - ( const r : myRealtype; const BCD : tBCD ) z : tBCD; Inline; {$endif} operator - ( const BCD : tBCD; const c : currency ) z : tBCD; Inline; operator - ( const c : currency; const BCD : tBCD ) z : tBCD; Inline; {$ifdef comproutines} operator - ( const BCD : tBCD; const c : Comp ) z : tBCD; Inline; operator - ( const c : Comp; const BCD : tBCD ) z : tBCD; Inline; {$endif} operator - ( const BCD : tBCD; const s : FmtBCDStringtype ) z : tBCD; Inline; operator - ( const s : FmtBCDStringtype; const BCD : tBCD ) z : tBCD; Inline; operator * ( const BCD1, BCD2 : tBCD ) z : tBCD; Inline; operator * ( const BCD : tBCD; const i : myInttype ) z : tBCD; Inline; operator * ( const i : myInttype; const BCD : tBCD ) z : tBCD; Inline; {$ifndef FPUNONE} operator * ( const BCD : tBCD; const r : myRealtype ) z : tBCD; Inline; operator * ( const r : myRealtype; const BCD : tBCD ) z : tBCD; Inline; {$endif} operator * ( const BCD : tBCD; const c : currency ) z : tBCD; Inline; operator * ( const c : currency; const BCD : tBCD ) z : tBCD; Inline; {$ifdef comproutines} operator * ( const BCD : tBCD; const c : Comp ) z : tBCD; Inline; operator * ( const c : Comp; const BCD : tBCD ) z : tBCD; Inline; {$endif} operator * ( const BCD : tBCD; const s : FmtBCDStringtype ) z : tBCD; Inline; operator * ( const s : FmtBCDStringtype; const BCD : tBCD ) z : tBCD; Inline; operator / ( const BCD1, BCD2 : tBCD ) z : tBCD; Inline; operator / ( const BCD : tBCD; const i : myInttype ) z : tBCD; Inline; operator / ( const i : myInttype; const BCD : tBCD ) z : tBCD; Inline; {$ifndef FPUNONE} operator / ( const BCD : tBCD; const r : myRealtype ) z : tBCD; Inline; operator / ( const r : myRealtype; const BCD : tBCD ) z : tBCD; Inline; {$endif} operator / ( const BCD : tBCD; const c : currency ) z : tBCD; Inline; operator / ( const c : currency; const BCD : tBCD ) z : tBCD; Inline; {$ifdef comproutines} operator / ( const BCD : tBCD; const c : Comp ) z : tBCD; Inline; operator / ( const c : Comp; const BCD : tBCD ) z : tBCD; Inline; {$endif} operator / ( const BCD : tBCD; const s : FmtBCDStringtype ) z : tBCD; Inline; operator / ( const s : FmtBCDStringtype; const BCD : tBCD ) z : tBCD; Inline; operator := ( const i : Byte ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : Byte; Inline; operator := ( const i : Word ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : Word; Inline; operator := ( const i : longword ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : longword; Inline; {$if declared ( qword ) } operator := ( const i : qword ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : qword; Inline; {$endif} operator := ( const i : ShortInt ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : ShortInt; Inline; operator := ( const i : smallint ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : smallint; Inline; operator := ( const i : LongInt ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : LongInt; Inline; {$if declared ( int64 ) } operator := ( const i : int64 ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : int64; Inline; {$endif} {$ifndef FPUNONE} operator := ( const r : Single ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : Single; Inline; operator := ( const r : Double ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : Double; Inline; {$if sizeof ( extended ) <> sizeof ( double )} operator := ( const r : Extended ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : Extended; Inline; {$endif} {$endif} operator := ( const c : currency ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : currency; Inline; {$ifdef comproutines} operator := ( const c : Comp ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : Comp; Inline; {$endif} operator := ( const s : string ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : string; Inline; operator := ( const s : AnsiString ) z : tBCD; Inline; operator := ( const BCD : tBCD ) z : AnsiString; Inline; {$endif} function __get_null : tBCD; Inline; function __get_one : tBCD; Inline; PROPERTY NullBCD : tBCD Read __get_null; OneBCD : tBCD Read __get_one; //{$define __lo_bh := 1 * ( -( MaxFmtBCDFractionSize * 1 + 2 ) ) } //{$define __hi_bh := 1 * ( MaxFmtBCDFractionSize * 1 + 1 ) } {$define helper_declarations := const __lo_bh = -( MaxFmtBCDFractionSize + 2 ); __hi_bh = ( MaxFmtBCDFractionSize + 1 ); type tBCD_helper = Maybe_Packed record Prec : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif}; Plac : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif}; FDig, LDig : {$ifopt r+} __lo_bh..__hi_bh {$else} Integer {$endif}; Singles : Maybe_packed array [ __lo_bh..__hi_bh ] of {$ifopt r+} 0..9 {$else} Byte {$endif}; Neg : Boolean; end; { in the tBCD_helper the bcd is stored for computations, shifted to the right position } // {$define __lo_bhb := 1 * ( __lo_bh + __lo_bh ) } // {$define __hi_bhb := 1 * ( __hi_bh + __hi_bh + 1 ) } const __lo_bhb = __lo_bh + __lo_bh - 1; __hi_bhb = __hi_bh + __hi_bh; type tBCD_helper_big = Maybe_Packed record Prec : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif}; Plac : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif}; FDig, LDig : {$ifopt r+} __lo_bhb..__hi_bhb {$else} Integer {$endif}; Singles : Maybe_packed array [ __lo_bhb..__hi_bhb ] of {$ifopt r+} 0 * 0..9 * 9 * Pred ( MaxFmtBCDDigits ) {$else} Integer {$endif}; Neg : Boolean; end; } {$ifdef debug_version} helper_declarations procedure unpack_BCD ( const BCD : tBCD; var bh : tBCD_helper ); function pack_BCD ( var bh : tBCD_helper; var BCD : tBCD ) : Boolean; procedure dumpBCD ( const v : tBCD ); {$endif} IMPLEMENTATION USES classes {$ifopt r+}, sysconst {$endif}; type TFMTBcdFactory = CLASS(TPublishableVarianttype) PROTECTED function GetInstance(const v : TVarData): tObject; OVERRIDE; PUBLIC procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp); override; procedure Clear(var V: TVarData); override; procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override; function CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean; override; procedure Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); override; procedure Cast(var Dest: TVarData; const Source: TVarData); override; procedure CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); override; end; TFMTBcdVarData = CLASS(TPersistent) PRIVATE FBcd : tBCD; PUBLIC constructor create; constructor create(const BCD : tBCD); PROPERTY BCD : tBCD Read FBcd Write FBcd; end; var NullBCD_ : tBCD; OneBCD_ : tBCD; function __get_null : tBCD; Inline; begin __get_null := NullBCD_; end; function __get_one : tBCD; Inline; begin __get_one := OneBCD_; end; type range_digits = 1..maxfmtbcdfractionsize; range_digits0 = 0..maxfmtbcdfractionsize; range_fracdigits = 0..pred ( MaxFmtBCDFractionSize ); {$ifopt r+} procedure RangeError; begin raise ERangeError.Create(SRangeError); end; {$endif} {$ifndef debug_version} helper_declarations {$endif} var null_ : record case Boolean of False: ( bh : tBCD_helper ); True: ( bhb : tBCD_helper_big ); end; FMTBcdFactory : TFMTBcdFactory = NIL; {$ifndef bigger_BCD} const NegBit = 1 SHL 7; SpecialBit = 1 SHL 6; PlacesMask = $ff XOR ( NegBit OR SpecialBit ); {$endif} {$define _select := {$define _when := if {$define _when := end else if } } {$define _then := then begin } {$define _whenother := end else begin } {$define _endselect := end } } {$ifdef debug_version} procedure dumpBCD ( const v : tBCD ); var i, j : Integer; const ft : ARRAY [ Boolean ] of Char = ( 'f', 't' ); begin {$ifndef bigger_BCD} Write ( 'Prec:', v.Precision, ' ', 'Neg:', ft[( v.SignSpecialPlaces AND NegBit ) <> 0], ' ', 'Special:', ft[( v.SignSpecialPlaces AND SpecialBit ) <> 0], ' ', 'Places:', v.SignSpecialPlaces AND PlacesMask, ' ' ); {$else} Write ( 'Prec:', v.Precision, ' ', 'Neg:', ft[v.Negativ], ' ', 'Places:', v.Places, ' ' ); {$endif} j := 0; for i := 1 TO v.Precision do if Odd ( i ) then Write ( ( v.Fraction[j] AND $f0 ) SHR 4 ) else begin Write ( v.Fraction[j] AND $0f ); Inc ( j ); end; WriteLn; end; procedure dumpbh ( const v : tBCD_helper ); var i : Integer; const ft : ARRAY [ Boolean ] of Char = ( 'f', 't' ); begin Write ( 'Prec:', v.Prec, ' ', 'Neg:', ft[v.Neg], ' ', 'Places:', v.Plac, ' ', 'FDig:', v.FDig, ' ', 'LDig:', v.LDig, ' ', 'Digits:', v.LDig - v.FDig + 1, ' ' ); for i := v.FDig TO v.LDig do Write ( v.Singles[i] ); WriteLn; end; {$endif} {$if sizeof ( integer ) = 2 } {$ifdef BCDgr4 } var myMinIntBCD : tBCD; {$endif} {$else} {$if sizeof ( integer ) = 4 } {$ifdef BCDgr9 } var myMinIntBCD : tBCD; {$endif} {$else} {$if sizeof ( integer ) = 8 } {$ifdef BCDgr18 } var myMinIntBCD : tBCD; {$endif} {$else} {$fatal You have an interesting integer type! Sorry, not supported} {$endif} {$endif} {$endif} procedure not_implemented; begin RAISE eBCDNotImplementedException.create ( 'not implemented' ); end; procedure unpack_BCD ( const BCD : tBCD; var bh : tBCD_helper ); var i : {$ifopt r+} __lo_bh + 1 ..__hi_bh {$else} Integer {$endif}; j : {$ifopt r+} -1..__high_fraction {$else} Integer {$endif}; vv : {$ifopt r+} $00..$99 {$else} Integer {$endif}; begin bh := null_.bh; WITH bh, BCD do begin Prec := Precision; if Prec > 0 then begin {$ifndef bigger_BCD} Plac := SignSpecialPlaces AND PlacesMask; Neg := ( SignSpecialPlaces AND NegBit ) <> 0; {$else} Plac := Places; Neg := Negativ; {$endif} LDig := Plac; FDig := LDig - Prec + 1; j := -1; i := FDig; while i <= LDig do begin Inc ( j ); vv := Fraction[j]; Singles[i] := ( vv {AND $f0} ) SHR 4; if i < LDig then Singles[i+1] := vv AND $0f; Inc ( i, 2 ); end; end; end; end; function pack_BCD ( var bh : tBCD_helper; var BCD : tBCD ) : Boolean; { return TRUE if successful (BCD valid) } var pre : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 {$else} Integer {$endif}; fra : {$ifopt r+} -1 * ( __hi_bh - __lo_bh + 1 )..__hi_bh - __lo_bh + 1 {$else} Integer {$endif}; tm : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 - Pred ( MaxFmtBCDFractionSize ) {$else} Integer {$endif}; i : {$ifopt r+} low ( bh.FDig ) - 1..high ( bh.LDig ) {$else} Integer {$endif}; rp : {$ifopt r+} low ( BCD.Fraction )..high ( BCD.Fraction ) + 1 {$else} Integer {$endif}; ue : {$ifopt r+} 0..1 {$else} Integer {$endif}; v : {$ifopt r+} 0..10 {$else} Integer {$endif}; lnz : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif}; doround, lnzf : Boolean; begin pack_BCD := False; BCD := NullBCD; WITH BCD, bh do begin lnzf := FDig < 0; while lnzf do if Singles[FDig] = 0 then begin Inc ( FDig ); if FDig = 0 then lnzf := False; end else lnzf := False; pre := LDig - FDig + 1; fra := Plac; doround := False; if fra >= MaxFmtBCDFractionSize then begin doround := True; tm := fra - Pred ( MaxFmtBCDFractionSize ); { dec ( pre, tm ); Dec/Inc error? } pre := pre - tm; { Dec ( fra, tm ); Dec/Inc error? } fra := fra - tm; { Dec ( LDig, tm ); Dec/Inc error? } LDig := LDig - tm; end; if pre > MaxFmtBCDFractionSize then begin doround := True; tm := pre - MaxFmtBCDFractionSize; { Dec ( pre, tm ); Dec/Inc error? } pre := pre - tm; { Dec ( fra, tm ); Dec/Inc error? } fra := fra - tm; { Dec ( LDig, tm ); Dec/Inc error? } LDig := LDig - tm; end; if fra < 0 then EXIT; if doround then begin v := Singles[fra + 1]; if v > 4 then begin ue := 1; i := LDig; while ( i >= FDig ) AND ( ue <> 0 ) do begin v := Singles[i] + ue; ue := v DIV 10; Singles[i] := v MOD 10; Dec ( i ); end; if ue <> 0 then begin Dec ( FDig ); Singles[FDig] := ue; Dec ( LDig ); Dec ( fra ); if fra < 0 then EXIT; end; end; end; lnzf := False; i := LDig; while ( i >= FDig ) AND ( NOT lnzf ) do begin if Singles[i] <> 0 then begin lnz := i; lnzf := True; end; Dec ( i ); end; if lnzf then begin tm := LDig - lnz; if tm <> 0 then begin { Dec ( pre, tm ); Dec/Inc error? } pre := pre - tm; { Dec ( fra, tm ); Dec/Inc error? } fra := fra - tm; { Dec ( LDig, tm ); Dec/Inc error? } LDig := LDig - tm; if fra < 0 then begin { Dec ( pre, fra ); Dec/Inc error? } pre := pre - fra; { Dec ( LDig, fra ); Dec/Inc error? } LDig := LDig - fra; fra := 0; end; end; end else begin LDig := FDig; fra := 0; pre := 0; Neg := False; end; if pre <> 0 then begin Precision := pre; rp := 0; i := FDig; while i <= LDig do begin if i < LDig then Fraction[rp] := ( Singles[i] SHL 4 ) OR Singles[i + 1] else Fraction[rp] := Singles[i] SHL 4; Inc ( rp ); Inc ( i, 2 ); end; {$ifndef bigger_BCD} if Neg then SignSpecialPlaces := NegBit; SignSpecialPlaces := SignSpecialPlaces OR fra; {$else} Negativ := Neg; Places := fra; {$endif} end; end; pack_BCD := True; end; function BCDPrecision ( const BCD : tBCD ) : Word; Inline; begin BCDPrecision := BCD.Precision; end; function BCDScale ( const BCD : tBCD ) : Word; Inline; begin {$ifndef bigger_BCD} BCDScale := BCD.SignSpecialPlaces AND PlacesMask; {$else} BCDScale := BCD.Places; {$endif} end; function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline; begin {$ifndef bigger_BCD} IsBCDNegative := ( BCD.SignSpecialPlaces AND NegBit ) <> 0; {$else} IsBCDNegative := BCD.Negativ; {$endif} end; { BCD Arithmetic} procedure BCDNegate ( var BCD : tBCD ); Inline; begin { with-statement geht nicht !! with bcd do if precision <> 0 then signspecialplaces := signspecialplaces xor negbit; } if BCD.Precision <> 0 then {$ifndef bigger_BCD} BCD.SignSpecialPlaces := BCD.SignSpecialPlaces XOR NegBit; {$else} BCD.Negativ := NOT BCD.Negativ; {$endif} end; { returns -1 if BCD1 < BCD2, 0 if BCD1 = BCD2, 1 if BCD1 > BCD2 } function BCDCompare ( const BCD1, BCD2 : tBCD ) : Integer; var pl1 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif}; pl2 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif}; pr1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif}; pr2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif}; pr : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif}; idig1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif}; idig2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif}; i : {$ifopt r+} __low_Fraction..__high_Fraction + 1 {$else} Integer {$endif}; f1 : {$ifopt r+} $00..$99 {$else} Integer {$endif}; f2 : {$ifopt r+} $00..$99 {$else} Integer {$endif}; res : {$ifopt r+} -1..1 {$else} Integer {$endif}; neg1, neg2 : Boolean; begin {$ifndef bigger_BCD} neg1 := ( BCD1.SignSpecialPlaces AND NegBit ) <> 0; neg2 := ( BCD2.SignSpecialPlaces AND NegBit ) <> 0; {$else} neg1 := BCD1.Negativ; neg2 := BCD2.Negativ; {$endif} _SELECT _WHEN neg1 AND ( NOT neg2 ) _THEN result := -1; _WHEN ( NOT neg1 ) AND neg2 _THEN result := +1; _WHENOTHER pr1 := BCD1.Precision; pr2 := BCD2.Precision; {$ifndef bigger_BCD} pl1 := BCD1.SignSpecialPlaces AND PlacesMask; pl2 := BCD2.SignSpecialPlaces AND PlacesMask; {$else} pl1 := BCD1.Places; pl2 := BCD2.Places; {$endif} idig1 := pr1 - pl1; idig2 := pr2 - pl2; if idig1 <> idig2 then begin if ( idig1 > idig2 ) = neg1 then result := -1 else result := +1; end else begin if pr1 < pr2 then pr := pr1 else pr := pr2; res := 0; i := __low_Fraction; while ( res = 0 ) AND ( i < ( __low_Fraction + ( pr DIV 2 ) ) ) do begin { if BCD1.Fraction[i] < BCD2.Fraction[i] then res := -1 else if BCD1.Fraction[i] > BCD2.Fraction[i] then res := +1; } _SELECT _WHEN BCD1.Fraction[i] < BCD2.Fraction[i] _THEN res := -1 _WHEN BCD1.Fraction[i] > BCD2.Fraction[i] _THEN res := +1; _WHENOTHER _endSELECT; Inc ( i ); end; if res = 0 then begin if Odd ( pr ) then begin f1 := BCD1.Fraction[i] AND $f0; f2 := BCD2.Fraction[i] AND $f0; { if f1 < f2 then res := -1 else if f1 > f2 then res := +1; } _SELECT _WHEN f1 < f2 _THEN res := -1 _WHEN f1 > f2 _THEN res := +1; _endSELECT; end; end; if neg1 then result := 0 - res else result := res; end; _endSELECT end; { Convert string/Double/Integer to BCD struct } function TryStrToBCD ( const aValue : FmtBCDStringtype; var BCD : tBCD ) : Boolean; begin Result := TryStrToBCD(aValue, BCD, DefaultFormatSettings); end; function TryStrToBCD ( const aValue : FmtBCDStringtype; var BCD : tBCD; Const Format : TFormatSettings) : Boolean; var {$ifndef use_ansistring} lav : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif}; i : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif}; {$else} lav : {$ifopt r+} longword {$else} longword {$endif}; i : {$ifopt r+} longword {$else} longword {$endif}; {$endif} ch : Char; type ife = ( inint, infrac, inexp ); {$define max_exp_scanned := 9999 } var inife : ife; lvars : record fp, lp : ARRAY [ ife ] {$ifndef use_ansistring} of {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif}; pfnb : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif}; ps : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif}; pse : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif}; errp : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif}; {$else} of {$ifopt r+} longword {$else} longword {$endif}; pfnb : {$ifopt r+} longword {$else} longword {$endif}; ps : {$ifopt r+} longword {$else} longword {$endif}; pse : {$ifopt r+} longword {$else} longword {$endif}; errp : {$ifopt r+} longword {$else} longword {$endif}; {$endif} exp : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif}; p : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif}; bh : tBCD_helper; nbf : Boolean; end; begin result := True; FillChar ( lvars, SizeOf ( lvars ), #0 ); BCD := NullBCD; lav := Length ( aValue ); if lav <> 0 then WITH lvars, bh do begin while ( pfnb < lav ) AND ( NOT nbf ) do begin Inc ( pfnb ); nbf := aValue[pfnb] <> ' '; end; if nbf then begin if aValue[pfnb] IN [ '+', '-' ] then begin ps := pfnb; Inc ( pfnb ); end; inife := low ( inife ); for i := pfnb TO lav do begin ch := aValue[i]; case ch of '0'..'9': begin case inife of inint, inexp: if fp[inife] = 0 then begin if ch <> '0' then begin fp[inife] := i; lp[inife] := i; end; end else lp[inife] := i; infrac: begin if fp[infrac] = 0 then fp[infrac] := i; if ch <> '0' then lp[infrac] := i; end; end; end; ',', '.': if ch = Format.DecimalSeparator then begin if inife <> inint then result := False else inife := infrac; end; 'e', 'E': if inife = inexp then result := False else inife := inexp; '+', '-': if ( inife = inexp ) AND ( fp[inexp] = 0 ) then pse := i else result := False; else begin result := False; errp := i; end; end; end; if not result then begin result := True; for i := errp TO lav do if aValue[i] <> ' ' then result := False; end; if not result then EXIT; if ps <> 0 then Neg := aValue[ps] = '-'; if lp[infrac] = 0 then fp[infrac] := 0; if fp[inexp] <> 0 then begin exp := 0; for i := fp[inexp] TO lp[inexp] do if result then if aValue[i] <> Format.ThousandSeparator then begin exp := exp * 10 + ( Ord ( aValue[i] ) - Ord ( '0' ) ); if exp > 999 then result := False; end; if not result then EXIT; if pse <> 0 then if aValue[pse] = '-' then exp := -exp; end; p := -exp; if fp[infrac] <> 0 then begin for i := fp[infrac] TO lp[infrac] do if aValue[i] <> Format.ThousandSeparator then begin if p < ( MaxFmtBCDFractionSize + 2 ) then begin Inc ( p ); Singles[p] := Ord ( aValue[i] ) - Ord ( '0' ); end; end; end; LDig := p; p := 1 - exp; if fp[inint] <> 0 then for i := lp[inint] DOWNTO fp[inint] do if aValue[i] <> Format.ThousandSeparator then begin if p > - ( MaxFmtBCDFractionSize + 2 ) then begin Dec ( p ); Singles[p] := Ord ( aValue[i] ) - Ord ( '0' ); end else result := False; end; if not result then EXIT; FDig := p; if LDig < 0 then LDig := 0; Plac := LDig; result := pack_BCD ( bh, BCD ); end; end; end; function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD; begin Result := StrToBCD(aValue, DefaultFormatSettings); end; function StrToBCD ( const aValue : FmtBCDStringtype; Const Format : TFormatSettings ) : tBCD; begin if not TryStrToBCD ( aValue, Result, Format ) then raise eBCDOverflowException.create ( 'in StrToBCD' ); end; {$ifndef FPUNONE} procedure DoubleToBCD ( const aValue : myRealtype; var BCD : tBCD ); var s : string [ 30 ]; f : TFormatSettings; begin Str ( aValue : 25, s ); f.DecimalSeparator := '.'; f.ThousandSeparator := #0; BCD := StrToBCD ( s, f ); end; function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline; begin DoubleToBCD ( aValue, result ); end; {$endif} function IntegerToBCD ( const aValue : myInttype ) : tBCD; var bh : tBCD_helper; v : {$ifopt r+} 0..high ( myInttype ) {$else} Integer {$endif}; p : {$ifopt r+} low ( bh.Singles ) - 1..0 {$else} Integer {$endif}; exitloop : Boolean; begin _SELECT _WHEN aValue = 0 _THEN result := NullBCD; _WHEN aValue = 1 _THEN result := OneBCD; _WHEN aValue = low ( myInttype ) _THEN {$if declared ( myMinIntBCD ) } result := myMinIntBCD; {$else} RAISE eBCDOverflowException.create ( 'in IntegerToBCD' ); {$endif} _WHENOTHER bh := null_.bh; WITH bh do begin Neg := aValue < 0; if Neg then v := -aValue else v := +aValue; LDig := 0; p := 0; REPEAT Singles[p] := v MOD 10; v := v DIV 10; exitloop := v = 0; Dec ( p ); if p < low ( Singles ) then begin exitloop := True; (* what to do if error occured? *) RAISE eBCDOverflowException.create ( 'in IntegerToBCD' ); end; UNTIL exitloop; FDig := p + 1; end; pack_BCD ( bh, result ); _endSELECT; end; function CurrToBCD ( const Curr : currency; var BCD : tBCD; Precision : Integer = 32; Decimals : Integer = 4 ) : Boolean; { this works under the assumption that a currency is an int64, except for scale of 10000 } var i : int64 absolute Curr; begin BCD := IntegerToBCD ( i ); {$ifndef bigger_BCD} BCD.SignSpecialPlaces := 4 OR ( BCD.SignSpecialPlaces AND NegBit ); {$else} BCD.Places := 4; {$endif} if Decimals <> 4 then Result := NormalizeBCD ( BCD, BCD, Precision, Decimals ) else CurrToBCD := True; end; {$ifdef comproutines} function CompToBCD ( const Curr : Comp ) : tBCD; Inline; var cc : int64 absolute Curr; begin result := IntegerToBCD ( cc ); end; function BCDToComp ( const BCD : tBCD ) : Comp; Inline; var zz : record case Boolean of False: ( i : int64 ); True: ( c : Comp ); end; begin zz.i := BCDToInteger ( BCD ); BCDToComp := zz.c; end; {$endif} { Convert BCD struct to string/Double/Integer } function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype; begin Result := BCDToStr(BCD, DefaultFormatSettings); end; function BCDToStr ( const BCD : tBCD; Const Format : TFormatSettings ) : FmtBCDStringtype; var bh : tBCD_helper; l : {$ifopt r+} 0..maxfmtbcdfractionsize + 1 + 1 {$else} Integer {$endif}; i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif}; pp : {$ifopt r+} low ( bh.FDig ) - 1..1 {$else} Integer {$endif}; begin {$ifdef use_ansistring} result := ''; {$endif} unpack_BCD ( BCD, bh ); WITH bh do begin l := 0; if Neg then begin {$ifndef use_ansistring} Inc ( l ); result[l] := '-'; {$else} result := result + '-'; {$endif} end; if Prec = Plac then begin {$ifndef use_ansistring} Inc ( l ); result[l] := '0'; {$else} result := result + '0'; {$endif} end; if Prec > 0 then begin pp := low ( bh.FDig ) - 1; if Plac > 0 then pp := 1; for i := FDig TO LDig do begin if i = pp then begin {$ifndef use_ansistring} Inc ( l ); result[l] := Format.DecimalSeparator; {$else} result := result + Format.DecimalSeparator; {$endif} end; {$ifndef use_ansistring} Inc ( l ); result[l] := Chr ( Singles[i] + Ord ( '0' ) ); {$else} result := result + Chr ( Singles[i] + Ord ( '0' ) ); {$endif} end; end; end; {$ifndef use_ansistring} result[0] := Chr ( l ); {$endif} end; {$ifndef FPUNONE} function BCDToDouble ( const BCD : tBCD ) : myRealtype; var bh : tBCD_helper; i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif}; r, e : myRealtype; begin unpack_BCD ( BCD, bh ); WITH bh do begin r := 0; e := 1; for i := 0 DOWNTO FDig do begin r := r + Singles[i] * e; e := e * 10; end; e := 1; for i := 1 TO LDig do begin e := e / 10; r := r + Singles[i] * e; end; if Neg then BCDToDouble := -r else BCDToDouble := +r; end; end; {$endif} function BCDToInteger ( const BCD : tBCD; Truncate : Boolean = False ) : myInttype; var bh : tBCD_helper; res : myInttype; i : {$ifopt r+} low ( bh.FDig )..0 {$else} Integer {$endif}; { unclear: behaviour if overflow: abort? return 0? return something? so: checks are missing yet } begin unpack_BCD ( BCD, bh ); res := 0; WITH bh do begin for i := FDig TO 0 do res := res * 10 - Singles[i]; if NOT Truncate then if Plac > 0 then if Singles[1] > 4 then Dec ( res ); if Neg then BCDToInteger := +res else BCDToInteger := -res; end; end; { From DB.pas } function BCDToCurr ( const BCD : tBCD; var Curr : currency ) : Boolean; var bh : tBCD_helper; res : int64; c : currency absolute res; i : {$ifopt r+} low ( bh.FDig )..4 {$else} Integer {$endif}; { unclear: behaviour if overflow: abort? return 0? return something? } begin BCDToCurr := True; unpack_BCD ( BCD, bh ); res := 0; WITH bh do begin for i := FDig TO 4 do res := res * 10 + Singles[i]; if Plac > 4 then if Singles[5] > 4 then Inc ( res ); if Neg then Curr := -c else Curr := +c; end; end; procedure BCDAdd ( const BCDin1, BCDin2 : tBCD; var BCDout : tBCD ); var bhr, bh1, bh2 : tBCD_helper; ue : {$ifopt r+} 0..1 {$else} Integer {$endif}; i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif}; v : {$ifopt r+} 0..9 + 9 + 1 {$else} Integer {$endif}; BCD : tBCD; negate : Boolean; begin negate := IsBCDNegative ( BCDin1 ); if negate <> IsBCDNegative ( BCDin2 ) then begin if negate then begin BCD := BCDin1; BCDNegate ( BCD ); BCDSubtract ( BCDin2, BCD, BCDout ); EXIT; end; BCD := BCDin2; BCDNegate ( BCD ); BCDSubtract ( BCDin1, BCD, BCDout ); EXIT; end; bhr := null_.bh; WITH bhr do begin unpack_BCD ( BCDin1, bh1 ); unpack_BCD ( BCDin2, bh2 ); if bh1.FDig < bh2.FDig then FDig := bh1.FDig else FDig := bh2.FDig; if bh1.LDig > bh2.LDig then LDig := bh1.LDig else LDig := bh2.LDig; Plac := LDig; ue := 0; for i := LDig DOWNTO FDig do begin v := bh1.Singles[i] + bh2.Singles[i] + ue; ue := v DIV 10; Singles[i] := v MOD 10; end; if ue <> 0 then begin Dec ( FDig ); Singles[FDig] := ue; end; Neg := negate; end; if NOT pack_BCD ( bhr, BCDout ) then begin RAISE eBCDOverflowException.create ( 'in BCDAdd' ); end; end; procedure BCDSubtract ( const BCDin1, BCDin2 : tBCD; var BCDout : tBCD ); var bhr, bh1, bh2 : tBCD_helper; cmp : {$ifopt r+} -1..1 {$else} Integer {$endif}; ue : {$ifopt r+} 0..1 {$else} Integer {$endif}; i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif}; v : {$ifopt r+} 0 - 9 - 1..9 - 0 - 0 {$else} Integer {$endif}; negate : Boolean; BCD : tBCD; begin negate := IsBCDNegative ( BCDin1 ); if negate <> IsBCDNegative ( BCDin2 ) then begin if negate then begin BCD := BCDin1; BCDNegate ( BCD ); BCDAdd ( BCDin2, BCD, BCDout ); BCDNegate ( BCDout ); EXIT; end; BCD := BCDin2; BCDNegate ( BCD ); BCDAdd ( BCDin1, BCD, BCDout ); EXIT; end; cmp := BCDCompare ( BCDin1, BCDin2 ); if cmp = 0 then begin BCDout := NullBCD; EXIT; end; bhr := null_.bh; { n n } WITH bhr do { > < > < } begin { } if ( cmp > 0 ) = negate { +123 +12 -12 -123 } then begin { - +12 - +123 - -123 - -12 } unpack_BCD ( BCDin1, bh2 ); { x x } unpack_BCD ( BCDin2, bh1 ); { s s s s } negate := NOT negate; { nn n nn n } end else begin unpack_BCD ( BCDin1, bh1 ); unpack_BCD ( BCDin2, bh2 ); end; if bh1.FDig < bh2.FDig then FDig := bh1.FDig else FDig := bh2.FDig; if bh1.LDig > bh2.LDig then LDig := bh1.LDig else LDig := bh2.LDig; Plac := LDig; ue := 0; for i := LDig DOWNTO FDig do begin v := Integer ( bh1.Singles[i] ) - bh2.Singles[i] - ue; ue := 0; if v < 0 then begin ue := 1; Inc ( v, 10 ); end; Singles[i] := v; end; Neg := negate; if NOT pack_BCD ( bhr, BCDout ) then begin {should never occur!} RAISE eBCDOverflowException.create ( 'in BCDSubtract' ); end; end; end; { Returns True if successful, False if Int Digits needed to be truncated } function NormalizeBCD ( const InBCD : tBCD; var OutBCD : tBCD; const Prec, Scale : Word ) : Boolean; var bh : tBCD_helper; tm : {$ifopt r+} 1..maxfmtbcdfractionsize - 1 {$else} Integer {$endif}; begin NormalizeBCD := True; {$ifopt r+} if ( Prec < 0 ) OR ( Prec > MaxFmtBCDFractionSize ) then RangeError; if ( Scale < 0 ) OR ( Prec >= MaxFmtBCDFractionSize ) then RangeError; {$endif} if BCDScale ( InBCD ) > Scale then begin unpack_BCD ( InBCD, bh ); WITH bh do begin tm := Plac - Scale; Plac := Scale; { dec ( prec, tm ); Dec/Inc error? } Prec := Prec - tm; { dec ( ldig, tm ); Dec/Inc error? } LDig := LDig - tm; NormalizeBCD := False; end; if NOT pack_BCD ( bh, OutBCD ) then begin RAISE eBCDOverflowException.create ( 'in BCDAdd' ); end; end; end; procedure BCDMultiply ( const BCDin1, BCDin2 : tBCD; var BCDout : tBCD ); var bh1, bh2, bhr : tBCD_helper; bhrr : tBCD_helper_big; i1 : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif}; i2 : {$ifopt r+} low ( bh2.FDig )..high ( bh2.LDig ) {$else} Integer {$endif}; i3 : {$ifopt r+} low ( bhrr.FDig )..high ( bhrr.LDig ) {$else} Integer {$endif}; v : {$ifopt r+} low ( bhrr.Singles[0] )..high ( bhrr.Singles[0] ) {$else} Integer {$endif}; ue : {$ifopt r+} low ( bhrr.Singles[0] ) DIV 10..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif}; begin unpack_BCD ( BCDin1, bh1 ); unpack_BCD ( BCDin2, bh2 ); if ( bh1.Prec = 0 ) OR ( bh2.Prec = 0 ) then begin BCDout := NullBCD; EXIT; end; bhr := null_.bh; bhrr := null_.bhb; WITH bhrr do begin Neg := bh1.Neg XOR bh2.Neg; { writeln ( __lo_bhb, ' ', __hi_bhb, ' ', bh1.fdig, ' ', bh2.fdig, ' ', low ( fdig ), ' ', low ( ldig ) ); } FDig := bh1.FDig + bh2.FDig; LDig := bh1.LDig + bh2.LDig; for i1 := bh1.FDig TO bh1.LDig do for i2 := bh2.FDig TO bh2.LDig do begin Inc ( Singles[i1 + i2], bh1.Singles[i1] * bh2.Singles[i2] ); { write ( Singles[i1 + i2], ' ', bh1.Singles[i1], ' ', bh2.Singles[i2], ' : ' ); writeln ( Singles[i1 + i2] + bh1.Singles[i1] + bh2.Singles[i2] ); } { Singles[i1 + i2] := Singles[i1 + i2] + bh1.Singles[i1] * bh2.Singles[i2]; } end; { for i3 := fdig to ldig do write ( ' ', singles[i3] ); writeln; } if FDig < low ( bhr.Singles ) then RAISE eBCDOverflowException.create ( 'in BCDMultiply' ); ue := 0; for i3 := LDig DOWNTO FDig do begin v := Singles[i3] + ue; ue := v DIV 10; v := v MOD 10; bhr.Singles[i3] := v; end; while ue <> 0 do begin Dec ( FDig ); if FDig < low ( bhr.Singles ) then RAISE eBCDOverflowException.create ( 'in BCDMultiply' ); bhr.Singles[FDig] := ue MOD 10; ue := ue DIV 10; end; bhr.neg := bh1.Neg XOR bh2.Neg; bhr.Plac := LDig; bhr.FDig := FDig; if LDig > high ( bhr.Singles ) then bhr.LDig := high ( bhr.Singles ) else bhr.LDig := LDig; end; if NOT pack_BCD ( bhr, BCDout ) then begin RAISE eBCDOverflowException.create ( 'in BCDMultiply' ); end; end; {$ifndef FPUNONE} procedure BCDMultiply ( const BCDIn : tBCD; const DoubleIn : myRealtype; var BCDout : tBCD ); Inline; begin BCDMultiply ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout ); end; {$endif} procedure BCDMultiply ( const BCDIn : tBCD; const StringIn : FmtBCDStringtype; var BCDout : tBCD ); Inline; begin BCDMultiply ( BCDIn, StrToBCD ( StringIn ), BCDout ); end; procedure BCDMultiply ( const StringIn1, StringIn2 : FmtBCDStringtype; var BCDout : tBCD ); Inline; begin BCDMultiply ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout ); end; procedure BCDDivide ( const Dividend, Divisor : tBCD; var BCDout : tBCD ); var bh1 : ARRAY [ Boolean ] of tBCD_helper; bh2, bh : tBCD_helper; p : {$ifopt r+} low ( bh.FDig ) - high ( bh.FDig )..high ( bh.FDig ) - low ( bh.FDig ) {$else} Integer {$endif}; v1 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif}; v2 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif}; lFDig : {$ifopt r+} low ( bh.FDig )..high ( bh.FDig ) {$else} Integer {$endif}; d1 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif}; d2 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif}; d : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif}; lLdig : {$ifopt r+} low ( lFDig ) + low ( d )..high ( lFDig ) + high ( d ) {$else} Integer {$endif}; tm : {$ifopt r+} low ( lLdig ) - high ( bh2.Singles )..high ( lLdig ) - high ( bh2.Singles ) {$else} Integer {$endif}; i2 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif}; i3 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif}; ie : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif}; i4 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif}; nFDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif}; nLDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif}; dd : {$ifopt r+} 0..9 {$else} Integer {$endif}; Add : {$ifopt r+} 0..99 {$else} Integer {$endif}; ue : {$ifopt r+} 0..99 {$else} Integer {$endif}; 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}; v4 : {$ifopt r+} low ( bh.Singles[0] ) + low ( add )..high ( bh.Singles[0] ) + high ( add ) {$else} Integer {$endif}; FlipFlop, nz, sf, sh, fdset : Boolean; { bh1p : ARRAY [ Boolean ] of ^ tBCD_helper; } begin { test: bh1p[false] := @ bh1[false]; bh1p[true] := @ bh1[true]; v := bh1[false].singles[0]; v := bh1[true].singles[0]; v := bh1p[false]^.singles[0]; v := bh1p[true]^.singles[0]; v := bh1[nz].singles[0]; v := bh1p[nz]^.singles[0]; } unpack_BCD ( Divisor, bh2 ); unpack_BCD ( Dividend, bh1[False] ); p := bh1[False].FDig - bh2.FDig; _SELECT _WHEN bh2.Prec = 0 _THEN RAISE eBCDException.create ( 'Division by zero' ); _WHEN bh1[False].Prec = 0 _THEN BCDout := NullBCD; _WHEN p < low ( bh2.Singles ) _THEN RAISE eBCDOverflowException.create ( 'in BCDDivide' ); _WHENOTHER bh := null_.bh; bh.Neg := bh1[False].Neg XOR bh2.Neg; if p <= high ( bh.Singles ) then begin bh1[True] := null_.bh; FlipFlop := False; fdset := p > 0; if fdset then bh.FDig := 0; add := 0; nz := True; while nz do WITH bh1[FlipFlop] do begin { WriteLn('#####'); dumpbh ( bh1[flipflop] ); dumpbh ( bh2 ); dumpbh ( bh ); } if ( Singles[FDig] + bh2.Singles[bh2.FDig] ) = 0 then begin if ( FDig >= LDig ) OR ( bh2.FDig >= bh2.LDig ) then nz := False else begin Inc ( FDig ); Inc ( bh2.FDig ); end; end else begin v1 := Singles[FDig]; v2 := bh2.Singles[bh2.FDig]; sh := v1 < v2; if ( v1 = v2 ) then begin nz := False; i3 := Succ ( FDig ); ie := LDig; while ( i3 <= ie ) AND ( NOT nz ) AND ( NOT sh ) do begin v1 := Singles[i3]; v2 := bh2.Singles[i3 - p]; if v1 <> v2 then begin nz := True; if v1 < v2 then sh := True; end; Inc ( i3 ); end; end; if NOT nz then Add := 1 else begin if sh then begin Inc ( p ); { if p > 3 then halt; } if p > high ( bh.Singles ) then nz := False else Dec ( bh2.FDig ); end else begin lFDig := FDig; d1 := LDig - FDig; d2 := bh2.LDig - bh2.FDig; if d1 > d2 then d := d1 else d := d2; lLdig := lFDig + d; if lLdig > high ( bh2.Singles ) then begin tm := ( lLdig ) - high ( bh2.Singles ); d := d - tm; lLdig := lLdig - tm; {runden?} end; sf := True; Add := 0; nFDig := 0; nLDig := 0; ue := 0; dd := Singles[lFDig] DIV ( bh2.Singles[lFDig - p] + 1 ); { dd := 1; } if dd < 1 then dd := 1; { writeln ( 'p=', p, ' dd=', dd, ' lFdig=', lfdig, ' lldig=', lldig ); } for i2 := lLdig DOWNTO lFDig do begin v3 := Singles[i2] - bh2.Singles[i2 - p] * dd - ue; ue := 0; while v3 < 0 do begin Inc ( ue );; v3 := v3 + 10; end; { if v3 <> 0 then begin } bh1[NOT FlipFlop].Singles[i2] := v3; { nFDig := i2; if sf then begin nLDig := i2; sf := False; end; end; } end; sf := False; nfdig := lfdig; nldig := lldig; Inc ( Add, dd ); if NOT fdset then begin bh.FDig := p; fdset := True; end; if bh.LDig < p then begin bh.LDig := p; if ( bh.LDig - bh.FDig ) > Succ ( MaxFmtBCDFractionSize ) then nz := False; end; if sf then nz := False else begin FillChar ( bh1[FlipFlop], SizeOf ( bh1[FlipFlop] ), #0 ); FlipFlop := NOT FlipFlop; WITH bh1[FlipFlop] do begin FDig := nFDig; LDig := nLDig; end; end; end; end; if Add <> 0 then begin i4 := p; while ( Add <> 0 ) AND ( i4 >= bh.FDig ) do begin { writeln ( '> ', i4, ' ', bh.Singles[i4], ' ', Add ); } v4 := bh.Singles[i4] + Add; Add := v4 DIV 10; bh.Singles[i4] := v4 MOD 10; Dec ( i4 ); end; if Add <> 0 then begin Dec ( bh.FDig ); bh.Singles[bh.FDig] := Add; Add := 0; end; end; end; end; end; WITH bh do begin if LDig < 0 then LDig := 0; if LDig > 0 then Plac := LDig else Plac := 0; end; if NOT pack_BCD ( bh, BCDout ) then begin RAISE eBCDOverflowException.create ( 'in BCDDivide' ); end; _endSELECT end; procedure BCDDivide ( const Dividend, Divisor : FmtBCDStringtype; var BCDout : tBCD ); Inline; begin BCDDivide ( StrToBCD ( Dividend ), StrToBCD ( Divisor ), BCDout ); end; {$ifndef FPUNONE} procedure BCDDivide ( const Dividend : tBCD; const Divisor : myRealtype; var BCDout : tBCD ); Inline; begin BCDDivide ( Dividend, DoubleToBCD ( Divisor ), BCDout ); end; {$endif} procedure BCDDivide ( const Dividend : tBCD; const Divisor : FmtBCDStringtype; var BCDout : tBCD ); Inline; begin BCDDivide ( Dividend, StrToBCD ( Divisor ), BCDout ); end; { TBCD variant creation utils } procedure VarFmtBCDCreate ( var aDest : Variant; const aBCD : tBCD ); begin VarClear(aDest); TVarData(aDest).Vtype:=FMTBcdFactory.Vartype; TVarData(aDest).VPointer:=TFMTBcdVarData.create(aBCD); end; function VarFmtBCDCreate : Variant; begin VarFmtBCDCreate ( result, NullBCD ); end; function VarFmtBCDCreate ( const aValue : FmtBCDStringtype; Precision, Scale : Word ) : Variant; begin VarFmtBCDCreate ( result, StrToBCD ( aValue ) ); end; {$ifndef FPUNONE} function VarFmtBCDCreate ( const aValue : myRealtype; Precision : Word = 18; Scale : Word = 4 ) : Variant; begin VarFmtBCDCreate ( result, DoubleToBCD ( aValue ) ); end; {$endif} function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant; begin VarFmtBCDCreate ( result, aBCD ); end; function VarIsFmtBCD ( const aValue : Variant ) : Boolean; begin Result:=TVarData(aValue).VType=FMTBcdFactory.VarType; end; function VarFmtBCD : TVartype; begin Result:=FMTBcdFactory.VarType; end; { Formatting BCD as string } function BCDToStrF ( const BCD : tBCD; Format : TFloatFormat; const Precision, Digits : Integer ) : FmtBCDStringtype; var P, E: integer; Negative: boolean; DS, TS: char; procedure RoundDecimalDigits(const D: integer); var i,j: integer; begin j:=P+D; if (Length(Result) > j) and (Result[j+1] >= '5') then for i:=j downto 1+ord(Negative) do begin if Result[i] = '9' then begin Result[i] := '0'; if i = 1+ord(Negative) then begin Insert('1', Result, i); inc(P); inc(j); end; end else if Result[i] <> DS then begin inc(Result[i]); break; end; end; Result := copy(Result, 1, j); end; procedure AddDecimalDigits; var n,d: integer; begin if Digits < 0 then d := 2 else d := Digits; n := d + P - Length(Result); if n > 0 then Result := Result + StringOfChar('0', n) else if n < 0 then RoundDecimalDigits(d); end; procedure AddThousandSeparators; begin Dec(P, 3); While (P > 1) Do Begin If (Result[P - 1] <> '-') And (TS <> #0) Then Insert(TS, Result, P); Dec(P, 3); End; end; begin Result := BCDToStr(BCD); if Format = ffGeneral then Exit; DS:=DefaultFormatSettings.DecimalSeparator; TS:=DefaultFormatSettings.ThousandSeparator; Negative := Result[1] = '-'; P := Pos(DS, Result); if P = 0 then begin P := Length(Result) + 1; if Digits <> 0 then Result := Result + DS; end; Case Format Of ffExponent: Begin E := P - 2 - ord(Negative); if (E = 0) and (Result[P-1] = '0') then repeat dec(E); until (Length(Result) <= P-E) or (Result[P-E] <> '0'); if E <> 0 then begin System.Delete(Result, P, 1); dec(P, E); Insert(DS, Result, P); end; RoundDecimalDigits(Precision-1); if E < 0 then begin System.Delete(Result, P+E-1, -E); Result := Result + SysUtils.Format('E%.*d' , [Digits,E]) end else Result := Result + SysUtils.Format('E+%.*d', [Digits,E]); End; ffFixed: Begin AddDecimalDigits; End; ffNumber: Begin AddDecimalDigits; AddThousandSeparators; End; ffCurrency: Begin //implementation based on FloatToStrFIntl() if Negative then System.Delete(Result, 1, 1); AddDecimalDigits; AddThousandSeparators; If Not Negative Then Begin Case CurrencyFormat Of 0: Result := CurrencyString + Result; 1: Result := Result + CurrencyString; 2: Result := CurrencyString + ' ' + Result; 3: Result := Result + ' ' + CurrencyString; End End Else Begin Case NegCurrFormat Of 0: Result := '(' + CurrencyString + Result + ')'; 1: Result := '-' + CurrencyString + Result; 2: Result := CurrencyString + '-' + Result; 3: Result := CurrencyString + Result + '-'; 4: Result := '(' + Result + CurrencyString + ')'; 5: Result := '-' + Result + CurrencyString; 6: Result := Result + '-' + CurrencyString; 7: Result := Result + CurrencyString + '-'; 8: Result := '-' + Result + ' ' + CurrencyString; 9: Result := '-' + CurrencyString + ' ' + Result; 10: Result := CurrencyString + ' ' + Result + '-'; End; End; End; End; end; function FormatBCD ( const Format : string; BCD : tBCD ) : FmtBCDStringtype; begin not_implemented; result:=''; end; {$ifdef additional_routines} function CurrToBCD ( const Curr : currency ) : tBCD; Inline; begin CurrToBCD ( Curr, result ); end; procedure BCDAdd ( const BCDIn : tBCD; const IntIn : myInttype; var BCDout : tBCD ); var BCD : tBCD; bhr : tBCD_helper; p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif}; ue : {$ifopt r+} 0..high ( IntIn ) - 9 {$else} Integer {$endif}; v : {$ifopt r+} 0..{high ( ue ) + 9} high ( IntIn ) {$else} Integer {$endif}; nz : Boolean; begin if IntIn = 0 then begin BCDout := BCDIn; EXIT; end; if IntIn = low ( myInttype ) then begin {$if declared ( myMinIntBCD ) } BCDAdd ( BCDIn, myMinIntBCD, BCDout ); EXIT; {$else} RAISE eBCDOverflowException.create ( 'in BCDAdd' ); {$endif} end; if IsBCDNegative ( BCDIn ) then begin BCD := BCDIn; BCDNegate ( BCD ); if IntIn < 0 then BCDAdd ( BCD, -IntIn, BCDout ) else BCDSubtract ( BCD, IntIn, BCDout ); BCDNegate ( BCDout ); EXIT; end; if IntIn < 0 then begin BCDSubtract ( BCDIn, -IntIn, BCDout ); EXIT; end; if IntIn > ( high ( IntIn ) - 9 ) then begin BCDAdd ( BCDIn, IntegerToBCD ( IntIn ), BCDout ); EXIT; end; unpack_BCD ( BCDIn, bhr ); p := 0; nz := True; ue := IntIn; while nz do begin v := bhr.Singles[p] + ue; bhr.Singles[p] := v MOD 10; ue := v DIV 10; if ue = 0 then nz := False else Dec ( p ); end; if p < bhr.FDig then begin bhr.FDig := p; bhr.Prec := bhr.Prec + ( bhr.FDig - p ); end; if NOT pack_BCD ( bhr, BCDout ) then begin RAISE eBCDOverflowException.create ( 'in BCDAdd' ); end; end; procedure BCDSubtract ( const BCDIn : tBCD; const IntIn : myInttype; var BCDout : tBCD ); {} var BCD : tBCD; bhr : tBCD_helper; p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif}; ue : {$ifopt r+} 0..pred ( 100000000 ) {$else} Integer {$endif}; v : {$ifopt r+} -9..9 {$else} Integer {$endif}; direct : Boolean; {} begin if IntIn = 0 then begin BCDout := BCDIn; EXIT; end; if IntIn = low ( myInttype ) then begin {$if declared ( myMinIntBCD ) } BCDSubtract ( BCDIn, myMinIntBCD, BCDout ); EXIT; {$else} RAISE eBCDOverflowException.create ( 'in BCDSubtract' ); {$endif} end; if IsBCDNegative ( BCDIn ) then begin BCD := BCDIn; BCDNegate ( BCD ); if IntIn < 0 then BCDSubtract ( BCD, -IntIn, BCDout ) else BCDAdd ( BCD, IntIn, BCDout ); BCDNegate ( BCDout ); EXIT; end; if IntIn < 0 then begin BCDAdd ( BCDIn, -IntIn, BCDout ); EXIT; end; direct := False; case BCDIn.Precision - {$ifndef bigger_BCD} ( BCDIn.SignSpecialPlaces AND PlacesMask ) {$else} BCDIn.Places {$endif} of 2: direct := IntIn < 10; 3: direct := IntIn < 100; 4: direct := IntIn < 1000; 5: direct := IntIn < 10000; 6: direct := IntIn < 100000; 7: direct := IntIn < 1000000; 8: direct := IntIn < 10000000; 9: direct := IntIn < 100000000; end; { write(direct);dumpbcd(bcdin);write('[',intin,']'); } if direct then begin unpack_BCD ( BCDIn, bhr ); WITH bhr do begin p := 0; ue := IntIn; while p >= FDig do begin v := Singles[p] - ue MOD 10; ue := ue DIV 10; if v < 0 then begin v := v + 10; ue := ue + 1; end; Singles[p] := v; Dec ( p ); end; end; if NOT pack_BCD ( bhr, BCDout ) then begin RAISE eBCDOverflowException.create ( 'in BCDSubtract' ); end; end else {} BCDSubtract ( BCDIn, IntegerToBCD ( IntIn ), BCDout ); end; procedure BCDAdd ( const IntIn : myInttype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDAdd ( BCDIn, IntIn, BCDout ); end; {$ifndef FPUNONE} procedure BCDAdd ( const BCDIn : tBCD; const DoubleIn : myRealtype; var BCDout : tBCD ); Inline; begin BCDAdd ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout ); end; procedure BCDAdd ( const DoubleIn : myRealtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDAdd ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout ); end; {$endif} procedure BCDAdd ( const BCDIn : tBCD; const Currin : currency; var BCDout : tBCD ); Inline; begin BCDAdd ( BCDIn, CurrToBCD ( Currin ), BCDout ); end; procedure BCDAdd ( const Currin : currency; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDAdd ( CurrToBCD ( Currin ), BCDIn, BCDout ); end; {$ifdef comproutines} procedure BCDAdd ( const BCDIn : tBCD; const Compin : Comp; var BCDout : tBCD ); Inline; begin BCDAdd ( BCDIn, CompToBCD ( Compin ), BCDout ); end; procedure BCDAdd ( const Compin : Comp; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDAdd ( CompToBCD ( Compin ), BCDIn, BCDout ); end; {$endif} procedure BCDAdd ( const BCDIn : tBCD; const StringIn : FmtBCDStringtype; var BCDout : tBCD ); Inline; begin BCDAdd ( BCDIn, StrToBCD ( StringIn ), BCDout ); end; procedure BCDAdd ( const StringIn : FmtBCDStringtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDAdd ( StrToBCD ( StringIn ), BCDIn, BCDout ); end; procedure BCDAdd ( const StringIn1, StringIn2 : FmtBCDStringtype; var BCDout : tBCD ); Inline; begin BCDAdd ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout ); end; procedure BCDSubtract ( const IntIn : myInttype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDSubtract ( BCDIn, IntIn, BCDout ); BCDNegate ( BCDout ); end; {$ifndef FPUNONE} procedure BCDSubtract ( const BCDIn : tBCD; const DoubleIn : myRealtype; var BCDout : tBCD ); Inline; begin BCDSubtract ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout ); end; procedure BCDSubtract ( const DoubleIn : myRealtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDSubtract ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout ); end; {$endif} procedure BCDSubtract ( const BCDIn : tBCD; const Currin : currency; var BCDout : tBCD ); Inline; begin BCDSubtract ( BCDIn, CurrToBCD ( Currin ), BCDout ); end; procedure BCDSubtract ( const Currin : currency; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDSubtract ( CurrToBCD ( Currin ), BCDIn, BCDout ); end; {$ifdef comproutines} procedure BCDSubtract ( const BCDIn : tBCD; const Compin : Comp; var BCDout : tBCD ); Inline; begin BCDSubtract ( BCDIn, CompToBCD ( Compin ), BCDout ); end; procedure BCDSubtract ( const Compin : Comp; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDSubtract ( CompToBCD ( Compin ), BCDIn, BCDout ); end; {$endif} procedure BCDSubtract ( const BCDIn : tBCD; const StringIn : FmtBCDStringtype; var BCDout : tBCD ); Inline; begin BCDSubtract ( BCDIn, StrToBCD ( StringIn ), BCDout ); end; procedure BCDSubtract ( const StringIn : FmtBCDStringtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDSubtract ( StrToBCD ( StringIn ), BCDIn, BCDout ); end; procedure BCDSubtract ( const StringIn1, StringIn2 : FmtBCDStringtype; var BCDout : tBCD ); Inline; begin BCDSubtract ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout ); end; procedure BCDMultiply ( const BCDIn : tBCD; const IntIn : myInttype; var BCDout : tBCD ); var bh : tBCD_helper; bhr : tBCD_helper; bhrr : tBCD_helper_big; int : {$ifopt r+} 0..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif}; i1 : {$ifopt r+} low ( bh.Singles )..high ( bh.Singles ) {$else} Integer {$endif}; i3 : {$ifopt r+} low ( bhr.Singles )..high ( bhr.Singles ) {$else} Integer {$endif}; 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}; ue : {$ifopt r+} 1 * ( low ( bhrr.Singles[0] ) + low ( bhrr.Singles[0] ) DIV 10 ) DIV 10 ..( high ( bhrr.Singles[0] ) + high ( bhrr.Singles[0] ) DIV 10 ) DIV 10 {$else} Integer {$endif}; begin if IntIn = 0 then begin BCDout := NullBCD; EXIT; end; if IntIn = 1 then begin BCDout := BCDIn; EXIT; end; if IntIn = -1 then begin BCDout := BCDIn; BCDNegate ( BCDout ); EXIT; end; if IntIn = low ( myInttype ) then begin {$if declared ( myMinIntBCD ) } BCDMultiply ( BCDIn, myMinIntBCD, BCDout ); EXIT; {$else} RAISE eBCDOverflowException.create ( 'in BCDmultiply' ); {$endif} end; if Abs ( IntIn ) > low ( bhrr.Singles[0] ) DIV 10 then begin BCDMultiply ( BCDIn, IntegerToBCD ( IntIn ), BCDout ); EXIT; end; unpack_BCD ( BCDIn, bh ); if bh.Prec = 0 then begin BCDout := NullBCD; EXIT; end; bhr := null_.bh; bhrr := null_.bhb; int := Abs ( IntIn ); WITH bhrr do begin Neg := bh.Neg XOR ( IntIn < 0 ); FDig := bh.FDig; LDig := bh.LDig; for i1 := bh.FDig TO bh.LDig do Singles[i1] := bh.Singles[i1] * int; { for i3 := fdig to ldig do write ( ' ', singles[i3] ); writeln; } ue := 0; for i3 := LDig DOWNTO FDig do begin v := Singles[i3] + ue; ue := v DIV 10; v := v MOD 10; bhr.Singles[i3] := v; end; while ue <> 0 do begin Dec ( FDig ); if FDig < low ( bhr.Singles ) then RAISE eBCDOverflowException.create ( 'in BCDMultiply' ); bhr.Singles[FDig] := ue MOD 10; ue := ue DIV 10; end; bhr.Plac := LDig; bhr.FDig := FDig; if LDig > high ( bhr.Singles ) then bhr.LDig := high ( bhr.Singles ) else bhr.LDig := LDig; end; if NOT pack_BCD ( bhr, BCDout ) then begin RAISE eBCDOverflowException.create ( 'in BCDMultiply' ); end; end; procedure BCDMultiply ( const IntIn : myInttype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDMultiply ( BCDIn, IntIn, BCDout ); end; {$ifndef FPUNONE} procedure BCDMultiply ( const DoubleIn : myRealtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDMultiply ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout ); end; {$endif} procedure BCDMultiply ( const BCDIn : tBCD; const Currin : currency; var BCDout : tBCD ); Inline; begin BCDMultiply ( BCDIn, CurrToBCD ( Currin ), BCDout ); end; procedure BCDMultiply ( const Currin : currency; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDMultiply ( CurrToBCD ( Currin ), BCDIn, BCDout ); end; {$ifdef comproutines} procedure BCDMultiply ( const BCDIn : tBCD; const Compin : Comp; var BCDout : tBCD ); Inline; begin BCDMultiply ( BCDIn, CompToBCD ( Compin ), BCDout ); end; procedure BCDMultiply ( const Compin : Comp; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDMultiply ( CompToBCD ( Compin ), BCDIn, BCDout ); end; {$endif} procedure BCDMultiply ( const StringIn : FmtBCDStringtype; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDMultiply ( StrToBCD ( StringIn ), BCDIn, BCDout ); end; procedure BCDDivide ( const Dividend : tBCD; const Divisor : myInttype; var BCDout : tBCD ); Inline; begin BCDDivide ( Dividend, IntegerToBCD ( Divisor ), BCDout ); end; procedure BCDDivide ( const Dividend : myInttype; const Divisor : tBCD; var BCDout : tBCD ); Inline; begin BCDDivide ( IntegerToBCD ( Dividend ), Divisor, BCDout ); end; {$ifndef FPUNONE} procedure BCDDivide ( const Dividend : myRealtype; const Divisor : tBCD; var BCDout : tBCD ); Inline; begin BCDDivide ( DoubleToBCD ( Dividend ), Divisor, BCDout ); end; {$endif} procedure BCDDivide ( const BCDIn : tBCD; const Currin : currency; var BCDout : tBCD ); Inline; begin BCDDivide ( BCDIn, CurrToBCD ( Currin ), BCDout ); end; procedure BCDDivide ( const Currin : currency; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDDivide ( CurrToBCD ( Currin ), BCDIn, BCDout ); end; {$ifdef comproutines} procedure BCDDivide ( const BCDIn : tBCD; const Compin : Comp; var BCDout : tBCD ); Inline; begin BCDDivide ( BCDIn, CompToBCD ( Compin ), BCDout ); end; procedure BCDDivide ( const Compin : Comp; const BCDIn : tBCD; var BCDout : tBCD ); Inline; begin BCDDivide ( CompToBCD ( Compin ), BCDIn, BCDout ); end; {$endif} procedure BCDDivide ( const Dividend : FmtBCDStringtype; const Divisor : tBCD; var BCDout : tBCD ); Inline; begin BCDDivide ( StrToBCD ( Dividend ), Divisor, BCDout ); end; operator = ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; begin z := BCDCompare ( BCD1, BCD2 ) = 0; end; operator < ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; begin z := BCDCompare ( BCD1, BCD2 ) < 0; end; operator > ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; begin z := BCDCompare ( BCD1, BCD2 ) > 0; end; operator <= ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; begin z := BCDCompare ( BCD1, BCD2 ) <= 0; end; operator >= ( const BCD1, BCD2 : tBCD ) z : Boolean; Inline; begin z := BCDCompare ( BCD1, BCD2 ) >= 0; end; (* ######################## not allowed: why? operator + ( const BCD : tBCD ) z : tBCD; Inline; begin z := bcd; end; ##################################################### *) operator - ( const BCD : tBCD ) z : tBCD; Inline; begin z := BCD; BCDNegate ( z ); end; operator + ( const BCD1, BCD2 : tBCD ) z : tBCD; Inline; begin BCDAdd ( BCD1, BCD2, z ); end; operator + ( const BCD : tBCD; const i : myInttype ) z : tBCD; Inline; begin BCDAdd ( BCD, i, z ); end; operator + ( const i : myInttype; const BCD : tBCD ) z : tBCD; Inline; begin BCDAdd ( i, BCD, z ); end; {$ifndef FPUNONE} operator + ( const BCD : tBCD; const r : myRealtype ) z : tBCD; Inline; begin BCDAdd ( BCD, DoubleToBCD ( r ), z ); end; operator + ( const r : myRealtype; const BCD : tBCD ) z : tBCD; Inline; begin BCDAdd ( DoubleToBCD ( r ), BCD, z ); end; {$endif} operator + ( const BCD : tBCD; const c : currency ) z : tBCD; Inline; begin BCDAdd ( BCD, CurrToBCD ( c ), z ); end; operator + ( const c : currency; const BCD : tBCD ) z : tBCD; Inline; begin BCDAdd ( CurrToBCD ( c ), BCD, z ); end; {$ifdef comproutines} operator + ( const BCD : tBCD; const c : Comp ) z : tBCD; Inline; begin BCDAdd ( BCD, CompToBCD ( c ), z ); end; operator + ( const c : Comp; const BCD : tBCD ) z : tBCD; Inline; begin BCDAdd ( CompToBCD ( c ), BCD, z ); end; {$endif} operator + ( const BCD : tBCD; const s : FmtBCDStringtype ) z : tBCD; Inline; begin BCDAdd ( BCD, StrToBCD ( s ), z ); end; operator + ( const s : FmtBCDStringtype; const BCD : tBCD ) z : tBCD; Inline; begin BCDAdd ( StrToBCD ( s ), BCD, z ); end; operator - ( const BCD1, BCD2 : tBCD ) z : tBCD; Inline; begin BCDSubtract ( BCD1, BCD2, z ); end; operator - ( const BCD : tBCD; const i : myInttype ) z : tBCD; Inline; begin BCDSubtract ( BCD, i, z ); end; operator - ( const i : myInttype; const BCD : tBCD ) z : tBCD; Inline; begin BCDSubtract ( BCD, i, z ); BCDNegate ( z ); end; {$ifndef FPUNONE} operator - ( const BCD : tBCD; const r : myRealtype ) z : tBCD; Inline; begin BCDSubtract ( BCD, DoubleToBCD ( r ), z ); end; operator - ( const r : myRealtype; const BCD : tBCD ) z : tBCD; Inline; begin BCDSubtract ( DoubleToBCD ( r ), BCD, z ); end; {$endif} operator - ( const BCD : tBCD; const c : currency ) z : tBCD; Inline; begin BCDSubtract ( BCD, CurrToBCD ( c ), z ); end; operator - ( const c : currency; const BCD : tBCD ) z : tBCD; Inline; begin BCDSubtract ( CurrToBCD ( c ), BCD, z ); end; {$ifdef comproutines} operator - ( const BCD : tBCD; const c : Comp ) z : tBCD; Inline; begin BCDSubtract ( BCD, CompToBCD ( c ), z ); end; operator - ( const c : Comp; const BCD : tBCD ) z : tBCD; Inline; begin BCDSubtract ( CompToBCD ( c ), BCD, z ); end; {$endif} operator - ( const BCD : tBCD; const s : FmtBCDStringtype ) z : tBCD; Inline; begin BCDSubtract ( BCD, StrToBCD ( s ), z ); end; operator - ( const s : FmtBCDStringtype; const BCD : tBCD ) z : tBCD; Inline; begin BCDSubtract ( StrToBCD ( s ), BCD, z ); end; operator * ( const BCD1, BCD2 : tBCD ) z : tBCD; Inline; begin BCDMultiply ( BCD1, BCD2, z ); end; operator * ( const BCD : tBCD; const i : myInttype ) z : tBCD; Inline; begin BCDMultiply ( BCD, i, z ); end; operator * ( const i : myInttype; const BCD : tBCD ) z : tBCD; Inline; begin BCDMultiply ( BCD, i, z ); end; {$ifndef FPUNONE} operator * ( const BCD : tBCD; const r : myRealtype ) z : tBCD; Inline; begin BCDMultiply ( BCD, DoubleToBCD ( r ), z ); end; operator * ( const r : myRealtype; const BCD : tBCD ) z : tBCD; Inline; begin BCDMultiply ( DoubleToBCD ( r ), BCD, z ); end; {$endif} operator * ( const BCD : tBCD; const c : currency ) z : tBCD; Inline; begin BCDMultiply ( BCD, CurrToBCD ( c ), z ); end; operator * ( const c : currency; const BCD : tBCD ) z : tBCD; Inline; begin BCDMultiply ( CurrToBCD ( c ), BCD, z ); end; {$ifdef comproutines} operator * ( const BCD : tBCD; const c : Comp ) z : tBCD; Inline; begin BCDMultiply ( BCD, CompToBCD ( c ), z ); end; operator * ( const c : Comp; const BCD : tBCD ) z : tBCD; Inline; begin BCDMultiply ( CompToBCD ( c ), BCD, z ); end; {$endif} operator * ( const BCD : tBCD; const s : FmtBCDStringtype ) z : tBCD; Inline; begin BCDMultiply ( BCD, StrToBCD ( s ), z ); end; operator * ( const s : FmtBCDStringtype; const BCD : tBCD ) z : tBCD; Inline; begin BCDMultiply ( StrToBCD ( s ), BCD, z ); end; operator / ( const BCD1, BCD2 : tBCD ) z : tBCD; Inline; begin BCDDivide ( BCD1, BCD2, z ); end; operator / ( const BCD : tBCD; const i : myInttype ) z : tBCD; Inline; begin BCDDivide ( BCD, i, z ); end; operator / ( const i : myInttype; const BCD : tBCD ) z : tBCD; Inline; begin BCDDivide ( IntegerToBCD ( i ), BCD, z ); end; {$ifndef FPUNONE} operator / ( const BCD : tBCD; const r : myRealtype ) z : tBCD; Inline; begin BCDDivide ( BCD, DoubleToBCD ( r ), z ); end; operator / ( const r : myRealtype; const BCD : tBCD ) z : tBCD; Inline; begin BCDDivide ( DoubleToBCD ( r ), BCD, z ); end; {$endif} operator / ( const BCD : tBCD; const c : currency ) z : tBCD; Inline; begin BCDDivide ( BCD, CurrToBCD ( c ), z ); end; operator / ( const c : currency; const BCD : tBCD ) z : tBCD; Inline; begin BCDDivide ( CurrToBCD ( c ), BCD, z ); end; {$ifdef comproutines} operator / ( const BCD : tBCD; const c : Comp ) z : tBCD; Inline; begin BCDDivide ( BCD, CompToBCD ( c ), z ); end; operator / ( const c : Comp; const BCD : tBCD ) z : tBCD; Inline; begin BCDDivide ( CompToBCD ( c ), BCD, z ); end; {$endif} operator / ( const BCD : tBCD; const s : FmtBCDStringtype ) z : tBCD; Inline; begin BCDDivide ( BCD, StrToBCD ( s ), z ); end; operator / ( const s : FmtBCDStringtype; const BCD : tBCD ) z : tBCD; Inline; begin BCDDivide ( StrToBCD ( s ), BCD, z ); end; operator := ( const i : Byte ) z : tBCD; Inline; begin z := IntegerToBCD ( myInttype ( i ) ); end; operator := ( const BCD : tBCD ) z : Byte; Inline; begin z := BCDToInteger ( BCD ); end; operator := ( const i : Word ) z : tBCD; Inline; begin z := IntegerToBCD ( myInttype ( i ) ); end; operator := ( const BCD : tBCD ) z : Word; Inline; begin z := BCDToInteger ( BCD ); end; operator := ( const i : longword ) z : tBCD; Inline; begin z := IntegerToBCD ( myInttype ( i ) ); end; operator := ( const BCD : tBCD ) z : longword; Inline; begin z := BCDToInteger ( BCD ); end; {$if declared ( qword ) } operator := ( const i : qword ) z : tBCD; Inline; begin z := IntegerToBCD ( myInttype ( i ) ); end; operator := ( const BCD : tBCD ) z : qword; Inline; begin z := BCDToInteger ( BCD ); end; {$endif} operator := ( const i : ShortInt ) z : tBCD; Inline; begin z := IntegerToBCD ( myInttype ( i ) ); end; operator := ( const BCD : tBCD ) z : ShortInt; Inline; begin z := BCDToInteger ( BCD ); end; operator := ( const i : smallint ) z : tBCD; Inline; begin z := IntegerToBCD ( myInttype ( i ) ); end; operator := ( const BCD : tBCD ) z : smallint; Inline; begin z := BCDToInteger ( BCD ); end; operator := ( const i : LongInt ) z : tBCD; Inline; begin z := IntegerToBCD ( myInttype ( i ) ); end; operator := ( const BCD : tBCD ) z : LongInt; Inline; begin z := BCDToInteger ( BCD ); end; {$if declared ( int64 ) } operator := ( const i : int64 ) z : tBCD; Inline; begin z := IntegerToBCD ( myInttype ( i ) ); end; operator := ( const BCD : tBCD ) z : int64; Inline; begin z := BCDToInteger ( BCD ); end; {$endif} {$ifndef FPUNONE} operator := ( const r : Single ) z : tBCD; Inline; begin z := DoubleToBCD ( myRealtype ( r ) ); end; operator := ( const BCD : tBCD ) z : Single; Inline; begin z := BCDToDouble ( BCD ); end; operator := ( const r : Double ) z : tBCD; Inline; begin z := DoubleToBCD ( myRealtype ( r ) ); end; operator := ( const BCD : tBCD ) z : Double; Inline; begin z := BCDToDouble ( BCD ); end; {$if sizeof ( extended ) <> sizeof ( double )} operator := ( const r : Extended ) z : tBCD; Inline; begin z := DoubleToBCD ( {myRealtype (} r {)} ); end; operator := ( const BCD : tBCD ) z : Extended; Inline; begin z := BCDToDouble ( BCD ); end; {$endif} {$endif} operator := ( const c : currency ) z : tBCD; Inline; begin CurrToBCD ( c, z ); end; operator := ( const BCD : tBCD ) z : currency; Inline; begin BCDToCurr ( BCD, z ); end; {$ifdef comproutines} {$undef makedirect} {$ifdef makedirect} operator := ( const c : Comp ) z : tBCD; Inline; var cc : int64 absolute c; begin z := IntegerToBCD ( cc ); end; { $define version1} { only one of these may be defined! } { $define version2} { version 1 produces a compiler error (with INLINE only!)} {$define version3} { I wasn't able to reduce the problem, sorry } {$ifdef version1} operator := ( const BCD : tBCD ) z : Comp; Inline; var zz : Comp absolute z; begin zz := BCDToInteger ( BCD ); end; {$endif} {$ifdef version2} operator := ( const BCD : tBCD ) z : Comp; Inline; var zz : int64; zzz : Comp absolute zz; begin zz := BCDToInteger ( BCD ); z := zzz; end; {$endif} {$ifdef version3} operator := ( const BCD : tBCD ) z : Comp; Inline; var zz : record case Boolean of False: ( i : int64 ); True: ( c : Comp ); end; begin zz.i := BCDToInteger ( BCD ); z := zz.c; end; {$endif} {$else} operator := ( const c : Comp ) z : tBCD; Inline; begin z := CompToBCD ( c ); end; operator := ( const BCD : tBCD ) z : Comp; Inline; begin z := BCDToComp ( BCD ); end; {$endif} {$endif} operator := ( const s : string ) z : tBCD; Inline; begin z := StrToBCD ( s ); end; operator := ( const BCD : tBCD ) z : string; Inline; begin z := BCDToStr ( BCD ); end; operator := ( const s : AnsiString ) z : tBCD; Inline; begin z := StrToBCD ( s ); end; operator := ( const BCD : tBCD ) z : AnsiString; Inline; begin z := BCDToStr ( BCD ); end; {$endif} Function VariantToBCD(const VargSrc : TVarData) : TBCD; begin with VargSrc do case vType and not varTypeMask of 0: case vType of varEmpty : Result := 0; varSmallInt : Result := vSmallInt; varShortInt : Result := vShortInt; varInteger : Result := vInteger; varSingle : Result := vSingle; varDouble : Result := vDouble; varCurrency : Result := vCurrency; varDate : Result := vDate; varBoolean : Result := Integer(vBoolean); varVariant : Result := VariantToBCD(PVarData(vPointer)^); varByte : Result := vByte; varWord : Result := vWord; varLongWord : Result := vLongWord; varInt64 : Result := vInt64; varQword : Result := vQWord; varString : Result := AnsiString(vString); else if vType=VarFmtBCD then Result := TFMTBcdVarData(vPointer).BCD else not_implemented; end; varByRef: if Assigned(vPointer) then case vType and varTypeMask of varSmallInt : Result := PSmallInt(vPointer)^; varShortInt : Result := PShortInt(vPointer)^; varInteger : Result := PInteger(vPointer)^; varSingle : Result := PSingle(vPointer)^; varDouble : Result := PDouble(vPointer)^; varCurrency : Result := PCurrency(vPointer)^; varDate : Result := PDate(vPointer)^; varBoolean : Result := SmallInt(PWordBool(vPointer)^); varVariant : Result := VariantToBCD(PVarData(vPointer)^); varByte : Result := PByte(vPointer)^; varWord : Result := PWord(vPointer)^; varLongWord : Result := PLongWord(vPointer)^; varInt64 : Result := PInt64(vPointer)^; varQword : Result := PQWord(vPointer)^; else { other vtype } not_implemented; end else { pointer is nil } not_implemented; else { array or something like that } not_implemented; end; end; function VarToBCD ( const aValue : Variant ) : tBCD; begin Result:=VariantToBCD(TVarData(aValue)); end; constructor TFMTBcdVarData.create; begin inherited create; FBcd:=NullBCD; end; constructor TFMTBcdVarData.create(const BCD : tBCD); begin inherited create; FBcd:=BCD; end; function TFMTBcdFactory.GetInstance(const v : TVarData): tObject; begin result:=tObject(v.VPointer); end; procedure TFMTBcdFactory.BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp); var l, r: TBCD; begin l:=VariantToBCD(Left); r:=VariantToBCD(Right); case Operation of opAdd: l:=l+r; opSubtract: l:=l-r; opMultiply: l:=l*r; opDivide: l:=l/r; else RaiseInvalidOp; end; if Left.vType=VarType then TFMTBcdVarData(Left.VPointer).BCD := l else RaiseInvalidOp; end; procedure TFMTBcdFactory.Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); var l, r: TBCD; CmpRes: integer; begin l:=VariantToBCD(Left); r:=VariantToBCD(Right); CmpRes := BCDCompare(l,r); if CmpRes=0 then Relationship := crEqual else if CmpRes<0 then Relationship := crLessThan else Relationship := crGreaterThan; end; function TFMTBcdFactory.CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean; var l, r: TBCD; begin l:=VariantToBCD(Left); r:=VariantToBCD(Right); case Operation of opCmpEq: Result := l=r; opCmpNe: Result := l<>r; opCmpLt: Result := lr; opCmpGe: Result := l>=r; else RaiseInvalidOp; end; end; procedure TFMTBcdFactory.Clear(var V: TVarData); begin FreeAndNil(tObject(V.VPointer)); V.VType:=varEmpty; end; procedure TFMTBcdFactory.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); begin if Indirect then Dest.VPointer:=Source.VPointer else Dest.VPointer:=TFMTBcdVarData.Create(TFMTBcdVarData(Source.VPointer).BCD); Dest.VType:=VarType; end; procedure TFMTBcdFactory.Cast(var Dest: TVarData; const Source: TVarData); begin not_implemented; end; procedure TFMTBcdFactory.CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); var v: TVarData; begin if Source.vType=VarType then if aVarType = varString then VarDataFromStr(Dest, BCDToStr(TFMTBcdVarData(Source.vPointer).BCD)) else begin VarDataInit(v); v.vType:=varDouble; v.vDouble:=BCDToDouble(TFMTBcdVarData(Source.vPointer).BCD); VarDataCastTo(Dest, v, aVarType); //now cast Double to any requested type { finalizing v is not necessary here (Double is a simple type) } end else inherited; end; {$if declared ( myMinIntBCD ) } (* {$if sizeof ( integer ) = 2 } {$ifdef BCDgr4 } const myMinIntBCDValue : packed array [ 1..3 ] of Char = #$32#$76#$80; {$endif} {$else} {$if sizeof ( integer ) = 4 } *) {$ifdef BCDgr9 } const myMinIntBCDValue : packed array [ 1..10 ] of Char = #$21#$47#$48#$36#$48; {$endif} (* {$else} {$if sizeof ( integer ) = 8 } {$ifdef BCDgr18 } const myMinIntBCDValue : packed array [ 1..19 ] of Char = #$92#$23#$37#$20#$36#$85#$47#$75#$80#$80; {$endif} {$else} {$fatal You have an interesting integer type! Sorry, not supported} {$endif} {$endif} {$endif} *) {$endif} initialization FillChar ( null_, SizeOf ( null_ ), #0 ); FillChar ( NullBCD_, SizeOf ( NullBCD_ ), #0 ); FillChar ( OneBCD_, SizeOf ( OneBCD_ ), #0 ); OneBCD_.Precision := 1; OneBCD_.Fraction[low ( OneBCD_.Fraction )] := $10; {$if declared ( myMinIntBCD ) } FillChar ( myMinIntBCD, SizeOf ( myMinIntBCD ), #0 ); {$ifndef bigger_BCD} myMinIntBCD.SignSpecialPlaces := NegBit; {$else} myMinIntBCD.Negativ := True; {$endif} {$if sizeof ( integer ) = 2 } {$ifdef BCDgr4 } myMinIntBCD.Precision := 5; Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) ); {$endif} {$else} {$if sizeof ( integer ) = 4 } {$ifdef BCDgr9 } myMinIntBCD.Precision := 10; Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) ); {$endif} {$else} {$if sizeof ( integer ) = 8 } {$ifdef BCDgr18 } myMinIntBCD.Precision := 19; Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) ); {$endif} {$else} {$fatal You have an interesting integer type! Sorry, not supported} {$endif} {$endif} {$endif} {$endif} FMTBcdFactory:=TFMTBcdFactory.create; finalization FreeAndNil(FMTBcdFactory) end.