EDA Eiffel Decimal Arithmetic - User Guide

# Content

1. Introduction
2. Concepts
3. Classes
4. Usage
5. Installation
6. Reference documents

# Introduction

Floating point arithmetic using binary representation does not meet requirements of many application fields like accounting, legal, tax, and more. Many programmers experienced problems using binary floating point arithmetic : loss of accurracy, problems of inexact representation, etc...
Existing databases store a lot of data using decimal representation. Unfortunately, not many languages support decimal arithmetic natively. What's the use of storing decimal data if arithmetic operations do not support this representation?
Thanks to the excellent specification work of Mike Cowlishaw, IBM Fellow, it is now possible to develop a standards-compliant decimal arithmetic library.

EDA is an Eiffel implementation of the "General Decimal Arithmetic Specification" (GDAS, in the rest of this text) version 1.08 (see References, 1).

By following the GDAS, this Eiffel implementation conforms to the requirements of the ANSI/IEEE standard 854-1987, while supporting integer and unrounded floating-point arithmetic as a subset (see GDAS page 1). EDA uses the acceptance tests of IBM, so that the implementation can be trusted.

EDA has been incorporated in the acclaimed GOBO library since 2004.

## Content of the package

    ${GOBO}
       |
       + doc
       |   + math
       |      + decimal             -- index.html
       |
       + example
       |   + math
       |      + decimal
       |         + telco            -- Telco benchmark application

       ...

       + library
       |   + math
       |      + decimal
       |         + abstract
       |         + implementation
       |         + spec

       ...

       + test
       |   + math
       |      + decimal
       |         + acceptance       -- Acceptance/non-regression tests using IBM's test cases
       ...

## GDAS Standard conformance

Arithmetic operations
  abs, add and subtract, compare, divide, divide-integer, max, min, minus, plus, multiply, normalize, remainder, rescale, round-to-integer.
Conversion
  to_scientific_string, to_engineering_string, to_number (as creation routine 'make_from_string').
Context
  7 rounding modes : Round_up, Round_down, Round_ceiling, Round_floor, Round_half_up, Round_half_down, Round_half_even.
Not Implemented
  remainder-near, square-root, power.

## Acknowledgements

Special thanks to Mike Cowlishaw for his work on decimal arithmetic and for the help he provided, answering promptly to many questions. He helped understand the specification. He also helped clarify problems when running the test cases.

# Concepts

Users who want to get the most of this library, should have read thoroughly the GDAS specification.

## Decimal numbers

Decimal numbers can be finite or special.

A finite number has the following characteristics :

sign
  positive or negative
coefficient
  a sequence of digits (0 through 9). This sequence represents a positive integer number, and may not be empty.
exponent
  a signed integer. This is the power of ten by which the coefficient is multiplied.

Finite numbers can be represented by a triad [sign, coefficient, exponent] that fully represent a number.
[0, 2708, -2] represents 27.08;
[1, 1289, 0] represents -1289.

Special numbers are :

Infinity
  A value whose magnitude is infinitely large. It may be positive or negative.
quiet NaN
  Undefined result ("Not a Number"), which shall not raise an Invalid operation signal.
signaling NaN
  Undefined result, which shall raise an Invalid operation signal.

Special numbers can be represented by a diad [sign, symbol] : [1, Inf] is -Infinity; [0, Inf] is +Infinity ; [0, qNaN] is quiet NaN ; [0, sNaN] is signaling NaN.

## Operations

Conversions
  conversion to numeric string in scientific or engineering format : to-scientific-string, to-engineering-string; creation of number from another type : from-integer, from-double, from-string
Arithmetic operations
  abs, add, subtract, compare, divide, divide-integer, max,min, minus, plus, multiply, normalize, remainder, rescale, round-to-integer

## Mathematical context

Nearly all the operations are relative to a mathematical context. A context is the set of parameters and rules which govern the results of arithmetic operations. Those parameters and rules are user-selectable. The next sections contain extracts from the GDAS document.

Digits
  also know as precision. Maximum number of significant digits that can results from arithmetic operations.
Rounding mode
  Algorithm to be used when rounding is necessary, i.e. when a result value has more significant digits than digits.
Flags
  Flags that represent exceptional conditions. A raised flag is known as a signal.
Traps
  A trap can be enabled or disabled. There are as many traps as there are exceptional conditions. An enabled trap raises an exception when the corresponding signal occurs.

### Rounding modes

When a result value has more significant digits than digits, the digits in excess are discarded with respect to the rounding mode.

round-down
  Truncate : just drop the digits in excess.
round-half-up
  If the discarded digits represent greater than or equal to half (0.5) of the value of a one in the next left position then the result should be incremented by 1 (rounded up).
round-half-even
  If the discarded digits represent greater than half (0.5) the value of a one in the next left position then the result should be incremented by 1 (rounded up). If they represent less than half, then the result is not adjusted (that is, the discarded digits are ignored). Otherwise (they represent exactly half) the result is unaltered if its rightmost digit is even, or incremented by 1 (rounded up) if its rightmost digit is odd (to make an even digit).
round-ceiling
  Round toward +Infinity. If all of the discarded digits are zero or if the sign is negative the result is unchanged. Otherwise, the result should be incremented by 1 (rounded up). If this would cause overflow then the result will be +Infinity.
round-floor
  Round toward -Infinity. If all of the discarded digits are zero or if the sign is positive the result is unchanged. Otherwise, the sign is 1 and the coefficient should be incremented by 1. If this would cause overflow then the result will be -Infinity.
round-half-down
  Round to nearest, where a 0.5 case is rounded down.
round-up
  Round away from zero.

### Signals - Exceptional conditions

SIGNAL
  RAISED WHEN ...
division-by-zero
  Non-zero dividend is divided by zero.
inexact
  Result is not exact (one or more non-zero coefficient digits were discarded during rounding).
invalid-operation
  Result would be undefined or impossible.
overflow
  The exponent of a result is too large to be represented.
rounded
  Result has been rounded (that is, some zero or non-zero coefficient digits were discarded).
subnormal
  Result is subnormal (its adjusted exponent is less than Emin), before any rounding.
underflow
  Result is both subnormal and inexact.

# Classes

Class
  Description
MA_DECIMAL
  Decimal numbers whoses operations are specified by GDAS.
MA_DECIMAL_CONTEXT
  Mathematical contexts that hold status flags and various control options like current rounding mode.
MA_SHARED_DECIMAL_CONTEXT
  Objects that give access to a single, shared, decimal context. Decimal operations whose signature do not use an explicit context do use this shared context.

## MA_DECIMAL

sign
  +1 positive, -1 negative.
exponent
  Power of ten by which the (invisible) coefficient is multiplied.
+, -, *, /, //, \\
  Infix operations using shared_decimal_context : add, subract, multiply, divide, divide-integer, remainder respectively.
+, -
  Prefix operations using shared_decimal_context : plus, minus respectively.
is_nan, is_quiet_nan,
is_signaling_nan
  NaN indicators.
is_infinity
  Infinity indicator.
is_special
  Special value indicator.
is_zero
  Zero indicator - shortcut to avoid comparing with zero.
to_double,
to_integer,
to_scientific_string,
to_engineering_string
  Conversion to integer, double, and string representations.
add, subract,
multiply, divide,
divide_integer, remainder
  Operations using an explicit context.
rescale
  rescale to specific exponent.
normalize
  normalize internal representation.
abs, min, max
  abs, min, max relative to implicit shared_decimal_context
abs_ctx, min_ctx, max_ctx
  abs, min, max using explicit context
compare
  three way comparison using explicit context
<, >, <=, >=
  Comparison infix operators using implicit shared_decimal_context.

## MA_DECIMAL_CONTEXT

digits
  maximum number of significant digits.
rouding_mode
  integer value specifying the rounding algorithm to be used.
set_digits
  digits setter.
set_rounding_mode
  rouding_mode setter.
is_flagged (signal)
  Status of signal : is it raised (flagged) ?
is_trapped (signal)
  Is signal trapped ?
exception_on_trap
  Is an exception raised when a trap occurs.
is_extended
  Is the context extended?

Signals are flagged when they occur. If the signal is trapped, then an exception is raised if exception_on_trap is True.

## MA_SHARED_DECIMAL_CONTEXT

Features

shared_decimal_context
  decimal context implicitly used by various operations.
set_shared_decimal_context
  sets the current shared decimal context.
decimal_zero
  Constant zero : neutral element for addition.
decimal_one
  Constant one : neutral element for multiplication.

The default decimal context has the following characteristics : digits = 9, rounding_mode = round_half_up,
is_trapped (Signal_division_by_zero), is_trapped (Signal_invalid_operation),is_trapped (Signal_overflow), is_trapped (Signal_underflow).

# Usage

### Local Definitions for the code

    	a, b, c, d, r : MA_DECIMAL
    	ctx, dbl_ctx : MA_DECIMAL_CONTEXT

### Creation

    	--| using a default decimal context for general purpose arithmetic (IEEE 854),
    	create a.make_from_integer (4)
    	create b.make_from_string ("314e-2")

    	--| using an explicit double precision decimal context
    	create ctx.make_double
    	create a.make_from_string_ctx ("3.141598", ctx)

### Basic Operations

    	create dbl_ctx.make_double

    	--| using explicit context
    	a := a.multiply (b, dbl_ctx)

    	--| using implicit shared decimal context
    	--| set desired context first
    	set_shared_decimal_context (dbl_ctx)

    	r := a * b + c \\ d

### Code fragment using shared context and infix operations

    --| establish math contexts
    create price_context.make_double
    price_context.set_digits (31)
    price_context.set_rounding_mode (price_context.Round_half_even)
    tax_context := price_context.cloned_object
    tax_context.set_rounding_mode (tax_context.Round_down)
    create default_context.make_double
    default_context.set_digits (31)

    ...

    --| 1. Price
    set_shared_decimal_context (default_context)
    if long_distance then
    	price := number * distance_rate
    	long_distance_count := long_distance_count + 1
    else
    	price := number * base_rate
    end
    price := price.rescale (-2, price_context)
    if tax then
    	--| 2. Basic tax
    	set_shared_decimal_context (tax_context)
    	base_tax := price * base_tax_rate
    	base_tax := base_tax.rescale (-2, tax_context)
    	sum_b := sum_b + base_tax
    	total_price := price + base_tax
    	--| 3. Long distance calls
    	if long_distance then
    		distance_tax := price * distance_tax_rate
    		distance_tax := distance_tax.rescale (-2, tax_context)
    		sum_d := sum_d + distance_tax
    		--| 4. total price
    		total_price := total_price + distance_tax
    	end
    else
    	total_price := price
    end

### Conversion

    	print ("Scientific representation : ")
    	print (a.to_scientific_string)

    	print ("Engineering representation : ")
    	print (b.to_engineering_string)

With a = b = [1,123,-12], the output is

    Scientific representation : -1.23e-10
    Engineering representation : -123e-12

# Installation

PLATFORMS
  Should run on any platform.
COMPILERS
  Any GOBO supported Eiffel compiler.

1. Create an application
   - Create a ECF project definition, and add the library the ${GOBO}/library/math/library.ecf
   - Create a 'build.eant' file.
2. Generate the application : Automate build with geant.

EDA has currently been tested using

- ESI EiffelStudio 5.2, 5.3, 5.4 (Win32, Linux)
- SmartEiffel 1.0, 1.1 (Win32, Linux),
- Visual Eiffel v4.1 (Win32, Linux)

.NET acceptance tests have no errors but MA_DECIMAL_CONTEXT flags for comparison operations are not set correctly.

# Reference Documents

1. GDA Specification
  "General Decimal Arithmetic Specification" version 1.08, Mike Cowlishaw, IBM UK Laboratories.
2. GOBO Library
  http://sourceforge.net/projects/gobo-eiffel; https://www.gobosoft.com.
3. Decimal Arithmetic
  "IBM's site dedicated to Decimal Arithmetic" : http://www2.hursley.ibm.com/decimal.
4. Acceptance Tests specification
  IBM's acceptance tests specification documentation, whose version is in sync with GDAS 1.08.