DEC64

dec64.asm

dec64.asm is a software implementation of elementary operators of DEC64 for x64 processors. (obj listing)

dec64.h includes C function prototypes for these functions:

Three types are provided:

These constants are also provided:

The comparison functions will return either DEC64_TRUE or DEC64_FALSE.

nan

nan (not-a-number) is a popular but poorly named concept in floating-point systems. It is a number value that represents numbers that are undefined or not representable. DEC64 has 72 057 594 037 927 936 possible nan values. When these functions return a nan value, they will always return DEC64_NULL, the normal nan, regardless of the input.

Two nan values, DEC64_TRUE and DEC64_FALSE, are reserved for representing boolean values.

The remaining nan values may be used to hold object pointers or other useful values.

These operations will produce a result of DEC64_NULL:

dec64_abs(nan)
dec64_ceiling(nan)
dec64_dec(nan)
dec64_floor(nan)
dec64_half(nan)
dec64_inc(nan)
dec64_int(nan)
dec64_neg(nan)
dec64_normal(nan)
dec64_signum(nan)

These operations will produce a result of DEC64_ZERO for all values of n, even if n is nan:

dec64_divide(0, n)
dec64_integer_divide(0, n)
dec64_modulo(0, n)
dec64_multiply(0, n)
dec64_multiply(n, 0)

These operations will produce a result of DEC64_NULL for all values of n except 0:

dec64_divide(n, 0)
dec64_divide(n, nan)
dec64_integer_divide(n, 0)
dec64_integer_divide(n, nan)
dec64_modulo(n, 0)
dec64_modulo(n, nan)
dec64_multiply(n, nan)
dec64_multiply(nan, n)

These operations will produce a result of DEC64_NULL for all values of n:

dec64_add(n, nan)
dec64_add(nan, n)
dec64_divide(nan, n)
dec64_integer_divide(nan, n)
dec64_modulo(nan, n)
dec64_round(n, nan)
dec64_round(nan, n)
dec64_subtract(n, nan)
dec64_subtract(nan, n)

Zero

DEC64 has 255 zero values. DEC64 treats them as if they are all equal to each other. The only zero value returned from these functions is the normal zero, DEC64_ZERO, which is the same as the native int64 zero, 0.

Functions

Rounding is to the nearest value. Ties are rounded away from zero. Integer division is floored. The result of dec64_modulo has the sign of the divisor. There is no negative zero.

dec64_abs(number: dec64) returns absolution: dec64

The absolute value function removes the sign from a number value.

If number is   return
  nan DEC64_NULL
  zero DEC64_ZERO
  positive number
  negative -number

dec64_add(augend: dec64, addend: dec64) returns sum: dec64

The add function adds an augend and an addend and returns the sum. If either is nan, or if the sum is not representable, then the result is DEC64_NULL.

dec64_ceiling(number: dec64) returns integer: dec64

The ceiling function returns the smallest integer that is greater than or equal to the number. If the number is nan, the result is DEC64_NULL. If the number is zero, the result is DEC64_ZERO. If the number is an integer, the result is the number.

dec64_coefficient(number: dec64) returns coefficient: int64

A DEC64 number is made up of two parts: a coefficient and an exponent.

63 87 0
coefficient exponent

This function returns the coefficient part as an int64.

dec64_coefficient(DEC64_NULL)

returns 0.

dec64_dec(augend: dec64) returns difference: dec64

The decrement function subtracts 1 from a number. That can be faster than

dec64_subtract(augend, DEC64_ONE)

dec64_divide(dividend: dec64, divisor: dec64) returns quotient: dec64

This function divides the dividend by the divisor.

dec64_exponent(number: dec64) returns exponent: int64

A DEC64 number is made up of two parts: a coefficient and an exponent.

63 87 0
coefficient exponent

This function returns the exponent part as an int64.

dec64_exponent(nan)

returns -128.

dec64_floor(number: dec64) returns integer: dec64

Produce the largest integer that is less than or equal to the number. This is sometimes called the entier function. In the result, the exponent will be greater than or equal to zero unless it is DEC64_NULL. Numbers with positive exponents will not be modified, even if the numbers are outside of the safe integer range.

dec64_half(dividend: dec64) returns quotient: dec64

Divide a dec64 number by two. This will always be faster than

dec64_divide(dividend, dec64_new(2, 0))

dec64_inc(augend: dec64) returns sum: dec64

The increment function adds 1 to a number. That can be faster than

dec64_add(augend, DEC64_ONE)

dec64_int(number: dec64) returns integer: dec64

Convert the number such that the exponent will be zero, discarding the fraction part. It will produce nan if the result cannot be represented in 56 signed bits. This is used to extract an int56 from a dec64 for bitwise operations. It accepts a broader range than the safe integer range:

-36028797018963968 thru 72057594037927935

dec64_integer_divide(dividend: dec64, divisor: dec64) returns quotient: dec64

Divide, with a floored integer result. It produces the same result as

 dec64_floor(dec64_divide(dividend, divisor))

but can sometimes produce that result more quickly.

dec64_is_equal(comparahend: dec64, comparator: dec64) returns comparison: dec64

Compare two numbers. If they are exactly equal, return DEC64_TRUE, otherwise return DEC64_FALSE. Denormal zeros are equal but denormal nans are not.

dec64_is_false(boolean: dec64) returns comparison: dec64

If the boolean is DEC64_FALSE, the result is DEC64_TRUE. Otherwise, the result is DEC64_FALSE. This is similar to the not function.

dec64_is_integer(number: dec64) returns comparison: dec64

If the number contains a non-zero fractional part or if it is nan, return DEC64_FALSE. Otherwise, return DEC64_TRUE.

dec64_is_less(comparahend: dec64, comparator: dec64) returns comparison: dec64

Compare two numbers. If the comparahend is less than the comparator, return DEC64_TRUE, otherwise return DEC64_FALSE. Any nan is greater than any number. All nan values are equal to each other.

The other 3 comparison functions are easily implemented with dec64_is_less:

dec64_is_greater(a, b)          => dec64_is_less(b, a)
dec64_is_greater_or_equal(a, b) => dec64_is_false(dec64_is_less(a, b))
dec64_is_less_or_equal(a, b)    => dec64_is_false(dec64_is_less(b, a))

dec64_is_nan(number: dec64) returns comparison: dec64

If the number is any nan, return DEC64_TRUE, otherwise return DEC64_FALSE. To test if a number is the normal DEC64_NULL, just use ==.

dec64_is_zero(number: dec64) returns comparison: dec64

If the number is any zero, return DEC64_TRUE, otherwise return DEC64_FALSE. To test if a number is DEC64_ZERO, use ==.

dec64_modulo(dividend: dec64, divisor: dec64) returns modulus: dec64

The modulo function produces the same result as

dec64_subtract(
    dividend,
    dec64_multiply(
        dec64_integer_divide(dividend, divisor),
        divisor
    )
)

dec64_multiply(multiplicand: dec64, multiplier: dec64) returns product: dec64

Multiply two numbers.

dec64_neg(number: dec64) returns negation: dec64

Negate a number.

dec64_new(coefficient: int64, exponent: int64) returns number: dec64

A DEC64 number is made up of two parts: a coefficient and an exponent.

63 87 0
coefficient exponent

Construct a new dec64 number with a coefficient and an exponent.

dec64_normal(number: dec64) returns normalization: dec64

Normalize the number by making the exponent as close to zero as possible without losing any signficance. Usually normalization is not needed since it does not materially change the value of a number.

dec64_round(number: dec64, place: dec64) returns quantization: dec64

Round the number. Ties are rounded away from zero.

The place determines which decimal place to round to. The place should be between -16 and 16.

place round to nearest
-2 cent
0 integer
3 thousand
6 million
9 billion

dec64_signum(number: dec64) returns signature: dec64

If the number is nan, the result is DEC64_NULL. If the number is less than zero, the result is DEC64_NEGATIVE_ONE. If the number is zero, the result is DEC64_ZERO. If the number is greater than zero, the result is DEC64_ONE.

dec64_subtract(minuend: dec64, subtrahend: dec64) returns difference: dec64

Subtract a subtrahend from from a minuend.

MASM

dec64.asm can be processed with Microsoft's ML64.exe. Visual Studio does not have good defaults for building with MASM, and apparently provides no documentation. These hints may be useful:

Platform > x64
Solution Explorer > dec64 > Build Dependencies > Build Customizations... > masm

There might be other assemblers that can process this file, but that has not been tested yet.