User documentation for MachineInt
The class MachineInt
is intended to help you write functions which
accept arguments whose type is a machine integer (see Why? below).
We recommend that you use MachineInt
only to specify function
argument types; other uses may result in disappointing performance.
You cannot perform arithmetic directly with values of type MachineInt
.
The primary operations are those for extracting a usable value from a
MachineInt
object:
Operations
Arithmetic directly with MachineInt
values is not possible. The
value(s) must be converted to long
or unsigned long
before
operating on them.
Queries and views
IsZero(n)
-- true iffn
is zeroIsOne(n)
-- true iffn
is oneIsMinusOne(n)
-- true iffn
is minus oneIsNegative(n)
-- true iffn
is negative, if false the value can be extracted as anunsigned long
, if true the value can be extracted as asigned long
IsSignedLong(n)
-- true iffn
can be extracted as asigned long
AsUnsignedLong(n)
-- extractn
as anunsigned long
-- see NOTE!AsSignedLong(n)
-- extractn
as asigned long
-- see NOTE!IsInRange(lo,x,hi)
-- true ifflo
<=x
<=hi
negate(n)
-- return-n
as anunsigned long
(valid only ifIsNegative(n)
)uabs(n)
-- returnabs(n)
as anunsigned long
NOTE: converting to long or unsigned long
You should not call AsUnsignedLong
if the value is negative, nor should
you call AsSignedLong
if the value is large and positive --- currently, an
error is signalled only if debugging is active. Here's an outline of the
recommended usage:
void SomeProcedure(const MachineInt& n) { if (IsNegative(n)) { const long N = AsSignedLong(n); ... } else // n is non-negative { const unsigned long N = AsUnsignedLong(n); ... } }
Why?
The class MachineInt
was created in an attempt to circumvent C++'s
innate automatic conversions between the various integral types; most
particularly the silent conversion of negative signed values into unsigned
ones (which necessarily changes the value).
Various C++ programming style guides recommend avoiding unsigned integer types. Unfortunately values of such types appear frequently as the result of various counting functions in the STL. So it is somewhat impractical to avoid unsigned values completely.
The class MachineInt
employs automatic user-defined conversions to
force all integral values into the largest integral type, viz. long
or
unsigned long
. An extra "sign bit" inside a MachineInt
indicates
whether the value is negative (i.e. must be regarded as a signed long
).
Passing an argument as a MachineInt
is surely not as fast as using a
built in integral type, but should avoid "nasty surprises" which can
arise with C++'s automatic conversions (e.g. a large unsigned long
could
be viewed as a negative long
).
Maintainer documentation for MachineInt
On the whole everything is very simple; the hard part was establishing a reasonable design that interoperates with C++'s overload resolution rules.
An object of type MachineInt
contains two data fields:
myValue
-- the original integer value converted tounsigned long
IamNegative
-- true iff the original value was (signed and) negative
The flag IamNegative
allows the field myValue
to be
interpreted correctly: if IamNegative
is true
then the correct
value of myValue
may be obtained by casting it to a (signed)
long
; conversely, if IamNegative
is false
then the value
of myValue
is correct as it stands (i.e. as an unsigned long
).
Most functions are so simple that an inline implementation is appropriate.
The implementation of the function abs
will work correctly even if
the value being represented is the most negative signed long
.
Note that the C++ standard allows the system to produce an error when
negating a long
whose value is the most negative representable
value; in contrast, operations on unsigned long
values will never
produce errors (except division by zero).
The impl of IsInRange
is a bit involved; it must avoid overflow,
and may not assume anything about the internal representations of
signed and unsigned long values.
Bugs, Shortcomings and other ideas
My biggest doubt is whether this is really the right way to tackle the
problem of silent automatic conversion between long
and unsigned long
.
Anyway, I'm using it (until a better solution comes along).
Arg validity checking happens only if debugging is active.
This will require changes when long long int
becomes commonplace.
Main changes
2015
- October (v0.99540): changed name
abs
touabs
; added fnnegate
. 2011 - November (v0.9949): this class was previously called MachineInteger