Decimal Arithmetic Specification, version 1.70
Copyright (c) IBM Corporation, 2009. All rights reserved. ©
7 Apr 2009
[previous | contents | next]

Miscellaneous operations

This section describes miscellaneous operations on decimal numbers, including non-numeric comparisons, sign and other manipulations, and logical operations.

The logical operations (and, invert, or, and xor) take logical operands, which are finite numbers with a sign of 0, an exponent of 0, and a coefficient whose digits must all be either 0 or 1.[1]  The length of the result will be at most precision digits (all of which will be either 0 or 1); operands are truncated on the left or padded with zeros on the left as necessary. The result of a logical operation is never rounded and the only flag that might be set is invalid-operation (set if an operand is not a valid logical operand). The operations described are:

Notes:

  1. This section uses the simplified notation introduced in the previous section to illustrate operations.
  2. It is possible to express the results of all these operations as a decimal number or string, but for some implementations other types may be available and might be more efficient.[2]  If an implementation does return types which are not decimal numbers or strings then there must also be conversion operations provided to convert from those types to decimal values or strings, so a wholly decimal usage is possible.
  3. As in the previous section, for any examples below, the context (where relevant) is assumed to have precision set to 9, rounding set to round-half-up, and all trap-enablers set to 0.


and

and is a logical operation which takes two logical operands (see above). The result is the digit-wise and of the two operands; each digit of the result is the logical and of the corresponding digits of the operands, aligned at the least-significant digit. A result digit is 1 if both of the corresponding operand digits are 1; otherwise it is 0.

Examples:

  and(’0’, ’0’)        ==>  ’0’
  and(’0’, ’1’)        ==>  ’0’
  and(’1’, ’0’)        ==>  ’0’
  and(’1’, ’1’)        ==>  ’1’
  and(’1100’, ’1010’)  ==>  ’1000’
  and(’1111’, ’10’)    ==>  ’10’


canonical

canonical takes one operand. The result has the same value as the operand but always uses a canonical encoding. The definition of canonical is implementation-defined; if more than one internal encoding for a given NaN, Infinity, or finite number is possible then one ‘preferred’ encoding is deemed canonical. This operation then returns the value using that preferred encoding.

If all possible operands have just one internal encoding each, then canonical always returns the operand unchanged (that is, it has the same effect as copy). This operation is unaffected by context and is quiet – no flags are changed in the context.

Example:

  canonical(’2.50’)  ==>  ’2.50’


class

class takes one operand. The result is an indication of the class of the operand, where the class is one of ten possibilities, corresponding to one of the strings "sNaN" (signaling NaN), "NaN" (quiet NaN), "-Infinity" (negative infinity), "-Normal" (negative normal finite number), "-Subnormal" (negative subnormal finite number), "-Zero" (negative zero), "+Zero" (non-negative zero), "+Subnormal" (positive subnormal finite number), "+Normal" (positive normal finite number), or "+Infinity" (positive infinity). This operation is quiet; no flags are changed in the context.

Implementations may indicate the class using a more easily tested representation than a string (for example, an integer or an enumeration), but in this case a mechanism for converting that representation to the corresponding class string listed above must be provided.

Finite numbers can only be classified as subnormal if the exponent range is limited (that is, there is a known value for Emin). In the following examples, Emin is assumed to be –999.

Examples:

  class(’Infinity’)   ==>  "+Infinity"
  class(’1E-10’)      ==>  "+Normal"
  class(’2.50’)       ==>  "+Normal"
  class(’0.1E-999’)   ==>  "+Subnormal"
  class(’0’)          ==>  "+Zero"
  class(’-0’)         ==>  "-Zero"
  class(’-0.1E-999’)  ==>  "-Subnormal"
  class(’-1E-10’)     ==>  "-Normal"
  class(’-2.50’)      ==>  "-Normal"
  class(’-Infinity’)  ==>  "-Infinity"
  class(’NaN’)        ==>  "NaN"
  class(’-NaN’)       ==>  "NaN"
  class(’sNaN’)       ==>  "sNaN"
Note that unlike the special values in the model, the sign of any NaN is ignored in the classification, as required by IEEE 754.


compare-total

compare-total takes two operands and compares them using their abstract representation rather than their numerical value. A total ordering is defined for all possible abstract representations, as described below. If the first operand is lower in the total order than the second operand then the result is ’-1’, if the operands have the same abstract representation then the result is ’0’, and if the first operand is higher in the total order than the second operand then the result is ’1’.

The total ordering is defined as follows.

  1. The following items describe the ordering for representations whose sign is 0. If the sign is 1, the order is reversed. A representation with a sign of 1 is always lower in the ordering than one with a sign of 0.
  2. Numbers (representations which are not NaNs) are ordered such that a larger numerical value is higher in the ordering. If two representations have the same numerical value then the exponent is taken into account; larger (more positive) exponents are higher in the ordering.
  3. All quiet NaNs are higher in the total ordering than all signaling NaNs.
  4. Quiet NaNs and signaling NaNs are ordered according to their payload; a larger payload is higher in the ordering.
For example, the following values are ordered from lowest to highest: -NaN -sNaN -Infinity -127 -1.00 -1 -0.000 -0 0 1.2300 1.23 1E+9 Infinity sNaN NaN NaN456.

Examples:

  compare-total(’12.73’, ’127.9’)   ==>  ’-1’
  compare-total(’-127’,  ’12’)      ==>  ’-1’
  compare-total(’12.30’, ’12.3’)    ==>  ’-1’
  compare-total(’12.30’, ’12.30’)   ==>  ’0’
  compare-total(’12.3’,  ’12.300’)  ==>  ’1’
  compare-total(’12.3’,  ’NaN’)     ==>  ’-1’
Notes:
  1. The result of compare-total is always finite, exact, and unrounded.
  2. The compare operation can be used when a numerical comparison of values is required.


compare-total-magnitude

compare-total-magnitude takes two operands and compares them using their abstract representation rather than their numerical value and with their sign ignored and assumed to be 0. The result is identical to that obtained by using compare-total on two operands which are the copy-abs copies of the operands to compare-total-magnitude; that is:
  compare-total-magnitude(x, y)
is given by
  compare-total(copy-abs(x), copy-abs(y))


copy

copy takes one operand. The result is a copy of the operand. This operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  copy(’2.1’)    ==>  ’2.1’
  copy(’-1.00’)  ==>  ’-1.00’


copy-abs

copy-abs takes one operand. The result is a copy of the operand with the sign set to 0. Unlike the abs operation, this operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  copy-abs(’2.1’)   ==>  ’2.1’
  copy-abs(’-100’)  ==>  ’100’


copy-negate

copy-negate takes one operand. The result is a copy of the operand with the sign inverted (a sign of 0 becomes 1 and vice versa). Unlike the minus operation, this operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  copy-negate(’101.5’)   ==>  ’-101.5’
  copy-negate(’-101.5’)  ==>  ’101.5’


copy-sign

copy-sign takes two operands. The result is a copy of the first operand with the sign set to be the same as the sign of the second operand. This operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  copy-sign( ’1.50’,  ’7.33’)  ==>  ’1.50’
  copy-sign(’-1.50’,  ’7.33’)  ==>  ’1.50’
  copy-sign( ’1.50’, ’-7.33’)  ==>  ’-1.50’
  copy-sign(’-1.50’, ’-7.33’)  ==>  ’-1.50’


invert

invert is a logical operation which takes one logical operand (see above). The result is the digit-wise inversion of the operand; each digit of the result is the inverse of the corresponding digit of the operand. A result digit is 1 if the corresponding operand digit is 0; otherwise it is 0.

Examples:

  invert(’0’)          ==>  ’111111111’
  invert(’1’)          ==>  ’111111110’
  invert(’111111111’)  ==>  ’0’
  invert(’101010101’)  ==>  ’10101010’


is-canonical

is-canonical takes one operand. The result is 1 if the operand is canonical; otherwise it is 0. The definition of canonical is implementation-defined; if more than one internal encoding for a given NaN, Infinity, or finite number is possible then one ‘preferred’ encoding is deemed canonical. This operation then tests whether the internal encoding is that preferred encoding.

If all possible operands have just one internal encoding each, then is-canonical always returns 1. This operation is unaffected by context and is quiet – no flags are changed in the context.

Example:

  is-canonical(’2.50’)  ==>  ’1’


is-finite

is-finite takes one operand. The result is 1 if the operand is neither infinite nor a NaN (that is, it is a normal number, a subnormal number, or a zero); otherwise it is 0. This operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  is-finite(’2.50’)  ==>  ’1’
  is-finite(’-0.3’)  ==>  ’1’
  is-finite(’0’)     ==>  ’1’
  is-finite(’Inf’)   ==>  ’0’
  is-finite(’NaN’)   ==>  ’0’


is-infinite

is-infinite takes one operand. The result is 1 if the operand is an Infinity; otherwise it is 0. This operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  is-infinite(’2.50’)  ==>  ’0’
  is-infinite(’-Inf’)  ==>  ’1’
  is-infinite(’NaN’)   ==>  ’0’


is-NaN

is-NaN takes one operand. The result is 1 if the operand is a NaN (quiet or signaling); otherwise it is 0. This operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  is-NaN(’2.50’)   ==>  ’0’
  is-NaN(’NaN’)    ==>  ’1’
  is-NaN(’-sNaN’)  ==>  ’1’


is-normal

is-normal takes one operand. The result is 1 if the operand is a positive or negative normal number; otherwise it is 0. This operation is quiet; no flags are changed in the context.

Finite numbers can only be classified as normal or subnormal if the exponent range is limited (that is, there is a known value for Emin); if Emin is unknown, 1 is returned. In the following examples, Emin is assumed to be –999.

Examples:

  is-normal(’2.50’)      ==>  ’1’
  is-normal(’0.1E-999’)  ==>  ’0’
  is-normal(’0.00’)      ==>  ’0’
  is-normal(’-Inf’)      ==>  ’0’
  is-normal(’NaN’)       ==>  ’0’


is-qNaN

is-qNaN takes one operand. The result is 1 if the operand is a quiet NaN; otherwise it is 0. This operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  is-qNaN(’2.50’)  ==>  ’0’
  is-qNaN(’NaN’)   ==>  ’1’
  is-qNaN(’sNaN’)  ==>  ’0’


is-signed

is-signed takes one operand. The result is 1 if the sign of the operand is 1; otherwise it is 0. This operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  is-signed(’2.50’)  ==>  ’0’
  is-signed(’-12’)   ==>  ’1’
  is-signed(’-0’)    ==>  ’1’


is-sNaN

is-sNaN takes one operand. The result is 1 if the operand is a signaling NaN; otherwise it is 0. This operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  is-sNaN(’2.50’)  ==>  ’0’
  is-sNaN(’NaN’)   ==>  ’0’
  is-sNaN(’sNaN’)  ==>  ’1’


is-subnormal

is-subnormal takes one operand. The result is 1 if the operand is a positive or negative subnormal number; otherwise it is 0. This operation is quiet; no flags are changed in the context.

Finite numbers can only be classified as normal or subnormal if the exponent range is limited (that is, there is a known value for Emin); if Emin is unknown, 0 is returned. In the following examples, Emin is assumed to be –999.

Examples:

  is-subnormal(’2.50’)      ==>  ’0’
  is-subnormal(’0.1E-999’)  ==>  ’1’
  is-subnormal(’0.00’)      ==>  ’0’
  is-subnormal(’-Inf’)      ==>  ’0’
  is-subnormal(’NaN’)       ==>  ’0’


is-zero

is-zero takes one operand. The result is 1 if the operand is a zero; otherwise it is 0. This operation is unaffected by context and is quiet – no flags are changed in the context.

Examples:

  is-zero(’0’)      ==>  ’1’
  is-zero(’2.50’)   ==>  ’0’
  is-zero(’-0E+2’)  ==>  ’1’


logb

logb takes one operand. If the operand is a NaN then the general arithmetic rules apply. If the operand is infinite then +Infinity is returned. If the operand is a zero, then –Infinity is returned and the Division by zero exceptional condition is raised.

Otherwise, the result is the integer which is the exponent of the magnitude of the most significant digit of the operand (as though the operand were truncated to a single digit while maintaining the value of that digit and without limiting the resulting exponent). All results are exact unless an integer result does not fit in the available precision.

Examples:

  logb(’250’)   ==>  ’2’
  logb(’2.50’)  ==>  ’0’
  logb(’0.03’)  ==>  ’-2’
  logb(’0’)     ==>  ’-Infinity’
Note: The scaleb operation can be used to change the exponent of a number.


or

or is a logical operation which takes two logical operands (see above). The result is the digit-wise inclusive or of the two operands; each digit of the result is the logical or of the corresponding digits of the operands, aligned at the least-significant digit. A result digit is 1 if either or both of the corresponding operand digits is 1; otherwise it is 0.

Examples:

  or(’0’, ’0’)        ==>  ’0’
  or(’0’, ’1’)        ==>  ’1’
  or(’1’, ’0’)        ==>  ’1’
  or(’1’, ’1’)        ==>  ’1’
  or(’1100’, ’1010’)  ==>  ’1110’
  or(’1110’, ’10’)    ==>  ’1110’


radix

radix takes no operands. The result is the radix (base) in which arithmetic is effected; for this specification the result will have the value 10.[3] 

Example:

  radix()  ==>  ’10’


rotate

rotate takes two operands. The second operand must be an integer (with an exponent of 0) in the range –precision through precision. If the first operand is a NaN then the general arithmetic rules apply, and if it is infinite then the result is the Infinity unchanged.

Otherwise (the first operand is finite) the result has the same sign and exponent as the first operand, and a coefficient which is a rotated copy of the digits in the coefficient of the first operand. The number of places of rotation is taken from the absolute value of the second operand, with the rotation being to the left if the second operand is positive or to the right otherwise.

If the coefficient of the first operand has fewer than precision digits, it is treated as though it were padded on the left with zeros to length precision before the rotation. Similarly, if the coefficient of the first operand has more than precision digits, it is truncated on the left before use.

The only flag that might be set is invalid-operation (set if the first operand is an sNaN or the second is not valid).

Examples:

  rotate(’34’, ’8’)          ==>  ’400000003’
  rotate(’12’, ’9’)          ==>  ’12’
  rotate(’123456789’, ’-2’)  ==>  ’891234567’
  rotate(’123456789’, ’0’)   ==>  ’123456789’
  rotate(’123456789’, ’+2’)  ==>  ’345678912’
The shift operation can be used to shift rather than rotate a coefficient.


same-quantum

same-quantum takes two operands, and returns 1 if the two operands have the same exponent or 0 otherwise. The result is never affected by either the sign or the coefficient of either operand.

If either operand is a special value, 1 is returned only if both operands are NaNs or both are infinities.

same-quantum does not change any flags in the context. Implementations which support the concept of a boolean type may return true for 1 and false for 0.

Examples:

  samequantum(’2.17’, ’0.001’)  ==>  ’0’
  samequantum(’2.17’, ’0.01’)   ==>  ’1’
  samequantum(’2.17’, ’0.1’)    ==>  ’0’
  samequantum(’2.17’, ’1’)      ==>  ’0’
  samequantum(’Inf’, ’-Inf’)    ==>  ’1’
  samequantum(’NaN’, ’NaN’)     ==>  ’1’


scaleb

scaleb takes two operands. If either operand is a NaN then the general arithmetic rules apply. Otherwise, the second operand must be a finite integer with an exponent of zero[4]  and in the range ±2 × (Emax + precision) inclusive, where Emax is the largest value that can be returned by the logb operation at the same precision setting.[5]  (If is is not, the Invalid Operation condition is raised and the result is NaN.)

If the first operand is infinite then that Infinity is returned, otherwise the result is the first operand modified by adding the value of the second operand to its exponent. The result may Overflow or Underflow.

Examples:

  scaleb(’7.50’, ’-2’)  ==>  ’0.0750’
  scaleb(’7.50’, ’0’)   ==>  ’7.50’
  scaleb(’7.50’, ’3’)   ==>  ’7.50E+3’


shift

shift takes two operands. The second operand must be an integer (with an exponent of 0) in the range –precision through precision. If the first operand is a NaN then the general arithmetic rules apply, and if it is infinite then the result is the Infinity unchanged.

Otherwise (the first operand is finite) the result has the same sign and exponent as the first operand, and a coefficient which is a shifted copy of the digits in the coefficient of the first operand. The number of places to shift is taken from the absolute value of the second operand, with the shift being to the left if the second operand is positive or to the right otherwise. Digits shifted into the coefficient are zeros.

The only flag that might be set is invalid-operation (set if the first operand is an sNaN or the second is not valid).

Examples:

  shift(’34’, ’8’)          ==>  ’400000000’
  shift(’12’, ’9’)          ==>  ’0’
  shift(’123456789’, ’-2’)  ==>  ’1234567’
  shift(’123456789’, ’0’)   ==>  ’123456789’
  shift(’123456789’, ’+2’)  ==>  ’345678900’
The rotate operation can be used to rotate rather than shift a coefficient.


xor

xor is a logical operation which takes two logical operands (see above). The result is the digit-wise exclusive or of the two operands; each digit of the result is the logical exclusive-or of the corresponding digits of the operands, aligned at the least-significant digit. A result digit is 1 if one of the corresponding operand digits is 1 and the other is 0; otherwise it is 0.

Examples:

  xor(’0’, ’0’)        ==>  ’0’
  xor(’0’, ’1’)        ==>  ’1’
  xor(’1’, ’0’)        ==>  ’1’
  xor(’1’, ’1’)        ==>  ’0’
  xor(’1100’, ’1010’)  ==>  ’110’
  xor(’1111’, ’10’)    ==>  ’1101’

Footnotes:
[1] This digit-wise representation of bits in a decimal representation has been used since the 1950s; see, for example, Binary and truth-function operations on a decimal computer with an extract command, William H. Kautz, Communications of the ACM, Vol. 1 #5, pp12-13, ACM Press, May 1958.
[2] For example, the operations which test whether a value is in a particular class might return a boolean.
[3] This might be 1E+1 in the extraordinary case of precision=1.
[4] Strictly speaking this is more restrictive that IEEE 754, which would allow 1E+1 for the second operand; however, it is in the spirit of IEEE 754 also permitting that the second operand be specifiable as an integer.
[5] This Emax is the same as that described in IEEE 754.

[previous | contents | next]