用了这些年的Delphi,竟然对Currency及TBCDField一知半解,下文给了很好的讲解,值得一读。
一. BCD类型
BCD即Binary-Coded Decimal?,在Delphi中,BCD字段类型可以精确保存浮点数据类型。
Delphi支持的BCD码的数据类型名为TBCD,它的定义如下:
TBcd = packed record Precision: Byte; { 1..64 } SignSpecialPlaces: Byte; { Sign:1, Special:1, Places:6 } Fraction: packed array [0..31] of Byte; { BCD Nibbles, 00..99 per Byte, high Nibble 1st } end; |
对BCD的支持是在FMTBcd单元中,所以要使用BCD函数,则需要引用此单元。
Delphi的BCD函数有:
BcdAdd |
计算两个BCD码的和 |
BcdCompare |
比较两个BCD的大小 |
BcdDivide |
BCD数据相除 |
BcdMultiply |
BCD数据相乘 |
BcdPrecision |
返回BCD的数据个数。如BCD的123返回值为3,BCD值为9382时返回值为4。 |
BcdScale |
返回BCD码的小数位数 |
BcdSubtract |
两个BCD码相减 |
BCDToCurr |
转换BCD码为Current格式的数据类型 |
BcdToDouble |
BCD码转换为Double格式的数据类型 |
BcdToInteger |
BCD码转换为Integer格式的数据类型 |
BcdToStr |
BCD码转换为字符串 |
BcdToStrF |
BCD码转换为带格式控制的字符串 |
CurrToBCD |
Current数据类型转换为BCD码 |
DoubleToBcd |
Double数据类型转换为BCD码 |
FormatBcd |
格式化BCD码为字符串 |
IntegerToBcd |
Integer整数类型转换为BCD码 |
IsBcdNegative |
判断BCD是否为负数 |
NormalizeBcd |
将一个BCD的值根据给定的精度和小数位数转换为另外一个BCD码的值 |
NullBcd |
判断BCD是否为NULL |
StrToBcd |
字符串转换为BCD码 |
TryStrToBcd |
字符串转换为BCD码,转换失败返回给定的默认值 |
二. Currency类型
和SQL SERVER中money类型一模一样,Delphi中Currency类型:
1) 占用8个字节。
2) 总是4位小数。
3) 范围为:-2^63 ~ 2^63-1(-922,337,203,685,477.5808 ~ 922,337,203,685,477.5807)。存储格式相当于总是乘以10000,然后按整数格式保存。
三. BCD字段类型(TBCDField)
现在很多数据库中都有了Decimal和Numeric数据类型,它们可以精确保存浮点类型,可以将Decimal和Numeric类型映射为BCD字段类型。
在BDE的TDatabase控件,有一个EnableBCD选项:
在ADO的TADOQuery也有EnableBCD选项。
EnableBCD选项的用来说明如何处理数值类型(Decimal和Numeric)字段:
1) EnableBCD为TRUE时,数值类型字段映射为TBCDField类。
2) EnableBCD为FALSE时,数值类型字段映射为TFloatField类。
TBCDField定义在DB.pas文件中:
TBCDField = class(TNumericField) private FCurrency: Boolean; FCheckRange: Boolean; FMinValue: Currency; FMaxValue: Currency; FPrecision: Integer; procedure SetCurrency(Value: Boolean); procedure SetMaxValue(Value: Currency); procedure SetMinValue(Value: Currency); procedure SetPrecision(Value: Integer); procedure UpdateCheckRange; protected class procedure CheckTypeSize(Value: Integer); override; procedure CopyData(Source, Dest: Pointer); override; function GetAsBCD: TBcd; override; function GetAsCurrency: Currency; override; function GetAsFloat: Double; override; function GetAsInteger: Longint; override; function GetAsString: string; override; function GetAsVariant: Variant; override; function GetDataSize: Integer; override; function GetDefaultWidth: Integer; override; procedure GetText(var Text: string; DisplayText: Boolean); override; function GetValue(var Value: Currency): Boolean; procedure SetAsBCD(const Value: TBcd); override; procedure SetAsCurrency(Value: Currency); override; procedure SetAsFloat(Value: Double); override; procedure SetAsInteger(Value: Longint); override; procedure SetAsString(const Value: string); override; procedure SetVarValue(const Value: Variant); override; public constructor Create(AOwner: TComponent); override; property Value: Currency read GetAsCurrency write SetAsCurrency; published { Lowercase to avoid name clash with C++ Currency type } property currency: Boolean read FCurrency write SetCurrency default False; property MaxValue: Currency read FMaxValue write SetMaxValue; property MinValue: Currency read FMinValue write SetMinValue; property Precision: Integer read FPrecision write SetPrecision default 0; property Size default 4; end; |
因为TBCDField使用Currency类型来保存数据(注意:不是用TBCD来保存的),而Currency固定有且只有4位小数,所以精度超过4位请使用TFloatField(即EnableBCD位FALSE)。
四. 参考文献
- Delphi中对BCD码的直接支持 .
http://www.cnblogs.com/ywangzi/archive/2012/11/14/2769823.html