Copyright: (c) 1996 - Prospero Software Products Ltd.


PSPNUM - Table of Contents
PSPNUM by Prospero Software Products Ltd.

41 Athol Street, Douglas, Isle of Man IM1 1LA, United Kingdom

PHN: +44 (0)1624-681090  FAX: +44 (0)1624-681097

WWW: http://www.prosperosoftware.co.uk  EMAIL: CompuServe 100332,1257

1  PSPNUM - A one-page summary

2  PSPNUM properties

2.1  Table of properties

2.2  DigitsBeforeDP and DigitsAfterDP properties

2.3  ArrayDimension and ArrayBase properties

2.4  ArrayElement property

2.5  ValueString, Text, Mask and AutoRefresh properties

2.6  Round property

2.7  OverflowKey and OverflowCode properties

2.8  NumID property

2.9  Operation, NumID1, NumID2 and ParmString properties

2.10  CompareResult property

2.11 SelStart,SelLength and SelText properties

2.12 ActiveBackColor property

2.13 EditProtect property

2.14 ValueError and ParmError properties

2.15 Other Standard properties

3  Updating PSPNUM numeric values

3.1  Changing the value of a single number

3.2  Changing the value of a numeric array

4  PSPNUM operations

4.1  Introduction to Operations

4.2  Dual-parameter arithmetic operations

4.3  Numeric array operation principles

4.4  Numeric array operation examples

4.5  Table of number operations

4.6  Table of numeric array operations

5  PSPNUM edit masks

5.1  Setting mask value components

5.2  Mask component identifiers

5.3  Mask component examples

5.4  Restrictions for mask components

6  PSPNUM events

6.1  ValueChange and TextChange events

6.2  OverflowKey and OverflowCode events

6.3  ValueError and ParmError events

6.4  Other Standard events

7  PSPNUM programming examples

Appendix A - Numeric rounding principles

Appendix B - PSPNUM versus Currency data type

Appendix C - PSPNUM Errors

Appendix D - PSPNUM Text Keystrokes


PSPNUM - A one-page summary
1 PSPNUM - A one-page summary

What PSPNUM is

PSPNUM is a custom control (16-bit VBX or 32-bit OCX) for Microsoft Visual Basic (VB) and compatible development environments. This User Guide applies to version 2.7 of the PSPNUM control.

Overview of PSPNUM Features

PSPNUM supports functions specific to decimal numeric fields and decimal numeric arrays. These fields/arrays are always fixed-length. Suppose you are looking for "an account balance with 9 digits and 2 decimal places" or for "an exchange rate with 12 digits and 7 decimal places" or for "an array of 99 discount fractions each with 5 decimal places only". In all these cases, the length of the numeric item is fixed, so PSPNUM can be used.

PSPNUM is a 'visual' control. It has the basic properties of a single-line Edit Box. It can display the numeric value for the user to examine and edit. The value may optionally be contained within a box. At run-time the contents of a typical PSPNUM control edit box might look like this: 129,365.71 CR

All components of the displayed value are highly configurable through user-defined edit masks.

PSPNUM Alternatives

PSPNUM is fundamentally different from floating-point data types (double, float). PSPNUM is for exact precision numbers, whereas floating-point numbers are really designed for maximum precision. If you want to calculate the distance to the Moon, by all means use floating-point data types. But if you want to calculate your bank balance or bank interest, use a control like PSPNUM. You can be sure your bank is using proper decimal numbers like PSPNUM, certainly not floating-point numbers.

PSPNUM is also significantly different from data types such as VB 'currency'. The VB currency data type simply does not cope with variations in the sizes of numbers you typically encounter when you program regular business applications. Differences between PSPNUM and the VB currency data type are summarised in Appendix B.

To summarise

PSPNUM is not a complex control. It fits in well with the fixed-length nature of many numeric data items in our data-processing world. For example, fixed-length fields in a relational database. PSPNUM provides completely accurate operations for numbers whose size needs to be specified exactly. This is critical for developing reliable business systems.


Table of Properties
2.1 Table of Properties

This section presents an overview of PSPNUM properties. All properties are discussed in more detail in following pages.

The table below summarises PSPNUM properties which can be set 1) in the PSPNUM Properties window at design-time or 2) at run-time using program code.

Property	Purpose
DigitsAfterDP	Input. Number of numeric digits after decimal place i.e. number of decimal places. Minimum value 0. Maximum value 37. Default value 2.
DigitsBeforeDP	Input. Number of numeric digits before decimal place. Minimum value 0 if DigitsAfterDP is non-zero, otherwise minimum value 1. Maximum value 37. Default value 9.
ArrayDimension	Input. Zero for a single number (no array). Otherwise value in range 2 through 10000 for the number of elements in the array.
ArrayBase	Input. The base element of the array (lowest element number). Only relevant if ArrayDimension is non-zero. Value in range 0 through 20000.
ValueString	Input/Output. Numeric value of number as simple string.
ValueError	Input. Controls response to error in value assigned to ValueString.
Text	Input/Output. Formatted version of ValueString displayed in edit box.
Mask	Input. Optional string. Mask used to control display of formatted Text property.
AutoRefresh	Input. Boolean TRUE/FALSE. Default TRUE. Specifies whether the Text property is automatically refreshed from the ValueString property.
Round	Input. Boolean TRUE/FALSE. Default TRUE. Specifies whether values assigned to the number are rounded or truncated.
OverflowKey	Input. Controls behaviour when excess high-order digits occur as a result of user keying into edit box (Text property).
OverflowCode	Input. Controls behaviour when excess high-order digits occur as a result of  an operation in VB code e.g. assigning to ValueString property.
ActiveBackColor	Input. Background color when control has input focus.
EditProtect	Input. Boolean TRUE/FALSE controls whether user can edit Text value.
ParmError	Input. Controls response to error in value assigned to ParmString.
The table below summarises PSPNUM properties which you set using program code only i.e. the properties do not appear in the PSPNUM Properties window at design-time.

Property	Purpose
ArrayElement	Input. Current element of numeric array i.e. element to be used for operations. Only relevant if ArrayDimension is non-zero. Minimum value = ArrayBase. Maximum value = ArrayBase + ArrayDimension - 1.
NumID	Output. Internal identifier for each number automatically assigned. Used for operations on other PSPNUMs.
Operation	Input. String value set to indicate desired operation on number.
ParmString	Input. Numeric value (as string) to be used as parameter in an operation for this number.
NumID1and NumID2	Input. Two numeric identifiers (NumIDs) of other PSPNUMs to be used as parameters in an operation for this number.
CompareResult	Output. Boolean TRUE/FALSE values set automatically following logical operations in user code e.g. testing to see if the value of the number is zero.
SelStart, SelLength and SelText	Input/Output. Control the selection of part of the Text property.


DigitsBeforeDP and DigitsAfterDP Properties
2.2 DigitsBeforeDP and DigitsAfterDP Properties

See also: Table of Properties.

The DigitsBeforeDP and DigitsAfterDP properties of PSPNUM define the size of the single number or of each number in the array if you have selected an array (ArrayDimension positive). These default to 'sensible' values of 9 and 2 respectively for new PSPNUM controls.

At design-time you should select values for DigitsBeforeDP and DigitsAfterDP which are appropriate for your application in the PSPNUM Properties window. You can also change both DigitsBeforeDP and DigitsAfterDP at run-time. For example you may have a multi-currency application where you want to change a design-time setting of 2 decimal places to 0 decimal places if the run-time value is for a currency with no fractions (e.g. Japanese Yen, Italian Lire).

When you change either DigitsBeforeDP or DigitsAfterDP at run-time, PSPNUM creates an internal number with the new size then assigns the value of the number with the old size to it. The principles of rounding and overflow (discussed in sections 2.6 and 2.7 below) therefore apply.

Run-time changes to DigitsBeforeDP and DigitsAfterDP should be the exception not the rule. For example, if a PSPNUM on a VB Form always has one size, set this at design-time rather than in the Form start-up procedure. This is more efficient and ensures that the PSPNUM does not quietly adjust run-time values if they are invalid.


ArrayDimension and ArrayBase Properties
2.3 ArrayDimension and ArrayBase Properties

See also: Table of Properties.

The ArrayDimension property defines the size (total number of elements) of the array. Selecting any non-zero value for ArrayDimension automatically identifies the PSPNUM as an array rather than a single number. PSPNUM does not allow an ArrayDimension value of exactly 1 which is pointless because it represents a single number (same as ArrayDimension zero).

The ArrayBase property defines the index number of the first element of the array. You can change ArrayBase even if ArrayDimension is zero - the ArrayBase value will only be processed when ArrayDimension is set to positive.

You should select values for ArrayDimension and ArrayBase which are appropriate for your application in the PSPNUM Properties window at design-time. You can also change both ArrayDimension and ArrayBase at run-time. Run-time changes to ArrayDimension and ArrayBase will probably be the exception not the rule. If you know these array characteristics in advance, set the property values at design-time rather than in the Form start-up procedure. This is more efficient and ensures that the PSPNUM does not quietly adjust run-time values if they are invalid.

A change to ArrayBase is quite simple - the PSPNUM simply records the new Base value internally with no change to any numeric array element values. If you increase ArrayDimension, extra zero-value elements are added to the numeric array. If you decrease ArrayDimension, the excess numeric array elements are quietly dropped (gone forever).


ArrayElement Property
2.4 ArrayElement Property

See also: Table of Properties.

A PSPNUM numeric array contains multiple values (one per array element) which you need to access individually. For example, to check if the 3rd element of the array is zero. To specify which element to access, set the ArrayElement property. This is the 'current' element. You can only set ArrayElement if ArrayDimension is positive - otherwise ArrayElement is forced to zero.

Array elements number from ArrayBase (first element in array) to ArrayBase + ArrayDimension - 1 (last element in array). At all times PSPNUM ensures that ArrayElement is in this range.

If you change ArrayBase, the ArrayElement property adjusts pro-rata automatically.


ValueString, Text, Mask and AutoRefresh Properties
2.5 ValueString, Text, Mask and AutoRefresh Properties

See also: Table of Properties.

The ValueString property is the value of the number as a simple string e.g. "-1234.56". If the PSPNUM is a numeric array (ArrayDimension is positive), ValueString is the value of the current element (ArrayElement property) of the array.

The ValueString property is the one to use for import/export of the PSPNUM value. For example, if you wish to set the value of the PSPNUM (e.g. from another control, or perhaps from an external data source), then assign to ValueString in your program code. Section 2.14 of this manual shows how you can respond to ValueString errors using the ValueError property.

By default, PSPNUM always formats the ValueString value as per the edit mask (Mask property) and displays it as the Text property e.g. "US$1,234.56CR". The Mask property is discussed in more detail in section 5 PSPNUM Edit Masks.

You can stop the Text property being refreshed by changing the AutoRefresh property of the PSPNUM to FALSE. Then any changes you make to the ValueString property will NOT be immediately reflected in the Text property. As soon as you set the AutoRefresh property back to TRUE, the Text property is immediately updated by formatting the ValueString property.

If AutoRefresh is set to FALSE, you can still force the Text property to be refreshed by invoking the standard Refresh method. This is a 'one-time' refresh. The Text property will not thereafter be refreshed until you next set AutoRefresh to TRUE or again invoke the Refresh method.


Round Property
2.6 Round Property

See also: Table of Properties.

A new value assigned to a single PSPNUM number - or to any element of the PSPNUM if it is a numeric array - may have more digits after the decimal place than the number itself. If the Round property is set to TRUE, the digit in the new value one place to the right of the DigitsAfterDP value is reviewed. If this is 0-4, no rounding occurs. If this is 5-9, rounding occurs. For example, if DigitsAfterDP has the value 2 and the new value is ".786", then the PSPNUM value becomes ".79" if Round is TRUE and ".78" if Round is FALSE.

All this happens internally - you never get a final result for a number with more decimal places than you specified for the number itself. Refer to Appendix A for further discussion of rounding principles.


OverflowKey and OverflowCode Properties
2.7 OverflowKey and OverflowCode Properties

See also: Table of Properties.

These properties concern numeric values which have more digits before the decimal place than the PSPNUM itself e.g. a numeric value of 1234.00 for a number with DigitsBeforeDP set to 3. When such a value is assigned to a number, overflow is said to occur.

Overflow may occur by user keying into the edit box (Text property). For example, the edit box displays 123.00 then the user keys the final 4. How PSPNUM responds in this case is determined by the OverflowKey property.

Overflow may also occur following actions in your program code. For example, the program assigns the value 1234.00 to the ValueString property or the numeric value 1234.00 is assigned to the PSPNUM after an arithmetic operation using the Operation property. How PSPNUM responds in this case is determined by the OverflowCode property.

The OverflowKey and OverflowCode properties allow the following values:

Property Value	What happens when overflow occurs
0 - TruncateBeep	The excess high-order digit(s) are truncated i.e. chopped off. For example, 1234.00 simply becomes 234.00. The new truncated value is assigned to the number. The system also beeps.
1 - Truncate	Same as above, but no beep.
2 - IgnoreBeep	The new value (excess high-order digits and all other digits) is ignored. The value of the number does not change. The system also beeps.
3 - Ignore	Same as above, but no beep.
4 - GenEvent	The new value (excess high-order digits and all other digits) is ignored. The value of the number does not change. An event (OverflowKey or OverflowCode) is generated. This event has a string parameter called NewValue. This is the unformatted numeric value (including excess high-order digits) that has been ignored.
5 - BumpBeforeDP	PSPNUM automatically increments the DigitsBeforeDP value to accomodate the new numeric value, which is immediately assigned. Any increase to DigitsBeforeDP is permanent i.e. DigitsBeforeDP is not automatically reduced later if smaller numeric values are assigned to the number. If the DigitsBeforeDP limit (37) is reached, then further overflow is treated the same as 4 - GenEvent above. Note that the text box displaying the Text property is not resized automatically to cater for a larger displayed value when DigitsBeforeDP is incremented.

Typically you may want to ignore numeric values that trigger overflow. The values 2-4 in the table above allow you to do this. Automatically incrementing DigitsBeforeDP (value 5 in table above) makes sense only if the rest of your application can live with an incremented DigitsBeforeDP.

A truncated numeric value (values 0 and 1 in table above) may be quite acceptable in certain circumstances. For example, you may deliberately isolate the fractional portion of one number by assigning it's value to another number which has DigitsBeforeDP set to zero.


NumID Property
2.8 NumID Property

See also: Table of Properties.

This property is automatically set for each PSPNUM control. It is a simple sequential number (starting at 1) which provides a unique global identifier for each PSPNUM control. The PSPNUM control maintains a set of internal arrays where it stores data about each PSPNUM. The NumID value is the index to these internal arrays. The maximum size of these arrays determines how many PSPNUMs in total may be active (on loaded forms). For demonstration versions of PSPNUM this is quite low - around 20. For fully licensed versions of PSPNUM this is much higher e.g. 1024.

Apart from providing a count of the total number of active PSPNUM controls, the NumID property is required for operations on PSPNUMs - discussed further on following pages.


Operation, NumID1, NumID2 and ParmString Properties
2.9 Operation, NumID1, NumID2 and ParmString Properties

See also: Table of Properties.

The Operation property specifies what operation to perform on a number. The Operation property is used in conjuction with the NumID1 and/or NumID2 and/or ParmString properties. These identify required parameters for the operation. This is best illustrated with a VB code fragment as follows:

'***************************************************

' Assume two PSPNUMs called Balance and Transaction.

' We want to add Transaction value to Balance value.

'***************************************************

' First identify Transaction as a parameter for

' the Balance operation. In this case we will use

' NumID1 (first parameter).

Balance.NumID1 = Transaction.NumID

' Then do the operation for Balance.

Balance.Operation = "Add1"

'***************************************************

' Now assume we want to double the Balance.

'***************************************************

' Use string parameter to hold constant value.

Balance.ParmString = "2"

' Then do the operation for Balance.

Balance.Operation = "Mult"

You always set the Operation property for the PSPNUM which is to be updated (e.g. Balance) not for a parameter (e.g. Transaction). The actual values you can set for Operation (such as 'Add1' and 'Mult' above) are predetermined by PSPNUM. Permissible values are discussed in section 4.5 Table of Number Operations and 4.6 Table of Numeric Array Operations.

Operations take between zero and two parameters. For example:

1) the 'AssnZero' operation simply zeroises the PSPNUM value with no parameter required,

2) the 'Add1' operation above requires one parameter (NumID1),

3) the 'Add12' operation requires two parameters (both NumID1 and NumID2 properties).

If an operation requires parameters, you must always set these (by assigning to the NumID1, NumID2 or ParmString properties) before you set the Operation property for the actual operation to be performed. The value you assign to NumID1/NumID2 must be the NumID of a parameter PSPNUM. You should never assign any other value to NumID1/NumID2. The value you assign to the ParmString property can be any number in a string with optional leading/trailing sign and a decimal place determined by the DV component of the Mask property. Section 2.14 of this manual shows how you can respond to ParmString errors using the ParmError property.

Section 7 PSPNUM Programming Examples provides many more examples of VB code showing uses of the Operation and NumID1/NumID2/ParmString properties.

The Operation, NumID1, NumID2 and ParmString properties may only be set in program code i.e. they do not appear in the PSPNUM Properties window at design-time.


CompareResult Property
2.10 CompareResult Property

See also: Table of Properties.

You specify operations by setting a value for the Operation property. Most PSPNUM operations manipulate the PSPNUM numeric value e.g. via simple decimal arithmetic. However other operations produce a logical result e.g. from a logical comparison of the number value to zero. For these operations, PSPNUM sets CompareResult to TRUE or FALSE to show the result of the comparison. You can then test the value of CompareResult in your program code and execute whatever conditional program logic is required.

Like the Operation property, the CompareResult property may only be used in program code i.e. it does not appear in the PSPNUM Properties window at design-time.


SelStart, SelLength and SelText Properties
2.11 SelStart,SelLength and SelText Properties

See also: Table of Properties.

These three properties relate to characters selected in the PSPNUM edit box i.e. one or more characters selected for the PSPNUM Text property. None of them are available at design-time i.e. they do not appear in the PSPNUM Properties window.

SelStart is the first position of the selected characters (zero value indicates first position in Text). SelLength is the number of characters selected (zero value indicates no selection). Neither SelStart nor SelLength may be negative. SelStart can not exceed the number of characters in the Text property.

You can set the selection range (set SelStart and SelLength) in one of three ways:

1) assign to the properties in your program code,

2) click with a mouse on a character in the Text then drag the mouse cursor over other characters,

3) position the caret at a character in the Text then hold down the Shift key and move the caret (e.g. via arrow keys) over other characters.

In all cases the selection range is highlighted. The selection remains in effect until you reset it e.g. by another keystroke or mouse click. If there is no selection range (SelLength is zero), then SelStart simply indicates the position of the caret in the Text property. Changing SelStart sets SelLength to zero.

SelText is the actual selected text value. This is NULL if there is no selection i.e. SelLength is zero.

You can assign to SelText in program code. This is treated the same as pasting to a selected Text range. Any current selection range is first deleted. Then digits (0-9 only) from the SelText string (or clipboard string if pasting) are copied into the Text value. Note that only digits are copied - any alphabetic characters (e.g. for sign or decimal place) are ignored. So assigning to SelText only works well for numeric characters. If you want to reliably change the value of a PSPNUM from external data, you can better do this by assigning to the ValueString property in your program code.  Any new value you assign in this way can include part of a string from an external source - with or without alphabetic characters.


ActiveBackColor Property
2.12 ActiveBackColor Property

See also: Table of Properties.

PSPNUM supports the standard properties BackColor and ForeColor. In addition it also has a special ActiveBackColor property.

The ActiveBackColor property specifies the background color to use when the PSPNUM has the input focus. When the PSPNUM does not have the input focus, the standard BackColor property determines the background color.

You can use ActiveBackColor to highlight which control has the input focus. Setting ActiveBackColor once (typically at design -time) is much easier than setting BackColor repeatedly for each control in the standard GotFocus and LostFocus events.

You should exercise a degree of restraint in setting both BackColor and ActiveBackColor properties. In particular, a light/pastel color is advisable for ActiveBackColor. Some colors, particularly those with hatched shading, display badly or not at all. Test for a standard ActiveBackColor then enforce the standard.


EditProtect Property
2.13 EditProtect Property

See also: Table of Properties.

This is a boolean property (has TRUE or FALSE values) which controls whether the user can edit the value displayed in the PSPNUM edit box (i.e. the Text property). If set to FALSE, then the PSPNUM control can still get the input focus, but will then reject with a beep any keystroke as the user attempts to change the value of the displayed Text.


ValueError and ParmError Properties
2.14 ValueError and ParmError Properties

See also: Table of Properties.

The ValueError property controls how PSPNUM responds to any error detected when the ValueString property is set. Similarly, the ParmError property controls how PSPNUM responds to any error detected when the ParmString property is set.

You may assign new ValueString and ParmString property values 1) in the Properties window at design-time or 2) directly in program code at run-time. The ValueString property may also be updated indirectly if the PSPNUM is a bound control.

Any new value you assign to either ValueString or to ParmString must be a valid string number. Apart from digits (0-9), the number may have a leading/trailing sign (+ or -) and a decimal place determined by the DV component of the Mask property. If there are any invalid characters in the string value, these are treated as an error by PSPNUM. For example, you may assign an incorrect value "US$ 100.69" to ValueString whereas the value "100.69" should have been assigned.

 The ValueError and ParmError properties allow the following values:

Property Value	What happens when ValueString/ParmString error occurs
0 - Message	The erroneous ValueString/ParmString value is completely ignored i.e. PSPNUM is not updated. A error message is generated: 28274 for a ValueString error, 28276 for a ParmString error. Both these messages give the position of the first character in error. For example, "ValueString error at position 3".
1 - Event	The erroneous ValueString/ParmString value is completely ignored i.e. PSPNUM is not updated. An event is generated: ValueError event for a ValueString error, ParmError event for a ParmString error. Both these events have two parameters 1) the string value in error, 2) the position of the first character in error.
2 - IgnoreValue	The erroneous ValueString/ParmString value is completely ignored i.e. PSPNUM is not updated. This is done silently - no message or event is generated.
3 - IgnoreChar	Only the error characters in the ValueString/ParmString value are ignored. For example if the string assigned is "US$ 1,000.00CR", then PSPNUM treats this as "1000.00". This is done silently - no message or event is generated. You need to take some care with this option if the sign and position of the decimal place may not be exactly what you expect. For example, any sign specified as DR/CR is completely ignored because PSPNUM is looking for +/-.


Other Standard Properties
2.15 Other Standard Properties

In addition to the preceding properties which are specific to PSPNUM, PSPNUM also supports properties which are common to a range of custom controls. These are listed briefly in the table below. Note that on-line help is available for all these properties if you press F1 on the property name in the Properties window.

Properties	Description
DataField, DataSource	Enable the PSPNUM to be bound to a field in a database via the Data control. Note that PSPNUM allows fields of the following types to be selected via the DataField property: Byte, Binary, Integer, Long, Currency, Single, Double, Text, Memo. Other field types (including Bool and DateTime) are not supported by PSPNUM.
Appearance, BorderStyle	The shape and highlighting (e.g. for a three-dimensional effect) of the border of the PSPNUM edit box.
FontBold.... FontUnderline	A range of properties controlling the font used for characters in the PSPNUM edit box. PSPNUM automatically adjusts the minimum height of the edit box to correlate with the characteristics of the font you select.
ForeColor, BackColor	The color of the displayed characters in the edit box, and of the background pane. See also the special ActiveBackColor property.
Width, Height, Left, Top	The overall size and positioning of the edit box on the form.
TabStop,TabIndex	Whether you can use the tab key to give the PSPNUM the input focus and the relative tab sequence vis-a-vis other tabbed controls.
Tag	Sundry user-identifier for the control.
Index	Uniquely identifies the control in a control array.
Visible, Enabled	Whether the control can be seen on the form (or should be hidden) and whether it responds to user-generated events.
Name	The unique identifier of the control for programming purposes.
DragMode	Controls manual or automatic dragging mode for a drag-and-drop operation.


Changing the value of a single number
3.1 Changing the value of a single number

The table below shows how you can change the value of a single number i.e. a PSPNUM with ArrayDimension set to zero.

Value Changed By	What Happens
Editing the Text property value displayed in the edit box at run-time.	PSPNUM evaluates each keyed character. Valid display characters (0-9,+,-, input decimal place determined by DI component of the Mask property) and nondisplay characters (DEL and BACKSPACE) immediately update the ValueString property. Invalid characters are quietly ignored. Appendix D discusses further how PSPNUM processes your keystrokes in the edit box.
Changing ValueString property 1) in program code at run-time or 2) in the Properties window at design-time.	PSPNUM evaluates the input string which apart from digits (0-9) may have 1) a leading or trailing +/- sign and 2) a single input decimal place determined by the DV component of the PSPNUM Mask property. Any other characters generate an error condition which is dealt with according to the ValueError property setting. If the input string is valid, the Text property is updated provided AutoRefresh property is TRUE.
Change in bound data field value at run-time.	See section 2.15. Treated exactly the same as run-time change to the ValueString property i.e. the new value extracted from the database is assigned internally to the ValueString property.
Changing Text property at run-time.	PSPNUM generates error 28272. This error advises you to assign instead to ValueString property.
Changing Text property in the Properties window at design-time.	Mnemonic only. At design-time, value you set is ignored - PSPNUM does not validate it, format it or process it in any other way. At run-time, the initial value for Text property is determined by the initial value for ValueString property.
Changing Mask property.	No change to ValueString property unless DV component of Mask is reset. New mask details are reflected in changes to the Text property value provided AutoRefresh property is TRUE.
Changing Operation property at run-time.	See section 2.9 and section 4. Successful processing of specified operation may update ValueString in which case Text property also updated provided AutoRefresh property is TRUE.
Changing DigitsBeforeDP or DigitsAfterDP properties.	Any revised numeric value (e.g. for digits dropped) immediately relected in ValueString. Text property also updated provided AutoRefresh property is TRUE. See section 2.2 for further discussion.


Changing the value of a numeric array
3.2 Changing the value of a numeric array

The table below shows how you can change the value of a numeric array i.e. a PSPNUM with ArrayDimension non-zero.

Value Changed By	What Happens
Editing the Text property value displayed in the edit box at run-time.	PSPNUM evaluates each keyed character. Valid display characters  (0-9,+,-, input decimal place determined by DI component of the Mask property) and nondisplay characters (DEL and BACKSPACE) immediately update the current array element and the ValueString property. Invalid characters are quietly ignored. Appendix D discusses further how PSPNUM processes your keystrokes in the Edit Box.
Changing ValueStringproperty 1) in program code at run-time or 2) in the Properties window at design-time.	PSPNUM evaluates the input string which apart from digits (0-9) may have 1) a leading or trailing +/- sign and 2) a single input decimal place determined by the DV component of the PSPNUM Mask property. Any other characters generate an error condition which is dealt with according to the ValueError property setting. If the input string is valid, then 1) at run-time it updates the current element of the numeric array 2) at design-time it updates every element of the numeric array. The Text property is also updated provided AutoRefresh property is TRUE.
Change in bound data field value at run-time.	See section 2.15. Treated exactly the same as run-time change to the ValueString property i.e. the new value extracted from the database is assigned internally to the ValueString property.
Changing Text property at run-time.	PSPNUM generates error 28272. This error advises you to instead assign to ValueString property.
Changing Text property in the Properties window at design-time.	Mnemonic only. At design-time, value you set is ignored - PSPNUM does not validate it, format it or process it in any way. At run-time, initial value for Text property is determined by initialisation value for ValueString property.
Changing Mask property.	No change to ValueString property. New mask details reflected in change to Text property value if AutoRefresh property is TRUE.
Changing Operation property at run-time.	See section 2.9 and section 4. Successful processing of specified operation may change value of current element of numeric array current, in which case ValueString always updated. Text property also updated provided AutoRefresh property is TRUE.
Changing DigitsBeforeDP or DigitsAfterDP properties.	Any change to current element value (e.g. for digits dropped) immediately relected in ValueString. Text property also updated provided AutoRefresh property is TRUE. See section 2.2 for further discussion.
Changing ArrayElement property at run-time.	Changes current element of numeric array. New element value reflected in ValueString. Text property also updated provided AutoRefresh property is TRUE.


Introduction to Operations
4.1 Introduction to Operations

This section discusses in detail the use of the Operation property. The possible values you can set for this property are discussed in tables at the end of this section (see 4.5 and 4.6). Before these detailed tables, certain aspects of PSPNUM operation handling are discussed.

Before you use the Operation property, you need to understand the role of the NumID1,  NumID2 and ParmString properties as parameters. Refer section 2.9 for a short discussion and example. Section 7 PSPNUM Programming Examples provides many more examples of VB code showing possible uses of the Operation and related properties.


Dual-Parameter Arithmetic Operations
4.2 Dual-Parameter Arithmetic Operations

For a number 'A' you can use an operation such as 'Add12' which uses both parameters NumID1 and NumID2. The 'Add12' operation behaves the same as A=B+C in regular procedural code (B, C are parameters).

This is obviously more convenient than two separate single-parameter operations (A=B then A+=C).

Apart from convenience, there is something else to note about dual-parameter arithmetic operations for numbers. They may involve different DigitsBeforeDP/DigitsAfterDP values. For example, 'A', 'B' and 'C' in A=B+C may all have a different number of decimal places. So two separate operations (A=B then A+=C) might not yield the same result as A=B+C if the first operation A=B rounds/truncates the value of B assigned to A. PSPNUM ensures that this does not happen if you use dual-parameter operations. The results are arithmetically correct because PSPNUM internal routines use intermediate values large enough for arithmetic accuracy.

If the PSPNUM is a numeric array (ArrayDimension non-zero), arithmetic accuracy is maintained for dual-parameter operations for any element of the numeric array in the same way as for individual numbers.


Numeric Array Operation Principles
4.3 Numeric Array Operation Principles

Operations for PSPNUM numeric arrays may have numeric arrays and/or single numbers as parameters. To understand what PSPNUM does, you need to distinguish two cases.

Firstly, the case where all parameters for an operation are single numbers i.e. the ParmStringproperty is used or every PSPNUM identified by NumID1 or NumID2 has ArrayDimension zero. Here it is only possible to derive a single numeric value from the parameter (s). For example, the sum of NumID1 and NumID2 can only ever be a single value - never an array of values. Depending upon the operation specified, PSPNUM then assigns the derived value to A) the current element or B) all elements of the array. For example, the 'Add12' operation assigns the sum of NumID1 and NumID2 to the current element of the array, while the 'AddAll12' operation assigns the sum of NumID1 and NumID2 to every element of the array.

Secondly, the case where at least one of the parameters is an array i.e. a PSPNUM identified by NumID1 and/or NumID2 has ArrayDimension positive. Here PSPNUM always derives an array of values from the parameters. For example, if NumID1 and NumID2 are both arrays, then the sum of NumID1 and NumID2 is an array where corresponding elements of NumID1 and NumID2 are added together. PSPNUM then always assigns elements of the derived array - element by element - to the PSPNUM array itself.

There are a few additional points you should know about array processing in PSPNUM:

1) Operations on multiple elements of an array always start with the first element,

2) The array base (ArrayBase property) is irrelevant for operations,

3) Operations on multiple elements in multiple arrays continue until any array has no more elements, all remaining elements in all arrays being ignored.

The following section contains some small code fragments which illustrate the above principles.


Numeric Array Operation Examples
4.4 Numeric Array Operation Examples

Start with the following:

Array A with dimension 5 and values:   {65,4,18,-6,0}

Array B with dimension 6 and values:   {2,84,10,2,-4,12}

Array C with dimension 3 and values:   {100,200,300}

A single number D with value:              {10}

Now consider the effect of Add... operations in the following table (the same principles apply for other operations):

Code Example	New value  of Array A	Comment
A.ArrayElement = 3 A.NumID1 = D.NumID A.Operation = 'Add1'	{65,4,28,-6,0}	Add 10 to current element (3rd) of A.
A.NumID1 = D.NumID A.Operation = 'AddAll1'	{75,14,28,4,10}	Add 10 to every element of A.
A.NumID1 = C.NumID A.Operation = 'Add1'	{165,204,318,-6,0}	Add every element of C to corresponding element of A. Stop at minimum dimension 3, ignoring last two elements of A.
A.NumID1 = B.NumID A.NumID2 = D.NumID A.Operation = 'Add12'	{12,94,20,12,6}	Add single D value 10 to every element of B to derive value {12,94,20,12,6,22}. Assign this derived value to A, ignoring last element with value 22.
A.NumID1 = C.NumID A.NumID2 = B.NumID A.Operation = 'Add12'	{102,284,310,-6,0}	Add each element of B to corresponding element of C to derive value {102,284,310}. Stop at minimum dimension 3. Assign this derived value to A, ignoring last two elements of A.

There are more complete examples of VB code for using PSPNUMs in section 7 PSPNUM programming examples. The table above is merely to help you understand PSPNUM array operations in particular.


Number Operations: Add - DivRem12
4.5 Table of Number Operations

The following table shows what happens when you set a value for the Operation property for a single PSPNUM number (ArrayDimension zero). Note that the Operation value is case-insensitive e.g. 'Add1', 'add1', 'aDD1' and 'ADD1' are the same.

Operation	Effect on this PSPNUM number
Add	Add numeric value in ParmString to this number. Rounding applies.
Add1	Add NumID1 number (current element if NumID1 is a numeric array) to this number. Rounding applies.
Add2	Add NumID2 number (current element if NumID2 is a numeric array) to this number. Rounding applies.
Add12	Assign to this number the result of adding NumID1 and NumID2 numbers (current element if either is a numeric array). Rounding applies.
Assn	Assign numeric value in ParmString to this number. Rounding applies. This is the same thing as assigning to the ValueString property.
Assn1	Assign NumID1 number (current element if NumID1 is a numeric array) to this number. Rounding applies.
Assn2	Assign NumID2 number (current element if NumID2 is a numeric array) to this number. Rounding applies.
AssnRem1	Assign internal remainder from division (from preceding 'DivRem12' operation) to this number. Rounding applies. NumID1 must identify the result (excluding remainder) of the preceding division.
AssnRem2	Assign internal remainder from division (from preceding 'DivRem12' operation) to this number. Rounding applies. NumID2 must identify the result (excluding remainder) of the preceding division.
AssnZero	Assign the value zero to this number.
Div	Divide numeric value in ParmString into this number. Rounding applies. Discard any remainder from division.
Div1	Divide NumID1 number (current element if NumID1 is a numeric array) into this number. Rounding applies. Discard any remainder from division.
Div2	Divide NumID2 number (current element if NumID2 is a numeric array) into this number. Rounding applies. Discard any remainder from division.
Div12	Assign to this number the result of dividing NumID1 number by NumID2 number (current element if either is a numeric array). Rounding applies. Discard any remainder from division.
DivRem12	Assign to this number the result of dividing NumID1 number by NumID2 number (current element if either is a numeric array) without rounding. This is logically the same as 'Div12' operation with Round property set to FALSE. Remainder from this division stored internally for use by subsequent 'AssnRem1' or 'AssnRem2' operation.


Number Operations: isXX - SumAr2
4.5 Table of Number Operations (continued)

Operation	Effect on this PSPNUM number
isXX ('XX' is EQ,NE, GT,LT,GE,LE)	Compare this number to numeric value in ParmString. For example, 'isLE' compares: this number <= ParmString. Assign value TRUE or FALSE to CompareResult property of this number to reflect result of comparison.
isXX1 ('XX' is EQ,NE, GT,LT,GE,LE)	Compare this number to NumID1 number (current element if NumID1 is a numeric array). For example, 'isLE1' compares: this number <= NumID1. Assign value TRUE or FALSE to CompareResult property of this number to reflect result of comparison.
isXX2 ('XX' is EQ,NE, GT,LT,GE,LE)	Compare this number to NumID2 number (current element if NumID2 is a numeric array). For example, 'isLE2' compares: this number <= NumID2. Assign value TRUE or FALSE to CompareResult property of this number to reflect result of comparison.
isXXzero ('XX' is EQ, NE, GT, LT, GE, LE)	Compare this number to the constant value zero. For example, 'isLEzero' compares: this number <= 0. Assign value TRUE or FALSE to CompareResult property of this number to reflect result of comparison.
Mult	Multiply this number by numeric value in ParmString. Rounding applies.
Mult1	Multiply this number by NumID1 number (current element if NumID1 is a numeric array). Rounding applies.
Mult2	Multiply this number by NumID2 number (current element if NumID2 is a numeric array). Rounding applies.
Mult12	Assign to this number the result of multiplying NumID1 and NumID2 numbers (current element if either is a numeric array). Rounding applies.
Sub	Subtract numeric value in ParmString from this number. Rounding applies.
Sub1	Subtract NumID1 number (current element if NumID1 is a numeric array) from this number. Rounding applies.
Sub2	Subtract value of NumID2 number (current element if NumID2 is a numeric array) from this number. Rounding applies.
Sub12	Assign to this number the result of subtracting value of NumID2 number from NumID1 number (current element if either is a numeric array). Rounding applies.
SumAr1	Assign to this number the sum of all elements of NumID1 (which must be a numeric array). Rounding applies.
SumAr2	Assign to this number the sum of all elements of NumID2 (which must be a numeric array). Rounding applies.


Numeric Array Operations: Add - Assn1
4.6 Table of Numeric Array Operations

The following table shows what happens when you set a value for the Operation property for a PSPNUM numeric array (ArrayDimension non-zero). Note that the Operation value is case-insensitive e.g. 'Add1', 'add1', 'aDD1' and 'ADD1' are the same.

Operation	Effect on this PSPNUM numeric array
Add	Add numeric value in ParmString to current element of this numeric array. Rounding applies.
Add1	Add NumID1 number (current element if NumID1 is a numeric array) to current element of this numeric array. Rounding applies.
Add2	Add NumID2 number (current element if NumID2 is a numeric array) to current element of this numeric array. Rounding applies.
Add12	Assign to current element of this numeric array the result of adding NumID1 and NumID2 numbers (current element if either is a numeric array). Rounding applies.
AddAll	Add numeric value in ParmString to every element of this numeric array. Rounding applies.
AddAll1	A) If NumID1 is a number: Add it to every element of this numeric array. Rounding applies. B) If NumID1 is a numeric array: Add every element of NumID1 to corresponding element of this numeric array. Rounding applies.
AddAll2	A) If NumID2 is a number: Add it to every element of this numeric array. Rounding applies. B) If NumID2 is a numeric array: Add every element of NumID2 to corresponding element of this numeric array. Rounding applies.
AddAll12	A) If both NumID1 and NumID2 are numbers: Assign to every element of this numeric array the result of adding NumID1 and NumID2 numbers. Rounding applies. B) If both NumID1 and NumID2 are numeric arrays: Assign to each element of this numeric array the result of adding corresponding elements of NumID1 and NumID2 arrays. Rounding applies. C) If NumID1 is number and NumID2 is numeric array: Assign to each element of this numeric array the result of adding NumID1 to corresponding element of NumID2 array. Rounding applies. D) If NumID1 is numeric array and NumID2 is number: Assign to each element of this numeric array the result of adding NumID2 to corresponding element of NumID1 array. Rounding applies.
Assn	Assign numeric value in ParmString to current element of this numeric array. Rounding applies. This is the same thing as assigning to the ValueString property.
Assn1	Assign NumID1 number (current element if NumID1 is a numeric array) to current element of this numeric array. Rounding applies.


Numeric Array Operations: Assn2 - DivAll1
4.6 Table of Numeric Array Operations (continued)

Operation	Effect on this PSPNUM numeric array
Assn2	Assign NumID2 number (current element if NumID2 is a numeric array) to current element of this numeric array. Rounding applies.
AssnAll	Assign numeric value in ParmString to every element of this numeric array. Rounding applies.
AssnAll1	A) If NumID1 is a number: Assign it to every element of this numeric array. Rounding applies. B) If NumID1 is a numeric array: Assign every element of NumID1 to corresponding element of this numeric array. Rounding applies.
AssnAll2	A) If NumID2 is a number: Assign it to every element of this numeric array. Rounding applies. B) If NumID2 is a numeric array: Assign every element of NumID2 to corresponding element of this numeric array. Rounding applies.
AssnAllZero	Assign the value zero to every element of this numeric array.
AssnRem1	Assign internal remainder from division (from preceding 'DivRem12' operation) to current element of this numeric array. Rounding applies. NumID1 must identify the result (excluding remainder) of the preceding division.
AssnRem2	Assign internal remainder from division (from preceding 'DivRem12' operation) to current element of this numeric array. Rounding applies. NumID2 must identify the result (excluding remainder) of the preceding division.
AssnZero	Assign the value zero to current element of this numeric array.
Div	Divide numeric value in ParmString into current element of this numeric array. Rounding applies. Discard any remainder from division.
Div1	Divide NumID1 number (current element if NumID1 is a numeric array) into current element of this numeric array. Rounding applies. Discard any remainder from division.
Div2	Divide NumID2 number (current element if NumID2 is a numeric array) into current element of this numeric array. Rounding applies. Discard any remainder from division.
Div12	Assign to current element of this numeric array the result of dividing NumID1 number by NumID2 number (current element if either is a numeric array). Rounding applies. Discard any remainder from division.
DivAll	Divide every element of this numeric array by numeric value in ParmString. Rounding applies.
DivAll1	A) If NumID1 is a number: Divide every element of this numeric array by NumID1. Rounding applies. B) If NumID1 is a numeric array: Divide every element of this numeric array by corresponding element of NumID1. Rounding applies.


Numeric Array Operations: DivAll2 - isXXzero
4.6 Table of Numeric Array Operations (continued)

Operation	Effect on this PSPNUM numeric array
DivAll2	A) If NumID2 is a number: Divide every element of this numeric array by NumID2. Rounding applies. B) If NumID2 is a numeric array: Divide every element of this numeric array by corresponding element of NumID2. Rounding applies.
DivAll12	A) If both NumID1 and NumID2 are numbers: Assign to every element of this numeric array the result of dividing NumID1 by NumID2. Rounding applies. B) If both NumID1 and NumID2 are numeric arrays: Assign to each element of this numeric array the result of dividing corresponding element of NumID1 by corresponding element of NumID2. Rounding applies. C) If NumID1 is number and NumID2 is numeric array: Assign to each element of this numeric array the result of dividing NumID1 by corresponding element of NumID2 array. Rounding applies. D) If NumID1 is numeric array and NumID2 is number: Assign to each element of this numeric array the result of dividing corresponding element of NumID1 array by NumID2 number. Rounding applies.
DivRem12	Assign to current element of this numeric array the result of dividing NumID1 number by NumID2 number (current element if either is a numeric array) without rounding. This is logically the same as 'Div12' operation with Round property set to FALSE. Remainder from this division stored internally for use by subsequent 'AssnRem1' or 'AssnRem2' operation.
isXX ('XX' is EQ,NE, GT,LT,GE,LE)	Compare current element of this numeric array to numeric value in ParmString. For example, 'isLE' compares: this numeric array[ArrayElement] <= ParmString. Assign value TRUE or FALSE to CompareResult property of this numeric array to reflect result of comparison.
isXX1 ('XX' is EQ,NE, GT,LT,GE,LE)	Compare current element of this numeric array to NumID1 number (current element if NumID1 is a numeric array). For example, 'isLE1' compares: this numeric array[ArrayElement] <= NumID1. Assign value TRUE or FALSE to CompareResult property of this numeric array to reflect result of comparison.
isXX2 ('XX' is EQ,NE, GT,LT,GE,LE)	Compare current element of this numeric array to NumID2 number (current element if NumID2 is a numeric array). For example, 'isLE2' compares: this numeric array[ArrayElement] <= NumID2. Assign TRUE or FALSE to CompareResult property of this numeric array to reflect result of comparison.
isXXzero ('XX' is EQ,NE, GT,LT,GE,LE)	Compare current element of this numeric array to the constant value zero. For example, 'isLEzero' compares: this numeric array[ArrayElement] <= 0. Assign value TRUE or FALSE to CompareResult property of this numeric array to reflect result of comparison.


Numeric Array Operations: isAllXX - LookUpXX2
4.6 Table of Numeric Array Operations (continued)

Operation	Effect on this PSPNUM numeric array
isAllXX ('XX' is EQ,NE, GT,LT,GE,LE)	Compare every element of this numeric array to numeric value in ParmString. For example, 'isAllNE' compares: this numeric array[All] != ParmString. Assign TRUE or FALSE to CompareResult property of this numeric array to reflect result of comparison.
isAllXX1 ('XX' is EQ,NE, GT,LT,GE,LE)	Compare every element of this numeric array to NumID1 number (current element if NumID1 is a numeric array). For example, 'isAllNE1' compares: this numeric array[All] != NumID1. Assign TRUE or FALSE to CompareResult property of this numeric array to reflect result of comparison.
isAllXX2 ('XX' is EQ,NE, GT,LT,GE,LE)	Compare every element of this numeric array to NumID2 number (current element if NumID2 is a numeric array). For example, 'isAllGT2' compares: this numeric array[All] > NumID1. Assign TRUE or FALSE to CompareResult property of this numeric array to reflect result of comparison.
isAllXXzero ('XX' is EQ,NE, GT,LT,GE,LE)	Compare every element of this numeric array to the constant value zero. For example, 'isAllLEzero' compares: this numeric array[All] <= 0. Assign TRUE or FALSE to CompareResult property of this numeric array to reflect result of comparison.
LookUpXX ('XX' is EQ,NE, GT,LT,GE,LE)	Search the numeric array elements - starting with the current element - for an element which meets the 'XX' requirement compared to the numeric value in ParmString. If a matching element is found, set the CompareResult property to TRUE and the ArrayElement property of this numeric array to the number of the matched element in this numeric array. If no matching element is found, set the CompareResult property of this numeric array to FALSE and leave ArrayElement property the same as before.
LookUpXX1 ('XX' is EQ,NE, GT,LT,GE,LE)	Search the numeric array elements - starting with the current element - for an element which meets the 'XX' requirement compared to the NumID1 number (current element if NumID1 is a numeric array). If a matching element is found, set the CompareResult property to TRUE and the ArrayElement property of this numeric array to the number of the matched element in this numeric array. If no matching element is found, set the CompareResult property of this numeric array to FALSE and leave ArrayElement property the same as before.
LookUpXX2 ('XX' is EQ,NE, GT,LT,GE,LE)	Search the numeric array elements - starting with the current element - for an element which meets the 'XX' requirement compared to the NumID2 number (current element if NumID2 is a numeric array). If a matching element is found, set the CompareResult property to TRUE and the ArrayElement property of this numeric array to the number of the matched element in this numeric array. If no matching element is found, set the CompareResult property of this numeric array to FALSE and leave ArrayElement property the same as before.


Numeric Array Operations: Mult - Subl
4.6 Table of Numeric Array Operations (continued)

Operation	Effect on this PSPNUM numeric array
Mult	Multiply current element of this numeric array by numeric value in ParmString. Rounding applies.
Mult1	Multiply current element of this numeric array by NumID1 number (current element if NumID1 is a numeric array). Rounding applies.
Mult2	Multiply current element of this numeric array by NumID2 number (current element if NumID2 is a numeric array). Rounding applies.
Mult12	Assign to current element of this numeric array the result of multiplying NumID1 and NumID2 numbers (current element if either is a numeric array). Rounding applies.
MultAll	Multiply every element of this numeric array by numeric value in ParmString. Rounding applies.
MultAll1	A) If NumID1 is a number: Multiply every element of this numeric array by NumID1. Rounding applies. B) If NumID1 is a numeric array: Multiply every element of this numeric array by corresponding element of NumID1. Rounding applies.
MultAll2	A) If NumID2 is a number: Multiply every element of this numeric array by NumID2. Rounding applies. B) If NumID2 is a numeric array: Multiply every element of this numeric array by corresponding element of NumID2. Rounding applies.
MultAll12	A) If both NumID1 and NumID2 are numbers: Assign to every element of this numeric array the result of multiplying NumID1 and NumID2 numbers. Rounding applies. B) If both NumID1 and NumID2 are numeric arrays: Assign to each element of this numeric array the result of multiplying corresponding elements of NumID1 and NumID2 arrays. Rounding applies. C) If NumID1 is number and NumID2 is numeric array: Assign to each element of this numeric array the result of multiplying NumID1 by corresponding element of NumID2 array. Rounding applies. D) If NumID1 is numeric array and NumID2 is number: Assign to each element of this numeric array the result of multiplying NumID2 by corresponding element of NumID1 array. Rounding applies.
SortA	Sort array elements into ascending sequence by numeric value. No numeric array property (e.g. ArrayElement property) is updated.
SortD	Sort array elements into descending sequence by numeric value. No numeric array property (e.g. ArrayElement property) is updated.
Sub	Subtract numeric value in ParmString from current element of this numeric array. Rounding applies.
Sub1	Subtract NumID1 number (current element if NumID1 is a numeric array) from current element of this numeric array. Rounding applies.


Numeric Array Operations: Sub2 - SumAr2
4.6 Table of Numeric Array Operations (continued)

Operation	Effect on this PSPNUM numeric array
Sub2	Subtract NumID2 number (current element if NumID2 is a numeric array) from current element of this numeric array. Rounding applies.
Sub12	Assign to current element of this numeric array the result of subtracting NumID2 number from NumID1 number (current element if either is a numeric array). Rounding applies.
SubAll	Subtract numeric value in ParmString from every element of this numeric array. Rounding applies.
SubAll1	A) If NumID1 is a number: Subtract it from every element of this numeric array. Rounding applies. B) If NumID1 is a numeric array: Subtract every element of NumID1 from corresponding element of this numeric array. Rounding applies.
SubAll2	A) If NumID2 is a number: Subtract it from every element of this numeric array. Rounding applies. B) If NumID2 is a numeric array: Subtract every element of NumID2 from corresponding element of this numeric array. Rounding applies.
SubAll12	A) If both NumID1 and NumID2 are numbers: Assign to every element of this numeric array the result of subtracting NumID2 from NumID1. Rounding applies. B) If both NumID1 and NumID2 are numeric arrays: Assign to each element of this numeric array the result of subtracting corresponding element of NumID2 from corresponding element of NumID1. Rounding applies. C) If NumID1 is number and NumID2 is numeric array: Assign to each element of this numeric array the result of subtracting corresponding element of NumID2 array from NumID1 value. Rounding applies. D) If NumID1 is numeric array and NumID2 is number: Assign to each element of this numeric array the result of subtracting NumID2 number from corresponding element of NumID1 array. Rounding applies.
SumAr1	Assign to current element of this numeric array the sum of all elements of NumID1 (which must be a numeric array). Rounding applies.
SumAr2	Assign to current element of this numeric array the sum of all elements of NumID2 (which must be a numeric array). Rounding applies.


Mask Components - Setting
5.1 Setting Mask Components

The Mask property of the PSPNUM controls 1) how the ValueString property of the PSPNUM is displayed as the Text property and 2) the values which can be used for input of decimal places. You can set the Mask property as in the following examples:

Num1.Mask = "[DP.][3S,][NB-][OBUS$ ]"

Num1.Mask = "[ZB*][3S,][PA+][NA-][NB]"

It is generally a good idea to set critical mask values at design-time.

In the string value assigned to Mask, there must be one or more components delimited by [ ]. The first two characters following the opening '[' identify the mask component being set. Any characters after this and before the closing ']' are the new component value. For example, the mask component [DP.] means that the decimal place in an output Text value is being set to '.'. As another example, the mask component [DP and ] would set the same decimal place value to the phrase ' and '.

You may specify any number of components in each mask value. The values remain in effect until reset. So you can set/reset some components once, and reset other components repeatedly. All components are optional (do not have to be set in the Mask), with the exception of the DV component.

You can reset most components to NULL (nothing), by simply including no value. For example, the mask component [NB] sets the component identified by the letters 'NB' to NULL.

Following sections discuss mask components in more detail and show you the effect of masks on the displayed Text value.


Mask Component Identifiers
5.2 Mask Component Identifiers

The mask component identifier is the 2 characters immediately following the opening '[' in each mask component. Most mask components control how parts of the Text value are displayed in the PSPNUM edit box. This is illustrated in the following table:

ID	Characters controlled in Text display
OB	Other (sundry) at very start of value. Example: US$ in US$123.45
NB	-ve sign before digits. Example: - in -123.45
PB	+ve sign before digits. Example: + in +123.45
ZB	zero sign spacer before digits. Example: (NOVALUE)  in (NOVALUE) 0.00
ZL	Leading zero characters in integer digits. Example: *** in ***1.23
3S	Thousand-separator in integer digits. Example: , in 12,345
4S	Ten-thousand-separator in integer digits. Example: , in 123,4567
DP	Decimal place. Example:  and  in 1 and 23
NA	-ve sign after digits. Example: CR in 1.23CR
PA	+ve sign after digits. Example: DR in 1.23DR
ZA	zero sign spacer after digits. Example:  ZERO! in 0.00 ZERO!
OA	Other (sundry) at very end of value. Example:  dollars in 1.23 dollars
In addition, two mask components control how an input decimal place is identified as follows:

ID	Input controlled
DI	Input decimal place keyed in PSPNUM edit box. For example, [DI.] identifies the full-stop character as the input decimal place. When you key a full-stop, PSPNUM takes that keystroke position as being the new decimal place.
DV	Input decimal place in numeric values assigned to the PSPNUM via the ValueString and ParmString properties. For example, [DV.] specifies that in both the ValueString and ParmString property values, the decimal place will be identified by the full-stop character. This is the only compulsory component. If you ever have a Mask value which does not include this component, PSPNUM adds it automatically.


Mask Component Examples
5.3 Mask Component Examples

In the table below, the effect of new mask values are shown for a PSPNUM with DigitsBeforeDP set to 6 and DigitsAfterDP set to 2. Note that mask revisions in the table are cumulative.

Mask set to	-1234.56 displayed in PSPNUM edit-box as:	+1234.56 displayed in PSPNUM edit-box as:	Comment
[DP.][3S,][NB-]	-1,234.56	1,234.56	Suitable for most countries - full-stop decimal place and comma for thousand-separator.
[3S.][DP,]	-1.234,56	1.234,56	Swap output decimal place and thousand-separator (as in some European countries).
[DI,][DV,]	-1.234,56	1.234,56	Also change input decimal place to comma.
[DI.][DV.][DP.] [3S,][PB+]	-1,234.56	+1,234.56	Leading plus sign for +ve values.
[NA-][NB]	1,234.56-	+1,234.56	Move negative sign for -ve values to end.
[PA DR][PB]	1,234.56-	1,234.56 DR	Show +ve values as debit.
[NA CR][NB]	1,234.56 CR	1,234.56 DR	Show -ve values as credit.
[NB(][NA)]	(1,234.56)	1,234.56 DR	Show -ve values within brackets ().
[OBUS$ ]	US$ (1,234.56)	US$ 1,234.56 DR	Use sundry initial characters for currency.
[NA CR][NB]	US$ 1,234.56 CR	US$ 1,234.56 DR	Show -ve values as credit.
[OB][NA]	1,234.56	1,234.56 DR	Drop currency and any indication for -ve value.
[ZL*]	**1,234.56	**1,234.56 DR	Introduce * for leading integer zeroes e.g. for cheque-print.
[ZL][DP $ and ] [OA cents]	1,234 $ and 56 cents	1,234 $ and 56 DR cents	Introduce text for parts of format.


Mask Components - Restrictions
5.4 Restrictions for Mask Components

The following rules apply to mask components:

1)	Each component value may have a maximum of 30 characters, with the exception of the DI and DV components which must each have only one character.
2)	No mask component value may include the characters '[' or ']' or the numeric digits '0' through '9'. If these values are found in a component value they will be ignored.
3)	The DP component can not be set to NULL or blank. That is, you must have at least one non-blank character for any output decimal place.
4)	The DI and DV component (a single character value) can only be set to a printable character other than space, '+', '-', '[' and ']'.
5)	The PB and NB components can not have the same value except if both are NULL.
6)	The PA and NA components can not have the same value except if both are NULL.
7)	The PB, PA, NB and NA components can not all be NULL or blank. That is, you must have at least one distinguishing non-blank character for positive and negative values.
8)	All components get default values when a PSPNUM is initialised. These values are then overridden by the setting of the Mask property. The DI, DP and DV components are defaulted with the 'decimal place' value in the 'International' section of Windows setup. The 3S component is defaulted with the 'thousand separator' value in the 'International' section of Windows setup. If any of these Windows settings are invalid, DI, DP, and DV default to '.' and 3S defaults to ','. All other components are defaulted to NULL.

In addition to the above rules, consider the following recommendations:

1)	Never set DP and 3S/4S components to the same value. PSPNUM may mistake the first thousand-separator for the decimal place.
2)	Avoid setting other mask components to very similar values.
3)	If you want complicated formatting beyond the capabilities of a PSPNUM edit mask, copy the Text or ValueString property to a separate string, then format and display this separately.
4)	Given that any changes to the Text property are immediately applied (not just when the PSPNUM loses the input focus), you may design your application such that your users have an opportunity to ignore any new values they have keyed. For example, only update database fields when an 'OK' button is clicked, or provide a 'Reset' button which restores PSPNUM ValueString properties saved when the form was loaded.
5)	Use the OA and OB values with care. For example, in true multi-currency applications it is probably better to use a completely different control to show/input currency codes rather than trying to use the OA/OB components of the PSPNUM edit mask.

See Appendix D for a discussion of how keystrokes in the PSPNUM edit box (to update Text property) are processed at run-time.


ValueChange and TextChange Events
6.1 ValueChange and TextChange events

PSPNUM has two events which allow you to detect changes to the internal value (ValueString property) and displayed value (Text property). These are the ValueChange and TextChange events respectively.

The ValueChange event may be triggered for one of the following reasons:

1) You set a new value in your program code by assigning to the ValueString property.

2) You change the size of the number (by reducing DigitsBeforeDP or DigitsAfterDP) and the value of the number changes accordingly i.e. digits are dropped from either end of the number.

3) You change the value of the number by keying any valid character (0-9 etc.) into the edit box (Text property).

4) You set a value for the Operation property (e.g. 'Add1') which causes the value of the number to change as a result of the operation.

5) You change the ArrayElement property (if the PSPNUM is an array i.e. has ArrayDimension positive) and the new element has a different numeric value from the old element.

The ValueChange event is based on a strict numeric check i.e. the event is not triggered if the internal numeric value remains the same following one of the above actions. Note also that the event does not depend upon the value of the AutoRefresh property. If this is set to FALSE, then a change in numeric value may not be visible in the PSPNUM edit box. However the ValueChange event is triggered anyway.

The TextChange event may be triggered for one of the following reasons:

1) The numeric value changes (i.e. a preceding ValueChange event has been triggered) and the AutoRefresh property is set to TRUE.

2) The AutoRefresh property is FALSE but you do a one-off refresh using the standard Refresh method.

3) The mask changes (you set/reset the Mask property).


OverflowKey and OverflowCode Events
6.2 OverflowKey and OverflowCode events

These two events arise where numeric values have more digits before the decimal place than the PSPNUM itself e.g. a numeric value of 1234.00 for a number with DigitsBeforeDP set to 3. When such a value is assigned to a number, overflow is said to occur.

Overflow may occur 1) as a result of user keying in the PSPNUM edit box or 2) as a result of operations in your program code. There are two PSPNUM properties (OverflowKey and OverflowCode) which allow you to decide how to respond to these two types of overflow. See section 2.7 for more details of these properties.

Both the OverflowKey and OverflowCode properties allow the value '4 - GenEvent'. If this value is selected then the event of the same name (OverflowKey, OverflowCode) is generated when overflow occurs.

The OverflowKey and OverflowCode events have a string parameter called NewValue. This is the unformatted numeric value (including excess high-order digits) that has been ignored.


ValueError and ParmError Events
6.3 ValueError and ParmError events

You may assign new values to the ValueString and ParmString property values 1) in the Properties window at design-time or 2) directly in program code at run-time. The ValueString property may also be updated indirectly if the PSPNUM is a bound control. These new values must be valid numbers in strings e.g. "123.45-".

The ValueError property controls how PSPNUM responds to any error detected when the ValueString property is set. Similarly, the ParmError property controls how PSPNUM responds to any error detected when the ParmString property is set.

Both the ValueError and ParmError properties allow the value '1 - Event'. If this value is selected then the event of the same name (ValueError, ParmError) is generated when an invalid string number is detected.

The ValueError and ParmError events have two parameters: 1) the string value in error, 2) the position of the first character in error.


Other Standard Events
6.4 Other standard events

In addition to the preceding special events, PSPNUM has a number of events which work in exactly the same way as a standard edit box control. These are:

Click

DblClick

DragDrop

DragOver

GotFocus

KeyDown

KeyPress

KeyUp

LostFocus

MouseDown

MouseMove

MouseUp

To see a description of these standard events in VB, press F1 when a Code Window is open for one of the events. This will then display the standard VB help from where you may obtain further information about events common to a number of standard controls.


Programming Examples
7 PSPNUM programming examples

 This section shows fragments of VB code which demonstrate what you might want to do in VB.

The examples are based on the PSPNUMs used in the demonstration VB project PSPD1.MAK. This has forms which contain six PSPNUMs (Num1, Num2, Num3, NumAr1, NumAr2, NumAr3) with the following important properties set at design-time:

Property	Num1	Num2	Num3	NumAr1	NumAr2	NumAr3
DigitsBeforeDP	5	5	5	3	3	5
DigitsAfterDP	2	2	2	3	1	2
ArrayDimension	0	0	0	4	3	5
ArrayBase	0	0	0	0	0	0
ArrayElement	0	0	0	0	0	0
ValueString	"11.11"	"22.22"	"33.33"	""	""	""
Mask	""	""	""	""	""	""
AutoRefresh	TRUE	TRUE	TRUE	TRUE	TRUE	TRUE
Round	TRUE	TRUE	TRUE	TRUE	TRUE	TRUE
OverflowCode	3 - Ignore	3 - Ignore	3 - Ignore	3 - Ignore	3 - Ignore	3 - Ignore
OverflowKey	3 - Ignore	3 - Ignore	3 - Ignore	3 - Ignore	3 - Ignore	3 - Ignore


Programming Examples: set value, current element
7 PSPNUM programming examples (continued)

How To	Code Example
Change the value of a PSPNUM directly	Sub SetValue ()    ' Change value of Num1 from 11.11 to 77.45    Num1.ValueString = "77.45"    ' Change value of Num1 from 77.45 to -3,879.00    Num1.ValueString = "-3,879.00"    ' Change value of Num1 to value of Num2    Num1.ValueString = Num2.ValueString    ' Change value of current element of NumAr2    NumAr2.ValueString = "35.97-"    ' Change value of current element of NumAr2 to    ' value of current element of NumAr3     NumAr2.ValueString = NumAr3.ValueString End Sub
Determine or set the current element of a numeric array	Sub SetElem ()    ' Check if NumAr3 current element is 2    If (NumAr3.ArrayElement = 2) Then       ' Other code here    End If    ' Set NumAr3 current element to 1    NumAr3.ArrayElement = 1    ' Reset NumAr3 current element to first    NumAr3.ArrayElement = NumAr3.ArrayBase ' Reset NumAr3 current element to last NumAr3.ArrayElement = NumAr3.ArrayBase + NumAr3.Dimension - 1   End Sub


Programming Examples: process all array elements, initialise to zero
7 PSPNUM programming examples (continued)

How To	Code Example
Process all elements of a numeric array	' This procedure checks NumAr1 elements to see if any ' are equal to 76.53. Sub CheckAr ()    ' Local work variables    Dim ElemSave% MaxElem%    ' First save current element    ElemSave% = NumAr1.ArrayElement    ' Initialise current element to first    NumAr1.ArrayElement = NumAr1.ArrayBase    ' Process all elements.    MaxElem% = NumAr1.ArrayBase + NumAr1.Dimension - 1    ' Initialise constant parameter to check    NumAr1.ParmString = "76.53"    Do While (NumAr1.ArrayElement <= MaxElem%)       NumAr1.Operation = "IsEQ"       If (NumAr1.CompareResult = TRUE) Then          ' Other code here       End If       NumAr1.ArrayElement = NumAr1.ArrayElement + 1    Loop    ' Finally restore current element    NumAr1.ArrayElement = ElemSave% End Sub
Initialise PSPNUM values to zero	Sub SetZero ()    ' Change value of Num1 to zero     Num1.ValueString = "0"    ' Change value of Num2 to zero (this method    ' is faster and generally preferable)     Num2.Operation = "AssnZero"    ' Zeroise current element of NumAr2    NumAr2.ValueString = "0"    ' Zeroise current element of NumAr3    NumAr3.Operation = "AssnZero"    ' Zeroise every element of NumAr1 (no loop    ' required in your program)    NumAr1.Operation = "AssnAllZero" End Sub


Programming Examples: compare to zero, compare two values
7 PSPNUM programming examples (continued)

How To	Code Example
Compare PSPNUM values to zero	Sub CheckZero ()    ' For Num1, can check value of 'ValueString' directly    ' but must get string value exactly correct e.g.    ' "0.00" not "0.000"    If (Num1.ValueString = "0.00") Then    End If    ' Otherwise use special method isXXzero    Num1.Operation = "isEQzero"    ' then check result of comparison in CompareResult    If (Num1.CompareResult = TRUE) Then    End If    ' Check if current element of NumAr2 is positive    NumAr2.Operation = "isGTzero"    If (NumAr2.CompareResult = TRUE) Then    End If    ' Check if all elements of NumAr3 are non-positive    ' (no loop required in your program)    NumAr3.Operation = "isAllLEzero"    If (NumAr3.CompareResult = TRUE) Then    End If End Sub
Compare values of two PSPNUMs	' Compare value of Num1 to value of Num2: Sub CompareNums1 ()    ' First provide identifier of Num2 to Num1    Num1.NumID1 = Num2.NumID    ' Then trigger operation for Num1    Num1.Operation = "isEQ1"    ' Finally check result of comparison in CompareResult    If (Num1.CompareResult = TRUE) Then       ' Num1 & Num2 have same value    End If End Sub ' Compare Num1 to current element of NumAr3: Sub CompareNums2 ()    Num1.NumID1 = NumAr3.NumID    Num1.Operation = "isNE1"    If (Num1.CompareResult = TRUE) Then       ' Num1 & NumAr3 have different value    End If End Sub


Programming Examples: search array
7 PSPNUM programming examples (continued)

How To	Code Example
Search a numeric array for a particular value	Sub FindArVal ()    ' Num1 has value to be searched for in NumAr2    NumAr2.NumID1 = Num1.NumID    NumAr2.Operation = "LookUp1"    If (NumAr2.CompareResult = TRUE) Then       ' Successful search, therefore current element       ' of NumAr2 reset       If (NumAr2.ArrayElement = 2)          ' 2nd element has same value as Num1       End If    End If End Sub
Search a numeric array for all occurrences of a particular value	' Check NumAr1 elements: how many greater than a set value. Sub ScanAr ()    Dim ElemSave% MaxElem% Count%    ' First save current element    ElemSave% = NumAr1.ArrayElement    ' NumAr2 current element has GT compare value    NumAr1.NumID1 = NumAr2.NumID    ' Initialise current element to first then    ' process all elements    NumAr1.ArrayElement = NumAr1.ArrayBase    MaxElem% = NumAr1.ArrayBase + NumAr1.Dimension - 1      Do While (NumAr1.ArrayElement <= MaxElem%)       NumAr1.Operation = "LookUpGT1"        ' Exit if no more matching elements       If (NumAr1.CompareResult = FALSE) Then          GoTo Exit       End If       ' Otherwise TRUE, so increment count and resume       ' look-up from next element.       Count% = Count% + 1       NumAr1.ArrayElement = NumAr1.ArrayElement + 1    Loop    Exit:    ' Count% tells how many NumAr1 elements GT NumAr2    If (Count% > 0) Then       ' Other operations here    End If    ' Finally restore current element    NumAr1.ArrayElement = ElemSave% End Sub


Programming Examples: arithmetic operations, rounding/truncation
7 PSPNUM programming examples (continued)

How To	Code Example
Do basic PSPNUM arithmetic operations e.g. add, subtract, multiply, divide	' Note 1: Add same principles as Sub, Mult, Div ' Note 2: NumID1 and NumID2 interchangeable for Add Sub AddNums ()    ' Add constant 10 to Num1    Num1.ParmString = "10"    Num1.Operation = "Add"    ' Add Num2 to Num1 (result in Num1)    Num1.NumID1 = Num2.NumID    Num1.Operation = "Add1"    ' Add Num2 to Num1 (result in Num3)    Num3.NumID1 = Num1.NumID    Num3.NumID2 = Num2.NumID    Num3.Operation = "Add12"    ' Add current element of NumAr3 to current    ' element of NumAr2 (one NumAr2 element updated)    NumAr2.NumID2 = NumAr3.NumID    NumAr2.Operation = "Add2"    ' Add current element of NumAr3 to Num3    ' (sum in current element of NumAr2)    NumAr2.NumID1 = NumAr3.NumID    NumAr2.NumID2 = Num3.NumID    NumAr2.Operation = "Add12"    ' Add elements of Ar3 to corresponding elements    ' of Ar2 (all 3 elements of Ar2 updated)     NumAr2.NumID2 = NumAr3.NumID    NumAr2.Operation = "AddAll2" End Sub
Specify rounding or truncation for PSPNUM arithmetic operations	Sub DivideRound ()   ' Divide Num2 by Num1 and round result   Num2.Round = TRUE ' the default   Num2.NumID1 = Num1.NumID   Num2.Operation = "Div1"   ' Round TRUE remains in effect for   ' Num2 until changed again End Sub Sub DivideTruncate ()   ' Divide Num2 by Num1 and truncate result   Num2.Round = FALSE ' not the default   Num2.NumID1 = Num1.NumID   Num2.Operation = "Div1"   ' Round FALSE remains in effect for   ' Num2 until changed again End Sub


Programming Examples: divide with remainder, display Text property
7 PSPNUM programming examples (continued)

How To	Code Example
Divide and get a remainder	Sub DivideWithRemainder ()    ' Before Values:    ' Num1 = 7.5 Num2 = 3.1 Num3 = 17.0    ' Num3 used for quotient    Num3.NumID1 = Num1.NumID ' Num1 for dividend    Num3.NumID2 = Num2.NumID ' Num2 for divisor    ' Do division (Round for Num3 ignored)    Num3.Operation = "DivRem12"    ' Now assign internal remainder to current element    ' of NumAr1 (with rounding/truncation if needs be)    NumAr1.NumID1 = Num3.NumID    NumAr1.AssnRem1    ' After Values:    ' Num1 = 7.5 Num2 = 3.1 Num3 = 2.41 NumAr1 = 0.029    ' i.e. 7.5 / 3.1 = 2.41 remainder 0.029 End Sub
Prevent/Specify display of Text property value	' In this example, use Num1 as a temporary variable Sub AccumulateSpecial ()    ' Save current value of Num1    Dim SaveValue$    SaveValue$ = Num1.ValueString    ' Now stop Text value of Num1 from displaying    Num1.AutoRefresh = FALSE    ' Now do calculations (invisible to user)    Num1.ValueString = "7.73"    Num1.NumID1 = NumAr2.NumID    Num1.Operation = "Mult1"    Num1.NumID2 = Num3.NumID    Num1.Operation = "Sub2"    ' Save derived value of Num1 to another variable    ' (Note: Can NOT use Num1.Text because this has    ' not been refreshed)    NumAr1.NumID1 = Num1.NumID    NumAr1.Operation = "Assn1"    ' Then reinstate saved value of Num1    Num1.ValueString = SaveValue$    ' Reset Num1 to display Text value from now on    Num1.AutoRefresh = TRUE End Sub


Programming Examples: use/reset Base, numeric overflow
7 PSPNUM programming examples (continued)

How To	Code Example
Use/reset numeric array Base	Sub ArrayBase ()    ' Before: NumAr2 3 elements 0/1/2    NumAr2.ArrayElement = 1 ' OK - second element    NumAr2.ArrayBase = 1970    ' Now: NumAr2 3 elements 1970/1971/1972    NumAr2.ArrayElement = 1 ' Not OK - too low    NumAr2.ArrayElement = 1990 ' Not OK - too high    NumAr2.ArrayElement = NumAr2.ArrayBase ' Always OK End Sub
Prevent/Specify numeric overflow error	' In this example, we want to strip off the Integer ' digits of current element of NumAr1 (has 3 digits ' either side of the decimal place). ' Assume current element value = 123.456 Sub OverflowErr ()    ' Save current value of Num1    Dim SaveValue$    SaveValue$ = Num1.ValueString    ' Now stop Text value of Num1 from displaying    Num1.AutoRefresh = FALSE    ' Assign temporary value to Num1    Num1.ValueString = "1000"    NumAr1.NumID1 = Num1.NumID    ' Do NOT want overflow error for subsequent multiply    NumAr1.OverflowCode = 1  Truncate no beep    ' Multiply by 1000 loses all 3 Integer digits of    ' NumAr1. Value after multiply is 456.000    NumAr1.Operation = "Mult1"    ' Divide by 1000 reinstates Precision digits    ' Value after divide is 000.456    NumAr1.Operation = "Div1"    ' Reinstate overflow error for future operations    NumAr1.OverflowCode = 3  Ignore no beep    ' Then reinstate saved value of Num1    Num1.ValueString = SaveValue$    ' Reset Num1 to display Text value from now on    Num1.AutoRefresh = TRUE End Sub


Programming Examples: run-time DigitsBeforeDP/DigitsAfterDP
7 PSPNUM programming examples (continued)

How To	Code Example
Reset DigitsBeforeDP or DigitsAfterDP	' In this example, we want to strip off the Integer ' digits of every element of NumAr1 (has 3 digits either ' side of the decimal place). ' Assume value of current element = 123.456 Sub StripInt ()    ' Do NOT want overflow error while digits being reset    NumAr1.OverflowCode = 1  Truncate no beep    ' Resetting Integer Digits to zero loses all 3    ' Integer digits of NumAr1. Value of current element    ' afterwards is .456    NumAr1.DigitsBeforeDP = 0    ' Resetting Integer Digits to three reinstates all 3    ' Integer digits of NumAr1. Value of current element    ' afterwards is 000.456    NumAr1.DigitsBeforeDP = 3    ' Reinstate overflow error for future operations    NumAr1.OverflowCode = 3  Ignore no beep End Sub


Numeric Rounding Principles
Appendix A - Numeric rounding principles

This appendix discusses differences between numeric rounding methods: half-adjust for PSPNUM and the method employed by VB Currency data types.

Assume a PSPNUM object 'Num' and a currency data item 'Ccy'. Assume both have 4 decimal places (user-defined for Num, compulsory for Ccy). Call the 5th digit after the decimal place the 'rounding digit' e.g. the 5 in the value 0.61275.

For Num, only the rounding digit itself is important. If 5-9, Num will round up. If 0-4, Num will round down. For example, 0.61275 rounds up to 0.6128 while 0.61274 rounds down to 0.6127. Digits after the rounding digit are irrelevant. For example, all the following will be rounded down: 0.61274, 0.612749, 0.6127491, 0.612749999999, 0.6127499999993.

For Ccy, rounding is different. Firstly, 0.61275 rounds down to 0.6127 not up to 0.6128. The value must be greater than 0.61275 to be rounded up. To see if this is the case, Ccy uses a degree of precision built-in to the data type. So the following will be rounded up: 0.612751, 0.612759, 0.6127501.

The major issue with Ccy rounding is simple - it absolutely requires digits after the rounding digit. For example, to determine that 0.612750000 should be rounded down but 0.612750001 should be rounded up. This immediately raises the question: How many digits after the rounding digit ?. There must always be some number of these digits which will not round correctly because they exceed the absolute maximum that the data item is designed to process.

So Ccy will round differently from Num for:

 1) a rounding value of exactly 5,

 2) some - but not all - values marginally greater than 5.

The half-adjust principle employed by PSPNUM is clear and consistent. Most non-computer people will agree with it (try an accountant at your company). With half-adjust, you can always predict whether rounding will occur or not - it never involves approximations. You do not have to consider issues like 'degrees of precision' as you do with rounding of VB Currency data types.

If you have not considered rounding issues before or have never heard of half-adjust, please accept our assurance that this technique is widely accepted on computer platforms. Even on personal computers, some software tools with built-in decimal data types use half-adjust rounding.

Finally, remember that rounding for a PSPNUM is only one issue that distinguishes it from the VB currency data type. For example, the ability to specify the exact value of DigitsAfterDP (0-37) for a PSPNUM is probably a more important feature to most people than the rounding technique employed.


PSPNUM versus Currency data type
Appendix B - PSPNUM versus Currency data type

The table below summarises the key features of a single PSPNUM number compared to the native Visual Basic 'Currency' data type.

Feature	PSPNUM Number	Currency Data Type
Visual display	Built in to control. Actual numeric values displayed according to edit mask.	Not part of data type - handled through separate control e.g. edit box with or without edit mask.
Number of digits before decimal place	0-37. User-defined for each Number.	Fixed for data type. Always 15.
Number of digits after decimal place	0-37. User-defined for each Number.	Fixed for data type. Always 4 .
Maximum digits	74 in total.	19 in total.
Internal storage of numeric value	Variable number of bytes depending upon user-defined number length (37-digit limits above can easily be increased).	Fixed - 8 bytes.
Choice of arithmetic rounding of low-order digit	Yes. User-defined for each number. Values may be rounded or truncated as desired.	No. Fixed for data type. Values always rounded up.
Technique for arithmetic rounding of low-order digit	Half-adjust (See Appendix A for further discussion).	Not half-adjust (See Appendix A for further discussion).
Error for overflow of high-order digits	User-defined. Several options allowed by setting OverflowCode and OverflowKey properties for each number.	Always generates VB error 6.
Operations	Performed when special property is set in user code.	Performed when standard arithmetic or logical operator is used in code.


PSPNUM Array versus array of Currency data type
Appendix B - PSPNUM versus Currency data type (continued)

In addition to individual numbers, PSPNUM supports arrays of numbers. The table below summarises the key features of a PSPNUM numeric array compared to an array of Visual Basic 'Currency' data types.

Feature	PSPNUM numeric array	Currency Data Type Array
Visual display	Built in to control. Actual numeric value of selected element displayed according to edit mask.	Not part of data type - requires separate control e.g. edit box with or without edit mask.
Multi-dimensional arrays	Each numeric array one dimension only. Arrays of numeric arrays can be defined in user code.	Yes.
Maximum dimension	10000.	32768.
Memory allocated only for used elements	No.	No.
Storage of DigitsBeforeDP and DigitsAfterDP values	Not in every element - only once per numeric array.	Not applicable - Integer length and Precision both fixed (15 and 4 digits respectively).
Operations for individual elements	Yes.	Yes.
Bulk operations for all elements	Yes.	No.


Errors: 28111-28127 and Introduction
Appendix C - PSPNUM Errors

PSPNUM generates error-conditions which you can trap in your code. This is illustrated in section 7 PSPNUM Programming Examples. Under certain circumstances no code exists which can trap an error condition. In this case an error number is displayed in the Text property. For example if an error is detected when a particular PSPNUM control is created, the Edit Box contents might display like this:     Err:28177

Other errors may occur which are PSPNUM internal errors. If you suspect an internal PSPNUM error, we recommend that you reproduce the error in 'clean' conditions first. This may isolate problems, for example, due to another application writing over memory used by our PSPNUMs.

The following table shows all error conditions you may encounter when using PSPNUMs. Note all error numbers are in the range 28100 through 28300. User errors are highlighted with an asterisk.

Error	Text	Cause/Cure
28111	Bad default number format.	A problem with the internal construction of a number. Contact PSP Technical Support.
28112	Bad Dimension	A problem with the internal construction of a numeric array. Contact PSP Technical Support.
28119	Bad Num format.	A problem with the internal construction of a number. Contact PSP Technical Support.
28120	Bad Num IntLen	A problem with the internal construction of a number. A number has been requested with more than 37 digits before the decimal place. Contact PSP Technical Support.
28121	Bad Num Precision	A problem with the internal construction of a number. A number has been requested with more than 37 digits after the decimal place. Contact PSP Technical Support.
28122	Bad Num TotLen	A problem with the internal construction of a number. A number has been requested with more than 74 digits in total. Contact PSP Technical Support.
28123	Bad Num high	A problem with the internal representation of a number. No operations can be applied to it. Contact PSP Technical Support.
28124	Bad Num low	A problem with the internal representation of a number. No operations can be applied to it. Contact PSP Technical Support.
28127	Bad string number	A problem with mapping a string value to the internal representation of a number. Contact PSP Technical Support.


Errors: 28136-28253
Appendix C - PSPNUM Errors (continued)

Error	Text	Cause/Cure
28136*	Divide by zero	Add user code prior to 'div1', 'div12' or 'divrem12' operation to check value of NumID1 or NumID2 being used as divisor.
28162	High index	A problem with the internal indexation of a numeric array. Contact PSP Technical Support.
28164	Low index	A problem with the internal indexation of a numeric array. Contact PSP Technical Support.
28173	Null pointer	A problem with a C/C++ pointer passed to one of our internal routines. Contact PSP Technical Support.
28177*	Out of memory	An internal routine could not successfully allocate a chunk of memory. Given that our code allocates the minimum amount of memory it actually needs (and deallocates memory no longer required), it is likely that there is simply not enough memory available in your current system configuration. You may need to unload other applications or reconfigure your system in some way. If all else fails, you may need to buy and install more physical memory.
28181*	Overflow has occurred	High-order digits would be dropped (overflow has occurred) if a value were to be assigned to a number or to one or more elements of a numeric array. No part of the value has been assigned. You should seldom, if ever, see this error. Any overflow problem should be dealt with based on the values you choose for the OverflowCode and OverflowKey properties.
28182*	Null internal pointer	An internal pointer used to record values is NULL i.e. no value can be recorded. This is highly likely to be because a chunk of memory could not be allocated beforehand (error 28177 above). The PSPNUM should be viewed as unstable. Values recorded will be at best incomplete and at worst corrupt.
28252	NumID is zero or negative	The NumID property (1+) is set automatically. An invalid low value has been encountered. It is possible that you have previously reached a limit on PSPNUM objects (see message 28254 below). Contact PSP Technical Support.
28253	NumID is invalid (too high)	The NumID property (1+) is set automatically. An invalid high value has been encountered. Contact PSP Technical Support.


Errors: 28254-28261
Appendix C - PSPNUM Errors (continued)

Error	Text	Cause/Cure
28254*	N maximum PSPNUM objects reached	The PSPNUM control has an internal limit of N objects (instances of the control). For demo versions of PSPNUM, N is quite low e.g. under 20. For production versions of PSPNUM, N is much higher e.g. 1024. Given the current implementation of a VBX/OCX control, this limit applies to each computer on which the control is loaded. In general terms you should not plan to approach this limit very closely in any one application. Note: If you view this limit in a production version of PSPNUM as unreasonable, please contact PSP Technical Support. The figure of N could well be increased in a new release of the PSPNUM control.
28255*	Invalid Operation Code	You have set the Operation property to a value which PSPNUM is unable to recognise. Check the spelling of the value (probably in a string). Avoid redundant characters e.g. leading/trailing blanks or whitespace.
28256	Internal number could not be constructed successfully	A problem with the internal representation of a number. No operations can be applied to it. Contact PSP Technical Support.
28257*	Can only set ArrayElement if ArrayDimension is positive	The ArrayElement property set at run-time only applies if the PSPNUM is identified as a numeric array rather than a single number.
28258*	ArrayElement too low for numeric array - forced to Base	You have set a value for the ArrayElement property which is less than the value of the ArrayBase property for the numeric array. The array index value is invalid. PSPNUM has reset the value of ArrayElement to be the same as ArrayBase.
28259*	ArrayElement too high for numeric array - forced to Base+Dimension-1	You have set a value for the ArrayElement property which exceeds the last element of the array. The array index value is invalid. PSPNUM has reset the value of ArrayElement to the highest permissible value.
28260*	NumID1 is zero or negative	You have set a value for the NumID1 property which does not identify another PSPNUM. It is possible that you have previously reached a limit on PSPNUM objects (see message 28254 above). No operation can be performed which uses NumID1.
28261*	NumID1 is invalid (too high)	You have set a value for the NumID1 property which does not identify another PSPNUM. The value is too high (exceeds the highest NumID number assigned so far to any PSPNUM). No operation can be performed which uses NumID1.


Errors: 28262-28270
Appendix C - PSPNUM Errors (continued)

Error	Text	Cause/Cure
28262*	NumID2 is zero or negative	You have set a value for the NumID2 property which does not identify another PSPNUM. It is possible that you have previously reached a limit on PSPNUM objects (see message 28254 above). No operation can be performed which uses NumID2.
28263*	NumID2 is invalid (too high)	You have set a value for the NumID2 property which does not identify another PSPNUM. The value is too high (exceeds the highest NumID number assigned so far to any PSPNUM). No operation can be performed which uses NumID2.
28264*	Operation with 'all' only valid for numeric array	You have set a value for the Operation property which includes the letters 'all' e.g. 'AddAll12'. 'All' operations target multiple result values and only apply if the PSPNUM is a numeric array (ArrayDimension is positive).
28265*	NumID1 must be numeric array for SumAr1 operation	The 'SumAr1' operation sums the elements of the numeric array identified by NumID1. The PSPNUM identified by NumID1 must have ArrayDimension positive.
28266*	NumID2 must be numeric array for SumAr2 operation	The 'SumAr2' operation sums the elements of the numeric array identified by NumID2. The PSPNUM identified by NumID2 must have ArrayDimension positive.
28267*	SortA or SortD operation only valid for numeric array	The 'SortA' and 'SortD' operations require the PSPNUM to have ArrayDimension positive (so that there are multiple values to sort).
28268*	LookUp1 or LookUp2 operation only valid for numeric array	The 'LookUp1' and 'LookUp2' operations require the PSPNUM to have ArrayDimension positive.
28269	Internal pointer is NULL.	A problem with the internal storage of values. Contact PSP Technical Support.
28270	Internal pointer is NULL.	A problem with the internal storage of values. Contact PSP Technical Support.


Errors: 28271-28278
Appendix C - PSPNUM Errors (continued)

Error	Text	Cause/Cure
28271	Internal pointer is NULL.	A problem with the internal storage of values. Contact PSP Technical Support.
28272*	Can not set directly (set ValueString instead).	The formatted Text property should not be assigned to at any time. Instead assign any new value you require to the ValueString property.
28273	Internal pointer is NULL.	A problem with parameters received on internal messages. Contact PSP Technical Support.
28274*	Bad ValueString character at position N.	The string assigned to the ValueString property has an invalid character e.g. the 'A' in "-12A.45". The value of N indicates the error character relative to the first position in the string. The entire string has been ignored  i.e. the value of the number has not been changed.
28275*	Out of memory for copy/paste.	PSPNUM has tried to allocate some memory for a cut or paste operation. The memory allocation has failed. See message 28177.
28276*	Bad ParmString character at position N.	The string assigned to the ParmString property has an invalid character e.g. the 'A' in "-12A.45". The value of N indicates the error character relative to the first position in the string. The entire string will be ignored as a parameter for any operation.
28277*	ParmString not set for operation.	The Operation property has been set for an operation (e.g. 'Add') which requires the ParmString property as a parameter. However no value has been set at all for ParmString or the value set was invalid (triggered message 28276). Set valid ParmString before setting Operation.
28278*	OverflowError property no longer supported - please remove from program.	Earlier versions of PSPNUM (2.2 and before) supported a boolean property called OverflowError. This has now been replaced by the multi-value OverflowCode and OverflowKey properties.


Keystrokes - Text property
Appendix D - PSPNUM Text Keystrokes

This appendix discusses what you can key into the PSPNUM edit box at run-time. The value you are actually updating is the PSPNUM Text property.

Your keystrokes are processed according to the following rules:

Moving the caret:

1)	You can use the arrow keys to move the caret (position for next keystroke) left or right. You can use the Home and End keys to jump the caret left or right. Pressing the Home or End key repeatedly oscillates the caret between the very first/last position in the Text and the first/last input-capable position.
2)	You can move the caret to a position which is not input-capable i.e. to non-numeric characters after the last digit 0-9. PSPNUM rejects with a beep any keystroke at this position. When you use the arrow keys, PSPNUM skips the caret over non input-capable positions between the first and last digits 0-9.

Value displayed:

3)	If the number has decimal places defined (DigitsAfterDP property is positive): A) At least one non-blank character is displayed for the decimal place. This is typically a single full-stop '.' but may be any other character(s) depending upon what is set for the DP component in the edit mask (refer section 5 of this manual). B) The numeric value displayed always shows digits for all decimal places. For example, if the number has three decimal places and the value is zero, you see three 0's following the decimal place.
4)	The numeric value displayed always shows at least one digit before the decimal place. If none have been defined for the number (DigitsBeforeDP property is zero), a single 0 is displayed before the decimal place. You can not change this single 0.
5)	Apart from a single 0 for rule 4), the displayed value never includes leading 0's.
6)	In addition to the decimal place, the displayed value may include other non-digit (not 0-9) characters depending upon the setting for edit mask components other than DP e.g. 'CR' for the sign of the number.


Keystrokes - Text property (continued)
Appendix D - PSPNUM Text Keystrokes (continued)

Your keystrokes:

7)	Any valid key immediately updates the Text property. There is no 'confirm input' in the number itself - although there may be a confirm/cancel facility in your application.
8)	The only valid visible keystrokes are '+', '-', 0-9 and the input decimal place i.e. the character determined by the DV component of the edit mask. Any other visible character (e.g. A-Z) is ignored.
9)	You change the sign of the number by keying plus '+' or minus '-' anywhere in the displayed Text.
10)	You can change the relative position of the decimal place by keying a new decimal place anywhere in the displayed value. If the number has no decimal places (DigitsAfterDP is zero), the keyed decimal place is ignored with a beep.
11)	When you key digits (0-9) the value is always in 'insert' mode. That is, the new digits are added to the existing digits. There is no 'overstrike' mode i.e. where new digits replace existing digits.
12)	When you key digits (0-9) before the decimal place, the value scrolls off to the left. That is, digits before the new digit are moved one place left. This may mean that the left-most digit is lost because there are now more digits than the DigitsBeforeDP property allows. In this case the OverflowKey property setting determines how PSPNUM responds.
13)	When you key digits (0-9) after the decimal place, the value scrolls off to the right. That is, digits after the new digit are moved one place right. This may mean that the right-most digit is lost because there are now more decimal places than the DigitsAfterDP property allows. In this case the numeric value is updated without a beep. Note that the value of the Round property has no effect on this behaviour because Round only applies to PSPNUM operations e.g. when the Operation property is set in program code.
14)	You can use the Delete and Backspace keys to delete digits (0-9) only. You can not delete any part of the displayed value (decimal place, sign etc.) which are determined by the edit mask. You can delete a number of digits at one time by selecting them first (e.g. by the Shift and Arrow keys), then immediately hitting either Delete or Backspace or by keying any new value.

Windows Clipboard support:

15)	You can select a range of Text using the Shift and Arrow keys or by dragging the mouse over a range of digits.
16)	The range selection can be copied to the clipboard by the Ctrl+C or Ctrl+Ins key combinations. The range selection will be deleted to the clipboard (copied then deleted) by the Ctrl+X or Shift+Del key combinations.
17)	You can paste from the clipboard into the Text value using the Ctrl+V or Shift+Ins key combinations. Any current range selection is first deleted before pasting. Note that only numeric characters (0-9) are pasted from the clipboard. Alphabetic characters in the clipboard string are ignored.