The spinoza papers: design of the extra-precision number object 2



[Best viewed in a monospace font such as courier new. Comments
welcome, flamers may flame and be damned.]



number Extra-precision numbers for the spinoza programming
language


This class implements a number object on behalf of the spinoza
programming language. The number object can be a long integer, a
double-precision real number, a real number with "unlimited"
precision, or
a binary expression a op b that represents an operation and its values
that the current version of this class can't solve. The last
expression
may be the top of an evaluation tree, representing an infix formula
that can't be solved.

The rest of this documentation addresses:


* Getting started using the number class
* Properties, methods and events of the number class
* Object state
* Inspection rules
* Multiprocessing considerations
* Change record
* Issues


GETTING STARTED USING THE NUMBER CLASS
--------------------------------

To get started, create an instance of the number class with a start
value. The start value may be a long integer or a double-precision
real
number.


number objNumber = new number((Long)0);
number objNumber = new number((Double)0.0);


After the number is created extended-precision arithmetic may be
performed:


objNumber.add(objNumber2);
objNumber.subtract(objNumber2);
objNumber.multiply(objNumber2);
objNumber.divide(objNumber2);


Each calculation modifies objNumber. objNumber becomes a value in the
narrowest possible form: a long integer, then a double-precision real
number, or a symbolic string. In the last format, the string will be
of two types:


* A single exact (resolved) number INTERNALLY represented all
the
digits of the mantissa and exponent using base 2^64 arrays of
unsigned long digits.

* An unresolved formula using two numbers, either exact or in
turn unresolved, and an arithmetic operator that cannot be
evaluated exactly; at this writing, these values cannot be
evaluated using the above methods.


In this documentation, numbers represented as long, numbers
represented
as double-precision, and resolved symbolic strings are called "exact",
and the unresolved values are just called "unresolved".

For addition, subtraction and multiplication of numbers that are long,
double-precision real, or exact resolved symbolic strings without an
operator, an exact result of the first type is guaranteed.

For division of any values, the result may be of the second type.
Also,
division by zero can of course yield a special NAN (not a number)
value.

Simple optimization is used, mostly to avoid the fact that in this
version, dumb and dumber algorithms are used (baby school addition,
baby school subtraction, repeated addition and repeated subtraction).
Addition or subtraction of zero is not evaluated, leaving the result
unchanged in the object instance. The same optimization is used for
multiplication and division by one. Also, multiplication and division
of long values uses bit shifting.


PROPERTIES, METHODS AND EVENTS OF THE NUMBER CLASS
--------------------

Properties of this class are named in Proper case. Methods are named
using camelCase. Events are named in camelCase and ending in Event.

At startup, the object instance is tested, evaluating several
assertions about its state. If the inspection is failed, the object
instance is marked Unusable.

The inspection may also be called directly using the inspect() method,
and this call will also make the object Unusable if the inspection is
failed.

The dispose() method inspects the instance one last time, gets rid of
any heap objects created on its behalf, and marks the instance
Unusable: for best results, use dispose() when your code no longer
needs the object instance.

Unusability cannot be undone. When the object instance is Unusable,
calling most public properties or method will Throw an error. However,
when the instance is Unusable, you can still:


* Obtain the Name (the name of the object instance)

* Obtain the Usability status (which will be false

* Perform the toString() and object2XML() methods (they will,
however, return error texts)

* Obtain static properties such as ClassName and About

* Perform static methods such as class2XML()


Methods, that do not have otherwise to return a value, will return
true on success and false on failure.

Here is the constructor syntax.


----- public number(long lngValue)
public number(double dblValue)

This method initializes the number to a long or double-precision
value.


Here are the other properties, methods and events of this class.


----- public static string About

This static property returns information about the class.


----- public bool add(number objAddend)

This method adds the value of objAddend to the augend (the object
instance), leaving the sum in the object instance.

If the signs of the object instance and the addend differ, the
subtract() method is used on the absolute values, and the signum of
the
result is set algebraically:


* To signumPositive when the absolute value of a positive
augend
is greater than that of a negative addend

* To signumNegative when the absolute value of a positive
augend
is less than that of a negative addend

* To signumNegative when the absolute value of a negative
augend
is greater than that of a positive addend

* To signumPositive when the absolute value of a negative
augend
is less than that of a positive addend

* To signumZero when the absolute value of any positive or
negative augend is equal to that of any addend


The result is the narrowest possible value: a long integer, a double-
precision real number, or a symbolic string. Since addition is
"closed", the add() method, when given exact inputs, guarantees an
exact result in all cases.


----- public static string class2XML()

This static method returns information about the class as an eXtended
Markup Language string.


----- public static string ClassName

This static property returns the class name "number".


----- public number clone()
public number clone(bool booCloneCheck)

This method clones the object instance. By default, clone() will use
compare() method to verify the clone. Using clone(false) suppresses
this check.


----- public numberComparision compare(number objComparand)

This method compares the object instance and objComparand, returning
the comparision as an enum of type ENUnumberComparision:


* ENUnumberComparision.LT: object instance number is less than
comparand

* ENUnumberComparision.EQ: object instance number is equal to
comparand

* ENUnumberComparision.GT: object instance number is greater
than
comparand

* ENUnumberComparision.undefined: relationship cannot be
determined because one or both objects contain unresolved
number instances


----- public bool dispose()

This method inspects the object (see the inspect() method), gets rid
of
any heap objects created, and marks the object instance not Usable. It
is recommended that code that uses number use dispose() when the
object
instance is no longer needed.


----- public bool divide(number objDivisor)
public bool divide(number objDivisor,
ref number objModulus)

This method divides the value of the object instance by the divisor
(the object instance), leaving the quotient in the object instance.

In the first overload (divide(objDivisor)), the object instance
exposing the method is set to one of the following:

* The exact real number division result. This will be the
narrowest possible representation:

+ A long if possible, then
+ A double-precision value is possible, then
+ A resolved symbolicNumber

* An unresolved symbolicNumber with its operator set to divide

* NAN (not a number).

In the second overload (divide(objDivisor, ref objModulus)) the object
instance is set to the long or symbolic integer quotient of itself
and
objDivisor when the division can be performed.

A new number instance, objModulus, is assigned to the reference
parameter, and it contains the division remainder. Here, if the
division is unresolvable, the exposing object instance is set to an
unresolved symbolic string or NAN (not a number) and objModulus is
set to null.


----- public bool HasValue

This property returns true when the number is available as a long
integer, a double-precision real number, or as an exect non-NAN
symbolic string with no operators, false otherwise.


----- public bool inspect(ref string strReport)

This method inspects the object, creating an inspection report in
strReport. The inspection rules appear in the next section. If the
inspection is failed, the object is marked unusable and false is
returned.


----- public bool mkUnusable()

This method makes the object unusable.


----- public bool multiply(number objMultiplier)

This method multiplies the value of objMultiplier by the multiplicand
(the object instance), leaving the product in the object instance.

The result is the narrowest possible value: a long integer, a double-
precision real number, or a symbolic string. Since multiplication is
"closed", the multiply() method guarantees a result when the object
instance and objMultiplier are exact.


----- public delegate void progressEndEventDelegate
(number objTaskDoer,
string strTaskName)

The progressEndEventDelegate is called at the normal end of a task.

The objTaskDoer will be the object performing the task.

strTaskName will be the task name.


----- public delegate void progressEventDelegate
(number objTaskDoer,
string strTaskName,
int intEntityNumber)

The progressEventDelegate is called just after or just before one
entity is processed.

The objTaskDoer will be the number object performing the task.

strTaskName should be the task name: it will be the same as the
strTaskName sent by the progressStartEventDelegate.

intEntityNumber will be the sequence number (from 1) of the current
entity.


----- public delegate void progressFailEventDelegate
(number objTaskDoer,
string strTaskName,
string strFailMessage)

The progressFailEventDelegate will be called when the task fails.

The objTaskDoer will be the object performing the task.

strTaskName will be the task name.

strFailMessage will be the reason for failure.


----- public delegate void progressStartEventDelegate
(number objTaskDoer,
thread objThread,
string strTaskName,
string strTask,
string strEntity,
int intEntityCount)

The progressStartEvent occurs just before a loop starts in the code of
the number class.

The objTaskDoer is the number object performing the task.

The objThread is the thread in which the task is being performed.

The strTaskName is used by all progress delegates to identify a task.

The strTask is a task description used only in this delegate.

The strEntity names the entity being processed.

intEntityCount will contain the total number of entities to be
processed.


----- public bool subtract(number objSubtrahend)

This method subtracts the value of objSubtrahend from the the object
instance, leaving the difference in the object instance.

The result is the narrowest possible value: a long integer, a double-
precision real number, or a symbolic string. Since subtraction is
"closed", the subtract() method guarantees a result when the object
instance and objSubtrahend contain exact values.


----- public bool test(ref string strReport)
public bool test(ref string strReport, bool booDeterministic)

This method creates a new instance of the number class, and it runs a
series of tests on this instance.

The first overload runs the same series each time it is run.

The second overload will run a non-determined series of tests when it
is called using test(ref strReport, false).

A test report is placed in strReport; on any test failure, the object
instance running the test is made Unusable.

If the test is failed, the object instance is marked unusable.


----- public bool Usable

This property returns true (object instance is usable) or false.


OBJECT STATE
----------------------------------------------------------

The state of the object is encapsulated within a single instance of
its
private class state. This section develops and discusses the object
state. The code shown won't match the class code exactly because the
class code contains some extra utility fields (usability, toString(),
and so on), not important to this discussion.

Each number has a signum which is 1 for a positive number > 0, 0 for
zero, -1 for negative numbers.


private enum ENUsignum
{
signumPositive, signumZero, signumNegative, unknown
}


The symbolic real structure contains extended precision numbers and
numbers that cannot be represented as long integers or double
precision real numbers. It represents the mantissa and exponent
digits
as arrays of unsigned Long numbers such that each "digit" is
internally
represented in base 2^64.


private struct TYPsymbolicReal
{
bool BOOnulled; // Null structure indicator
ENUsignum BOOmantissaSignum; // Mantissa signum
ulong[] LNGmantissaDigits; // Mantissa value base 2^64
ENUsignum BOOexponentSignum; // Exponent signum
ulong[] LNGexponentDigits; // Exponent value base 2^64
}


For any binary operation that can't be solved exactly as a long or
double-precision number, the result is a "symbolic number",
consisting
of zero, one or two symbolic reals and one unary or binary operator.

Exact values are represented as (nop, operand) where nop is the no-
operation and "operand" is the value as a TYPsymbolicReal.

Unevaluated values are represented as (binaryOp, operand1, operand2)
where binaryOp is one of add, subtract, multiply or divide and
operands
1 and 2 the operands. In turn, operands 1 and 2 may be further
unevaluated values, or they may be exact values, represented as
symbolic real numbers.

Values that cannot mathematically represented as real numbers have the
pseudo-operation NAN (not a number) and no values (null values) in
each
possible operand field.


private enum ENUbinaryOp
{
addOp,
subtractOp,
multiplyOp,
divideOp,
NOP, // Value is in single operand
NAN, // Not a real number (z/0, sqrt(-1))
invalid
}
private class symbolicNumber
{
public ENUbinaryOp ENUop;
public TYPsymbolicReal USRoperand; // Exact single value
public symbolicNumber OBJoperand1; // Uneval'd operand 1
public symbolicNumber OBJoperand2; // Uneval'd operand 2
}


We support longs, double precision reals, and symbolic numbers, of
course.


private enum ENUnumberType
{
longType, doublePrecisionType, symbolicType, unknown
}


The state of the object indicates its usability, its name, its type,
and its value.


private class state
{
public bool BOOusable; // Usability
public string STRname; // Instance name
public ENUnumberType ENUtype; // Number type
public long lngValue; // Value when long
public double dblValue; // Value when real
public symbolicNumber objValue; // Symbolic value
}


INSPECTION RULES
------------------------------------------------------

The object instance must adhere to these rules as checked on startup,
shutdown, and when the inspect() method is called.


* The object instance must be Usable

* The numberType must be long, double, or symbolic

+ When numberType is long, the dblValue in the state must be
zero: the objValue must be null

+ When numberType is double, the lngValue in the state must be
zero: the objValue must be null

+ When numberType is symbolic, the lngValue and dblValue in
the
state must be zero: the objValue must not be null

* The objValue has to conform (when not null) to its own
inspect() rules:

+ It must be Usable (a usability flag is present in the code
but not in the version shown in the preceding section)

+ enuOp must be one of add, subtract, multiply, divide or NOP

- When enuOp is add, subtract, multiply or divide,
OBJoperand1 and OBJoperand2 (the symbolicNumber operands
of
that operator) must be present (non-null): USRoperand
(the
symbolicReal element) must be absent (null).

- When enuOp is NOP, USRoperand (the symbolicReal value)
must
be present: OBJoperand1/2 must be null.

+ OBJoperand1 and OBJoperand2 must pass their own inspections
as symbolicNumbers when not null

+ USRoperand must pass its own inspection as a symbolicReal
when not null:

- It must be Usable
- Its ENUsignums must be valid


MULTIPROCESSING CONSIDERATIONS
----------------------------------------

The object is fully threadable: nonstatic methods and properties may
be used for the same object instance in multiple threads.

To support this, all public procedures and methods call a private
dispatch_() method. This method locks the state, makes sure the object
instance is Usable, and selects a private procedure implementing the
procedure or method logic.



C H A N G E R E C O R D
---------------------------------------------
DATE PROGRAMMER DESCRIPTION OF CHANGE
-------- ----------
---------------------------------------------
05 13 08 Nilges Version 1.0 started

05 23 08 Nilgess V2 of this doc posted to comp.programming


I S S U E S
-----------------------------------------------------------
DATE POSTER DESCRIPTION AND RESOLUTION
-------- ----------
---------------------------------------------
05 15 08 Nilges Evaluation of "nonevaluable" symbolic
strings

Ability to accept strings including math
expressions in constructor

Improve algorithms esp. multiply & divide



.



Relevant Pages

  • The spinoza papers: design of the extra-precision number object v1
    ... In the last format, the string will be ... leaving the result unchanged in the object instance. ... Division by zero returns a symbolicString that is NAN. ... consisting of two symbolic reals and one binary ...
    (comp.programming)
  • ANN: MeObjects Library for Delphi
    ... object type small and powerful. ... the Object instance can use the ClassType method return the ... Especially for lists of pointers to dynamically allocated memory. ... {Summary Adds Ansi String and correspondent object to a list. ...
    (borland.public.delphi.thirdpartytools.general)
  • RE: Formview Replace function: Add LineFeed
    ... it can be used with the vbcrlf when you are ... using VB.NET as the programming language. ... the string, it will return an object instance, so if you want to use string ...
    (microsoft.public.dotnet.framework.aspnet)
  • Re: Call sub or function using a string value for the name
    ... > This will most likely be a string array. ... > VB6 app then needs to run each of the functions. ... >>> a single string to the object instance. ... >>> Bill Baker ...
    (microsoft.public.vb.general.discussion)