Home > Articles > Programming > General Programming/Other Languages

This chapter is from the book

This chapter is from the book

Integer Types and Floating-Point Types

I assume that readers of this book can quickly come to terms with basic Pascal types. I will say a few words on the basics of the subject and then go on to cover some issues that might trip up experienced programmers new to this language or experienced programmers who need a refresher course on Pascal syntax. This approach will not be helpful for a newcomer to programming, but it should be enough information to get experts up to speed on Object Pascal in short order.

I'll start by talking briefly about integers and floating-point types. After getting that basic material out of the way, I'll discuss strings, pointers, and typecasting.

Here are two very basic definitions:

  • Integers are whole numbers, such as -1, 0, 1, 2, and 5,000,000.

  • Floating-point numbers are sometimes known as decimal numbers, such as 7.0, 3.2, -5.004, and 32,000.0000000034.

Ordinal Types

A whole series of types in Pascal are based on whole numbers. These include the Byte, Integer, Char, and Boolean types. All of these types are ordinal types.

Understanding the definition of the ordinal types is helpful for programmers who want to set sail on the good ship Pascal. All but the first and last members of ordinal types have a predecessor and a successor. For instance, an ordinal number such as 1 is followed by 2 and preceded by 0. The same cannot be said of a floating-point type. What is the predecessor to 1.0002? Is it 1.0001? Maybe. But perhaps it is 1.00019—or maybe 1.000199. How about 1.000199999999? Ultimately, there is no clearly defined predecessor to a floating-point number, so it is not an ordinal value.

Whole numbers are ordinal numbers. Simple types such as Char and Boolean are also ordinal numbers. For instance, the letter B is succeeded by the letter C and preceded by the letter A. It makes sense to talk about the successor and predecessor of a Char. The same is true of Boolean values. False, which is equivalent to 0, is succeeded by True, which is usually equivalent to 1. False is the predecessor of True, and True is the successor to False.

NOTE

When I use the word integer in a generic sense, I am talking about the numeric ordinal types such as Byte, LongInt, Integer, or Cardinal. When I talk specifically about Integers, with a capital I, then I mean the Pascal type named Integer. C and Java programmers make a similar distinction between the floating-point types and the type named float.

Two integer types exist in Pascal: generic and fundamental. The generic types, called Integer and Cardinal, will transform themselves to fit the compiler you are currently using. If you use Integers on a 16-bit platform, they will be 16 bits in size. Use them on a 32-bit platform with a 32-bit compiler, and they will be 32 bits in size. Use them on a 64-bit platform with a 64-bit compiler, and they will be 64 bits in size.

Integers are always signed values, which means that they use 1 bit to signal whether they are positive or negative and then use the remaining bits to record a number.

NOTE

Some readers might not be clear on the difference between signed and unsigned types. Consider the Byte and ShortInt types, both of which contain 8 bits. A Byte is unsigned, and a ShortInt is signed. The largest unsigned 8-bit number is 255, while its smallest value is 0. The largest signed 8-bit number is 127, while its smallest value is -128. The issue is simply that you can have 256 possible numbers that can be held in 8 bits. These 256 numbers can range from either -128 to 127, or from 0 to 255. The difference between signed and unsigned types is whether one of the bits is used to designate the plus and minus sign. Unsigned numbers have no plus and minus sign and, therefore, are always positive. Signed numbers range over both positive and negative values.

NOTE

At this time, there is only a 32-bit compiler in Kylix. On the Windows platform, at the time of this writing, there is a 16-bit and a 32-bit Delphi compiler.

In contrast to generic types, fundamental types are always a set size, regardless of what platform you use. For instance, a Byte is an 8-bit, unsigned number, regardless of the platform. The same rule applies to LongInts, which are always 32-bit signed numbers, regardless of the platform.

The generic types are shown in Table 3.1, and the fundamental types appear in Table 3.2.

Table 3.1  The Generic Types Are Ordinal Values with a Range That Changes Depending on the Number of Bits in the Native Type Word for Your Platform

Type

Range

Format

Integer

-2147483648 to 2147483647

Signed 32-bit

Cardinal

0 to 4294967295

Unsigned 32-bit

Table 3.2  The Fundamental Type Stays the Same, Regardless of Platform

Type

Range

Format

ShortInt

-128 to 127

Signed 8-bit

SmallInt

-32768 to 32767

Signed 16-bit

LongInt

-2147483648 to 2147483647

Signed 32-bit

Int64

-263 to 263-1

Signed 64-bit

Byte

0 to 255

Unsigned 8-bit

Word

0 to 65535

Unsigned 16-bit

LongWord

0 to 4294967295

Unsigned 32-bit

Most knowledgeable programmers try to use the generic types whenever possible. They help you port your code to new platforms, and they make your code backward compatible with old platforms. Furthermore, the generic Integer type should always be the fastest numeric type on any platform because it fits exactly the size of a word on that particular processor. Thus, the Integer type will usually be the best choice for producing fast code, even though it is larger than the ShortInt or SmallInt types. On 32-bit platforms, LongInts and Integers are equally fast, but when we move to 64-bit computers, LongInts will no longer be the native type, while Integers will continue in the anointed position. In short, Integers will have 64 bits on a 64-bit platform, 16 bits on a 16-bit platform, and 32 bits on a 32-bit platform.

If you have code that assumes that a particular variable has a certain number of bits in it or will always contain only a certain range of numbers, you should use fundamental types to make sure that your code does not break if you move to another platform. Obviously, most of the code that you write will not be dependant on the number of bits in a variable, but if your code does depend on such a thing, choose your types carefully. For instance, if you are writing a routine that needs to handle numbers larger than 32,767, don't use Integers if you think that the code will ever be run on a 16-bit platform. If you do choose Integers, they will not be large enough to hold the values that you want to use. If you choose LongInts, the type will be large enough, even if ported to a 16-bit platform. (Of course, the odds that you will port your code back to a 16-bit platform are low.)

Pascal Routines for Using Ordinal Numbers

The Integer types, by definition, are ordinal numbers. Ordinal numbers can be manipulated with the following routines: Ord, Pred, Succ, High, and Low. If applied to a Char, the Ord function returns its numeric value. For instance, the Ord of A is 65, and the Ord of a space is 32. In the following example, Num will be set to 66:

var
  MyChar: Char;
  Num: Integer;
begin
  MyChar := `B';
  Num := Ord(MyChar);
end;

The Pred routine returns the predecessor of a number. For instance, the Pred of 1 is 0. The Succ of 1 is 2.

High and Low give you the highest and lowest numbers that you can use with a type. Examples of how to use High and Low are shown in the SimpleTypes program, found on your CD and in Listing 3.1.

Listing 3.1  The SimpleTypes Program

unit Main;

interface

uses
  SysUtils, Types, Classes,
  QGraphics, QControls, QForms,
  QDialogs, QStdCtrls, QExtCtrls;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    RadioGroup1: TRadioGroup;
    procedure RadioGroup1Click(Sender: TObject);
  private
    procedure DoLongInt;
    procedure DoInteger;
    procedure DoCardinal;
    procedure DoLongWord;
    procedure DoWord;
    procedure DoShortInt;
    procedure DoSmallInt;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.xfm}

type
  TMethodType = (mtInteger, mtCardinal, mtLongInt,
    mtLongWord, mtWord, mtShortInt, mtSmallInt);

procedure TForm1.DoInteger;
var
  Value: Integer;
begin
  ListBox1.Items.Add(`Integer high value: ` + IntToStr(High(Value)));
  ListBox1.Items.Add(`Integer low value: ` + IntToStr(Low(Value)));
  ListBox1.Items.Add(`Size of Integer: ` + IntToStr(SizeOf(Value)) + ` bytes or 
` + IntToStr(8 * SizeOf(Value)) + ` bits.');
end;

procedure TForm1.DoLongInt;
var
  Value: LongInt;
begin
  ListBox1.Items.Add(`LongInt high value: ` + IntToStr(High(Value)));
  ListBox1.Items.Add(`LongInt low value: ` + IntToStr(Low(Value)));
  ListBox1.Items.Add(`Size of LongInt: ` + IntToStr(SizeOf(Value)) + ` bytes or 
` + IntToStr(8 * SizeOf(Value)) + ` bits.');
end;

procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
  case TMethodType(RadioGroup1.ItemIndex) of
    mtInteger: DoInteger;
    mtCardinal: DoCardinal;
    mtLongInt: DoLongInt;
    mtLongWord: DoLongWord;
    mtWord: DoWord;
    mtShortInt: DoShortInt;
    mtSmallInt: DoSmallInt;
  end;
end;

procedure TForm1.DoCardinal;
var
  Value: Cardinal;
begin
  ListBox1.Items.Add(`Cardinal high value: ` + IntToStr(High(Value)));
  ListBox1.Items.Add(`Cardinal low value: ` + IntToStr(Low(Value)));
  ListBox1.Items.Add(`Size of Cardinal: ` + IntToStr(SizeOf(Value)) + ` bytes 
or ` + IntToStr(8 * SizeOf(Value)) + ` bits.');
end;

procedure TForm1.DoLongWord;
var
  Value: LongWord;
begin
  ListBox1.Items.Add(`LongWord high value: ` + IntToStr(High(Value)));
  ListBox1.Items.Add(`LongWord low value: ` + IntToStr(Low(Value)));
  ListBox1.Items.Add(`Size of LongWord: ` + IntToStr(SizeOf(Value)) + ` bytes 
or ` + IntToStr(8 * SizeOf(Value)) + ` bits.');
end;

procedure TForm1.DoWord;
var
  Value: Word;
begin
  ListBox1.Items.Add(`Word high value: ` + IntToStr(High(Value)));
  ListBox1.Items.Add(`Word low value: ` + IntToStr(Low(Value)));
  ListBox1.Items.Add(`Size of Word: ` + IntToStr(SizeOf(Value)) + ` bytes or ` 
+ IntToStr(8 * SizeOf(Value)) + ` bits.');
end;

procedure TForm1.DoShortInt;
var
  Value: ShortInt;
begin
  ListBox1.Items.Add(`ShortInt high value: ` + IntToStr(High(Value)));
  ListBox1.Items.Add(`ShortInt low value: ` + IntToStr(Low(Value)));
  ListBox1.Items.Add(`Size of ShortInt: ` + IntToStr(SizeOf(Value)) + ` bytes 
or ` + IntToStr(8 * SizeOf(Value)) + ` bits.');
end;

procedure TForm1.DoSmallInt;
var
  Value: SmallInt;
begin
  ListBox1.Items.Add(`SmallInt high value: ` + IntToStr(High(Value)));
  ListBox1.Items.Add(`SmallInt low value: ` + IntToStr(Low(Value)));
  ListBox1.Items.Add(`Size of SmallInt: ` + IntToStr(SizeOf(Value)) + ` bytes 
or ` + IntToStr(8 * SizeOf(Value)) + ` bits.');
end;

end.

This program rather laboriously calls High and Low for all the integer types. Notice that it also uses the SizeOf function, which returns the size in bytes of any variable or type. The point of this program is to show you that you can discover this information at runtime.

You can learn even more about a type using Run Time Type Information (RTTI). An introduction to RTTI appears in the upcoming section "Floating-Point Types."

Enumerated Types

All major languages have enumerated types. This is an ordinal type. In fact, enumerated types are really nothing more than a few numbers starting from 0 and rarely ranging much higher than 10. The interesting thing about these numbers is that you can give them names.

Consider this example:

procedure TForm1.Button1Click(Sender: TObject);
type
  TComputerLanguage = (clC, clCpp, clJava, clPascal, clVB);
var
  ComputerLanguage: TComputerLanguage;
begin
  ComputerLanguage := clPascal
end;

Here the values clC, clCpp, clJava, clPascal, and clVB are just fancy ways to write 0, 1, 2, 3, and 4. In short, enumerated types are just a way to associate numbers with names. However, if you want to associate numbers with names, you are always in danger of forgetting which number belongs to which name. For instance, you might want to reference Java and accidentally write 3, when what you meant to write was 2. To avoid confusion, the enumerated type enables you to associate a name with a number. Furthermore, you can enforce that relationship through Pascal's strong type checking. For instance, you can't assign even a valid identifier named clTunaFish to the variable ComputerLanguage unless it is part of the TComputerLanguage type.

NOTE

The letters cl prefacing each name are a Pascal convention. The convention says that you put the letters of the name of the type before the name. So, Computer Language becomes cl.

You can use the Ord routine to convert an enumerated value to a number:

i := Ord(clPascal);

In this case, i is set equal to 3. In fact, you can go from the number to the name, but that is a complex operation involving routines found in the TypInfo unit. The TypInfo unit will be discussed in Chapter 4, and in the next section "Floating-Point Types."

Here is an example by Bob Swart that shows a simple way to write out the name of a type:

program BobEnum;  
{$APPTYPE CONSOLE}
type
  TEnum = (zero, one, two, three);
var
  E: TEnum;
begin
  E := TEnum(2); // E := two;
  if E = two then WriteLn(`Two!');
  ReadLn
end.

Floating-Point Types

Pascal has lots of floating point-types for helping you work with decimal numbers, or fractions of whole numbers. Table 3.3 lists the fundamental types you can choose from.

Table 3.3  The Fundamental Floating-Point Types—the Generic Type, Known as a Real, Is Currently Equivalent to a Double

Type

Range

Real48

2.9 x 10-39 to 1.7 x 1038 11-12 6

Single

1.5 x 10-45 to 3.4 x 1038 7-8 4

Double

5.0 x 10-324 to 1.7 x 10308 15-16 8

Extended

3.6 x 10-4951 to 1.1 x 104932 19-20 10

Comp

-263+1 to 2^63 -1 19-20 8

Currency

-922337203685477.5808 to 922337203685477.5807 19-20 8

The most commonly used type is the Double. However, there is a generic floating point type known as a Real. It is currently the same as a Double, much as an Integer is currently the same as a LongInt. If you declare your floating-point values to be Reals, they can be automatically converted to any new optimal floating-point type that might come along.

The Comp type is the floating-point type that is used the least frequently. In fact, it isn't really meant to represent floating-point numbers. In the bad old days of 16-bit computing, this used to be the best way to work with very large whole numbers. Now it has no function other than to support old code. If you need to work with really large Integer types, then you should now use the Int64 type.

NOTE

Back in the aforementioned bad old days, Pascal used to have a set of routines for working with a type of unique floating-point type known as a Real. (This is not the same thing as the current Real type, but it's a strange 48-bit beast that was custom-made by optimization-obsessed Borland programmers. Back in this time, the Real type and its associated code were considered to be very fast. However, those days are now little more than a memory. Modern operating systems and modern processors now have built-in routines that are superior to the once-ground-breaking code that supported the 48-bit Real type.

The current Real is the same as a Double. However, a type known as a Real48 is compatible with the old Real type used long ago, when Windows was a failed project that provided fodder for jokes and everyone believed that Apple might end up ruling the computer desktop. If you are an old Pascal programmer who has some code dependant on the implementation of the old Pascal Real type, then use Real48.

Remember that Real types, which are synonymous with the Double type, are now back in fashion. I'm having trouble adopting to this new state of affairs because I'm used to thinking of Reals as being out-of-date. So, you will find a lot of Doubles in my code, but I am trying to make the move to using Reals instead. I never use Real48s because I have no code dependant on them.

The TBcd and Floating-Point Accuracy

We now broach the treacherous topic of floating-point accuracy. This is a sea in which no ship is safe, and only caution can protect us from the reefs.

All experienced programmers know that floating-point types such as Doubles and Singles lose precision nearly every time they are part of a calculation. This loss of precision is usually not a problem in a standard math or graphics program, but it can be a serious issue in financial calculations. As a result, you should consider using the Currency type to avoid rounding errors. However, this is not a perfect solution.

The best way to avoid problems with rounding errors is to use the TBcd type, found in the FMTBcd unit. BCD stands for "binary coded decimal," and it is a widely used technology to avoid rounding errors when working with floating-point numbers. Borland did not invent the BCD technology any more than it invented the idea of the floating-point type. It's just a technology that it employs in this product.

Here is what the TBcd type looks like:

  PBcd = ^TBcd;
  TBcd  = packed record
    Precision: Byte;                        { 1..64 }
    SignSpecialPlaces: Byte;                { Sign:1, Special:1, Places:6 }
    Fraction: packed array [0..31] of Byte; { BCD Nibbles, 00..99 per Byte, high Nibble 1st }
  end;

Each of the numbers in your floating-point type is stored in a nibble, which is 4 bits in size. You can specify the number of digits in your number in the Precision field, and you can specify the number of places after the decimal in the SignSpecialPlaces field. In practice, you rarely end up working so directly with this type. Instead, you can use a series of routines to make working with the TBcd type a more palatable exercise.

Kylix provides a large number of routines in the FMTBcd unit for manipulating BCD values. A large sampling of these routines is found in Listing 3.2. You should find the time to open the unit itself and examine it as well.

NOTE

In the Kylix editor, if you put your cursor over any unit in your uses clause and then press Ctrl+Enter, the source for that unit should open in your editor.

Listing 3.2  Routines in FMTBcd That You Can Use to Help You Work with the BCD Type

  procedure VarFMTBcdCreate(var ADest: Variant; const ABcd: TBcd); overload;
  function VarFMTBcdCreate: Variant; overload;
  function VarFMTBcdCreate(const AValue: string;
    Precision, Scale: Word): Variant; overload;
  function VarFMTBcdCreate(const AValue: Double;
    Precision: Word = 18; Scale: Word = 4): Variant; overload;
  function VarFMTBcdCreate(const ABcd: TBcd): Variant; overload;
  function VarIsFMTBcd(const AValue: Variant): Boolean; overload;
  function VarFMTBcd: TVarType;

  // convert String/Double/Integer to BCD struct
  function StrToBcd(const AValue: string): TBcd;
  function TryStrToBcd(const AValue: string; var Bcd: TBcd): Boolean;
  function DoubleToBcd(const AValue: Double): TBcd; overload;
  procedure DoubleToBcd(const AValue: Double; var bcd: TBcd); overload;
  function IntegerToBcd(const AValue: Integer): TBcd;
  function VarToBcd(const AValue: Variant): TBcd;

  function CurrToBCD(const Curr: Currency; var BCD: TBcd; Precision: Integer = 
32;
    Decimals: Integer = 4): Boolean;

  // Convert Bcd struct to string/Double/Integer
  function BcdToStr(const Bcd: TBcd): string; overload;
  function BcdToDouble(const Bcd: TBcd): Double;
  function BcdToInteger(const Bcd: TBcd; Truncate: Boolean = False): Integer;
  function BCDToCurr(const BCD: TBcd; var Curr: Currency): Boolean;

  // Formatting Bcd as string
  function BcdToStrF(const Bcd: TBcd; Format: TFloatFormat;
    const Precision, Digits: Integer): string;
  function FormatBcd(const Format: string; Bcd: TBcd): string;
  function BcdCompare(const bcd1, bcd2: TBcd): Integer;

Most of these routines are encapsulations of technologies for converting back and forth from TBcd values to most major types. For instance, BcdToStr converts a TBcd value to a string, and StrToBcd performs the opposite task. However, there are more routines than the ones I show you here. Perhaps the best way to get up to speed is to simply look at the BCDVariant program, found in Listing 3.3.

Listing 3.3  The BCDVariant Program Gives You a Number of Examples on How to Use the BCD Type

unit Main;

interface

uses
  SysUtils, Types, Classes,
  QGraphics, QControls, QForms,
  QDialogs, QStdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure SimpleMathButtonClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  FMTBcd;

{$R *.xfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  B: TBcd;
  V: Variant;
begin
  V := VarFMTBcdCreate(36383.530534346, 32, 9);
  ListBox1.Items.Add(BCDToStr(VarToBCD(V)));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  B: TBcd;
  D: Double;
  V: Variant;
  S: String;
begin
  D := 32.346;
  V := VarFMTBcdCreate(D, 18, 3);
  B := VarToBcd(V);
  S := BcdToStr(B);
  ListBox1.Items.Add(S);
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  C: Currency;
  D: Double;
  B: TBcd;
  V: Variant;
  S: String;
begin
  C := 33334.43;
  CurrToBCD(C, B, 32, 4);
  D := BcdToDouble(B);
  S := Format(`%m', [D]);
  ListBox1.Items.Add(S);
end;

procedure TForm1.SimpleMathButtonClick(Sender: TObject);
var
  V1, V2, V3: Variant;
  B1, B2, B3: TBcd;
  S1, S2: String;
begin
  V1 := VarFMTBcdCreate(3.5011, 32, 12);
  V2 := VarFMTBcdCreate(3.5020, 32, 12);
  V3 := V1 + V2;
  ListBox1.Items.Add(BcdToStr(VarToBcd(V3)));
  V3 := V1 * V2;
  ListBox1.Items.Add(BcdToStr(VarToBcd(V3)));
  V3 := V1 / V2;
  ListBox1.Items.Add(BcdToStr(VarToBcd(V3)));
  V3 := V1 - V2;
  ListBox1.Items.Add(BcdToStr(VarToBcd(V3)));
  B1 := VarToBcd(V1);
  B2 := VarToBcd(V2);
  S1 := BcdToStr(B1);
  S2 := BcdToStr(B2);
  BcdAdd(B1, B2, B3);
  ListBox1.Items.Add(S1 + ` + ` + S2 + `=' + BcdToStr(B3));
  BcdMultiply(B1, B2, B3);
  ListBox1.Items.Add(S1 + ` * ` + S2 + `=' + BcdToStr(B3));
  BcdDivide(B1, B2, B3);
  ListBox1.Items.Add(S1 + ` / ` + S2 + `='  + BcdToStr(B3));
  BcdSubtract(B1, B2, B3);
  ListBox1.Items.Add(S1 + ` - ` + S2 + `='  + BcdToStr(B3));
end;

end.

The most important code found here is seen in the lines at the beginning of the SimpleMathButtonClick method:

  V1 := VarFMTBcdCreate(3.5011, 32, 12);
  V2 := VarFMTBcdCreate(3.5020, 32, 12);
  V3 := V1 + V2;
  ListBox1.Items.Add(BcdToStr(VarToBcd(V3)));
  V3 := V1 * V2;
  ListBox1.Items.Add(BcdToStr(VarToBcd(V3)));

This code uses VarFMTBcdCreate to create two BCD numbers as Variants. Pass the number that you want to encapsulate in a BCD type in the first parameter. In the second parameter, pass the number of digits used to capture your number. For instance, in the first case shown previously, I could safely pass 5 because there are only five digits in 3.5011. Passing 32 is probably overkill. The last parameter is the number of those digits that appear after the decimal point. Again, 12 is more than ample for the job because there are only four numbers after the decimal point. (Obviously, these later two values are simply being used to fill in the Precision and SignSpecialPlaces fields of the TBcd type.)

The big question here is not how to call VarFMTBcdCreate, but why I am calling it. After all, this function returns not a TBcd value, but a Variant. I create Variants because you can directly add, multiply, divide, and subtract TBcd values when they are inside Variants:

V3 := V1 + V2;

Go back again to the declaration for TBcd. Clearly, there is no simple way to add or multiply values of type TBcd. However, if we convert them to Variants, the chore of performing basic math with TBcd values is marvelously simplified!

NOTE

For now, you need know little more than that Variants are like variables declared in a BASIC program, or like variables in Perl or Python. They are very loosely typed—or, at least, appear to be loosely typed. You can assign an Integer, Real, Byte, String or Object, to a Variant. In fact, you can assign almost anything to a Variant.

Kylix will allow you to implement particular kinds of Variants, and then give them interesting characteristics. For instance, you can create a kind of Variant that handles BCD values, and then you can teach this kind of Variant to do all sorts of interesting things In particular, you can teach it to handle addition, multiplication, and division. Clearly, this is the closest thing that Pascal has to the wonders of C++ operator overloading. If you are a Delphi programmer, you might find my definition of Variants at odds with what you learned about Variants in the Windows world. That is because Variants in Linux (and also in Delphi 6) do wondrous things that they did not do in the old Delphi 5 days.

Later in the MathButtonClick method, you see that there is a way to add, subtract, multiply, and divide TBcd variables without converting them to Variants:

  BcdAdd(B1, B2, B3);
  ListBox1.Items.Add(S1 + ` + ` + S2 + `=' + BcdToStr(B3));
  BcdMultiply(B1, B2, B3);
  ListBox1.Items.Add(S1 + ` * ` + S2 + `=' + BcdToStr(B3));
  BcdDivide(B1, B2, B3);
  ListBox1.Items.Add(S1 + ` / ` + S2 + `='  + BcdToStr(B3));
  BcdSubtract(B1, B2, B3);
  ListBox1.Items.Add(S1 + ` - ` + S2 + `='  + BcdToStr(B3));

This code shows you the BcdAdd, BcdMultiply, BcdDivide, and BcdSubtract routines, all of which do precisely what their names imply. However, most programmers would probably prefer the Variant code shown earlier because it is provides a more intuitive syntax.

Again, the point of the TBcd type is to ensure that you have no loss of precision when working with floating-point numbers. It goes without saying that there is overhead associated with the TBcd type and that, if possible, you should stick with Doubles or Reals if speed is an issue for you.

I should perhaps make clear that floating-point types are not inordinately inaccurate. The problems that you encounter with them occur when you do the kind of rounding necessary when working with money. If you don't have to round the values that you are working with to two decimal places, the standard floating-point types will probably meet your needs in all but the most rigorous of circumstances. More specifically, Doubles will generally be accurate to at least seven or eight decimal places, which in most cases is all the accuracy you will need. But if you keep rounding those values back to two decimal places, as you do when working with money, then the process of rounding the numbers will lead to errors of at least one penny.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020