zoukankan      html  css  js  c++  java
  • bcd

    Delphi/Kylix Math Info

    AmazonTechnical.gif (2495 bytes)  in   look for 

    Mathematics
    Delphi


    Contents


    A. Delphi/Kylix Math Unit

    Question Answer
    A-1. Where is the Delphi Math unit? The math unit is included in all versions of Delphi 4/5/6 and Kylix. The Delphi Math unit is available only with the Professional or Client/Server versions of Delphi 3 -- it is not available with the "Standard" version. It is also available with the Developer version of Delphi 2 and with the Client/Server versions of Delphi 1 or 2. You'll find the source code unit in directory ..\source\rtl\sys\math.pas.
    A-2.  What's new in the Delphi/Kylix  Math unit?
    D6 The D6 math unit has everything listed next under Kylix, plus
    • a SimpleRoundTo function.  
    • VarCmplx unit defines a number of complex math functions (find the source in ..\Delphi6\Source\Rtl\Common):

    General:  VarComplexCreate (with overloads), VarComplex, VarIsComplex, VarAsComplex, VarComplexSimplify, VarComplexAbsSqr, VarComplexAbs, VarComplexAngle, VarComplexConjugate, VarComplexInverse, VarComplexExp, VarComplexLn, VarComplexSqr, VarComplexSqrt, VarComplexTimesPosI, VarComplexTimesNegI, VarComplexPower

    Trig/Hyperbolic:  VarComplexCos, VarComplexSin, VarComplexTan, VarComplexCot, VarComplexSec, VarComplexCsc, VarComplexArcCos, VarComplexArcSin, VarComplexArcTan, VarComplexArcCot, VarComplexArcSec, VarComplexArcCsc, VarComplexCosH, VarComplexSinH, VarComplexTanH, VarComplexCotH, VarComplexSecH, VarComplexCscH, VarComplexArcCosH, VarComplexArcSinH, VarComplexArcTanH, VarComplexArcCotH, VarComplexArcSecH,  VarComplexArcCscH

    Conversion:  VarComplexToPolar, VarComplexFromPolar

    Variables:  ComplexNumberSymbol, ComplexNumberSymbolBeforeImaginary

    • FMTBcd  unit defines a umber of binary-coded decimal (BCD) routines (find the source in ..\Delphi6\Source\Vcl):

    Types:   PBcd, TBcd
    Const:  NullBcd
    Exceptions:  EBcdException, EBcdOverflowException

    Utility:  BcdPrecision, BcdScale, IsBcdNegative

    Arithmetic:  BcdAdd, BcdSubtract, NormalizeBcd, BcdMultiply (8 overloads)

    Creation:  VarFMTBcdCreate (5 overloads), VarIsFMTBcd, VarFMTBcd

    Conversions:  StrToBcd, TryStrToBcd, DoubleToBcd, DoubleToBcd, IntegerToBcd, VarToBcd, CurrToBCD, BcdToStr, BcdToDouble, BcdToInteger, BCDToCurr, BcdToStrF, FormatBcd, BcdCompare 

    In addition, these minor changes were made to the D6 math unit:

    • A FLD1 assembly statement was added to the Secant and Cosecant functions just prior to the FDIVRP statement.
    • In Kylix, the math unit defined TValueRelationship, LessThanValue, EqualsValue and GreaterThanValue.  This type and constants were moved to the Types unit in D6.
    • The EnsureRange overloads (Integer, Int64, Double) all had the statement "assert (AMin <= aMax);" that was not present in the Kylix code. 
    • In Kylix, the SumInt, Sum, and SumOfSquares functions had a section that was conditionally compiled IFDEF PIC.  These sections were Delphi code and were dropped.  The ELSE section from Kylix, which was in assembly language, was all that was present in D6.
    • The GNU license statement was present in the Kylix math unit but was removed in D6.
    • Several cosmetic changes were made to align code and wrap comments in D6 compared to the Kylix version.  Some dead code (namely the AnnuityF function that was commented out in Kylix) was dropped in D6.
    Kylix The  Kylix math unit has everything below in A-3, plus the following:

    Constants for NaN (not-a-number), Infinity, NegInfinity
    Trig: Secant or Sec, Cosecant or Csc, Cot, ArcSec, ArcCsc, ArcCot, 
    Angles:  DegToGrad, DegToCycle, GradToDeg, GradToCycle, CycleToDeg, CycleToGrad
    Hyperbolic: CotH, SecH, CscH, ArcCotH, ArcSecH, ArcCscH

    Miscellaneous:  

    IsNan, IsInfinite, Sign overloads, CompareValue overloads, SameValue overloads, IsZero overlaods, IfThen overloads, InRange overloads, EnsureRange overloads, DivMod, RoundTo, GetRoundMode, SetRoundMode, GetPrecisionMode, SetPrecisionMode, GetExceptionMask, SetExceptionMask, ClearExceptions

    Type:  TValueSign, TValueRelationship, TRoundToRange, TFPURoundingRange, TFPUException, TFPUExceptionMask

    Const:  NegativeValue, ZeroValue, PositiveValue, LessThanValue, EqualsValue, GreaterThanValue

    Statistical: RandomRange, RandomFrom overloads

    D5 Only the copyright date was changed in D5.  There are no changes of any kind in the D5 math unit compared to the D4 math unit.
    D4
    • Overloaded Min(A,B) and Max(A,B) functions for types Integer, Int64, Single, Double, Extended.
    • Each of the functions Ceil, Floor and Power has the construct Integer(Trunc(X)) instead of Trunc(X)
    D3 Open array functions MinIntValue, MaxIntValue, SumInt
    According to Borland, "Some Math unit financial functions [were] corrected."
    A-3. What functions are in the Delphi 32 (i.e., Delphi 2 - 4) Math unit?

    (Note: [n] indicates function was new in Delphi n)
    Min and Max constants for Single, Double, Extended, Comp types
    Trig: ArcCos, ArcSin, ArcTan2, SinCos, Tan, CoTan, Hypot
    Angles: DegToRad, RadToDeg, GradToRad, RadToGrad, CycleToRad, RadToCycle
    Hyperbolic: Cosh, Sinh, Tanh, ArcCosh, ArcSinh, ArcTanh
    Logarithm: LnXP1, Log10, Log2, LogN
    Exponential: IntPower, Power
    Miscellaneous: Frexp, Ldexp, Ceil, Floor, Poly, EInvalidArgument type
    Statistical: Mean, Sum, SumInt [3], SumOfSquares, SumsAndSquares, MinValue, MinIntValue [3], Min overloads [4], MaxValue, MaxIntValue [3], Max  overloads[4], StdDev, MeanAndStdDev, PopnStdDev, Variance, PopnVariance, TotalVariance, Norm, MomentSkewKurtosis, RandG
    Financial: TPaymentTIme type, DoubleDecliningBalance, FutureValue, InterestPayment, InterestRate, InternalRateOfReturn, NumberOfPeriods, NetPresentValue, Payment, PeriodPayment, PresentValue, SLNDepreciation, SYDDepreciation

    Note:
    The function definitions for each of these functions may be found in the Delphi Math Functions Pages.

    Chapter 9, "The Shadowy Math Unit" in Kick Ass Delphi Programming

    A-4.  Where can I find other Delphi/ Pascal math function libraries? Delphi Math Functions Pages
    Source of Numerical Analysis Code in Pascal
    Jean Debord's TPMath page
    ESB Consultancy's ESBMaths
    Razor's Edge Software MathX
    SDL's (Software Development Lohninger) Math1 and Math2

    B. Floating-Point Numbers, IEEE Math

    Question Answer
    B-1.  Overview Info What Every Computer Scientist Should Know About Floating-Point Arithmetic
    http://docs.sun.com/source/806-3568/ncg_goldberg.html 
    B-2. What are the Object Pascal numeric ordinal types?
    Type Delphi
    Version
    Windows Unit
    Type
    Min Value Max Value Signed Bytes
    ShortInt all   -128 127 Yes 1
    Byte all UCHAR 0 255 No 1
    SmallInt all SHORT -32768 32767 Yes 2
    Word all   0 65535 No 2
    LongWord 4-6 DWORD,
    UINT
    0 232 - 1 =
    4,294,967,295
    No 4
    LongInt all   -231 =
    -2,147,483,648
    231 - 1 =
    2,147,483,647
    Yes 4
    Int64
    4-6 LongLong
    TLargeInteger*
    LARGE_INTEGER*
    -263 263 - 1 Yes 8
    - 4-5 TULargeInteger
    ULARGE_INTEGER*
    0 264 - 1 No 8
    Integer
    (generic)
    1   -32768 32767 Yes 2
    2-6   -2,147,483,648 2,147,483,647 Yes 4
    Cardinal
    (generic)
    1   0 65535 No 2
    2-3   0 2,147,483,647 No 4
    4-6 ULONG 0 4,294,967,295 No 4

    Notes:

    • Use generic types whenever possible for better performance.
    • See "Comp" below in B-3 for an alternative to Int64 especially for D1-D3.
    • In general, arithmetic operations on integers return a value of type Integer -- which, in Delphi 2-5, is equivalent to the 32-bit LongInt. Operations in Delphi 4-5 return a value of type Int64 only when performed on an Int64 operand. So if I is an Integer and J is an Int64, use the statement J := Int64(I) + 1 for correct results.
    • An integer-type value can be explicitly converted to another integer type through typecasting.
    • Most standard routines that take integer arguments truncate Int64 values to 32 bits. However, the High, Low, Succ, Pred, Inc, Dec, IntToStr, and IntToHex routines fully support Int64 arguments. Also, the Round, Trunc, StrToInt64, and StrToInt64Def functions return Int64 values. A few routines -- including Ord -- cannot take Int64 values at all.
    • *Both Delphi 4 and 5 define a ULARGE_INTEGER variant record that can be viewed as two DWORDs (LowPart and HighPart), or a single LongLong QuadPart.  While a ULARGE_INTEGER can hold an unsigned 64-bit quantitity, there are no known Delphi functions for manipulating these quantities.   The LARGE_INTEGER variant record is just like the ULARGE_INTEGER definition except the HighPart is a LongInt (instead of a DWORD).   In Delphi 3 The TLargeInteger variant record was defined like LARGE_INTEGER in D4/D5.
    • CAUTION: There is at least one problem introduced somehow indirectly by the new Int64 support in Delphi 4. Example: Given variables A and B of type Byte or Word, with A := 40 and B := 45, the expression A - B is -5 as expected (as it has been in Delphi 1, 2 and 3), but (A-B) DIV 4 is 1,073,741,822 (slightly unexpected). There is no compiler warning about this possible consequence. Borland claims this is NOT a bug. In Delphi 4, if A and B are LongWords (32-bit unsigned values), the expression A - B is 4,294,967,291. IMHO, Borland should treat all unsigned quantities in a like way. [Note: See 7/12/98 post "D4 Arithmetic Bug or Feature when subtracting byte values?" to various Delphi newsgroups and replies for some additional details.]  This is fixed in D5:  A - B = -5, and (A - B) DIV 4 = -1, as expected.
    • See Ray Lischner's "Delphi 4 Integers:  The Long and the Short of It" in March/April 1999 Visual Developer, pp. 92-93.
    • Ray Lischner's UseNet Post with reasons why to use Int64 instead of Comp.  Baji Kimran's comment about Ray's reason #1:  "I think the reason for only 18 digits being correct is that the
      FPU has a float to BCD instruction that is used to convert to decimal, and it has a bug for 19 digits."
    • See Marc Palmer's UseNet Post about Int64 range checking problems
    • See Performance of large integer types.  In a UseNet posting, Baji Kimran says "in my experience, if the dividend is > 2^32, Int64 div and mod are pretty slow.  Then a comp / is considerably faster than an Int64 div.  You can even do a mod function on comps faster than int64 mod (if the dividend is >2^32).  If you have a mixture of arithmetic types in a program, the actual mix of operations
      determines whether comp or int64 is faster.  If there are many div or mod operations, comp is usually faster, since they are so slow on int64, > 2^32."

    Thanks to Roman Krejci for correcting an error in the above table about the generic integer in Delphi versions 2-3. (2 Aug 1998)

    B-3. What are the floating-point data types?
    Type Delphi
    Version
    Min Value Max Value Significant
    Digits
    Bytes
    Real
    (generic)
    1-3 2.9 x 10-39 1.7 x 1038 11-12 6
    4-6 5.0 x 10-324 1.7 x 10308 15-16 8
    Real48 4-6 2.9 x 10-39 1.7 x 1038 11-12 6
    Single all 1.5 x 10-45 3.4 x 1038 7-8 4
    Double all 5.0 x 10-324 1.7 x 10308 15-16 8
    Extended all 3.4 x 10-4932 1.1 x 104932 19-20 10
    Comp all -263 + 1 or -9.2 x 1018 263 - 1 or 9.2 x 1018 19-20 8
    Currency 2-6 -922,337,203,685,477.5808 922,337,203,685,477.5807 19-20 8

    Notes:

    • The generic type Real in Delphi 4-5 is equivalent to Double.
    • The 6-byte Real48 type was called Real in earlier versions of Object Pascal. If you are recompiling code that uses the older, 6-byte Real type, you may want to change it to Real48. You can also use the {$REALCOMPATIBILITY ON} compiler directive to turn Real back into the 6-byte type.
    • Real48 is maintained for backward compatibility. Since its storage format is not native to the Intel CPU family, it results in slower performance than other floating-point types.
    • Extended offers greater precision than other real types but is less portable. Be careful using Extended if you are creating data files to share across platforms.
    • The Comp (computational) type is native to the Intel CPU and represents a 64-bit integer. A Comp is classified as a real, however, it does not behave like an ordinal type. Comp is maintained for backward compatibility only. Use the Int64 type for better performance.
    • Currency is a fixed-point data type that minimizes rounding errors in monetary calculations. It is stored as a scaled 64-bit integer with the four least-significant digits implicitly representing decimal places. When mixed with other real types in assignments and expressions, Currency values are automatically divided or multiplied by 10000.
    • Ray Lischner's UseNet Post with reasons why to use Int64 instead of Comp
    • Tips and Tricks from Delphi in a NutShell:
      Double type:  pp. 184-186:  shows how to extract sign, exponent, mantissa;
      Extended type:  pp. 202-204:  shows how to extract sign, exponent, mantissa;
      Single type:  pp. 342-344:  shows how to extract sign, exponent, mantissa;
      Real48 type:  p. 309;
      Comp type:  p. 166;
      Currency type:  p. 173
    B-4. How can I learn more about floating-point numbers? See Borland's Tech Info 1027, An Overview of Floating Point Numbers,
    http://community.borland.com/article/0,1410,15855,00.html 
    (The math in the article is OK, but the programming examples are in C, unfortunately.)

    The article "Reviewing Delphi by the numbers" in the April 1998 Delphi Developer's Journal (pp. 7-11) is a good overview of ordinal and floating-point types in Delphi.

    B-5. What is IEEE floating point? IEEE-754 is a standard way to store floating point values on a variety of computers. The Single, Double and Extended data types are all stored in IEEE format. The older Real values are not stored in IEEE format.

    See efg's NaN Tech Note

    IEEE Standard 754 Floating Point Numbers
    www.research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html

    Formally Verifying IEEE Compliance of Floating-Point Hardware
    http://developer.intel.com/technology/itj/q11999/articles/art_5.htm

    A German description of IEEE-754, Gleitkommazahlen nach IEEE, is available from http://www.informatik.uni-halle.de/lehre/pascal/sprache/pas_ieee.html.

    Future 64-bit Intel Architecture:
    The Computation of Transcendental Functions on the IA-64 Architecture
    http://developer.intel.com/technology/itj/q41999/articles/art_5.htm

    IA-64 Floating-Point Operations and the IEEE Standard for Binary Floating-Point Arithmetic
    http://developer.intel.com/technology/itj/q41999/articles/art_6.htm

    John Herbster's T_BinaryFloatingPoint program for analyzing the extended, double, and single binary point numbers.

    IEEE standard 754 for binary floating-point arithmetic
    http://cch.loria.fr/documentation/IEEE754/index.html 

    B-6. How can I convert my old Real values to IEEE doubles? See Richard Biffl's BPREAL.C function and related files: BPReal.ZIP

    To convert Turbo Pascal 3.0 BCD reals (10-byte binary coded decimal reals with 18 significant digits) to Turbo Pascal 5.0 floating point numbers, download Turbo Pascal 5.5 from the Borland Community Museum:  http://community.borland.com/museum, and install it.  Look for BCD.PAS in the Turbo3 directory.

    B-7. How can I convert between Microsoft Binary and IEEE format?  Mac format?

    TI1431C, Converting between Microsoft Binary and IEEE format
    http://community.borland.com/article/0,1410,16431,00.html  

    Mark Di Val's Usenet Post showing Microsoft's conversion functions (in C/C++)

    Alex Grigny de Castro's UseNet Post show Mac number float format conversion
    Jason Welter's E-Mail instructing how to reverse doubles for Macs

    B-8. What is a NAN? How can I test for one? What is an INF value? How can I do arithmetic with NAN and INF values? In IEEE math a NAN is "not a number," i.e., an undefined value. INF is infinity and can be positive or negative.

    Sample of easy way to define NAN and INF values:
    procedure TForm1.ButtonSpecialClick(Sender: TObject);
      CONST
        Infinity = 1.0/0.0;
        NaN      = 0.0/0.0;
    begin
      // INF NAN
      ShowMessage(FloatToStr(Infinity) + ' ' + FloatToStr(NaN))
    end;

    TI1716, Testing for Not a Number (NaN)
    http://community.borland.com/article/0,1410,16716,00.html 

    Ray Lischner's math10.zip has some information about NANs and INFs but only compiles in Delphi 1.

    See IEEE754.TXT for a short Delphi 3 unit that defines NAN, PositiveInfinity, etc. and shows an example of how to use such values in expressions. (Also includes a DoubleToHex function to display doubles in logical hex format.)

    See efg's Exploring Numbers, Not-a-Number, and Infinity, Delphi Developer, October 1998, pp. 9-14

    B-9. What is IEEE rounding? efg's Set8087CW and SetRoundMode rounding example.  See Set8087CW for examples.

    The default IEEE rounding rule is to round to the nearest even integer. For example:
    ROUND(2.5) = 2, but
    ROUND(3.5) = 4

    This is also called "banker's rounding.

    Ray Lischner's math10.zip only compiles in Delphi 1, but has code to control how the rounding is performed by manipulating the control word of the FPU. Look for functions GetRoundMode and SetRoundMode to control rounding with a TRoundMode constant with values rmNearest, rmDown, rmUp, rmTruncate.

    To change the rounding mode, see the function Set8087CW in the Miscellaneous Function section of the Delphi General Functions Page.

    B-10. How can I round a floating point number in the traditional way: below 0.5 rounds down, 0.5 and above, rounds up? FAQ1814D.txt Explaination (sic) of rounding
    http://community.borland.com/article/0,1410,16814,00.html 

    See Set8087CW for how to control rounding modes.

    B-11. When I do a StrToFloat('1234.5544') I get something like 1234.55440000000003. What is wrong here?
    Nothing is "wrong" here. This is just a limitation of floating-point numbers. The actual source of error is called roundoff error. This error is due to the fault of floating-point arithmetic and to the fact that most decimal fractions become repeating fractions in the binary number system. Such numbers cannot be represented in a finite number of bits. The word roundoff is not always accurate in this connection, and comes from the fact that many computers, when cutting off the last digits from a number, "round" the number to its closest equivalent. Some computers do not round but merely cut off the last bits, with the resulting error still properly called roundoff error (as opposed to truncation error, which is the term used when a series expansion is truncated). From Introduction to Numerical Methods, Peter A. Stark, Macmillian Company, 1970.
    B-12. I'm trying to compare two floating point numbers that should be equal. Why aren't the two values equal?

    TI2139, How to Compare Floating Point Numbers
    http://community.borland.com/article/0,1410,17139,00.html 

    Numerical Accuracy 101 for Delphi Developers
    http://efd.home.mindspring.com/acc101.htm

    Typically, you can use relative or absolute comparisons to avoid problems with "fuzz" (a term used with the language APL) with floating-point numbers.

    Because of this "fuzz" with floating point numbers, comparison of two calculated floating point numbers should be based on either absolute or relative error.

    For an absolute error comparison use something like:
    IF ABS(CalculatedValue - TrueValue) < FuzzValue THEN ..., where FuzzValue is application specific.

    For a relative error comparison use something like:

    IF ABS( (CalculatedValue - TrueValue) / TrueValue ) < AcceptableRelativeError THEN ... 

    where AcceptableRelativeError is application specific (and obviously TrueValue <> 0.0).  HOWEVER, this form of comparision can lead to divide-by-zero problems.  An alternative suggested in a UseNet Post by Hans-Bernhard Broeker avoids this problem by using:
    IF ABS( CalculatedValue - TrueValue ) < ABS(AcceptableRelativeError*TrueValue) THEN ...

    The Delphi 3 math unit performs relative comparisons like this (but it's not exposed in the unit's interface):

    FUNCTION RelSmall(X, Y: Extended): Boolean;
      //  Returns True if X is small relative to Y
      CONST
        C1:  Double = 1E-15;
        C2:  Double = 1E-12;
    BEGIN
      Result := Abs(X) < (C1 + C2 * Abs(Y))
    END;

    Ray Lischner has approximate comparison functions in his Math10.ZIP: FltLE, FltLT, FltGE, FltGT, FltEQ, FltNE
    B-13. Explain how a comp type is a floating point type but is a 64-bit integer.

    (Note: Use the new Int64 type in Delphi 4 or later)
    Since the floating point unit (FPU) deals with this 64-bit integer, the comp type is treated as if it were a floating point type even though it is a 64-bit integer. Delphi's VCL defines a type called TLargeInteger type that has a QuadPart comp type but also a LowPart and HighPart that are LongInts. You can speed up conversion of a comp to an integer type using TLargeInteger. See Borland's  Assigning a comp type to an integer (FAQ 1965D).

    In D4 the TLargeInteger is an Int64, but through a pLargeInteger pointer the LowPart, HighPart and QuadPart of the Int64 can still be accessed like in D3. 

    In D4 a TULargeInteger  and a pULargeInteger are defined much like the TLargeInteger and pLargeInteger.  The HighPart of a TULargeInteger is a DWORD (i.e., unsigned) while the HighPart of a TLargeInteger is a LongInt (i.e., signed).

    While not very intuitive, you must treat a comp type as a float when converting to a string. Specifically, you must use FloatToStr or FormatFloat to convert to a string. Consider the following example:

    VAR
      c: TLargeInteger;
      s: STRING;
    ...
    c.QuadPart := MaxComp; // MaxComp defined in Delphi math unit
    s := Format('%8X%8X %d %d %f', 
                [c.HighPart, c.LowPart, c.HighPart, c.LowPart, c.QuadPart]);

    The resulting string, s, contains the following: 7FFFFFFFFFFFFFFF 2147483647 -1 9.22337203685477581E18

    Another example of using TLargeInteger is in Using the WIN API high resolution performance counter (FAQ 2028D).

    B-14. How can I get Delphi to perform stronger type checking on user defined types?  For example, how can I define a type that descends from a double but not pass this type to any function expecting a double (without a warning)?

    See Borland FAQ 2126D, "Getting stronger type checking"

    B-15.  Unsigned 32 Integers for Delphi 2/3 By Ray Lischner.  The Unsigned unit implements unsigned 32-bit integer arithmetic: comparisons, conversions, and division. Freeware. Source code and help file included. In Delphi 1.0, you must also download the FltMath unit, in math10.zip.
    B-16.  Floating Point Optimzation Floating Point Optimization Guidelines
    www.optimalcode.com/float.htm 

    C. Delphi Math Tips and Tricks

    Topic Tip or Trick
    C-1. Integer to Float Simple assignment:
    x := i;
    C-2. Integer to String s := IntToStr(i);
    or
    Format('%6.6d', [1234]) returns '001234'
    C-3. Float to Integer TRUNC(3.5) = 3
    or ROUND (see "IEEE Rounding" above)
    C-4. Float to String Format, FormatFloat or FloatToStr, but also
    FloatToDecimal, FloatToStrF, FloatToText, FloatToTextFmt

    Examples:
    Format('%.3f times %d is %-16s', 
           [Measurement, Value, Key]); // "C" sprintf format specifications
    FormatFloat('##0.0', Factor);
    FloatToStr(x);
    C-5. String To Float; Sting To Integer If d is a double: d := StrToFloat('1234.5544');

    If i is an integer: i := StrToInt('1234');
    C-6. How can I localize numbers to display correctly in both the U.S. and European formats?

    What is the ThousandSeparator?

    What is the DecimalSeparator?
    VAR
      x: DOUBLE;
      i: INTEGER;
    BEGIN
      x := 1234567.8945;

      Button1.Caption := ThousandSeparator;
      ThousandSeparator := ',';
      DecimalSeparator := '.';
      LabelUSA.Caption := FormatFloat('#,###,###.###', x);

      ThousandSeparator := '.';
      DecimalSeparator := ',';
      LabelEuropean.Caption := FormatFloat('#,###,###.###', x);

    The resulting strings are (remember IEEE rounding rounds towards an even number):
    USA: 1,234,567.894
    European: 1.234.567,894


    Treat an integer the same way and use FormatFloat to get a ThousandSeparator in an integer string.
    C-7. Dynamically allocated arrays (one dimension) Arrays are incredibly useful and crop up in just about every project we create. But “out of the box” they are rather inflexible as you need to decide upfront how big your array should be. Not any more, Brian Long explains how to make your arrays dynamic: resizeable and powerful, for Delphi 1 right through to Delphi 4, with its new built-in dynamic arrays feature.
    Delphi Magazine, Issue 37, September 1998

    How to Create an Array of 2,000,000 doubles in Delphi 1: Delphi1LargeArray.ZIP

    Also, see example below in "Open Array; Slice Function."

    I don't particularly like Borland's solution, How can I resize an array?, (sorry Joe) since it requires turning off all range checking:  FAQ 1830D

    Also look at Borland's Tech Info Report, Dynamically Allocating Arrays:
    TI 1093D

    Dr. Dobb's Journal on huge arrays in Turbo Pascal: ftp://garbo.uwasa.fi/pc/turbopas/ddj8803.zip

    Dr. Dobb's Journal on virtual arrays in Turbo Pascal: ftp://garbo.uwasa.fi/pc/turbopas/ddj8810.zip

    C-8. 2D dynamic arrays D5 Example using new ARRAY OF ARRAY construct introduced in D4:

       How to create a Bitmap from numeric data? (D5)
    Shows how to read a TXT file into a TStringList.  Parses each line in TStringList and forms a dynamic matrix of real values to be displayed in a bitmap.

    // Delphi 3 Example of 2-Dimensional Dynamic Array
    CONST
    ArrayMaxCount = 65536;

    TYPE
    pDoubleArray = ^TDoubleArray;
    TDoubleArray = ARRAY[0..ArrayMaxCount-1] OF DOUBLE;
    pMatrix = ^TMatrix;
    TMatrix = ARRAY[0..ArrayMaxCount-1] OF pDoubleArray;

    procedure TForm1.Button1Click(Sender: TObject);
      CONST
        iCountMax = 500; // columns
        jCountMax = 1000; // rows
      VAR
        i : 0..iCountMax-1;
        j : 0..jCountMax-1;
        k : INTEGER;

        // Let's make Matrix 1000 rows of 500 columns =
        // 500,000 elements = 4,000,000 bytes
        Matrix: pMatrix;

        Sum : DOUBLE;
    begin
      // Allocate the pointers to each row
      GetMem(Matrix, jCountMax*SizeOf(pMatrix));
      TRY

        // Allocate each row of DOUBLEs
        FOR j := 0 TO jCountMax-1 DO
          GetMem(Matrix[j], iCountMax*SizeOf(DOUBLE));

        TRY
          // Assign value to each Matrix element
          k := 1;
          FOR j := 0 TO jCountMax - 1 DO
          BEGIN
            FOR i := 0 TO iCountMax -1 DO
            BEGIN
              Matrix[j]^[i] := k;
              INC(k);
            END;
          END;

          // Add up all values in Matrix. The sum of 1..N = N*(N+1)/2, so
          // the sum should be (iCountMax*jCountMax)*(iCountMax*jCountMax + 1) / 2,
          // or in this case SUM(1..500,000) = 125,000,250,000.
          Sum := 0;
          FOR j := 0 TO jCountMax - 1 DO
            FOR i := 0 TO iCountMax -1 DO
              Sum := Sum + Matrix[j]^[i];

          Button1.Caption := FloatToStr(Sum);

        FINALLY
          // Free each row of DOUBLEs
          FOR j := jCountMax-1 DOWNTO 0 DO
            FreeMem(Matrix[j]);

        END
      FINALLY
        // Free array of pointers
        FreeMem(Matrix)
      END
    end;

    C-9. Open Array Parameters;
    Slice Function
    From the Delphi 3 Object Pascal Language Guide: Open-array parameters allow arrays of varying sizes to be passed to the same procedure or function. A formal parameter declared using the syntax: ARRAY OF T. Within the procedure or function, the formal parameter behaves as if it was declared as ARRAY[0..N - 1] OF T, where N is the number of elements in the actual parameter. Note: When applied to open-array parameters, the Low standard function returns zero, the High standard function returns the index of the last element in the actual array parameter.

    The Slice function was introduced in Delphi 2. Use Slice for passing variable-sized "open" arrays to certain functions, e.g., mean, sum, SumInt, MaxValue, MaxIntValue, etc. in Borland math unit, or user-written routines.

    Simple Slice Example:

    CONST
      PointMaxCount = 25;

    VAR
      Points : ARRAY[0..PointMaxCount-1] OF TPoint;
    begin
      Points[ 0] := Point( 20, 40);
      Points[ 1] := Point( 30,400);
      Points[ 2] := Point( 40,450);
      Points[ 3] := Point(600,460);
    ...
      PointCount := 14; // or some other value < PointMaxCount
    ...
      Bitmap.Canvas.Polyline(Slice(Points, PointCount));

    Example defining open array function, dynamic allocation of array, and Slice:

    // Calculate median intensity of RGB array
    FUNCTION RGBMedian(RGB: ARRAY OF TRGBTriple): TRGBTriple;
      TYPE
        pIntegerArray = ^TIntegerArray;
        TIntegerArray = ARRAY[0..MaxPixelCount-1] OF INTEGER;
      VAR
        Count           : INTEGER;
        i                    : INTEGER;
        MedianIndex: INTEGER;
        MedianValue: INTEGER;
        pIntensity     : pIntegerArray;
    BEGIN
      Count := High(RGB) - Low(RGB) + 1;

      // Allocate temporary integer array for intensity values
      GetMem(pIntensity, Count*SizeOf(Integer));

      TRY
        FOR i := Low(RGB) to High(RGB) DO
        BEGIN
          pIntensity^[i] := RGBIntensity(RGB[i]);
        END;

        MedianValue := MedianInteger( Slice(pIntensity^, Count) );

        MedianIndex := Low(RGB);
        WHILE (MedianIndex < High(RGB)) AND (pIntensity^[MedianIndex] <> MedianValue) DO
        BEGIN
          INC (MedianIndex)
        END

      FINALLY
        FreeMem(pIntensity)
      END;

      RESULT := RGB[MedianIndex]
    END {RGBMedian};

    The above RGBMedian function is called by the following:

    RowLast := BitmapIn.Scanline[j-1];

    AssignRGBTriple(rowOut[i],
    RGBMedian([RowLast[i-1], RowLast[i], RowLast[i+1],
    RowIn[i-1], RowIn[i], RowIn[i+1],
    RowNext[i-1], RowNext[i+1], RowNext[i+1] ]) );

    An Open Array function called by the above example:

    FUNCTION MedianInteger (x: ARRAY OF INTEGER): INTEGER;
       VAR
        i        : INTEGER;
        j        : INTEGER;
        Middle   : INTEGER;
        Temporary: INTEGER;
    BEGIN
      // Use truncated selection sort to find median

      Middle := (High(x)+1) DIV 2;

      FOR i := 0 TO Middle DO
      BEGIN
        FOR j := 1 TO High(x)-i DO
        BEGIN
          IF x[j] > x[j-1]
          THEN BEGIN
            Temporary := x[j];
            x[j] := x[j-1];
            x[j-1] := Temporary
          END
        END

      END;

      IF Odd(High(x))
      THEN BEGIN
        // When High(x) is Odd, there are an even number of elements in array.
        // Define median as average of two middle values.
        RESULT := (x[middle] + x[middle-1]) DIV 2
      END
      ELSE BEGIN
        // When High(x) is Even, there are an odd number of elements in array.
        // Median is the middle value.
        RESULT := x[middle]
      END
    END {MedianInteger};

    C-10. Passing Multidimensional Arrays as Parameters Borland's TI 1477D
    C-11.  How to use array of const Borland TI 582D
    C-12. Dynamic Arrays? A Class Wrapper for TList Delphi Informant article, Feb. 1997, pp. 58-65. 
    C-13. Linked Lists -- When the Data is Too Dynamic for Arrays Delphi Informant article, May 1998, pp. 64-67. Source code is
    www.informant.com/libs/delphi/3x/DI9805RS.ZIP
    C-14. Dynamic array of TPoints to draw a polygon See Borland's FAQ 919D
    C-15. Initialization of two-dimensional array CONST
      A: ARRAY[1..2, 1..3] OF INTEGER = ( (1,2,3), (4,5,6));

    Also see:   Joselito G. Real UseNet Post about "Initializing n-dimensional array-type constants or static arrays"

    C-16. Pointer Math Subject: Re: Pointer Math
    From: Earl F. Glynn 
    Date: Thursday, February 19, 1998 10:09 PM
    Newsgroups: borland.public.delphi.winapi
    ...
    In Delphi 2/3, if p is a pointer, you can always do something like this:

    p := Pointer(INTEGER(p) + 8);

    If p were a ^INTEGER before the above statement, it will point to "p+8" afterwards.

    For Delphi 1, see Borland's
    - TI 926D "How to do pointer arithmetic in Delphi"
    - TI 1542D, "A better way to do pointer arithmetic"
    C-17. Numeric Edit Box The NumEdit component is an edit box that only accepts valid numeric values either from the keyboard or through code. Download from Delphi Super Page: http://delphi.icm.edu.pl/ftp/d10free/numedit.zip
    C-18.  Numeric panel Jean-Yves Qu閕nec's NumPanel demo program.  Numpanel is a program sample (not a component) for "mouse only" numeric matrix input. It's very easy to use and simple to code. Two separate zip files contain the program (Numpanel.zip), and the text (Numpaneldoc.zip) in Html format with 3 images.

    Links Verified 12 Nov 2000
    Updated 09 Mar 2003


    since 1 Nov 1998

  • 相关阅读:
    springboot(六):如何优雅的使用mybatis
    springboot(四):thymeleaf使用详解
    springboot(三):Spring boot中Redis的使用
    springboot(二):web综合开发
    Springboot(一):入门篇
    js判断对象的某个属性是否存在
    查看node.js全局安装的插件路径
    切片地图服务器
    element ui loading加载开启与关闭
    vue 引入 leaflet1.4.0
  • 原文地址:https://www.cnblogs.com/fuyingke/p/282208.html
Copyright © 2011-2022 走看看