mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-05-01 08:53:49 +02:00
4092 lines
115 KiB
ObjectPascal
4092 lines
115 KiB
ObjectPascal
{
|
|
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 := l<r;
|
|
opCmpLe:
|
|
Result := l<=r;
|
|
opCmpGt:
|
|
Result := l>r;
|
|
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.
|