# libmawk numerics

Mawk implemented all numeric calculations using double precision floating point numbers. Libmawk has a compile-time option for using different types for numerics, with the following choices available:

- double (default)
- int

## handling exceptions and NaNs

Mawk was geared towards catching floating point errors (such as division by zero or log(-1)) and report a runtime error as soon as possible. Libmawk, targeting embedded script application, should minimize runtime errors by providing means for the script to check for them and recover.

There are multiple approaches for handling suc errors. A design decision has been made for exclusively using NaN (Not a Number) - on platforms where it is not implemented by the FPU or by libc, it's emulated. NaN support shall work the same way for all available numeric types.

Rules about NaN are few and simple:

- 1. NaN should be a sepcial value that can not be mistaken for a valid number by the script
- 2. math library calls (e.g. log()) should return NaN for invalid input; library calls shall accept NaN as input and return NaN as output
- 3. other library functions should handle NaN properly (i.e. printf %f or print shall write "nan" and a string-to-number conversion shall be able to understand "nan")
- 4. if any input of a calculation is NaN, the result shall be NaN (e.g. NaN+1 is NaN); such calculations never cause runtime error
- 5. 1/0, 0/0 and similar corner cases are all NaN - there is no inf
- 6. the only runtime error that may be caused by NaNs is when a conditional jump depends on a NaN (e.g. if (nan) {})
- 7. isnan(x) returns 1 if x is NaN.

In practice this means a block of numeric calculations can be done safely, without checking any input or intermediate results. At the end of the block the result(s) shall be checked with isnan(). As long as the results (even indirectly) depend on an input or intermediate result that is NaN, the result is guaranteed to be NaN too, without the risk of a runtime error.

## Implementation

### type: double

If the system has FPE, it's disabled. If the system does not have native NaN, a special NaN value is defined (using HUGE_VAL) and before each operation all inputs are checked for NaN to make sure the output is NaN too. On systems with NaN ### TODO: inf? ###

### type: int

### TODO: ###

### division by zero

Before divisions input is always checked and division by zero is replaced by a NaN. The same mechanism is in place for all numeric types.