Skip to content

Commit

Permalink
Docs: Add documentation page
Browse files Browse the repository at this point in the history
  • Loading branch information
barucden committed Nov 11, 2024
1 parent 92225ac commit e6a5acd
Show file tree
Hide file tree
Showing 11 changed files with 419 additions and 195 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Documentation

on:
push:
branches:
- master
tags: '*'
pull_request:

jobs:
build:
permissions:
actions: write
contents: write
pull-requests: read
statuses: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v2
with:
version: '1'
- uses: julia-actions/cache@v2
- name: Install dependencies
run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
- name: Build and deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: julia --project=docs/ docs/make.jl
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
*.cov

docs/build/
197 changes: 5 additions & 192 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Decimals.jl: Arbitrary precision decimal floating point arithmetics in Julia

[![Coverage Status](https://coveralls.io/repos/github/JuliaMath/Decimals.jl/badge.svg?branch=master)](https://coveralls.io/github/JuliaMath/Decimals.jl?branch=master)
[![CI Status](https://github.com/JuliaMath/Decimals.jl/workflows/CI/badge.svg)]( https://github.com/JuliaMath/Decimals.jl/actions?query=workflows/CI)
[![Coverage Status](https://codecov.io/github/JuliaMath/Decimals.jl/branch/master/graph/badge.svg)](https://codecov.io/github/JuliaMath/Decimals.jl)
[![Documentation](https://img.shields.io/badge/docs-master-blue.svg)](http://juliamath.github.io/Decimals.jl)

The `Decimals` package provides basic data type and functions for arbitrary precision [decimal floating point](https://en.wikipedia.org/wiki/Decimal_floating_point) arithmetic in Julia. It supports addition, subtraction, negation, multiplication, division, and equality operations.
The `Decimals` package provides basic data type and functions for arbitrary precision [decimal floating point](https://en.wikipedia.org/wiki/Decimal_floating_point) arithmetic in Julia.

Why is this needed? The following code in Julia gives an answer

Expand All @@ -11,204 +13,15 @@ Why is this needed? The following code in Julia gives an answer

In words, the binary floating point arithmetics implemented in computers has finite resolution - not all real numbers (even within the limits) can be expressed exactly. While many scientific and engineering fields can handle this behavior, it is not acceptable in fields like finance, where it's important to be able to trust that $0.30 is actually 30 cents, rather than 30.000000000000004 cents.

## Installation
See [documentation](http://juliamath.github.io/Decimals.jl).

```julia
julia> Pkg.add("Decimals")
```
or just `Ctrl`+`]` and
```julia
(v1.2) pkg> add Decimals
```

## Usage

```julia
julia> using Decimals
```

### Construction


`Decimal` is constructed by passing values `s`, `c`, `q` such that
`x = (-1)^s * c * 10^q`:
```julia
julia> Decimal(0, 1, -1)
0.1

julia> Decimal(1, 1, -1)
-0.1
```


### Parsing from string

You can parse `Decimal` objects from strings:

```julia
julia> x = "0.2"
"0.2"

julia> parse(Decimal, x)
0.2

julia> tryparse(Decimal, x)
0.2
```
Parsing support scientific notation. Alternatively, you can use the `@dec_str`
macro, which also supports the thousands separator `_`:
```julia
julia> dec"0.2"
0.2

julia> dec"1_000.000_001"
1000.000001
```

### Conversion

Any real number can be converted to a `Decimal`:
```julia
julia> Decimal(0.2)
0.2

julia> Decimal(-10)
-10
```

A `Decimal` can be converted to numeric types that can represent it:
```julia
julia> Float64(Decimal(0.2))
0.2

julia> Int(Decimal(10))
10

julia> Float64(Decimal(0, 1, 512))
ERROR: ArgumentError: cannot parse "100[...]" as Float64

julia> Int(Decimal(0.4))
ERROR: ArgumentError: invalid base 10 digit '.' in "0.4"
```

### String representation

A string in the decimal form of a `Decimal` can be obtained via
`string(::Decimal)`:
```julia
julia> string(Decimal(0.2))
"0.2"
```

The 2- and 3-args methods for `show` are implemented:
```julia
julia> repr(Decimal(1000000.0))
"Decimal(0, 10, 5)"

julia> repr("text/plain", Decimal(1000000.0))
"1.0E+6"
```

### Operations
```julia
julia> x, y = decimal("0.2"), decimal("0.1");
```
#### Addition
```julia
julia> string(x + y)
"0.3"
```

#### Subtraction
```julia
julia> string(x - y)
"0.1"
```

#### Negation
```julia
julia> string(-x)
"-0.2"
```
#### Multiplication
```julia
julia> string(x * y)
"0.02"
```

#### Division
```julia
julia> string(x / y)
"2"
```

#### Inversion
```julia
julia> string(inv(x))
"5"
```

#### Broadcasting
```julia
julia> [x y] .* 2
2-element Array{Decimal,1}:
Decimal(0,1,-1)
Decimal(0,5,-2)
```
#### Equals (`==` and `isequal`)
```julia
julia> x == decimal("0.2")
true

julia> x != decimal("0.1")
true
```

#### Inequality
```julia
julia> x >= y
true

julia> isless(x, y)
false
```

#### `==` returns true for Decimal vs. Number comparisons
```julia
julia> x == 0.2
true
```

#### Rounding
```julia
julia> round(decimal(3.1415), digits=2)
Decimal(0,314,-2)

julia> string(ans)
"3.14"
```

## Comparison with other packages

Unlike another Julia package called [`DecFP`](https://github.com/JuliaMath/DecFP.jl), which aims at implementing the [IEEE 754-2008 standard](https://en.wikipedia.org/wiki/IEEE_754-2008_revision) introducing 32, 64, and 64-bit precisions ([decimal32](https://en.wikipedia.org/wiki/Decimal32_floating-point_format), [decimal64](https://en.wikipedia.org/wiki/Decimal64_floating-point_format) and [decimal128](https://en.wikipedia.org/wiki/Decimal128_floating-point_format), respectively), this package allows arbitrary precision. Note, however, that in comparision with `DecFP`, which is is essentially a wrapper for a specialized [Intel® Decimal Floating-Point Math Library](https://software.intel.com/en-us/articles/intel-decimal-floating-point-math-library), the present package is more computationally demanding. If more computational efficiency is demanded, functions from [`libmpdec`](http://www.bytereef.org/mpdecimal/index.html) library can be called directly.

The closest equivalent (and inspiration) for the present package in Python is the standard built-in [`decimal`](https://docs.python.org/3.7/library/decimal.html) package, which is based on [General Decimal Arithmetic Specification by IBM](http://speleotrove.com/decimal/decarith.html). Since version 3.3 of Python, it is actually [`libmpdec`](http://www.bytereef.org/mpdecimal/index.html)/[`cdecimal`](https://www.bytereef.org/mpdecimal/doc/cdecimal/index.html) that is under the hood.

## Development

### Standard tests

There is a standard test suite called
[DecTests](https://speleotrove.com/decimal/dectest.html). The test suite is
provided in a [custom format](https://speleotrove.com/decimal/dtfile.html). We
have a script `scripts/dectest.jl` for translating test cases from the custom
format to common Julia tests. The script should be called like this:
```
julia scripts/dectest.jl <testset name> <dectest path> <output path>
```
For example:
`julia scripts/dectest.jl Plus dectests/plus.decTest test/dectests/test_plus.jl`.
We put these test files into the `test/dectests` subdirectory.

## Further reading

Expand Down
2 changes: 2 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build
Manifest.toml
3 changes: 3 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[deps]
Decimals = "abce61dc-4473-55a0-ba07-351d65e31d42"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
8 changes: 8 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Decimals
using Documenter

makedocs(sitename="Decimals.jl",
pages=["index.md",
"operations.md"])
deploydocs(repo="github.com/JuliaMath/Decimals.jl.git",
push_preview=true)
15 changes: 15 additions & 0 deletions docs/src/contrib.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Development

### Standard tests

There is a standard test suite called
[DecTests](https://speleotrove.com/decimal/dectest.html). The test suite is
provided in a [custom format](https://speleotrove.com/decimal/dtfile.html). We
have a script `scripts/dectest.jl` for translating test cases from the custom
format to common Julia tests. The script should be called like this:
```
julia scripts/dectest.jl <testset name> <dectest path> <output path>
```
For example:
`julia scripts/dectest.jl Plus dectests/plus.decTest test/dectests/test_plus.jl`.
We put these test files into the `test/dectests` subdirectory.
72 changes: 72 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
```@meta
DocTestSetup = quote
using Decimals
end
```

# Introduction

This package is a Julia implementation of arbitrary precision decimal floating
point arithmetic, where numbers $x \in \mathbb{R}$ are represented using the
`Decimal` type as
```math
x = (-1)^s \cdot c \cdot 10^q,
```
where $s \in \{0, 1\}$ is the signbit, $c \in \mathbb{N}$ is the coefficient, and $q \in \mathbb{Z}$ is the exponent.


## Construction

The `Decimal` object can be created directly, or by conversion from a number,
or by parsing from a string:

```jldoctest
julia> Decimal(0, 5, -1) # (-1)^0 * 5 * 10^-1
0.5
julia> Decimal(0.5)
0.5
julia> Decimal(5E-1)
0.5
julia> parse(Decimal, "0.5")
0.5
julia> parse(Decimal, "5E-1")
0.5
```

Alternatively, a `Decimal` can be parsed from a string literal via the
`@dec_str` macro, which also supports the thousands separator `_`:
```jldoctest
julia> dec"1_000.000_000_1"
1000.0000001
```
The thousands separator is not supported by the `parse` function:
```jldoctest
julia> parse(Decimal, "1_000")
ERROR: ArgumentError: Invalid decimal: 1_000
```

!!! warning "Conversion from numbers is exact"
The constructor `Decimal(::Real)` converts the given number to a `Decimal`
exactly. The consequence is that `Decimal(x)` is not generally equal to
`parse(Decimal, string(x))`. For example,
```jldoctest
julia> Decimal(0.1)
0.1000000000000000055511151231257827021181583404541015625

julia> parse(Decimal, "0.1")
0.1

julia> dec"0.1" # Alternative to parse
0.1

julia> big(0.1) # Exact value of 0.1 represented by a binary floating-point number
0.1000000000000000055511151231257827021181583404541015625

julia> string(0.1) # The string representation of 0.1 is deceiving
"0.1"
```

Loading

0 comments on commit e6a5acd

Please sign in to comment.