# DEC64: Elementary Operators

This describes a software implementation of the `DEC64` elementary operators. Sources are available for Intel/AMD x64 and ARM64.

dec64.h includes C function prototypes for these functions:

Three types are provided:

• `dec64`
• `int64`
• `uint64`

These constants are also provided:

• `DEC64_NULL`
• `DEC64_ZERO`
• `DEC64_ONE`
• `DEC64_TWO`
• `DEC64_NEGATIVE_ONE`
• `DEC64_TRUE`
• `DEC64_FALSE`

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_floor(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_divide(nan, n)
dec64_integer_divide(nan, n)
dec64_modulo(nan, n)
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

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_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_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`.

### 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.

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. The default is zero.

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.