/[projects]/dao/DelphiScanner/Components/tpsystools_4.04/source/StBCD.pas
ViewVC logotype

Annotation of /dao/DelphiScanner/Components/tpsystools_4.04/source/StBCD.pas

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2671 - (hide annotations) (download)
Tue Aug 25 18:15:15 2015 UTC (8 years, 10 months ago) by torben
File size: 76467 byte(s)
Added tpsystools component
1 torben 2671 // Upgraded to Delphi 2009: Sebastian Zierer
2    
3     (* ***** BEGIN LICENSE BLOCK *****
4     * Version: MPL 1.1
5     *
6     * The contents of this file are subject to the Mozilla Public License Version
7     * 1.1 (the "License"); you may not use this file except in compliance with
8     * the License. You may obtain a copy of the License at
9     * http://www.mozilla.org/MPL/
10     *
11     * Software distributed under the License is distributed on an "AS IS" basis,
12     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13     * for the specific language governing rights and limitations under the
14     * License.
15     *
16     * The Original Code is TurboPower SysTools
17     *
18     * The Initial Developer of the Original Code is
19     * TurboPower Software
20     *
21     * Portions created by the Initial Developer are Copyright (C) 1996-2002
22     * the Initial Developer. All Rights Reserved.
23     *
24     * Contributor(s):
25     *
26     * ***** END LICENSE BLOCK ***** *)
27    
28     {*********************************************************}
29     {* SysTools: StBCD.pas 4.04 *}
30     {*********************************************************}
31     {* SysTools: BCD arithmetic functions *}
32     {*********************************************************}
33    
34     {$I StDefine.inc}
35    
36     {Notes:
37     The BCD format matches that defined by Turbo Pascal 3.0. It is as follows:
38    
39     LSB MSB (most significant byte at end)
40     |<------ Mantissa ------>|
41     1 2 3 4 5 6 7 8 9 10 <- Byte #
42     sE ML ML ML ML ML ML ML ML ML
43     ^ ^^--- Less significant digit
44     | |---- More significant digit
45     |
46     v
47     7 6 5 4 3 2 1 0 <-- Bit # (in Byte 1)
48     s E E E E E E E
49     ^ <--exponent->
50     | |
51     | |--- exponent has offset of $3F (eg, $41 means 10^2 = 100)
52     |----------- sign bit (0 = positive, 1 = negative)
53    
54     Unpacked BCD format
55     -------------------
56     Many of the routines that follow work with these reals in an unpacked
57     format. That is, before an arithmetic operation is performed, the mantissas
58     are expanded (unpacked) so that there is one digit per byte. After unpacking,
59     the reals look like this:
60    
61     LSB MSB
62     |<------------------ mantissa --------------------->|
63     1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
64     sE 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 0d 00
65     ^^
66     ||---- Digit
67     |----- 0
68     Byte 1 is unchanged.
69     Bytes 2-19 contain the digits in the mantissa, LSB first. The high
70     nibble of each byte is 0, and the low nibble contains the digit.
71     Byte 20, sometimes used to keep track of overflow, is set to 0.
72    
73     The constant BcdSize determines the size and accuracy of the Bcd
74     routines. It can be any value in the range 4-20 bytes. The default
75     value of 10 gives 18 digits of accuracy. A size of 20 gives 38 digits
76     of accuracy.
77    
78     The BCD routines are thread-aware; all temporary variables are local.
79    
80     STBCD uses the DecimalSeparator global variable from the SYSUTILS unit
81     wherever it needs a decimal point. As such the formatting of BCD
82     strings is aware of international differences.
83    
84     The transcendental routines (Sqrt, Ln, Exp, Pow) are accurate for
85     all but 1 or 2 of the available digits of storage. For BcdSize =
86     10, this means 16-17 accurate digits; for BcdSize = 20, this means
87     36-37 accurate digits. The last digit or two is lost to roundoff
88     errors during the calculations.
89    
90     Algorithms used for transcendental routines (depending on BcdSize):
91     Sqrt:
92     Herron's iterative approximation
93     Exp:
94     <= 10 bytes, Chebyshev polynomials per Cody and Waite
95     > 10 bytes, traditional series expansion
96     Ln:
97     <= 10 bytes, Chebyshev polynomials of rational approximation
98     per Cody and Waite
99     > 10 bytes, Carlson's iterative approximation
100     Pow:
101     straight multiplication for integer powers
102     use of Exp and Ln for non-integer powers
103    
104     Computation of Exp and Ln for BcdSize > 10 bytes is quite slow. Exp
105     takes up to 30 terms to fill in all the digits when BcdSize = 20.
106     Ln takes 9 iterations for BcdSize = 20, but each iteration is complicated
107     and involves a sqrt, a divide, and other simpler operations.
108    
109     FormatBcd mimics the FormatFloat routine from the SYSUTILS unit.
110     StrGeneralBcd mimics the FloatToStrF routine with the ffGeneral option.
111     See the documentation for those routines for more information.
112     }
113    
114    
115     unit StBCD;
116    
117     interface
118    
119     uses
120     Windows,
121     SysUtils,
122     StConst,
123     StBase,
124     StStrL;
125    
126     const
127     BcdSize = 10; {bytes in BCD, valid range 4-20}
128     {.Z+}
129     MantissaDigits = 2*(BcdSize-1); {digits in mantissa}
130     OverflowChar = '*'; {character used to fill an overflow string}
131     {.Z-}
132    
133     type
134     TBcd = array[0..BcdSize-1] of Byte;
135    
136     var
137     {these values are set up by the initialization block}
138     ZeroBcd : TBcd;
139     MinBcd : TBcd;
140     MaxBcd : TBcd;
141     BadBcd : TBcd;
142     PiBcd : TBcd;
143     eBcd : TBcd;
144     Ln10Bcd : TBcd;
145    
146     {$IFNDEF CBuilder}
147     function AddBcd(const B1, B2 : TBcd) : TBcd;
148     {-Return B1+B2}
149     function SubBcd(const B1, B2 : TBcd) : TBcd;
150     {-Return B1-B2}
151     function MulBcd(const B1, B2 : TBcd) : TBcd;
152     {-Return B1*B2}
153     function DivBcd(const B1, B2 : TBcd) : TBcd;
154     {-Return B1/B2}
155     function ModBcd(const B1, B2 : TBcd) : TBcd;
156     {-Return B1 mod B2}
157     function NegBcd(const B : TBcd) : TBcd;
158     {-Return the negative of B}
159     function AbsBcd(const B : TBcd) : TBcd;
160     {-Return the absolute value of B}
161     function FracBcd(const B : TBcd) : TBcd;
162     {-Return the fractional part of B}
163     function IntBcd(const B : TBcd) : TBcd;
164     {-Return the integer part of B, as a BCD real}
165     function RoundDigitsBcd(const B : TBcd; Digits : Cardinal) : TBcd;
166     {-Return B rounded to specified total digits of accuracy}
167     function RoundPlacesBcd(const B : TBcd; Places : Cardinal) : TBcd;
168     {-Return B rounded to specified decimal places of accuracy}
169     function ValBcd(const S : string) : TBcd;
170     {-Convert a string to a BCD}
171     function LongBcd(L : LongInt) : TBcd;
172     {-Convert a long integer to a BCD}
173     function ExtBcd(E : Extended) : TBcd;
174     {-Convert an extended real to a BCD}
175     function ExpBcd(const B : TBcd) : TBcd;
176     {-Return e**B}
177     function LnBcd(const B : TBcd) : TBcd;
178     {-Return natural log of B}
179     function IntPowBcd(const B : TBcd; E : LongInt) : TBcd;
180     {-Return B**E, where E is an integer}
181     function PowBcd(const B, E : TBcd) : TBcd;
182     {-Return B**E}
183     function SqrtBcd(const B : TBcd) : TBcd;
184     {-Return the square root of B}
185     {$ENDIF}
186    
187     function CmpBcd(const B1, B2 : TBcd) : Integer;
188     {-Return <0 if B1<B2, =0 if B1=B2, >0 if B1>B2}
189     function EqDigitsBcd(const B1, B2 : TBcd; Digits : Cardinal) : Boolean;
190     {-Return True if B1 and B2 are equal after rounding to specified digits}
191     function EqPlacesBcd(const B1, B2 : TBcd; Digits : Cardinal) : Boolean;
192     {-Return True if B1 and B2 are equal after rounding to specified decimal places}
193     function IsIntBcd(const B : TBcd) : Boolean;
194     {-Return True if B has no fractional part (may still not fit into a LongInt)}
195     function TruncBcd(const B : TBcd) : LongInt;
196     {-Return B after discarding its fractional part}
197     function BcdExt(const B : TBcd) : Extended;
198     {-Convert B to an extended real}
199     function RoundBcd(const B : TBcd) : LongInt;
200     {-Round B rounded to the nearest integer}
201     function StrBcd(const B : TBcd; Width, Places : Cardinal) : string;
202     {-Convert BCD to a string in floating point format}
203     function StrExpBcd(const B : TBcd; Width : Cardinal) : string;
204     {-Convert BCD to a string in scientific format}
205     function FormatBcd(const Format: string; const B : TBcd): string;
206     {-Format a BCD like FormatFloat does for Extended}
207     function StrGeneralBcd(const B : TBcd) : string;
208     {-Format a BCD like FloatToStrF does with ffGeneral format, MantissaDigits
209     for Precision, and zero for Digits}
210     function FloatFormBcd(const Mask : string; B : TBCD;
211     const LtCurr, RtCurr : string;
212     Sep, DecPt : Char) : string;
213     {-Returns a formatted string with digits from B merged into the Mask}
214     procedure ConvertBcd(const SrcB; SrcSize : Byte; var DestB; DestSize : Byte);
215     {-Convert a BCD of one size to another size}
216    
217     {the following routines are provided to support C++Builder}
218     {$IFDEF CBuilder}
219     procedure AddBcd_C(const B1, B2 : TBcd; var Res : TBcd);
220     procedure SubBcd_C(const B1, B2 : TBcd; var Res : TBcd);
221     procedure MulBcd_C(const B1, B2 : TBcd; var Res : TBcd);
222     procedure DivBcd_C(const B1, B2 : TBcd; var Res : TBcd);
223     procedure ModBcd_C(const B1, B2 : TBcd; var Res : TBcd);
224     procedure NegBcd_C(const B : TBcd; var Res : TBcd);
225     procedure AbsBcd_C(const B : TBcd; var Res : TBcd);
226     procedure FracBcd_C(const B : TBcd; var Res : TBcd);
227     procedure IntBcd_C(const B : TBcd; var Res : TBcd);
228     procedure RoundDigitsBcd_C(const B : TBcd; Digits : Cardinal; var Res : TBcd);
229     procedure RoundPlacesBcd_C(const B : TBcd; Places : Cardinal; var Res : TBcd);
230     procedure ValBcd_C(const S : string; var Res : TBcd);
231     procedure LongBcd_C(L : LongInt; var Res : TBcd);
232     procedure ExtBcd_C(E : Extended; var Res : TBcd);
233     procedure ExpBcd_C(const B : TBcd; var Res : TBcd);
234     procedure LnBcd_C(const B : TBcd; var Res : TBcd);
235     procedure IntPowBcd_C(const B : TBcd; E : LongInt; var Res : TBcd);
236     procedure PowBcd_C(const B, E : TBcd; var Res : TBcd);
237     procedure SqrtBcd_C(const B : TBcd; var Res : TBcd);
238     {$ENDIF}
239    
240     {the following function is interfaced to avoid hints from the compiler}
241     {for its non use when the BcdSize constant is set a value less than 11}
242     {$IFNDEF CBuilder}
243     function LnBcd20(const B : TBcd) : TBcd;
244     {$ENDIF}
245    
246     {=========================================================}
247    
248     implementation
249    
250     {Define to use assembly language in primitive routines below}
251     {$DEFINE UseAsm}
252    
253     const
254     NoSignBit = $7F; {mask to get just the exponent}
255     SignBit = $80; {mask to get just the sign}
256     ExpBias = $3F; {bias added to actual exponent value}
257     SigDigits = MantissaDigits+1; {counts overflow digit}
258    
259     type
260     TUnpBcd = array[0..SigDigits] of Byte; {unpacked BCD}
261     PUnpBcd = ^TUnpBcd;
262     TIntBcd = array[0..4*BcdSize-1] of Byte; {double size buffer for mult/div}
263    
264     {$IFDEF CBuilder}
265     function AddBcd(const B1, B2 : TBcd) : TBcd; forward;
266     function SubBcd(const B1, B2 : TBcd) : TBcd; forward;
267     function MulBcd(const B1, B2 : TBcd) : TBcd; forward;
268     function DivBcd(const B1, B2 : TBcd) : TBcd; forward;
269     function ModBcd(const B1, B2 : TBcd) : TBcd; forward;
270     function NegBcd(const B : TBcd) : TBcd; forward;
271     function AbsBcd(const B : TBcd) : TBcd; forward;
272     function FracBcd(const B : TBcd) : TBcd; forward;
273     function IntBcd(const B : TBcd) : TBcd; forward;
274     function RoundDigitsBcd(const B : TBcd; Digits : Cardinal) : TBcd; forward;
275     function RoundPlacesBcd(const B : TBcd; Places : Cardinal) : TBcd; forward;
276     function ValBcd(const S : string) : TBcd; forward;
277     function LongBcd(L : LongInt) : TBcd; forward;
278     function ExtBcd(E : Extended) : TBcd; forward;
279     function ExpBcd(const B : TBcd) : TBcd; forward;
280     function LnBcd(const B : TBcd) : TBcd; forward;
281     function IntPowBcd(const B : TBcd; E : LongInt) : TBcd; forward;
282     function PowBcd(const B, E : TBcd) : TBcd; forward;
283     function SqrtBcd(const B : TBcd) : TBcd; forward;
284     {$ENDIF}
285    
286     function FastValPrep(S : String) : String;
287     var
288     I : LongInt;
289     begin
290     I := Pos('.', S);
291     if I > 0 then
292     S[I] := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator;
293     Result := S;
294     end;
295    
296     procedure RaiseBcdError(Code : LongInt);
297     var
298     E : EStBCDError;
299     begin
300     E := EStBCDError.CreateResTP(Code, 0);
301     E.ErrorCode := Code;
302     raise E;
303     end;
304    
305     procedure AddMantissas(const UB1 : TUnpBcd; var UB2 : TUnpBcd);
306     {$IFDEF UseAsm}
307     asm
308     push esi
309     push edi
310     mov esi,UB1
311     mov edi,UB2
312     {inc esi}
313     {inc edi}
314     mov ecx,SigDigits
315     clc
316     @1: mov al,[esi] {UB1}
317     inc esi
318     adc al,[edi] {UB1+UB2+CF}
319     aaa
320     mov [edi],al {update UB2}
321     inc edi
322     dec ecx
323     jnz @1
324     jnc @2
325     inc byte ptr [edi]
326     @2: pop edi
327     pop esi
328     end;
329     {$ELSE}
330     var
331     I : Integer;
332     T, C : Byte;
333     begin
334     C := 0;
335     for I := 0 to MantissaDigits do begin
336     T := UB2[I]+UB1[I]+C;
337     if T > 9 then begin
338     C := 1;
339     dec(T, 10);
340     end else
341     C := 0;
342     UB2[I] := T;
343     end;
344     UB2[SigDigits] := C;
345     end;
346     {$ENDIF}
347    
348     function IsZeroMantissa(const UB : TUnpBcd) : Boolean;
349     {$IFDEF UseAsm}
350     asm
351     push edi
352     mov edi,UB
353     {inc edi}
354     xor al,al
355     mov ecx,SigDigits
356     repe scasb
357     jne @1
358     inc al
359     @1:pop edi
360     end;
361     {$ELSE}
362     var
363     I : Integer;
364     begin
365     for I := 0 to MantissaDigits do
366     if UB[I] <> 0 then begin
367     Result := False;
368     Exit;
369     end;
370     Result := True;
371     end;
372     {$ENDIF}
373    
374     procedure NegMantissa(var UB : TUnpBcd);
375     {$IFDEF UseAsm}
376     asm
377     push edi
378     mov edi,UB
379     {inc edi}
380     mov ecx,SigDigits
381     xor dh,dh
382     clc
383     @1: mov al,dh
384     sbb al,[edi]
385     aas
386     mov [edi],al
387     inc edi
388     dec ecx
389     jnz @1
390     pop edi
391     end;
392     {$ELSE}
393     var
394     I : Integer;
395     C : Byte;
396     begin
397     C := 1;
398     for I := 0 to MantissaDigits do begin
399     UB[I] := 9+C-UB[I];
400     if UB[I] > 9 then begin
401     dec(UB[I], 10);
402     C := 1;
403     end else
404     C := 0;
405     end;
406     end;
407     {$ENDIF}
408    
409     procedure NormalizeMantissa(var UB : TunpBcd; var E : Integer);
410     var
411     I, Shift : Integer;
412     begin
413     {find most significant non-zero digit}
414     for I := MantissaDigits downto 0 do
415     if UB[I] <> 0 then begin
416     Shift := MantissaDigits-I;
417     if Shift >= E then begin
418     {number disappears}
419     E := 0;
420     FillChar(UB[0], SigDigits, 0);
421     end else if Shift <> 0 then begin
422     dec(E, Shift);
423     move(UB[0], UB[Shift], SigDigits-Shift);
424     FillChar(UB[0], Shift, 0);
425     end;
426     Exit;
427     end;
428     {mantissa is all zeros}
429     E := 0;
430     end;
431    
432     procedure SetZero(var B : TBcd);
433     begin
434     FillChar(B, SizeOf(TBcd), 0);
435     end;
436    
437     procedure Pack(const UB : TUnpBcd; Exponent : Integer; Sign : Byte;
438     var B : TBcd);
439     {$IFNDEF UseAsm}
440     var
441     I : Integer;
442     {$ENDIF}
443     begin
444     if Exponent <= 0 then
445     SetZero(B)
446    
447     else begin
448     B[0] := Sign or Exponent;
449     {repack digits}
450     {$IFDEF UseAsm}
451     asm
452     push esi
453     push edi
454     mov esi,UB
455     mov edi,B
456     inc esi
457     inc edi
458     mov ecx,BcdSize-1
459     @1: mov ax,[esi]
460     inc esi
461     inc esi
462     shl ah,4
463     or al,ah
464     mov [edi],al
465     inc edi
466     dec ecx
467     jnz @1
468     pop edi
469     pop esi
470     end;
471     {$ELSE}
472     for I := 1 to BcdSize-1 do
473     B[I] := UB[2*I-1] or (UB[2*I] shl 4);
474     {overflow digit ignored}
475     {$ENDIF}
476     end;
477     end;
478    
479     procedure RoundMantissa(var UB : TUnpBcd; Start : Integer);
480     var
481     {$IFNDEF UseAsm}
482     I : Integer;
483     {$ENDIF}
484     C : Byte;
485     begin
486     if Start > MantissaDigits then begin
487     Start := SigDigits;
488     C := 0;
489     end else
490     C := UB[Start];
491     FillChar(UB[1], Start, 0);
492     if C < 5 then
493     Exit;
494     {$IFDEF UseAsm}
495     asm
496     push edi
497     mov edi,UB
498     mov eax,Start
499     add edi,eax
500     inc edi
501     mov ecx,MantissaDigits
502     sub ecx,eax
503     jle @2
504     stc
505     @1: mov al,[edi]
506     adc al,0
507     aaa
508     mov [edi],al
509     inc edi
510     jnc @3
511     dec ecx
512     jnz @1
513     @2: inc byte ptr [edi]
514     @3: pop edi
515     end;
516     {$ELSE}
517     C := 1;
518     for I := Start+1 to MantissaDigits do begin
519     inc(UB[I], C);
520     if UB[I] > 9 then begin
521     dec(UB[I], 10);
522     C := 1;
523     end else
524     {done rounding}
525     Exit;
526     end;
527     {set overflow digit if we get here}
528     inc(UB[SigDigits]);
529     {$ENDIF}
530     end;
531    
532     procedure ShiftMantissaDown(var UB : TUnpBcd; Shift : Integer);
533     begin
534     if Shift > MantissaDigits then
535     {UB disappears when shifted}
536     FillChar(UB[0], SigDigits+1, 0)
537    
538     else if Shift > 0 then begin
539     Move(UB[Shift], UB[0], SigDigits+1-Shift);
540     FillChar(UB[SigDigits+1-Shift], Shift, 0);
541     end;
542     end;
543    
544     procedure SubMantissas(const UB1 : TUnpBcd; var UB2 : TUnpBcd);
545     {$IFDEF UseAsm}
546     asm
547     push esi
548     push edi
549     mov esi,UB1
550     mov edi,UB2
551     {inc esi}
552     {inc edi}
553     mov ecx,SigDigits
554     clc
555     @1: mov al,[edi] {UB2}
556     sbb al,[esi] {UB2-UB1-CF}
557     aas
558     mov [edi],al {update UB2}
559     inc edi
560     inc esi
561     dec ecx
562     jnz @1
563     jnc @2
564     inc byte ptr [edi]
565     @2: pop edi
566     pop esi
567     end;
568     {$ELSE}
569     var
570     I : Integer;
571     T, C : ShortInt;
572     begin
573     C := 0;
574     for I := 0 to MantissaDigits do begin
575     T := UB2[I]-UB1[I]-C;
576     if T < 0 then begin
577     C := 1;
578     inc(T, 10);
579     end else
580     C := 0;
581     UB2[I] := T;
582     end;
583     UB2[SigDigits] := C;
584     end;
585     {$ENDIF}
586    
587     procedure Unpack(const B : TBcd; var UB : TUnpBcd;
588     var Exponent : Integer; var Sign : Byte);
589     {$IFNDEF UseAsm}
590     var
591     I : Integer;
592     {$ENDIF}
593     begin
594     {$IFDEF UseAsm}
595     asm
596     {$IFDEF VER140}
597     push ecx { get round a compiler bug in D6 }
598     {$ENDIF}
599     push esi
600     push edi
601     mov esi,B
602     mov edi,UB
603     inc esi
604     inc edi
605     mov ecx,BcdSize-1
606     @1: mov al,[esi]
607     inc esi
608     mov ah,al
609     and al,$0F
610     shr ah,4
611     mov [edi],ax
612     inc edi
613     inc edi
614     dec ecx
615     jnz @1
616     xor al,al
617     mov [edi],al
618     pop edi
619     pop esi
620     {$IFDEF VER140}
621     pop ecx { get round a compiler bug in D6 }
622     {$ENDIF}
623     end;
624     {$ELSE}
625     {unpack digits}
626     for I := 1 to BcdSize-1 do begin
627     UB[2*I-1] := B[I] and $F;
628     UB[2*I] := B[I] shr 4;
629     end;
630     {set last overflow digit to zero}
631     UB[2*BcdSize-1] := 0;
632     {$ENDIF}
633    
634     {copy sign/exponent}
635     UB[0] := 0;
636     Exponent := B[0] and NoSignBit;
637     Sign := B[0] and SignBit;
638     end;
639    
640     {----------------------------------------------------------------------}
641    
642     function AbsBcd(const B : TBcd) : TBcd;
643     begin
644     Result := B;
645     Result[0] := B[0] and noSignBit;
646     end;
647    
648     function AddBcd(const B1, B2 : TBcd) : TBcd;
649     var
650     E1, E2 : Integer;
651     S1, S2 : Byte;
652     UB1, UB2 : TUnpBcd;
653     begin
654     if B1[0] = 0 then
655     Result := B2
656    
657     else if B2[0] = 0 then
658     Result := B1
659    
660     else begin
661     Unpack(B1, UB1, E1, S1);
662     Unpack(B2, UB2, E2, S2);
663    
664     If E1 < E2 then begin
665     {shift UB1's mantissa to account for smaller exponent}
666     RoundMantissa(UB1, E2-E1-1);
667     ShiftMantissaDown(UB1, E2-E1);
668     end else if E1 > E2 then begin
669     {shift UB2's mantissa to account for smaller exponent}
670     RoundMantissa(UB2, E1-E2-1);
671     ShiftMantissaDown(UB2, E1-E2);
672     E2 := E1;
673     end;
674    
675     if S1 <> S2 then begin
676     {differing signs}
677     SubMantissas(UB1, UB2);
678     if UB2[SigDigits] <> 0 then begin
679     {negative result}
680     S2 := S2 xor SignBit;
681     UB2[SigDigits] := 0;
682     NegMantissa(UB2);
683     end;
684     {shift to get rid of any leading zeros}
685     NormalizeMantissa(UB2, E2);
686     end else begin
687     {same signs}
688     AddMantissas(UB1, UB2);
689     if UB2[SigDigits] = 0 then
690     RoundMantissa(UB2, 0);
691     if UB2[SigDigits] <> 0 then begin
692     {temporary overflow}
693     RoundMantissa(UB2, 1);
694     ShiftMantissaDown(UB2, 1);
695     inc(E2);
696     if E2 > NoSignBit then
697     {numeric overflow}
698     RaiseBcdError(stscBcdOverflow);
699     end;
700     end;
701    
702     {set sign and exponent}
703     if E2 = 0 then
704     UB2[0] := 0
705     else
706     UB2[0] := S2 or E2;
707    
708     Pack(UB2, E2, S2, Result);
709     end;
710     end;
711    
712     function BcdExt(const B : TBcd) : Extended;
713     var
714     Code : Integer;
715     S : string[59];
716     begin
717     S := StrExpBcd(B, 0);
718     if ({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator <> '.') then begin
719     while (pos({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator, S) > 0) do
720     S[pos({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator, S)] := '.';
721     end;
722     Val(S, Result, Code);
723     end;
724    
725     procedure ConvertBcd(const SrcB; SrcSize : Byte; var DestB; DestSize : Byte);
726     label
727     Repack;
728     type
729     TBA = array[0..40] of Byte; {largest BCD size times 2}
730     PBA = ^TBA;
731     var
732     I, O, Exponent : Integer;
733     PS : PBA;
734     C : Byte;
735     begin
736     if (SrcSize = 0) or (DestSize = 0) then
737     exit;
738    
739     Exponent := TBA(SrcB)[0] and NoSignBit;
740    
741     {transfer mantissa}
742     if SrcSize <= DestSize then begin
743     {dest is at least as big as src}
744     FillChar(TBA(DestB)[1], DestSize-SrcSize, 0);
745     Move(TBA(SrcB)[1], TBA(DestB)[DestSize-SrcSize+1], SrcSize-1);
746    
747     end else begin
748     {need to round src before copying to dest}
749     GetMem(PS, 2*SrcSize);
750    
751     {unpack digits}
752     for I := 1 to SrcSize-1 do begin
753     PS^[2*I-1] := TBA(SrcB)[I] and $F;
754     PS^[2*I] := TBA(SrcB)[I] shr 4;
755     end;
756     {set last overflow digit to zero}
757     PS^[2*SrcSize-1] := 0;
758     {O is a shift used when rounding causes an overflow}
759     O := 0;
760    
761     {round src starting at most significant lost digit}
762     if PS^[SrcSize-DestSize] >= 5 then begin
763     {rounding has an effect}
764     C := 1;
765     for I := SrcSize-DestSize+1 to 2*(SrcSize-1) do begin
766     inc(PS^[I], C);
767     if PS^[I] > 9 then begin
768     dec(PS^[I], 10);
769     C := 1;
770     end else
771     {done rounding}
772     goto Repack;
773     end;
774     {set overflow digit if we get here}
775     PS^[2*SrcSize-1] := 1;
776     inc(Exponent);
777     O := 1;
778     end;
779    
780     Repack:
781     {repack into same buffer taking account of overflow offset}
782     for I := 1 to SrcSize-1 do
783     PS^[I] := PS^[2*I-1+O] or (PS^[2*I+O] shl 4);
784    
785     {copy rounded src into dest}
786     Move(PS^[SrcSize-DestSize+1], TBA(DestB)[1], DestSize-1);
787    
788     FreeMem(PS, 2*SrcSize);
789     end;
790    
791     {copy sign/exponent}
792     TBA(DestB)[0] := Exponent or (TBA(SrcB)[0] and SignBit);
793     end;
794    
795     function EqDigitsBcd(const B1, B2 : TBcd; Digits : Cardinal) : Boolean;
796     begin
797     Result := (CmpBcd(RoundDigitsBcd(B1, Digits), RoundDigitsBcd(B2, Digits)) = 0);
798     end;
799    
800     function EqPlacesBcd(const B1, B2 : TBcd; Digits : Cardinal) : Boolean;
801     begin
802     Result := (CmpBcd(RoundPlacesBcd(B1, Digits), RoundPlacesBcd(B2, Digits)) = 0);
803     end;
804    
805     function CmpBcd(const B1, B2 : TBcd) : Integer;
806     var
807     {$IFNDEF UseAsm}
808     I : Integer;
809     {$ENDIF}
810     E1, E2 : Integer;
811     S1, S2 : Byte;
812     UB1, UB2 : TUnpBcd;
813     begin
814     Unpack(B1, UB1, E1, S1);
815     Unpack(B2, UB2, E2, S2);
816    
817     if S1 <> S2 then
818     {signs differ}
819     Result := Integer(S2)-S1
820    
821     else begin
822     {signs the same}
823     if E1 <> E2 then
824     {exponents differ}
825     Result := E1-E2
826    
827     else if E1 = 0 then
828     {both numbers are zero}
829     Result := 0
830    
831     else begin
832     {exponents the same, compare the mantissas}
833     {$IFDEF UseAsm}
834     asm
835     push esi
836     push edi
837     lea esi,UB1+MantissaDigits
838     lea edi,UB2+MantissaDigits
839     mov ecx,MantissaDigits
840     @1: mov al,[esi]
841     sub al,[edi]
842     jnz @2
843     dec esi
844     dec edi
845     dec ecx
846     jnz @1
847     @2: movsx eax,al
848     mov Result,eax
849     pop edi
850     pop esi
851     end;
852     {$ELSE}
853     for I := MantissaDigits downto 1 do begin
854     Result := Integer(UB1[I])-UB2[I];
855     if Result <> 0 then
856     break;
857     end;
858     {$ENDIF}
859     end;
860    
861     if S1 <> 0 then
862     {both numbers negative, reverse the result}
863     Result := -Result;
864     end;
865     end;
866    
867     function ModBcd(const B1, B2 : TBcd) : TBcd;
868     {-Return B1 mod B2}
869     begin
870     Result := IntBcd(DivBcd(B1, B2));
871     end;
872    
873     function DivBcd(const B1, B2 : TBcd) : TBcd;
874     {$IFNDEF UseAsm}
875     label
876     StoreDigit;
877     {$ENDIF}
878     var
879     {$IFNDEF UseAsm}
880     DivIntoCount, I, R : Integer;
881     T, C : ShortInt;
882     DDigit, NDigit : Byte;
883     {$ENDIF}
884     E1, E2, DivDigits, N : Integer;
885     S1, S2 : Byte;
886     UB1, UB2 : TUnpBcd;
887     TB : TIntBcd;
888     begin
889     if B2[0] = 0 then
890     {divide by zero}
891     RaiseBcdError(stscBcdDivByZero);
892    
893     if B1[0] = 0 then
894     {numerator is zero, return zero}
895     SetZero(Result)
896    
897     else begin
898     Unpack(B1, UB1, E1, S1);
899     Unpack(B2, UB2, E2, S2);
900    
901     {TB is the extended numerator}
902     FillChar(TB, 2*BcdSize, 0);
903     Move(UB1[1], TB[2*BcdSize], SigDigits);
904    
905     {UB1 is now used to store the result}
906    
907     {count significant mantissa digits in divisor}
908     {$IFDEF UseAsm}
909     asm
910     push edi
911     lea edi,UB2+1
912     mov ecx,SigDigits
913     xor al,al
914     repe scasb
915     mov DivDigits,ecx
916     pop edi
917     end;
918     {$ELSE}
919     DivDigits := 0;
920     for I := 1 to MantissaDigits do
921     if UB2[I] <> 0 then begin
922     DivDigits := SigDigits-I;
923     break;
924     end;
925     {$ENDIF}
926    
927     if DivDigits = 0 then
928     {divide by zero, shouldn't have gotten here, but just in case...}
929     RaiseBcdError(stscBcdDivByZero);
930    
931     {$IFDEF UseAsm}
932     asm
933     push ebx
934     push esi
935     push edi
936     mov ecx,SigDigits {number of digits in result}
937     lea edi,UB1+SigDigits {edi points to MSD of result}
938     lea esi,TB+2*MantissaDigits+1 {esi points to MSD of numerator}
939     mov dh,byte ptr DivDigits {keep DivDigits in dh}
940    
941     @1: push ecx {save result counter}
942     push edi {save result position}
943     mov ebx,esi {save numerator position}
944     xor dl,dl {dl = number of times divisor fits into numerator}
945    
946     @2: cmp byte ptr [esi+1],0 {check for remainder in numerator}
947     jnz @4 {divisor guaranteed to fit again}
948     xor ecx,ecx
949     mov cl,dh {ecx = number of divisor digits}
950     lea edi,UB2+MantissaDigits {last digit of divisor}
951    
952     @3: mov al,[esi] {al = numerator digit}
953     dec esi
954     mov ah,[edi] {ah = divisor digit}
955     dec edi
956     cmp al,ah
957     ja @4 {divisor fits if numerator digit > divisor}
958     jb @7 {doesn't fit if numerator digit < divisor}
959     dec ecx
960     jnz @3
961    
962     @4: inc dl {increment number of times divisor fits}
963     mov edi,ebx {restore numerator position to edi}
964     xor ecx,ecx
965     mov cl,dh {ecx = number of divisor digits}
966     lea esi,UB2+MantissaDigits {esi points to MSD of divisor}
967     dec ecx
968     sub esi,ecx {first significant digit of divisor}
969     sub edi,ecx {first active digit of numerator}
970     inc ecx
971     clc {no carry to start}
972    
973     @5: mov al,[edi] {al = digit from numerator}
974     sbb al,[esi] {subtract divisor from numerator}
975     aas
976     mov [edi],al {store back to numerator}
977     inc esi
978     inc edi
979     dec ecx
980     jnz @5
981     jnc @6
982     dec byte ptr [edi] {reduce last digit for borrow}
983    
984     @6: mov esi,ebx {restore numerator position to esi}
985     jmp @2 {see if divisor fits in numerator again}
986    
987     @7: mov esi,ebx {restore numerator position to esi}
988     pop edi {restore result position}
989     pop ecx {restore result counter}
990     mov [edi],dl {store times divisor went into numerator}
991     dec edi {next result digit}
992     dec esi {next numerator digit}
993     dec ecx
994     jnz @1 {compute next result digit}
995    
996     pop edi
997     pop esi
998     pop ebx
999     end;
1000     {$ELSE}
1001     {start with most significant digit of numerator}
1002     N := 2*MantissaDigits+1;
1003    
1004     {iterate until the result mantissa is filled}
1005     for R := SigDigits downto 1 do begin
1006     DivIntoCount := 0;
1007    
1008     repeat
1009     {subtract divisor from current numerator position as many times as possible}
1010     if TB[N+1] = 0 then begin
1011     {no overflow digit in this position of numerator}
1012     for I := 0 to DivDigits-1 do begin
1013     DDigit := UB2[MantissaDigits-I];
1014     NDigit := TB[N-I];
1015     if DDigit < NDigit then
1016     {divisor still fits}
1017     break
1018     else if DDigit > NDigit then
1019     {divisor doesn't fit}
1020     goto StoreDigit;
1021     end;
1022     end;
1023     inc(DivIntoCount);
1024    
1025     {subtract divisor once from numerator}
1026     C := 0;
1027     for I := DivDigits-1 downto 0 do begin
1028     T := TB[N-I]-UB2[MantissaDigits-I]-C;
1029     if T < 0 then begin
1030     C := 1;
1031     inc(T, 10);
1032     end else
1033     C := 0;
1034     TB[N-I] := T;
1035     end;
1036     {reduce last digit for borrow}
1037     dec(TB[N+1], C);
1038     until False;
1039    
1040     StoreDigit:
1041     {store this digit of result}
1042     UB1[R] := DivIntoCount;
1043     {next numerator digit}
1044     dec(N);
1045     end;
1046     {$ENDIF}
1047    
1048     if UB1[SigDigits] <> 0 then begin
1049     {round away the temporary digit}
1050     RoundMantissa(UB1, 1);
1051     ShiftMantissaDown(UB1, 1);
1052     inc(E1);
1053     end;
1054    
1055     {compute exponent}
1056     N := E1-E2+ExpBias;
1057     if N > NoSignBit then
1058     {numeric overflow}
1059     RaiseBcdError(stscBcdOverflow);
1060     Pack(UB1, N, S1 xor S2, Result);
1061     end;
1062     end;
1063    
1064     function FastVal(const S : string) : TBcd;
1065     {-Internal routine to quickly convert a string constant to a Bcd}
1066     {Assumes no leading spaces,
1067     no leading '+',
1068     no leading '.',
1069     always contains decimal point defined by international DecimalSeparator,
1070     no invalid characters,
1071     no exponent,
1072     < MantissaDigits before decimal point}
1073     var
1074     I, O, Digits, Exponent : Integer;
1075     Sign : Byte;
1076     Rounded : Boolean;
1077     UB : TUnpBcd;
1078    
1079     procedure AddDigit(Ch : Char);
1080     begin
1081     if O > 0 then begin
1082     UB[O] := Byte(Ch)-Byte('0');
1083     dec(O);
1084     end else if not Rounded then begin
1085     {got more significant digits than will fit, must round}
1086     Rounded := True;
1087     UB[0] := Byte(Ch)-Byte('0');
1088     RoundMantissa(UB, 0);
1089     if UB[SigDigits] <> 0 then begin
1090     ShiftMantissaDown(UB, 1);
1091     inc(Digits);
1092     end;
1093     end;
1094     end;
1095    
1096     begin
1097     FillChar(UB, SizeOf(TUnpBcd), 0);
1098    
1099     O := MantissaDigits;
1100     Rounded := False;
1101     Digits := 0;
1102    
1103     {get sign if any}
1104     if S[1] = '-' then begin
1105     Sign := SignBit;
1106     I := 2;
1107     end else begin
1108     Sign := 0;
1109     I := 1;
1110     end;
1111    
1112     {skip leading zeros}
1113     while S[I] = '0' do
1114     inc(I);
1115    
1116     {add significant digits}
1117     while S[I] <> '.' do begin
1118     AddDigit(S[I]);
1119     inc(I);
1120     inc(Digits);
1121     end;
1122    
1123     {handle dot}
1124     inc(I);
1125     if Digits = 0 then
1126     {no digits before dot, skip zeros after dot}
1127     while (I <= length(S)) and (S[I] = '0') do begin
1128     inc(I);
1129     dec(Digits);
1130     end;
1131    
1132     {add significant digits}
1133     while I <= Length(S) do begin
1134     AddDigit(S[I]);
1135     if Rounded then
1136     break;
1137     inc(I);
1138     end;
1139    
1140     {compute final exponent}
1141     Exponent := Digits+ExpBias;
1142    
1143     if (Exponent <= 0) or IsZeroMantissa(UB) then
1144     {return zero}
1145     Exponent := 0;
1146    
1147     {Return packed result}
1148     Pack(UB, Exponent, Sign, Result);
1149     end;
1150    
1151     function ExpBcd(const B : TBcd) : TBcd;
1152     var
1153     MI, Exponent : LongInt;
1154     B1, B2, B3, B4, B5 : TBcd;
1155     begin
1156     if CmpBcd(B, FastVal('147.36')) > 0 then
1157     {numeric overflow}
1158     RaiseBcdError(stscBcdOverflow);
1159    
1160     if CmpBcd(B, FastVal('-145.06')) < 0 then begin
1161     {return zero}
1162     SetZero(Result);
1163     Exit;
1164     end;
1165    
1166     if B[0] = 0 then begin
1167     {return one}
1168     Result := FastVal('1.0');
1169     Exit;
1170     end;
1171    
1172     {If BcdSize > 10, Delphi 2.0 generates a hint (if hints on) about B3 during compile}
1173     {this can be ignored or you can suppress warnings in STDEFINE.INC}
1174     {or suppress hints and warning for the IF..THEN block}
1175    
1176     if BcdSize <= 10 then begin
1177     {Burns (Cody-Waite) approximation}
1178     Exponent := RoundBcd(MulBcd(B, FastVal('0.868588963806503655')));
1179     MI := Exponent; {prevent D32 from generating a hint}
1180     B5 := LongBcd(MI);
1181    
1182     B3 := AddBcd(B, MulBcd(B5, FastVal('-1.151')));
1183     B1 := AddBcd(B3, MulBcd(B5, FastVal('-0.000292546497022842009')));
1184     B2 := MulBcd(B1, B1);
1185    
1186     B3 := MulBcd(B2, FastVal('42.0414268137450315'));
1187     B3 := MulBcd(B2, AddBcd(B3, FastVal('10097.4148724273918')));
1188     B4 := MulBcd(B1, AddBcd(B3, FastVal('333267.029226801611')));
1189    
1190     B3 := MulBcd(B2, AddBcd(B2, FastVal('841.243584514154545')));
1191     B3 := MulBcd(B2, AddBcd(B3, FastVal('75739.3346159883444')));
1192     B3 := AddBcd(B3, FastVal('666534.058453603223'));
1193     B3 := DivBcd(B4, SubBcd(B3, B4));
1194     Result := MulBcd(AddBcd(B3, FastVal('0.5')), FastVal('2.0'));
1195    
1196     if Odd(MI) then begin
1197     if MI < 0 then
1198     Result := DivBcd(Result, FastVal('3.16227766016837933'))
1199     else
1200     Result := MulBcd(Result, FastVal('3.16227766016837933'));
1201     end;
1202    
1203     inc(ShortInt(Result[0]), MI div 2);
1204    
1205     end else begin
1206     {series approximation}
1207     {compute B2, a number whose exp is close to 1.0}
1208     {and MI, a number whose exp is a power of 10}
1209     B2 := DivBcd(B, Ln10Bcd);
1210     if B[0] and SignBit <> 0 then
1211     B2 := SubBcd(B2, FastVal('0.5'))
1212     else
1213     B2 := AddBcd(B2, FastVal('0.5'));
1214     MI := TruncBcd(B2);
1215     B2 := SubBcd(B, MulBcd(IntBcd(B2), Ln10Bcd));
1216    
1217     {compute exp(B2)}
1218     B1 := FastVal('1.0');
1219     B4 := B1;
1220     Result := B1;
1221     B5 := B2;
1222     while B5[0] and NoSignBit > ExpBias-MantissaDigits-1 do begin
1223     Result := AddBcd(Result, B5);
1224     B4 := AddBcd(B4, B1);
1225     B5 := DivBcd(MulBcd(B5, B2), B4);
1226     end;
1227    
1228     {correct exponent for 10**MI}
1229     Exponent := Result[0] and NoSignBit;
1230     inc(Exponent, MI);
1231     if Exponent > NoSignBit then
1232     {numeric overflow}
1233     RaiseBcdError(stscBcdOverflow);
1234     if Exponent <= 0 then
1235     {underflow}
1236     SetZero(Result);
1237     Result[0] := Exponent;
1238     end;
1239     end;
1240    
1241     function ExtBcd(E : Extended) : TBcd;
1242     var
1243     S : string;
1244     begin
1245     Str(e:0:MantissaDigits, S);
1246     Result := ValBcd(FastValPrep(S));
1247     end;
1248    
1249     function StrGeneralBcd(const B : TBcd) : string;
1250     var
1251     I, EndI, Exponent : Integer;
1252    
1253     procedure RemoveTrailingZeros(StartI, EndI : Integer);
1254     var
1255     I : Integer;
1256     begin
1257     I := StartI;
1258     while (I > 0) and (Result[I] = '0') and (Result[I] <> {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator) do
1259     dec(I);
1260     if Result[I] = {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator then
1261     dec(I);
1262     Delete(Result, I+1, EndI-I);
1263     end;
1264    
1265     begin
1266     Exponent := B[0] and NoSignBit;
1267    
1268     if (Exponent = 0) or
1269     ((Exponent <= MantissaDigits+ExpBias) and (Exponent >= ExpBias-4)) then begin
1270     {use fixed point format for zero, digits to left of decimal point greater
1271     than or equal to MantissaDigits, or value greater than 0.00001}
1272     Result := StrBcd(B, 0, MantissaDigits);
1273     RemoveTrailingZeros(Length(Result), Length(Result));
1274    
1275     end else begin
1276     {otherwise use scientific format}
1277     Result := StrExpBcd(B, 0);
1278     if Result[1] = ' ' then
1279     Delete(Result, 1, 1);
1280     I := Length(Result)-1;
1281     EndI := I-3;
1282     while (I <= Length(Result)) and (Result[I] = '0') do
1283     Delete(Result, I, 1);
1284     if I > Length(Result) then begin
1285     {exponent was all zero}
1286     Delete(Result, Length(Result)-1, 2);
1287     I := Length(Result);
1288     end else
1289     {skip back over "e+"}
1290     I := EndI;
1291     RemoveTrailingZeros(I, EndI);
1292     end;
1293     end;
1294    
1295     function FormatBcd(const Format: string; const B : TBcd): string;
1296     label
1297     Restart;
1298     var
1299     SectNum, SectOfs, I, ExpDigits, ActPlaces : Integer;
1300     DigitCount, DecimalIndex, FirstDigit, LastDigit : Integer;
1301     DigitPlace, DigitDelta, Exponent : Integer;
1302     BufOfs, UBOfs : Integer;
1303     ThousandSep, Scientific : Boolean;
1304     Ch : Char;
1305     Sign : Byte;
1306     UB : TUnpBcd;
1307     SExponent : string;//[4];
1308     Buffer : array[0..255] of Char;
1309    
1310     function FindSection(SectNum : Integer) : Integer;
1311     {-Return the offset into Format for the given section number}
1312     var
1313     Ch : Char;
1314     begin
1315     if SectNum > 0 then begin
1316     Result := 1;
1317     while Result <= Length(Format) do begin
1318     Ch := Format[Result];
1319     case Ch of
1320     {labels in ASCII order so 32-bit compiler generates better code}
1321     '"', '''' : {skip literal}
1322     begin
1323     inc(Result);
1324     while (Result <= Length(Format)) and (Format[Result] <> Ch) do
1325     inc(Result);
1326     if Result > Length(Format) then
1327     break;
1328     end;
1329     ';' : {end of section}
1330     begin
1331     dec(SectNum);
1332     if SectNum = 0 then begin
1333     inc(Result);
1334     if (Result > Length(Format)) or (Format[Result] = ';') then
1335     {empty section}
1336     break
1337     else
1338     {found the section, return its offset}
1339     exit;
1340     end;
1341     end;
1342     end;
1343     inc(Result);
1344     end;
1345     end;
1346    
1347     {arrive here if desired section is empty, not found, or ill-formed}
1348     if (Length(Format) = 0) or (Format[1] = ';') then
1349     {first section is empty, use general format}
1350     Result := 0
1351     else
1352     {use first section}
1353     Result := 1;
1354     end;
1355    
1356     procedure ScanSection(SectOfs : Integer);
1357     {-Initialize DigitCount, DecimalIndex, ThousandSep,
1358     Scientific, FirstDigit, LastDigit}
1359     var
1360     FirstZero, LastZero : Integer;
1361     Ch : Char;
1362     begin
1363     FirstZero := 32767;
1364     LastZero := 0;
1365     DigitCount := 0;
1366     DecimalIndex := -1;
1367     ThousandSep := False;
1368     Scientific := False;
1369    
1370     repeat
1371     Ch := Format[SectOfs];
1372     case Ch of
1373     {labels in ASCII order so 32-bit compiler generates better code}
1374     '"' :
1375     begin
1376     inc(SectOfs);
1377     while (SectOfs <= Length(Format)) and (Format[SectOfs] <> Ch) do
1378     inc(SectOfs);
1379     if SectOfs > Length(Format) then
1380     break;
1381     end;
1382    
1383     '#' :
1384     inc(DigitCount);
1385    
1386     '''' :
1387     begin
1388     inc(SectOfs);
1389     while (SectOfs <= Length(Format)) and (Format[SectOfs] <> Ch) do
1390     inc(SectOfs);
1391     if SectOfs > Length(Format) then
1392     break;
1393     end;
1394    
1395     '0' :
1396     begin
1397     if DigitCount < FirstZero then
1398     FirstZero := DigitCount;
1399     inc(DigitCount);
1400     LastZero := DigitCount;
1401     end;
1402    
1403     ';' :
1404     break;
1405    
1406     'E', 'e' :
1407     if SectOfs < Length(Format) then begin
1408     inc(SectOfs);
1409     case Format[SectOfs] of
1410     '-', '+' :
1411     begin
1412     Scientific := True;
1413     repeat
1414     inc(SectOfs);
1415     until (SectOfs > Length(Format)) or (Format[SectOfs] <> '0');
1416     end;
1417     else
1418     {back up and look at character after 'e' again}
1419     dec(SectOfs);
1420     end;
1421     end;
1422     else
1423     if Ch = {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}ThousandSeparator then
1424     ThousandSep := True;
1425    
1426     if Ch = {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator then
1427     if DecimalIndex = -1 then
1428     DecimalIndex := DigitCount;
1429     end;
1430    
1431     inc(SectOfs);
1432     if SectOfs > Length(Format) then
1433     break;
1434     until False;
1435    
1436     if DecimalIndex = -1 then
1437     DecimalIndex := DigitCount;
1438     LastDigit := DecimalIndex-LastZero;
1439     if LastDigit > 0 then
1440     LastDigit := 0;
1441     FirstDigit := DecimalIndex-FirstZero;
1442     if FirstDigit < 0 then
1443     FirstDigit := 0;
1444     end;
1445    
1446     procedure StoreChar(Ch : Char);
1447     begin
1448     if BufOfs >= Length(Buffer) then
1449     {buffer overrun}
1450     RaiseBcdError(stscBcdBufOverflow);
1451     Buffer[BufOfs] := Ch;
1452     inc(BufOfs);
1453     end;
1454    
1455     procedure StoreDigitReally(ReadUB : Boolean);
1456     var
1457     BVal : Byte;
1458     begin
1459     if ReadUB then begin
1460     if UBOfs >= 0 then begin
1461     BVal := UB[UBOfs];
1462     dec(UBOfs);
1463     end else if DigitPlace <= LastDigit then begin
1464     dec(DigitPlace);
1465     Exit;
1466     end else
1467     BVal := 0;
1468     end else
1469     BVal := 0;
1470    
1471     if DigitPlace = 0 then begin
1472     StoreChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator);
1473     StoreChar(Char(BVal+Byte('0')));
1474     end else begin
1475     StoreChar(Char(BVal+Byte('0')));
1476     if ThousandSep then
1477     if DigitPlace > 1 then
1478     if DigitPlace mod 3 = 1 then
1479     StoreChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}ThousandSeparator);
1480     end;
1481    
1482     dec(DigitPlace);
1483     end;
1484    
1485     procedure StoreDigit;
1486     begin
1487     if DigitDelta = 0 then
1488     StoreDigitReally(True)
1489     else if DigitDelta < 0 then begin
1490     inc(DigitDelta);
1491     if DigitPlace <= FirstDigit then
1492     StoreDigitReally(False)
1493     else
1494     dec(DigitPlace);
1495     end else begin
1496     repeat
1497     StoreDigitReally(True);
1498     dec(DigitDelta);
1499     until DigitDelta = 0;
1500     StoreDigitReally(True);
1501     end;
1502     end;
1503    
1504     begin
1505     Unpack(B, UB, Exponent, Sign);
1506    
1507     Restart:
1508     if Exponent = 0 then
1509     {zero}
1510     SectNum := 2
1511     else if Sign <> 0 then
1512     {negative}
1513     SectNum := 1
1514     else
1515     {positive}
1516     SectNum := 0;
1517     SectOfs := FindSection(SectNum);
1518    
1519     if SectOfs = 0 then
1520     {general floating point format}
1521     Result := StrGeneralBcd(B)
1522    
1523     else begin
1524     {scan the section once to determine critical format properties}
1525     ScanSection(SectOfs);
1526    
1527     if Exponent <> 0 then begin
1528     {round based on number of displayed digits}
1529     ActPlaces := Integer(MantissaDigits)-Exponent+ExpBias;
1530     if DigitCount-DecimalIndex < ActPlaces then begin
1531     RoundMantissa(UB, ActPlaces-(DigitCount-DecimalIndex));
1532     if UB[SigDigits] <> 0 then begin
1533     ShiftMantissaDown(UB, 1);
1534     inc(Exponent);
1535     end else if IsZeroMantissa(UB) then begin
1536     {rounded to zero, possibly use a different mask}
1537     Exponent := 0;
1538     goto Restart;
1539     end;
1540     end;
1541     end;
1542    
1543     {apply formatting}
1544     if Scientific then begin
1545     DigitPlace := DecimalIndex;
1546     DigitDelta := 0;
1547     if Exponent = 0 then
1548     {for input = 0, display E+00}
1549     Exponent := ExpBias+1
1550     end else begin
1551     if Exponent = 0 then
1552     {special case for input = 0}
1553     Exponent := ExpBias
1554     else if Exponent-ExpBias > MantissaDigits then begin
1555     {all digits are integer part}
1556     Result := StrGeneralBcd(B);
1557     Exit;
1558     end;
1559     DigitPlace := Exponent-ExpBias;
1560     DigitDelta := DigitPlace-DecimalIndex;
1561     if DigitPlace < DecimalIndex then
1562     DigitPlace := DecimalIndex;
1563     end;
1564    
1565     BufOfs := 0;
1566     UBOfs := MantissaDigits;
1567    
1568     if Sign <> 0 then
1569     if SectOfs = 1 then
1570     StoreChar('-');
1571    
1572     repeat
1573     Ch := Format[SectOfs];
1574     case Ch of
1575     {labels in ASCII order so 32-bit compiler generates better code}
1576     '"' :
1577     begin
1578     inc(SectOfs);
1579     while (SectOfs <= Length(Format)) and (Format[SectOfs] <> Ch) do begin
1580     StoreChar(Format[SectOfs]);
1581     inc(SectOfs);
1582     end;
1583     if SectOfs > Length(Format) then
1584     break;
1585     end;
1586     '#' :
1587     StoreDigit;
1588    
1589     '''' :
1590     begin
1591     inc(SectOfs);
1592     while (SectOfs <= Length(Format)) and (Format[SectOfs] <> Ch) do begin
1593     StoreChar(Format[SectOfs]);
1594     inc(SectOfs);
1595     end;
1596     if SectOfs > Length(Format) then
1597     break;
1598     end;
1599    
1600     '0' :
1601     StoreDigit;
1602    
1603     ';' :
1604     break;
1605    
1606     'E', 'e' :
1607     if SectOfs < Length(Format) then begin
1608     inc(SectOfs);
1609     case Format[SectOfs] of
1610     '-', '+' :
1611     begin
1612     StoreChar(Ch);
1613     Ch := Format[SectOfs];
1614     ExpDigits := -1;
1615     repeat
1616     inc(ExpDigits);
1617     inc(SectOfs);
1618     until (SectOfs > Length(Format)) or (Format[SectOfs] <> '0');
1619     if ExpDigits > 4 then
1620     ExpDigits := 4;
1621     dec(Exponent, ExpBias+DecimalIndex);
1622     if (Exponent >= 0) and (Ch = '+') then
1623     StoreChar('+');
1624     if Exponent < 0 then begin
1625     StoreChar('-');
1626     Exponent := Abs(Exponent);
1627     end;
1628     Str(Exponent:ExpDigits, SExponent);
1629     for I := 1 to ExpDigits do
1630     if SExponent[I] = ' ' then
1631     StoreChar('0')
1632     else
1633     StoreChar(SExponent[I]);
1634     end;
1635     else
1636     StoreChar(Ch);
1637     StoreChar(Format[SectOfs]);
1638     end;
1639     end else
1640     StoreChar(Ch);
1641     else
1642     {these characters are automatically inserted in StoreDigit};
1643     if not (Ch in [{$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}ThousandSeparator, {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator]) then
1644     StoreChar(Ch);
1645     end;
1646    
1647     inc(SectOfs);
1648     if SectOfs > Length(Format) then
1649     break;
1650     until False;
1651    
1652     SetLength(Result, BufOfs);
1653     move(Buffer[0], Result[1], BufOfs * SizeOf(Char));
1654     end;
1655     end;
1656    
1657     function FracBcd(const B : TBcd) : TBcd;
1658     begin
1659     Result := SubBcd(B, IntBcd(B));
1660     end;
1661    
1662     function IsIntBcd(const B : TBcd) : Boolean;
1663     var
1664     {$IFNDEF UseAsm}
1665     I : Integer;
1666     {$ENDIF}
1667     Exponent : Integer;
1668     Sign : Byte;
1669     UB : TUnpBcd;
1670     begin
1671     Unpack(B, UB, Exponent, Sign);
1672    
1673     if Exponent = 0 then
1674     {0.0 has no fractional part}
1675     Result := True
1676    
1677     else if Exponent <= ExpBias then
1678     {value is less than one, but non-zero}
1679     Result := False
1680    
1681     else if Exponent-ExpBias >= MantissaDigits then
1682     {entire mantissa is non-fractional}
1683     Result := True
1684    
1685     else begin
1686     {see if any non-zero digits to left of decimal point}
1687     {$IFDEF UseAsm}
1688     asm
1689     push edi
1690     lea edi,UB+1
1691     mov ecx,MantissaDigits+ExpBias
1692     sub ecx,Exponent
1693     xor al,al
1694     cld
1695     repe scasb
1696     jne @1
1697     inc al
1698     @1: mov Result,al
1699     pop edi
1700     end;
1701     {$ELSE}
1702     for I := 1 to MantissaDigits-(Exponent-ExpBias) do
1703     if UB[I] <> 0 then begin
1704     Result := False;
1705     Exit;
1706     end;
1707     Result := True;
1708     {$ENDIF}
1709     end;
1710     end;
1711    
1712     function IntBcd(const B : TBcd) : TBcd;
1713     var
1714     Exponent : Integer;
1715     Sign : Byte;
1716     UB : TUnpBcd;
1717     begin
1718     Unpack(B, UB, Exponent, Sign);
1719    
1720     if Exponent <= ExpBias then
1721     {value is less than one}
1722     SetZero(Result)
1723    
1724     else if Exponent-ExpBias >= MantissaDigits then
1725     {entire mantissa is integer part}
1726     Result := B
1727    
1728     else begin
1729     {clear fractional digits}
1730     FillChar(UB[1], MantissaDigits-(Exponent-ExpBias), 0);
1731     Pack(UB, Exponent, Sign, Result);
1732     end;
1733     end;
1734    
1735     function IntPowBcd(const B : TBcd; E : LongInt) : TBcd;
1736     var
1737     I : LongInt;
1738     B1 : TBcd;
1739     begin
1740     B1 := FastVal('1.0');
1741     Result := B1;
1742     for I := 1 to Abs(E) do
1743     Result := MulBcd(Result, B);
1744     if E < 0 then
1745     Result := DivBcd(B1, Result);
1746     end;
1747    
1748     function LnBcd20(const B : TBcd) : TBcd;
1749     const
1750     Iterations = 9;
1751     var
1752     Exponent, N, K : integer;
1753     BN, B025, B05, B1, AN, GN, Pow : TBcd;
1754     DN1, DN : array[0..Iterations] of TBcd;
1755     begin
1756     {normalize input in range 0.10-0.99...}
1757     Exponent := B[0]-ExpBias;
1758     BN := B;
1759     BN[0] := ExpBias;
1760    
1761     {initialize some constants}
1762     B025 := FastVal('0.25');
1763     B05 := FastVal('0.5');
1764     B1 := FastVal('1.0');
1765    
1766     {compute initial terms of approximation}
1767     AN := MulBcd(B05, AddBcd(BN, B1));
1768     GN := SqrtBcd(BN);
1769     DN1[0] := AN;
1770    
1771     {converge on exact value}
1772     for N := 1 to Iterations do begin
1773     AN := MulBcd(B05, AddBcd(AN, GN));
1774     DN[0] := AN;
1775     Pow := B025;
1776     for K := 1 to N do begin
1777     DN[K] := DivBcd(SubBcd(DN[K-1], MulBcd(Pow, DN1[K-1])), SubBcd(B1, Pow));
1778     if K = N then
1779     break;
1780     Pow := MulBcd(Pow, B025);
1781     end;
1782    
1783     if N = Iterations then
1784     break;
1785     GN := SqrtBcd(MulBcd(AN, GN));
1786     DN1 := DN;
1787     end;
1788     Result := DivBcd(SubBcd(BN, B1), DN[Iterations]);
1789    
1790     {correct for normalization}
1791     Result := AddBcd(Result, MulBcd(LongBcd(Exponent), Ln10Bcd));
1792     end;
1793    
1794     function LnBcd10(const B : TBcd) : TBcd;
1795     var
1796     Exponent : Integer;
1797     BN, B1, S, W, T, AW, BW : TBcd;
1798     begin
1799     {normalize input in range 0.10-0.99...}
1800     Exponent := B[0]-ExpBias;
1801     BN := B;
1802     BN[0] := ExpBias;
1803    
1804     if CmpBcd(BN, FastVal('0.316227766016837933')) < 0 then begin
1805     {renormalize in range .316-3.16}
1806     dec(Exponent);
1807     inc(BN[0]);
1808     end;
1809    
1810     B1 := FastVal('1.0');
1811     S := DivBcd(SubBcd(BN, B1), AddBcd(BN, B1));
1812     W := MulBcd(S, S);
1813    
1814     T := MulBcd(W, FastVal('-0.741010784161919239'));
1815     T := MulBcd(W, AddBcd(T, FastVal('10.3338571514793865')));
1816     T := MulBcd(W, AddBcd(T, FastVal('-39.273741020315625')));
1817     T := MulBcd(W, AddBcd(T, FastVal('55.4085912041205931')));
1818     AW := AddBcd(T, FastVal('-26.0447002405557636'));
1819    
1820     T := MulBcd(W, AddBcd(W, FastVal('-19.3732345832854786')));
1821     T := MulBcd(W, AddBcd(T, FastVal('107.109789115668009')));
1822     T := MulBcd(W, AddBcd(T, FastVal('-244.303035341829542')));
1823     T := MulBcd(W, AddBcd(T, FastVal('245.347618868489348')));
1824     BW := AddBcd(T, FastVal('-89.9552077881033117'));
1825    
1826     T := MulBcd(W, DivBcd(AW, BW));
1827     T := MulBcd(S, AddBcd(T, FastVal('0.868588963806503655')));
1828    
1829     Result := MulBcd(AddBcd(T, LongBcd(Exponent)), Ln10Bcd);
1830     end;
1831    
1832     function LnBcd(const B : TBcd) : TBcd;
1833     begin
1834     if (B[0] = 0) or (B[0] and SignBit <> 0) then
1835     {ln of zero or a negative number}
1836     RaiseBcdError(stscBcdBadInput);
1837    
1838     if BcdSize <= 10 then
1839     Result := LnBcd10(B)
1840     else
1841     Result := LnBcd20(B);
1842     end;
1843    
1844     function LongBcd(L : LongInt) : TBcd;
1845     var
1846     S : string;
1847     begin
1848     Str(L, S);
1849     Result := ValBcd(FastValPrep(S));
1850     end;
1851    
1852     function MulBcd(const B1, B2 : TBcd) : TBcd;
1853     var
1854     E1, E2, Digits : Integer;
1855     S1, S2 : Byte;
1856     {$IFNDEF UseAsm}
1857     I1, I2 : Integer;
1858     CP, CN : Byte;
1859     T, T1, T2 : Byte;
1860     {$ENDIF}
1861     PB : PUnpBcd;
1862     UB1, UB2 : TUnpBcd;
1863     TB : TIntBcd;
1864     begin
1865     if (B1[0] = 0) or (B2[0] = 0) then
1866     SetZero(Result)
1867    
1868     else begin
1869     Unpack(B1, UB1, E1, S1);
1870     Unpack(B2, UB2, E2, S2);
1871    
1872     FillChar(TB, SizeOf(TIntBcd), 0);
1873    
1874     {multiply and sum the mantissas}
1875     {$IFDEF UseAsm}
1876     asm
1877     push ebx
1878     push esi
1879     push edi
1880     lea ebx,UB1 {multiplier}
1881     lea edi,TB {result}
1882     mov ecx,MantissaDigits
1883    
1884     @1: inc ebx {next multiplier digit}
1885     inc edi {next output digit}
1886     mov al,[ebx] {get next multiplier digit}
1887     or al,al {if zero, nothing to do}
1888     jz @3
1889    
1890     push ecx {save digit counter}
1891     mov dl,al {save multiplier}
1892     lea esi,UB2+1 {multiplicand}
1893     mov ecx,MantissaDigits
1894     xor dh,dh
1895    
1896     @2: mov al,[esi] {next multiplicand digit}
1897     inc esi
1898     mul dl {multiply by multiplier, overflow in ah}
1899     aam
1900     add al,[edi] {add previous result}
1901     aaa
1902     add al,dh {add previous overflow}
1903     aaa
1904     mov [edi],al {store temporary result}
1905     inc edi
1906     mov dh,ah {save overflow for next time}
1907     dec ecx
1908     jnz @2
1909     mov [edi],dh {save last overflow in next digit}
1910     sub edi,MantissaDigits {reset output offset for next multiplier}
1911     pop ecx
1912    
1913     @3: dec ecx {next multiplier digit}
1914     jnz @1
1915     pop edi
1916     pop esi
1917     pop ebx
1918     end;
1919     {$ELSE}
1920     for I1 := 1 to MantissaDigits do begin
1921     T1 := UB1[I1];
1922     if T1 <> 0 then begin
1923     CP := 0;
1924     for I2 := 1 to MantissaDigits do begin
1925     T := T1*UB2[I2];
1926     T2 := T mod 10;
1927     CN := T div 10;
1928     inc(T2, TB[I1+I2-1]);
1929     if T2 > 9 then begin
1930     dec(T2, 10);
1931     inc(CN);
1932     end;
1933     inc(T2, CP);
1934     if T2 > 9 then begin
1935     dec(T2, 10);
1936     inc(CN);
1937     end;
1938     TB[I1+I2-1] := T2;
1939     CP := CN;
1940     end;
1941     {store last carry in next digit of buffer}
1942     TB[I1+MantissaDigits] := CP;
1943     end;
1944     end;
1945     {$ENDIF}
1946    
1947     {normalize the product}
1948     if TB[2*MantissaDigits] <> 0 then begin
1949     PB := PUnpBcd(@TB[MantissaDigits]);
1950     Digits := 0;
1951     end else begin
1952     PB := PUnpBcd(@TB[MantissaDigits-1]);
1953     Digits := -1;
1954     end;
1955     RoundMantissa(PB^, 0);
1956     if PB^[SigDigits] <> 0 then begin
1957     inc(PByte(PB));
1958     inc(Digits);
1959     end;
1960     {copy back to UB2}
1961     UB2 := PB^;
1962    
1963     {set sign and exponent}
1964     inc(E2, E1+Digits-ExpBias);
1965     if E2 > NoSignBit then
1966     {numeric overflow}
1967     RaiseBcdError(stscBcdOverflow);
1968    
1969     Pack(UB2, E2, S1 xor S2, Result);
1970     end;
1971     end;
1972    
1973     function NegBcd(const B : TBcd) : TBcd;
1974     begin
1975     Result := B;
1976     if B[0] <> 0 then
1977     Result[0] := B[0] xor SignBit;
1978     end;
1979    
1980     function PowBcd(const B, E : TBcd) : TBcd;
1981     begin
1982     if E[0] = 0 then
1983     {anything raised to the zero power is 1.0}
1984     Result := FastVal('1.0')
1985    
1986     else if IsIntBcd(E) then
1987     {compute the power by simple multiplication}
1988     Result := IntPowBcd(B, TruncBcd(E))
1989    
1990     else begin
1991     if B[0] and SignBit <> 0 then
1992     {negative number raised to a non-integer power}
1993     RaiseBcdError(stscBcdBadInput);
1994    
1995     Result := ExpBcd(MulBcd(E, LnBcd(B)));
1996     end;
1997     end;
1998    
1999     function RoundBcd(const B : TBcd) : LongInt;
2000     var
2001     Exponent, I : Integer;
2002     Sign : Byte;
2003     UB : TUnpBcd;
2004     begin
2005     Unpack(B, UB, Exponent, Sign);
2006    
2007     Result := 0;
2008     if Exponent <> 0 then begin
2009     {Bcd is not zero}
2010     I := MantissaDigits;
2011     {add digits to left of decimal point}
2012     while (I >= 1) and (Exponent > ExpBias) do begin
2013     if Abs(Result) > MaxLongInt div 10 then
2014     {numeric overflow}
2015     RaiseBcdError(stscBcdOverflow);
2016     Result := 10*Result;
2017     if Sign <> 0 then begin
2018     if Result < -MaxLongInt-1+UB[I] then
2019     {numeric overflow}
2020     RaiseBcdError(stscBcdOverflow);
2021     dec(Result, UB[I]);
2022     end else begin
2023     if Result > MaxLongInt-UB[I] then
2024     {numeric overflow}
2025     RaiseBcdError(stscBcdOverflow);
2026     inc(Result, UB[I]);
2027     end;
2028     dec(I);
2029     dec(Exponent);
2030     end;
2031    
2032     {round last digit}
2033     if (I >= 1) and (Exponent = ExpBias) and (UB[I] >= 5) then begin
2034     if Sign <> 0 then begin
2035     if Result = -MaxLongInt-1 then
2036     {numeric overflow}
2037     RaiseBcdError(stscBcdOverflow);
2038     dec(Result);
2039     end else begin
2040     if Result = MaxLongInt then
2041     {numeric overflow}
2042     RaiseBcdError(stscBcdOverflow);
2043     inc(Result);
2044     end;
2045     end;
2046    
2047     end;
2048     end;
2049    
2050     function RoundDigitsBcd(const B : TBcd; Digits : Cardinal) : TBcd;
2051     var
2052     Exponent : Integer;
2053     Sign : Byte;
2054     UB : TUnpBcd;
2055     begin
2056     if B[0] = 0 then
2057     {input is zero}
2058     SetZero(Result)
2059    
2060     else if Digits >= MantissaDigits then
2061     {no actual rounding}
2062     Result := B
2063    
2064     else begin
2065     Unpack(B, UB, Exponent, Sign);
2066    
2067     {treat 0 digits same as 1}
2068     if Digits = 0 then
2069     Digits := 1;
2070    
2071     RoundMantissa(UB, MantissaDigits-Digits);
2072     if UB[SigDigits] <> 0 then begin
2073     ShiftMantissaDown(UB, 1);
2074     inc(Exponent);
2075     end else if IsZeroMantissa(UB) then
2076     Exponent := 0;
2077    
2078     Pack(UB, Exponent, Sign, Result);
2079     end;
2080     end;
2081    
2082     function RoundPlacesBcd(const B : TBcd; Places : Cardinal) : TBcd;
2083     var
2084     Exponent, ActPlaces : Integer;
2085     Sign : Byte;
2086     UB : TUnpBcd;
2087     begin
2088     if B[0] = 0 then
2089     {input is zero}
2090     SetZero(Result)
2091    
2092     else begin
2093     ActPlaces := Integer(MantissaDigits)-(B[0] and NoSignBit)+ExpBias;
2094    
2095     if LongInt(Places) >= ActPlaces then
2096     {no actual rounding}
2097     Result := B
2098    
2099     else begin
2100     Unpack(B, UB, Exponent, Sign);
2101    
2102     RoundMantissa(UB, ActPlaces-LongInt(Places));
2103     if UB[SigDigits] <> 0 then begin
2104     ShiftMantissaDown(UB, 1);
2105     inc(Exponent);
2106     end else if IsZeroMantissa(UB) then
2107     Exponent := 0;
2108    
2109     Pack(UB, Exponent, Sign, Result);
2110     end;
2111     end;
2112     end;
2113    
2114     function SqrtBcd(const B : TBcd) : TBcd;
2115     var
2116     Exponent, I, Iterations : Integer;
2117     BN, B05 : TBcd;
2118     begin
2119     if B[0] and SignBit <> 0 then
2120     {square root of a negative number}
2121     RaiseBcdError(stscBcdBadInput);
2122    
2123     if B[0] = 0 then begin
2124     {done for input of zero}
2125     SetZero(Result);
2126     Exit;
2127     end;
2128    
2129     {normalize input}
2130     Exponent := B[0]-ExpBias;
2131     BN := B;
2132     BN[0] := ExpBias;
2133    
2134     {create reused constant bcd}
2135     B05 := FastVal('0.5');
2136    
2137     {compute initial approximation of sqrt}
2138     Result := AddBcd(MulBcd(FastVal('0.894470'), BN),
2139     FastVal('0.223607'));
2140    
2141     if BcdSize <= 10 then
2142     Iterations := 3
2143     else
2144     Iterations := 5;
2145    
2146     {iterate to accurate normalized sqrt, Result = 0.5*((BN/Result)+Result)}
2147     for I := 1 to Iterations do
2148     Result := MulBcd(AddBcd(DivBcd(BN, Result), Result), B05);
2149    
2150     {final correction Result = (0.5*(BN/Result-Result))+Result}
2151     Result := AddBcd(MulBcd(SubBcd(DivBcd(BN, Result), Result), B05), Result);
2152    
2153     if Odd(Exponent) then begin
2154     Result := MulBcd(Result,
2155     FastVal('0.31622776601683793319988935444327185337')); {Sqrt(0.1)}
2156     inc(Exponent);
2157     end;
2158    
2159     inc(Result[0], Exponent shr 1);
2160     end;
2161    
2162     function StrBcd(const B : TBcd; Width, Places : Cardinal) : string;
2163     var
2164     I, O, Exponent, ActWidth, Digits, DecimalPos : Integer;
2165     Sign : Byte;
2166     UB : TUnpBcd;
2167    
2168     procedure AddChar(Ch : Char);
2169     begin
2170     Result[O] := Ch;
2171     inc(O);
2172     end;
2173    
2174     begin
2175     Unpack(B, UB, Exponent, Sign);
2176    
2177     if Exponent = 0 then begin
2178     {ensure mantissa is set to zero}
2179     FillChar(UB[1], SigDigits, 0);
2180     {fool the rest of the function}
2181     Exponent := ExpBias+1;
2182     end;
2183    
2184     {ActWidth is the non-padded width}
2185     {it has at least one digit before decimal point}
2186     ActWidth := 1;
2187     if Exponent > ExpBias+1 then
2188     {add other digits before decimal point}
2189     inc(ActWidth, Exponent-ExpBias-1);
2190    
2191     {add digits after decimal point}
2192     inc(ActWidth, Places);
2193    
2194     {see how many digits from mantissa to use}
2195     if Exponent < ExpBias+1 then begin
2196     Digits := LongInt(Places)-(ExpBias-Exponent);
2197     if Digits < 0 then
2198     Digits := 0;
2199     end else
2200     Digits := ActWidth;
2201    
2202     if Places <> 0 then
2203     {add one for decimal point}
2204     inc(ActWidth);
2205    
2206     if Sign <> 0 then
2207     {add one for minus sign}
2208     inc(ActWidth);
2209    
2210     if Digits < MantissaDigits then begin
2211     {need to round}
2212     RoundMantissa(UB, MantissaDigits-Digits);
2213     if UB[SigDigits] <> 0 then begin
2214     ShiftMantissaDown(UB, 1);
2215     inc(Exponent);
2216     inc(Digits);
2217     if Exponent > ExpBias+1 then
2218     inc(ActWidth);
2219     end;
2220     end else
2221     {use all mantissa digits}
2222     Digits := MantissaDigits;
2223    
2224     {adjust and limit Width}
2225     if Width = 0 then
2226     Width := ActWidth;
2227     {$IFDEF WStrings}
2228     if Width > 255 then
2229     Width := 255;
2230     {$ENDIF}
2231     SetLength(Result, Width);
2232    
2233     if LongInt(Width) < ActWidth then begin
2234     {result won't fit in specified width}
2235     Result := StringOfChar(OverflowChar, Length(Result)); //FillChar(Result[1], Length(Result) * SizeOf(Char), OverflowChar);
2236     Exit;
2237     end;
2238    
2239     if LongInt(Width) > ActWidth then begin
2240     {store leading spaces}
2241     StrPCopy(PChar(Result), StringOfChar(' ', LongInt(Width)-ActWidth)); //FillChar(Result[1], LongInt(Width)-ActWidth, ' ');
2242     O := LongInt(Width)-ActWidth+1;
2243     end else
2244     O := 1;
2245    
2246     if Sign <> 0 then
2247     AddChar('-');
2248    
2249     if Exponent < ExpBias+1 then begin
2250     {number is less than 1}
2251     AddChar('0');
2252     if Exponent <> 0 then begin
2253     AddChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator);
2254     for I := 1 to ExpBias-Exponent do
2255     if O <= LongInt(Width) then
2256     AddChar('0');
2257     end;
2258     end;
2259    
2260     if Places = 0 then
2261     {no decimal point}
2262     DecimalPos := 0
2263     else
2264     DecimalPos := Width-Places;
2265    
2266     {add digits from the mantissa}
2267     if Digits <> 0 then begin
2268     I := SigDigits;
2269     if UB[I] = 0 then
2270     dec(I);
2271     while (Digits > 0) and (O <= LongInt(Width)) do begin
2272     if O = DecimalPos then
2273     AddChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator);
2274     AddChar(Char(UB[I]+Byte('0')));
2275     dec(I);
2276     dec(Digits);
2277     end;
2278     end;
2279    
2280     {add trailing zeros, if any}
2281     while O <= LongInt(Width) do begin
2282     if O = DecimalPos then
2283     AddChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator);
2284     if O <= LongInt(Width) then
2285     AddChar('0');
2286     end;
2287     end;
2288    
2289     function StrExpBcd(const B : TBcd; Width : Cardinal) : string;
2290     const
2291     MinWidth = 8;
2292     MaxWidth = MantissaDigits+6;
2293     var
2294     I, O, Exponent : Integer;
2295     Sign : Byte;
2296     UB : TUnpBcd;
2297    
2298     procedure AddChar(Ch : Char);
2299     begin
2300     Result[O] := Ch;
2301     inc(O);
2302     end;
2303    
2304     begin
2305     Unpack(B, UB, Exponent, Sign);
2306    
2307     {validate and adjust Width}
2308     if Width = 0 then
2309     Width := MaxWidth
2310     else if Width < MinWidth then
2311     Width := MinWidth;
2312     {$IFDEF WStrings}
2313     if Width > 255 then
2314     Width := 255;
2315     {$ENDIF}
2316     SetLength(Result, Width);
2317    
2318     {store leading spaces}
2319     if Width > MaxWidth then begin
2320     StrPCopy(PChar(Result), StringOfChar(' ', Width-MaxWidth)); //FillChar(Result[1], Width-MaxWidth, ' ');
2321     O := Width-MaxWidth+1;
2322     end else
2323     O := 1;
2324    
2325     {store sign}
2326     if Sign <> 0 then
2327     AddChar('-')
2328     else
2329     AddChar(' ');
2330    
2331     if Exponent = 0 then begin
2332     {ensure mantissa is set to zero}
2333     FillChar(UB[1], SigDigits, 0);
2334     {force Exponent to display as 0}
2335     Exponent := ExpBias+1;
2336    
2337     end else if Width < MaxWidth then begin
2338     {need to round}
2339     RoundMantissa(UB, MaxWidth-Width);
2340     if UB[SigDigits] <> 0 then begin
2341     ShiftMantissaDown(UB, 1);
2342     inc(Exponent);
2343     end;
2344     end;
2345    
2346     {copy mantissa to string}
2347     I := MantissaDigits;
2348     AddChar(Char(UB[I]+Byte('0')));
2349     dec(I);
2350     AddChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator);
2351     while O < LongInt(Width-3) do begin
2352     AddChar(Char(UB[I]+Byte('0')));
2353     dec(I);
2354     end;
2355    
2356     {store exponent}
2357     AddChar('E');
2358     if Exponent < ExpBias+1 then begin
2359     AddChar('-');
2360     Exponent := ExpBias+1-Exponent;
2361     end else begin
2362     AddChar('+');
2363     dec(Exponent, ExpBias+1);
2364     end;
2365     AddChar(Char((Exponent div 10)+Byte('0')));
2366     AddChar(Char((Exponent mod 10)+Byte('0')));
2367     end;
2368    
2369     function SubBcd(const B1, B2 : TBcd) : TBcd;
2370     begin
2371     Result := AddBcd(B1, NegBcd(B2));
2372     end;
2373    
2374     function TruncBcd(const B : TBcd) : LongInt;
2375     var
2376     Exponent, I : Integer;
2377     Sign : Byte;
2378     UB : TUnpBcd;
2379     begin
2380     Unpack(B, UB, Exponent, Sign);
2381    
2382     Result := 0;
2383     if Exponent <> 0 then begin
2384     {Bcd is not zero}
2385     I := MantissaDigits;
2386     {Add digits to left of decimal point}
2387     while (I >= 1) and (Exponent > ExpBias) do begin
2388     if Abs(Result) > MaxLongInt div 10 then
2389     {numeric overflow}
2390     RaiseBcdError(stscBcdOverflow);
2391     Result := 10*Result;
2392     if Sign <> 0 then begin
2393     if Result < -MaxLongInt-1+UB[I] then
2394     {numeric overflow}
2395     RaiseBcdError(stscBcdOverflow);
2396     dec(Result, UB[I]);
2397     end else begin
2398     if Result > MaxLongInt-UB[I] then
2399     {numeric overflow}
2400     RaiseBcdError(stscBcdOverflow);
2401     inc(Result, UB[I]);
2402     end;
2403    
2404     dec(I);
2405     dec(Exponent);
2406     end;
2407     end;
2408     end;
2409    
2410     function ValBcd(const S : string) : TBcd;
2411     var
2412     I, O, Digits, Exponent : Integer;
2413     Sign : Byte;
2414     ExpSigned, Rounded : Boolean;
2415     UB : TUnpBcd;
2416    
2417     function SChar(I : Integer) : Char;
2418     begin
2419     if I > Length(S) then
2420     Result := #0
2421     else
2422     Result := S[I];
2423     end;
2424    
2425     function IsDigit(Ch : Char) : Boolean;
2426     begin
2427     Result := (Ch >= '0') and (Ch <= '9');
2428     end;
2429    
2430     procedure AddDigit(Ch : Char);
2431     begin
2432     if O > 0 then begin
2433     UB[O] := Byte(Ch)-Byte('0');
2434     dec(O);
2435     end else if not Rounded then begin
2436     {got more significant digits than will fit, must round}
2437     Rounded := True;
2438     UB[0] := Byte(Ch)-Byte('0');
2439     RoundMantissa(UB, 0);
2440     if UB[SigDigits] <> 0 then begin
2441     ShiftMantissaDown(UB, 1);
2442     inc(Digits);
2443     end;
2444     end;
2445     end;
2446    
2447     begin
2448     FillChar(UB, SizeOf(TUnpBcd), 0);
2449    
2450     I := 1; {input position}
2451     O := MantissaDigits; {output position}
2452     Exponent := 0;
2453     Sign := 0;
2454     Rounded := False;
2455    
2456     {digits before dot, or negative digits after dot in case of 0.0000n}
2457     Digits := 0;
2458    
2459     {skip leading spaces}
2460     while SChar(I) = ' ' do
2461     inc(I);
2462    
2463     {get sign if any}
2464     case SChar(I) of
2465     '+' :
2466     {skip +}
2467     inc(I);
2468     '-' :
2469     begin
2470     {negative number}
2471     Sign := SignBit;
2472     inc(I);
2473     end;
2474     end;
2475    
2476     {handle first digit}
2477     if SChar(I) <> {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator then begin
2478     if not IsDigit(SChar(I)) then
2479     RaiseBcdError(stscBcdBadFormat);
2480    
2481     {skip leading zeros}
2482     while SChar(I) = '0' do
2483     inc(I);
2484    
2485     {add significant digits}
2486     while IsDigit(SChar(I)) do begin
2487     AddDigit(SChar(I));
2488     inc(I);
2489     inc(Digits);
2490     end;
2491     end;
2492    
2493     {handle dot}
2494     if SChar(I) = {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator then begin
2495     inc(I);
2496     if Digits = 0 then begin
2497     {no digits before dot, skip zeros after dot}
2498     while SChar(I) = '0' do begin
2499     inc(I);
2500     dec(Digits);
2501     end;
2502     end;
2503    
2504     {add significant digits}
2505     while IsDigit(SChar(I)) do begin
2506     AddDigit(SChar(I));
2507     inc(I);
2508     end;
2509     end;
2510    
2511     {handle exponent}
2512     case SChar(I) of
2513     'e', 'E' :
2514     begin
2515     inc(I);
2516     ExpSigned := False;
2517     case SChar(I) of
2518     '+' :
2519     {skip +}
2520     inc(I);
2521     '-' :
2522     begin
2523     {negative exponent}
2524     ExpSigned := True;
2525     inc(I);
2526     end;
2527     end;
2528     if not IsDigit(SChar(I)) then
2529     {digit must follow 'e', invalid format}
2530     RaiseBcdError(stscBcdBadFormat);
2531    
2532     {collect exponent value}
2533     while IsDigit(SChar(I)) do begin
2534     Exponent := 10*Exponent+Byte(SChar(I))-Byte('0');
2535     inc(I);
2536     end;
2537    
2538     if ExpSigned then
2539     Exponent := -Exponent;
2540     end;
2541     end;
2542    
2543     if SChar(I) <> #0 then
2544     {should be end of string, otherwise invalid format}
2545     RaiseBcdError(stscBcdBadFormat);
2546    
2547     {compute final exponent}
2548     Inc(Exponent, Digits+ExpBias);
2549    
2550     if Exponent > NoSignBit then
2551     {numeric overflow}
2552     RaiseBcdError(stscBcdOverflow);
2553    
2554     if (Exponent <= 0) or IsZeroMantissa(UB) then
2555     {return zero}
2556     Exponent := 0;
2557    
2558     {Return packed result}
2559     Pack(UB, Exponent, Sign, Result);
2560     end;
2561    
2562     function FloatFormBcd(const Mask : string; B : TBCD;
2563     const LtCurr, RtCurr : string;
2564     Sep, DecPt : Char) : string;
2565     {-Returns a formatted string with digits from B merged into the Mask}
2566     const
2567     Blank = 0;
2568     Asterisk = 1;
2569     Zero = 2;
2570     const
2571     FormChars : string = '#@*$-+,.';
2572     PlusArray : array[Boolean] of Char = ('+', '-');
2573     MinusArray : array[Boolean] of Char = (' ', '-');
2574     FillArray : array[Blank..Zero] of Char = (' ', '*', '0');
2575     var
2576     ExpB : Byte absolute B; {B's sign/exponent byte}
2577     S : string; {temporary string}
2578     Filler : integer; {char for unused digit slots: ' ', '*', '0'}
2579     WontFit, {true if number won't fit in the mask}
2580     AddMinus, {true if minus sign needs to be added}
2581     Dollar, {true if floating dollar sign is desired}
2582     Negative : Boolean; {true if B is negative}
2583     StartF, {starting point of the numeric field}
2584     EndF : Word; {end of numeric field}
2585     RtChars, {# of chars to add to right}
2586     LtChars, {# of chars to add to left}
2587     DotPos, {position of '.' in Mask}
2588     Digits, {total # of digits}
2589     Places, {# of digits after the '.'}
2590     Blanks, {# of blanks returned by StrBcd}
2591     FirstDigit, {pos. of first digit returned by Str}
2592     Extras, {# of extra digits needed for special cases}
2593     DigitPtr : Byte; {pointer into temporary string of digits}
2594     I : Word;
2595     label
2596     EndFound,
2597     RedoCase,
2598     Done;
2599     begin
2600     Result := Mask;
2601    
2602     RtChars := 0;
2603     LtChars := 0;
2604    
2605     {check for empty string}
2606     if Length(Mask) = 0 then
2607     goto Done;
2608    
2609     {initialize variables}
2610     Filler := Blank;
2611     DotPos := 0;
2612     Places := 0;
2613     Digits := 0;
2614     Dollar := False;
2615     AddMinus := True;
2616     StartF := 1;
2617    
2618     {store the sign of the real and make it positive}
2619     Negative := (ExpB and $80) <> 0;
2620     ExpB := ExpB and $7F;
2621    
2622     {strip and count c's}
2623     for I := Length(Result) downto 1 do begin
2624     if Result[I] = 'C' then begin
2625     Inc(RtChars);
2626     System.Delete(Result, I, 1);
2627     end else if Result[I] = 'c' then begin
2628     Inc(LtChars);
2629     System.Delete(Result, I, 1);
2630     end;
2631     end;
2632    
2633     {find the starting point for the field}
2634     while (StartF <= Length(Result)) and
2635     not CharExistsL(FormChars, Result[StartF]) do
2636     Inc(StartF);
2637     if StartF > Length(Mask) then
2638     goto Done;
2639    
2640     {find the end point for the field}
2641     EndF := StartF;
2642     for I := StartF to Length(Result) do
2643     begin
2644     case Result[I] of
2645     '*' : Filler := Asterisk;
2646     '@' : Filler := Zero;
2647     '$' : Dollar := True;
2648     '-',
2649     '+' : AddMinus := False;
2650     '#' : {ignore} ;
2651     ',',
2652     '.' : DotPos := I;
2653     else
2654     goto EndFound;
2655     end;
2656     Inc(EndF);
2657     end;
2658    
2659     {if we get here at all, the last char was part of the field}
2660     Inc(EndF);
2661    
2662     EndFound:
2663     {if we jumped to here instead, it wasn't}
2664     Dec(EndF);
2665    
2666     {disallow Dollar if Filler is Zero}
2667     if Filler = Zero then
2668     Dollar := False;
2669    
2670     {we need an extra slot if Dollar is True}
2671     Extras := Ord(Dollar);
2672    
2673     {get total # of digits and # after the decimal point}
2674     if EndF > Length(Result) then {!!.02}
2675     EndF := Length(Result); {!!.02}
2676    
2677     for I := StartF to EndF do
2678     case Result[I] of
2679     '#', '@',
2680     '*', '$' :
2681     begin
2682     Inc(Digits);
2683     if (I > DotPos) and (DotPos <> 0) then
2684     Inc(Places);
2685     end;
2686     end;
2687    
2688     {need one more 'digit' if Places > 0}
2689     Inc(Digits, Ord(Places > 0));
2690    
2691     {also need an extra blank if (1) Negative is true, and (2) Filler is Blank,
2692     and (3) AddMinus is true}
2693     if Negative and AddMinus and (Filler = Blank) then
2694     Inc(Extras)
2695     else
2696     AddMinus := False;
2697    
2698     {translate the BCD to a string}
2699     S := StrBCD(B, Digits, Places);
2700    
2701    
2702     {count number of initial blanks}
2703     Blanks := 1;
2704     while S[Blanks] = ' ' do
2705     Inc(Blanks);
2706     FirstDigit := Blanks;
2707     Dec(Blanks);
2708    
2709     {the number won't fit if (a) S is longer than Digits or (b) the number of
2710     initial blanks is less than Extras}
2711     WontFit := (Length(S) > Digits) or (Blanks < Extras);
2712    
2713     {if it won't fit, fill decimal slots with '*'}
2714     if WontFit then begin
2715     for I := StartF to EndF do
2716     case Result[I] of
2717     '#', '@', '*', '$' : Result[I] := '*';
2718     '+' : Result[I] := PlusArray[Negative];
2719     '-' : Result[I] := MinusArray[Negative];
2720     end;
2721     goto Done;
2722     end;
2723    
2724     {fill initial blanks in S with Filler; insert floating dollar sign}
2725     if Blanks > 0 then begin
2726     StrPCopy(PChar(S), StringOfChar(FillArray[Filler], Blanks)); // FillChar(S[1], Blanks, FillArray[Filler]);
2727    
2728     {put floating dollar sign in last blank slot if necessary}
2729     if Dollar then begin
2730     S[Blanks] := LtCurr[1];
2731     Dec(Blanks);
2732     end;
2733    
2734     {insert a minus sign if necessary}
2735     if AddMinus then
2736     S[Blanks] := '-';
2737     end;
2738    
2739     {put in the digits / signs}
2740     DigitPtr := Length(S);
2741     for I := EndF downto StartF do begin
2742     RedoCase:
2743     case Result[I] of
2744     '#', '@', '*', '$' :
2745     if DigitPtr <> 0 then begin
2746     Result[I] := S[DigitPtr];
2747     Dec(DigitPtr);
2748     if (DigitPtr <> 0) and (S[DigitPtr] = '.') then {!!.02}
2749     // if (S[DigitPtr] = '.') and (DigitPtr <> 0) then
2750     Dec(DigitPtr);
2751     end
2752     else
2753     Result[I] := FillArray[Filler];
2754     ',' : begin
2755     Result[I] := Sep;
2756     if (I < DotPos) and (DigitPtr < FirstDigit) then begin
2757     Result[I] := '#';
2758     goto RedoCase;
2759     end;
2760     end;
2761     '.' : begin
2762     Result[I] := DecPt;
2763     if (I < DotPos) and (DigitPtr < FirstDigit) then begin
2764     Result[I] := '#';
2765     goto RedoCase;
2766     end;
2767     end;
2768     '+' : Result[I] := PlusArray[Negative];
2769     '-' : Result[I] := MinusArray[Negative];
2770     end;
2771     end;
2772    
2773     Done:
2774     if RtChars > 0 then begin
2775     S := RtCurr;
2776     if Length(S) > RtChars then
2777     SetLength(S, RtChars)
2778     else
2779     S := LeftPadL(S, RtChars);
2780     Result := Result + S;
2781     end;
2782    
2783     if LtChars > 0 then begin
2784     S := LtCurr;
2785     if Length(S) > LtChars then
2786     SetLength(S, LtChars)
2787     else
2788     S := PadL(S, LtChars);
2789     Result := S + Result;
2790     end;
2791    
2792     end;
2793    
2794     {routines to support C++Builder}
2795     {$IFDEF CBuilder}
2796     procedure AddBcd_C(const B1, B2 : TBcd; var Res : TBcd);
2797     begin
2798     Res := AddBcd(B1, B2);
2799     end;
2800    
2801     procedure SubBcd_C(const B1, B2 : TBcd; var Res : TBcd);
2802     begin
2803     Res := SubBcd(B1, B2);
2804     end;
2805    
2806     procedure MulBcd_C(const B1, B2 : TBcd; var Res : TBcd);
2807     begin
2808     Res := MulBcd(B1, B2);
2809     end;
2810    
2811     procedure DivBcd_C(const B1, B2 : TBcd; var Res : TBcd);
2812     begin
2813     Res := DivBcd(B1, B2);
2814     end;
2815    
2816     procedure ModBcd_C(const B1, B2 : TBcd; var Res : TBcd);
2817     begin
2818     Res := ModBcd(B1, B2);
2819     end;
2820    
2821     procedure NegBcd_C(const B : TBcd; var Res : TBcd);
2822     begin
2823     Res := NegBcd(B);
2824     end;
2825    
2826     procedure AbsBcd_C(const B : TBcd; var Res : TBcd);
2827     begin
2828     Res := AbsBcd(B);
2829     end;
2830    
2831     procedure FracBcd_C(const B : TBcd; var Res : TBcd);
2832     begin
2833     Res := FracBcd(B);
2834     end;
2835    
2836     procedure IntBcd_C(const B : TBcd; var Res : TBcd);
2837     begin
2838     Res := IntBcd(B);
2839     end;
2840    
2841     procedure RoundDigitsBcd_C(const B : TBcd; Digits : Cardinal; var Res : TBcd);
2842     begin
2843     Res := RoundDigitsBcd(B, Digits);
2844     end;
2845    
2846     procedure RoundPlacesBcd_C(const B : TBcd; Places : Cardinal; var Res : TBcd);
2847     begin
2848     Res := RoundPlacesBcd(B, Places);
2849     end;
2850    
2851     procedure ValBcd_C(const S : string; var Res : TBcd);
2852     begin
2853     Res := ValBcd(S);
2854     end;
2855    
2856     procedure LongBcd_C(L : LongInt; var Res : TBcd);
2857     begin
2858     Res := LongBcd(L);
2859     end;
2860    
2861     procedure ExtBcd_C(E : Extended; var Res : TBcd);
2862     begin
2863     Res := ExtBcd(E);
2864     end;
2865    
2866     procedure ExpBcd_C(const B : TBcd; var Res : TBcd);
2867     begin
2868     Res := ExpBcd(B);
2869     end;
2870    
2871     procedure LnBcd_C(const B : TBcd; var Res : TBcd);
2872     begin
2873     Res := LnBcd(B);
2874     end;
2875    
2876     procedure IntPowBcd_C(const B : TBcd; E : LongInt; var Res : TBcd);
2877     begin
2878     Res := IntPowBcd(B, E);
2879     end;
2880    
2881     procedure PowBcd_C(const B, E : TBcd; var Res : TBcd);
2882     begin
2883     Res := PowBcd(B, E);
2884     end;
2885    
2886     procedure SqrtBcd_C(const B : TBcd; var Res : TBcd);
2887     begin
2888     Res := SqrtBcd(B);
2889     end;
2890     {$ENDIF}
2891    
2892     initialization
2893     ZeroBcd := FastVal('0.0');
2894     MinBcd := ValBcd('-9'+{$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator+'9E+63');
2895     BadBcd := MinBcd;
2896     MaxBcd := ValBcd('9'+{$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator+'9E+63');
2897     PiBcd := FastVal('3.1415926535897932384626433832795028841971');
2898     Ln10Bcd := FastVal('2.3025850929940456840179914546843642076011');
2899     eBcd := FastVal('2.7182818284590452353602874713526624977572');
2900     end.

  ViewVC Help
Powered by ViewVC 1.1.20