Sign in Join
Wiki copytemporary

BcdUnit: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: BcdUnit

OldNewLine
1+## Welcome
2+
3+Welcome to information page about FMTBcd. Goal of this page is to contain information needed for implementing FPC version of the FMTBcd.
4+
5+------------------------------------------------------------------------
6+
7+FMTBcd unit defines a number of binary-coded decimal (BCD) routines:
8+
9+## Types
10+
11+`TBcd  = packed record`\
12+`   Precision: Byte;`\
13+`   SignSpecialPlaces: Byte;`\
14+`   Fraction: packed array [0..31] of Byte;`\
15+` end;`
16+
17+`PBcd: pointer to TBcd`
18+
19+### Precision
20+
21+Precision states how many decimal digits are valid out of the 64 nibbles available for use.
22+
23+### SignSpecialPlaces
24+
25+SignSpecialPlaces is three fields packed into a byte.
26+
27+- The first bit is the sign (bit value 128).
28+- The second bit is 'Special' (So special, I can't work out what it's for).
29+- The third - eights bits contain the number of decimals (less the number of default digits???). 6 bits gives us up to 32 digits.
30+
31+### Fraction
32+
33+array of BCD Nibbles, 00..99 per Byte, high Nibble 1st
34+
35+Can anybody correct the following test cases?
36+
37+
38+
39+What do you mean by 'correct'?
40+
41+## test cases
42+
43+### integers
44+
45+If you look at a Tbdc record in the debugger, it will display the Precision as an integer, the SignSpecialPlaces as an interger and the Fraction as an array of integers. The fraction parts of the TBCD are really arrays of nibbles - one nibble per digit, two per byte. Following are some 'debug displays' and their translations. There is a space between bytes. So...
46+
47+zero is boring...
48+
49+`      0 -> (Precision: 0;SignSpecialPlaces: 0;  Fraction:(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`
50+
51+1..3
52+
53+`      1 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
54+`      1 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(1,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
55+
56+`      2 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
57+`      2 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(2,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
58+
59+`      3 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
60+`      3 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(3,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
61+
62+`etc...`\
63+`      4 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
64+`      5 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
65+`      6 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
66+`      7 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
67+`      8 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
68+`      9 -> (Precision: 1;SignSpecialPlaces: 0;  Fraction:(144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`
69+
70+10 - note: the fractional part is the same as for 1, the precision is now 2. i.e. 10 = 1 * 10^2
71+
72+`     10 -> (Precision: 2;SignSpecialPlaces: 0;  Fraction:(16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
73+`     10 -> (Precision: 2;SignSpecialPlaces: 0;  Fraction:(1,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
74+
75+100 - note: the fractional part is the same as for 1, the precision is now 3. i.e. 10 = 1 * 10^3
76+
77+`    100 -> (Precision: 3;SignSpecialPlaces: 0;  Fraction:(16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
78+`    100 -> (Precision: 2;SignSpecialPlaces: 0;  Fraction:(1,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`\
79+`etc`\
80+`   1000 -> (Precision: 4;SignSpecialPlaces: 0;  Fraction:(16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
81+`   1000 -> (Precision: 4;SignSpecialPlaces: 0;  Fraction:(1,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
82+
83+some more interesting cases:
84+
85+`   1111 -> (Precision: 4;SignSpecialPlaces: 0;  Fraction:(17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
86+`   1111 -> (Precision: 4;SignSpecialPlaces: 0;  Fraction:(1,1, 1,1, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
87+
88+`   1234 -> (Precision: 4;SignSpecialPlaces: 0;  Fraction:(18,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
89+`   1234 -> (Precision: 4;SignSpecialPlaces: 0;  Fraction:(1,2, 3,4, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
90+
91+`     -5 -> (Precision: 1;SignSpecialPlaces: 128;Fraction:(80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
92+`     -5 -> (Precision: 1;SignSpecialPlaces: 128;Fraction:(5,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,... `
93+
94+`     -6 -> (Precision: 1;SignSpecialPlaces: 128;Fraction:(96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
95+`     -6 -> (Precision: 1;SignSpecialPlaces: 128;Fraction:(6,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,... `
96+
97+`   9999 -> (Precision: 4;SignSpecialPlaces: 0;  Fraction:(153,153,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
98+`   9999 -> (Precision: 4;SignSpecialPlaces: 0;  Fraction:(9,9, 9,9, 9,9, 9,9, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,... `
99+
100+`  -9999 -> (Precision: 4;SignSpecialPlaces: 128;Fraction:(153,153,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
101+`  -9999 -> (Precision: 4;SignSpecialPlaces: 128;  Fraction:(9,9, 9,9, 9,9, 9,9, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,... `
102+
103+Displaying the structure in HEX helps...(you should never see any hex digits in the fraction part - only 0..9 is used)
104+
105+`  32767 -> (Precision: 5;SignSpecialPlaces: 0;  Fraction:($32,$76,$70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
106+`  32767 -> (Precision: 5;SignSpecialPlaces: 0;  Fraction:(3,2, 7,6, 70,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
107+
108+` -32768 -> (Precision: 5;SignSpecialPlaces: 128;Fraction:($32,$76,$80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
109+` -32768 -> (Precision: 5;SignSpecialPlaces: 128;Fraction:(3,2, 7,6, 80,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
110+
111+`  2147483647 -> (Precision:10;SignSpecialPlaces: 0;  Fraction:($21,$47,$48,$36,$47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
112+`  2147483647 -> (Precision:10;SignSpecialPlaces: 0;  Fraction:(2,1, 4,7, 4,8, 3,6, 4,7, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
113+
114+` -2147483647 -> (Precision:10;SignSpecialPlaces: 128;Fraction:($21,$47,$48,$36,$47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))`\
115+` -2147483647 -> (Precision:10;SignSpecialPlaces: 128;Fraction:(2,1, 4,7, 4,8, 3,6, 4,7, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0,...`
116+
117+### floats
118+
119+`  -0.01234567 ->  (Precision:8; SignSpecialPlaces: 136 {$80+8} Fraction: ( 1,35,69,103, ... 0,0)`
120+
121+## Const
122+
123+` NullBcd: TBcd = (Precision: 0; SignSpecialPlaces: 0; Fraction:(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0));`
124+
125+it's a zero (according to Delphi documentation: "Use NullBcd to indicate an unknown or missing TBcd value. NullBcd is a TBcd with all its fields set to 0. ")
126+
127+## Exceptions
128+
129+` EBcdException, EBcdOverflowException`
130+
131+??
132+
133+`  EBcdException = Class(Exception);`\
134+`  EBcdOverflowException = Class(Exception);`
135+
136+## Utility
137+
138+` function BcdPrecision(const Bcd: TBcd): Word;`\
139+` function BcdScale(const Bcd: TBcd): Word;`\
140+` function IsBcdNegative(const Bcd: TBcd): Boolean;`
141+
142+??
143+
144+## Arithmetic
145+
146+` procedure BcdAdd(const bcdIn1, bcdIn2: TBcd; var bcdOut: TBcd);`\
147+` procedure BcdSubtract(const bcdIn1, bcdIn2: TBcd; var bcdOut: TBcd);`\
148+` function NormalizeBcd(const InBcd: TBcd; var OutBcd: TBcd; const Prec, Scale: Word): Boolean;`
149+
150+Returns True if successful, False if Int Digits needed to be truncated
151+
152+` procedure BcdMultiply(const bcdIn1, bcdIn2: TBcd; var bcdOut: TBcd); overload;`\
153+` procedure BcdMultiply(const bcdIn: TBcd; const DoubleIn: Double; var bcdOut: TBcd); overload;`\
154+` procedure BcdMultiply(const bcdIn: TBcd; const StringIn: string; var bcdOut: TBcd); overload;`\
155+` procedure BcdMultiply(StringIn1, StringIn2: string; var bcdOut: TBcd); overload;`\
156+` procedure BcdDivide(Dividend, Divisor: string; var bcdOut: TBcd); overload;`\
157+` procedure BcdDivide(const Dividend, Divisor: TBcd; var bcdOut: TBcd); overload;`\
158+` procedure BcdDivide(const Dividend: TBcd; const Divisor: Double; var bcdOut: TBcd); overload;`\
159+` procedure BcdDivide(const Dividend: TBcd; const Divisor: string; var bcdOut: TBcd); overload;`
160+
161+## Creation
162+
163+` procedure VarFMTBcdCreate(var ADest: Variant; const ABcd: TBcd); overload;`\
164+` function VarFMTBcdCreate: Variant; overload;`\
165+` function VarFMTBcdCreate(const AValue: string; Precision, Scale: Word):Variant; overload;`\
166+` function VarFMTBcdCreate(const AValue: Double; Precision: Word; Scale: Word ): Variant; overload;`\
167+` function VarFMTBcdCreate(const ABcd: TBcd): Variant; overload;`\
168+` function VarIsFMTBcd(const AValue: Variant): Boolean; overload;`\
169+` function VarFMTBcd: TVarType;`
170+
171+## Conversions
172+
173+` StrToBcd, TryStrToBcd, DoubleToBcd, DoubleToBcd, IntegerToBcd,`\
174+` VarToBcd, CurrToBCD, BcdToStr, BcdToDouble, BcdToInteger,`\
175+` BCDToCurr, BcdToStrF, FormatBcd, BcdCompare`
176+
177+### to BCD
178+
179+Convert String/Double/Integer to BCD struct
180+
181+` function StrToBcd(const AValue: string): TBcd;`\
182+` function TryStrToBcd(const AValue: string; var Bcd: TBcd): Boolean;`\
183+` function DoubleToBcd(const AValue: Double): TBcd; overload;`\
184+` procedure DoubleToBcd(const AValue: Double; var bcd: TBcd); overload;`\
185+` function IntegerToBcd(const AValue: Longint): TBcd;`\
186+` function VarToBcd(const AValue: Variant): TBcd;`\
187+` function CurrToBCD(const Curr: Currency; var BCD: TBcd; Precision: Integer; Decimals: Integer): Boolean;`\
188+` `
189+
190+### from BCD
191+
192+Convert Bcd struct to string/Double/Integer
193+
194+` function BcdToStr(const Bcd: TBcd): string; overload;`\
195+` function BcdToDouble(const Bcd: TBcd): Double;`\
196+` function BcdToInteger(const Bcd: TBcd; Truncate: Boolean): Longint;`\
197+` function BCDToCurr(const BCD: TBcd; var Curr: Currency): Boolean;`\
198+` function BcdToStrF(const Bcd: TBcd; Format: TFloatFormat; const Precision, Digits: Integer): string;`
199+
200+Formatting Bcd as string
201+
202+` function FormatBcd(const Format: string; Bcd: TBcd): string;`\
203+` function BcdCompare(const bcd1, bcd2: TBcd): Integer;`
204+
205+Warnings: 1. All these functions can accept integer as a parameter, but they produce a wrong result. For converting integers, use
206+
207+` function BCDToInt(Value: Integer):Integer; `
208+
209+from the *sysutils* unit.
210+
211+2\. Converting invalid BCD arrays cause exceptions.
212+
213+## Resources
214+
215+- [Additional information](http://homepages.borland.com/efg2lab/Library/Delphi/MathInfo/) available from efg's Computer Lab ([archived](https://web.archive.org/web/20080208085333/http://homepages.borland.com/efg2lab/Library/Delphi/MathInfo/) at archive.org).
216+
217+---
218+*From the Free Pascal wiki, page "BcdUnit", as it stood on 2021-02-17 after a change by Bart, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
219+Category: FPC
220+Category: Proposals

Back to history