Skip to content

Commit

Permalink
Rearrange and update documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
npatrick04 committed Jan 6, 2017
1 parent 1392a52 commit 79ef07e
Showing 1 changed file with 97 additions and 79 deletions.
176 changes: 97 additions & 79 deletions README.md
Expand Up @@ -2,90 +2,22 @@

A Common Lisp fixed-point numeric type package intended to be similar to the Ada language type. The focus is providing a useful abstraction for known reliable precision in a specific range. This package uses CLOS to encapsulate the underlying type.

Also provided is a utility package (:fixed/real-time) providing a portable fixed-point type representing the internal real time.
If the reader macro is installed ```(install-reader-macro)```, then fixed point values can be read without floating point precision issues.

## Syntax

**defdelta** *name delta [:small small-value] [:low low-value] [:high high-value]*

=> *delta-name*

**defdecimal** *name power [:low low-value] [:high high-value]*

=> *decimal-name*

### Arguments
*name* --- a symbol

*delta* --- real number

*power* --- integer

*small-value*, *low-value*, and *high-value* --- optional real numbers

### Description
A small utility package (:fixed/real-time) provides a portable fixed-point type representing the internal real time.

**defdelta** defines a fixed-point number type named *name* capable of representing a value with at least the accuracy provided in *delta*.

If *small-value* is provided in **defdelta**, it must be a real value no greater than *delta*. *small-value* is used as the minimum resolution scaling factor for the underlying value. When *small-value* is not provided, it will be chosen automatically and will be no larger than *delta*.

The *small-value* can be any real number, but rationals are recommended to avoid unexpected rounding behaviors for some of the operations. If necessary, consider entering a decimal value using the provided *#Q* reader macro. The following are equivalent.

```lisp
(defdelta a-fixed-type #qd 0.2 :small #qd 0.2)
(defdelta a-fixed-type 1/5 :small 1/5)
```

**defdecimal** defines a fixed-point number type named *name* capable of representing a base-10 decimal value with up to *power* number of digits to the right of the decimal. The *small-value* selected will be (expt 10 (- *power*)). *Note: This declaration is different from the Ada decimal type where you must still define the delta (but as a power-of-10), and you define the number of digits to use in the underlying type.*

*low-value* and *high-value* are both optional for **defdelta** or **defdecimal**, and are used to define the most-negative and most-positive values of the fixed point type.

**defdecimal** is essentially identical to **defdelta** when called with an identical *delta* and *small* that is a power of 10. The only difference is that values that have a **defdecimal** defined type will always be printed in decimal form. Values with a **defdelta** defined type may be printed as rationals.

### Operations
**defdelta** and **defdecimal** create a set of functions and generic methods associated with *name*.

| Operation | Type | Description |
| --- | --- | --- |
| (make-*name* value) | Function | Return a new instance of *name* with value rounded as necessary with \*rounding-method\* |
| (make-*name*-value value) | Function | Return a new instance of *name* with the provided underlying value |
| (*name* fp) | Function | Return the value in the *name* instance scaled by *small* |
| (*name*-value fp) | Function | Returns the underlying value of an instance of *name* |
| (set-*name* fp value) | Generic | Set the value of a *name* instance, rounding as necessary with \*rounding-method\* |
| (set-*name*-value fp value) | Function | Set the underlying integer value of an instance of *name* |
| (setf (*name* fp) value) | setf | Set the value of fp with rounding as necessary with \*rounding-method\* |
| (setf (*name*-value fp) value) | setf | Set the underlying value of fp |
| (small fp) or (small '*name*) | Generic | Return the *small* when passed '*name* or an instance of *name* |
| (delta fp) or (delta '*name*) | Generic | Return the *delta* when passed '*name* or an instance of *name* |
| (size fp) or (size '*name*) | Generic | Return the number of bits required to store the underlying value of *name* when it is ranged, otherwise return :INFINITY |

### Constants

*+MOST-POSITIVE-NAME+* is defined for each fixed-point type and is either the most positive value, or :POSITIVE-INFINITY if unlimited.

*+MOST-NEGATIVE-NAME+* is defined for each fixed-point type and is either the most negative value, or :NEGATIVE-INFINITY if unlimited.

### Math Operations
Generic Function Predicates:
f=
f/=
f>
f>=
f<
f<=

Generic Arithmetic Operations:
f+
f-
f*
f/
Please let me know if you find this useful, or encounter issues.

## Usage
```lisp
;; Ordinary power-of-2 fixed point type that supports a resolution of 1/10.
;; This is represented by a 1/16 resolution value.
> (defdelta foo 1/10)
;; Reader macro usage.
> #q foo 1.25
#<FOO 5/4>
;; Fixed point type with precise resolution
;; This is represented by a 1/10 resolution value.
> (defdelta bar 1/10 :small 1/10)
Expand All @@ -107,6 +39,21 @@ FB
#<FOOBAR 0.48999998>
> (f+ fb (make-foobar 0.51))
#<FOOBAR 1.0>
;; Base 10 decimal types are simply created like this:
> (fixed:defdecimal milli 3)
MILLI
;; Using the make-milli function works...but comes with
;; floating point precision issues.
> (make-milli 123456789.001)
#<MILLI 123456782.336>
0.0
;; Using the #q reader avoids floating point representation.
> #q milli 123456789.001
#<MILLI 123456789.001>
```

## Fixed-point Reader Macro
Expand Down Expand Up @@ -163,10 +110,81 @@ e.g.
1.234
```

## Future Work
- Fixed-point reader macro improvements
- Read into a superclass of defined delta types
- Determine if the second return value from rounding operations is in the best form.
## Syntax

**defdelta** *name delta [:small small-value] [:low low-value] [:high high-value]*

=> *delta-name*

**defdecimal** *name power [:low low-value] [:high high-value]*

=> *decimal-name*

### Arguments
*name* --- a symbol

*delta* --- real number

*power* --- integer

*small-value*, *low-value*, and *high-value* --- optional real numbers

### Description

**defdelta** defines a fixed-point number type named *name* capable of representing a value with at least the accuracy provided in *delta*.

If *small-value* is provided in **defdelta**, it must be a real value no greater than *delta*. *small-value* is used as the minimum resolution scaling factor for the underlying value. When *small-value* is not provided, it will be chosen automatically and will be no larger than *delta*.

The *small-value* can be any real number, but rationals are recommended to avoid unexpected rounding behaviors for some of the operations. If necessary, consider entering a decimal value using the provided *#Q* reader macro. The following are equivalent.

```lisp
(defdelta a-fixed-type #qd 0.2 :small #qd 0.2)
(defdelta a-fixed-type 1/5 :small 1/5)
```

**defdecimal** defines a fixed-point number type named *name* capable of representing a base-10 decimal value with up to *power* number of digits to the right of the decimal. The *small-value* selected will be (expt 10 (- *power*)). *Note: This declaration is different from the Ada decimal type where you must still define the delta (but as a power-of-10), and you define the number of digits to use in the underlying type.*

*low-value* and *high-value* are both optional for **defdelta** or **defdecimal**, and are used to define the most-negative and most-positive values of the fixed point type.

**defdecimal** is essentially identical to **defdelta** when called with an identical *delta* and *small* that is a power of 10. The only difference is that values that have a **defdecimal** defined type will always be printed in decimal form. Values with a **defdelta** defined type may be printed as rationals.

### Operations
**defdelta** and **defdecimal** create a set of functions and generic methods associated with *name*.

| Operation | Type | Description |
| --- | --- | --- |
| (make-*name* value) | Function | Return a new instance of *name* with value rounded as necessary with \*rounding-method\* |
| (make-*name*-value value) | Function | Return a new instance of *name* with the provided underlying value |
| (*name* fp) | Function | Return the value in the *name* instance scaled by *small* |
| (*name*-value fp) | Function | Returns the underlying value of an instance of *name* |
| (set-*name* fp value) | Generic | Set the value of a *name* instance, rounding as necessary with \*rounding-method\* |
| (set-*name*-value fp value) | Function | Set the underlying integer value of an instance of *name* |
| (setf (*name* fp) value) | setf | Set the value of fp with rounding as necessary with \*rounding-method\* |
| (setf (*name*-value fp) value) | setf | Set the underlying value of fp |
| (small fp) or (small '*name*) | Generic | Return the *small* when passed '*name* or an instance of *name* |
| (delta fp) or (delta '*name*) | Generic | Return the *delta* when passed '*name* or an instance of *name* |
| (size fp) or (size '*name*) | Generic | Return the number of bits required to store the underlying value of *name* when it is ranged, otherwise return :INFINITY |

### Constants

*+MOST-POSITIVE-NAME+* is defined for each fixed-point type and is either the most positive value, or :POSITIVE-INFINITY if unlimited.

*+MOST-NEGATIVE-NAME+* is defined for each fixed-point type and is either the most negative value, or :NEGATIVE-INFINITY if unlimited.

### Math Operations
Generic Function Predicates:
f=
f/=
f>
f>=
f<
f<=

Generic Arithmetic Operations:
f+
f-
f*
f/

# FIXED/REAL-TIME

Expand Down

0 comments on commit 79ef07e

Please sign in to comment.