Skip to content

Commit

Permalink
context: move example to a separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
db47h committed May 30, 2020
1 parent 05759ae commit 4addc6f
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 40 deletions.
28 changes: 13 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,18 @@ and an exactly rounded `Sqrt`. Other functions like Log will be implemented in a
future "math" sub-package. All results are rounded to the desired precision (no
manual rounding).

NaN values are not directly supported (like in `big.Float`). They can be
considered as "signaling NaNs" in IEEE-754 terminology, that is when a NaN is
generated as a result of an operation, it causes a panic. Applications that need
to handle NaNs gracefully can use Go's built-in panic/recover machanism to
handle these efficiently: NaNs cause a panic with an ErrNaN which can be tested
to distinguish NaNs from other causes of panic.

On the other hand, Contexts (implemented in the
[context](https://pkg.go.dev/github.com/db47h/decimal/context?tab=doc)
sub-package) provide panic-free operation and a form of quiet-NaNs whereby any
NaN generated by an operation will make the context enter into an error state.
Further operations with the context will be no-ops until (*Context).Err is
called to check for errors.
NaN values are not directly supported (like in `big.Float`). They can be seen as
"signaling NaNs" in IEEE-754 terminology, that is when a NaN is generated as a
result of an operation, it causes a panic. Applications that need to handle NaNs
gracefully can use Go's built-in panic/recover machanism to handle these
efficiently: NaNs cause a panic with an ErrNaN which can be tested to
distinguish NaNs from other causes of panic.

On the other hand, the [context](https://pkg.go.dev/github.com/db47h/decimal/context?tab=doc)
sub-package provides Contexts, which allow panic-free operation and a form of
quiet-NaNs whereby any NaN generated by an operation will make the context enter
into an error state. Further operations with the context will be no-ops until
(*Context).Err is called to check for errors.

Mantissae are always normalized, as a result, Decimals have a single possible
representation:
Expand All @@ -84,11 +83,10 @@ so there is no notion of scale and no Quantize operation.
- Complete decimal conversion tests
- A math sub-package that will provide at least the functions required by
IEEE-754
- A context sub-package
- Some performance improvement ideas:
- try a non-normalized mantissa.
- in add, there are some cycles to shave off by combining the shift and add
for simple cases.
for simple cases (initial testing yielded mitigated results. Wait and see)

The decimal API is frozen, that is, any additional features will be added in
sub-packages.
Expand Down
25 changes: 0 additions & 25 deletions context/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package context

import (
"errors"
"fmt"
"math"
"testing"

Expand Down Expand Up @@ -117,27 +116,3 @@ var pi = "3." +
"34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
"88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
"94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"

func ExampleContext_Err() {
c := New(0, decimal.ToNearestEven)

x := c.NewInt64(-1)
z := c.Sqrt(c.New(), x) // silently fails

zero := c.New()
// no-op, c.Err will still report "square root of negative operand" but the
// value of z is undefined.
c.Quo(z, zero, zero)

// calling c.Err clears the error state.
fmt.Println(c.Err())

x.SetInt64(4)
c.Sqrt(z, x)
fmt.Printf("√(%g) = %g", x, z)

//
// Output:
// square root of negative operand
// √(4) = 2
}
69 changes: 69 additions & 0 deletions context/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package context_test

import (
"errors"
"fmt"

"github.com/db47h/decimal"
"github.com/db47h/decimal/context"
)

var _four = new(decimal.Decimal).SetPrec(1).SetInt64(-4)
var two = new(decimal.Decimal).SetPrec(1).SetInt64(2)

// solve solves the quadratic equation ax² + bx + c = 0, using ctx's rounding
// mode and precision. It can fail with various combinations of inputs, for
// example a = 0, b = 2, c = -3 will result in dividing zero by zero when
// computing x0. So we need to check errors.
func solve(ctx context.Context, a, b, c *decimal.Decimal) (x0, x1 *decimal.Decimal, err error) {
d := ctx.New()
// compute discriminant
ctx.Mul(d, a, _four) // d = a × -4
ctx.Mul(d, d, c) // × c
ctx.FMA(d, b, b, d) // + b × b
if err != nil {
return nil, nil, fmt.Errorf("error computing discriminant: %w", err)
}
if d.Sign() < 0 {
return nil, nil, errors.New("no real roots")
}
// d = √d
ctx.Sqrt(d, d)
twoA := ctx.Mul(ctx.New(), a, two)
negB := ctx.Neg(ctx.New(), b)

x0 = ctx.Add(ctx.New(), negB, d)
ctx.Quo(x0, x0, twoA)
x1 = ctx.Sub(ctx.New(), negB, d)
ctx.Quo(x1, x1, twoA)

if err = ctx.Err(); err != nil {
return nil, nil, fmt.Errorf("error computing roots: %w", err)
}
return
}

// Example demonstrates various features of Contexts.
func Example() {
ctx := context.New(0, decimal.ToNearestEven)
a, b, c := ctx.NewInt64(1), ctx.NewInt64(2), ctx.NewInt64(-3)
x0, x1, err := solve(ctx, a, b, c)
if err != nil {
fmt.Printf("failed to solve %g×x²%+gx%+g: %v\n", a, b, c, err)
return
}
fmt.Printf("roots of %g×x²%+gx%+g: %g, %g\n", a, b, c, x0, x1)

a = ctx.New() // zero
x0, x1, err = solve(ctx, a, b, c)
if err != nil {
// obviously, our solve() algorithm cannot handle a == 0
fmt.Printf("failed to solve %g×x²%+gx%+g: %v\n", a, b, c, err)
return
}
fmt.Printf("roots of %g×x²%+gx%+g: %g, %g\n", a, b, c, x0, x1)
//
// Output:
// roots of 1×x²+2x-3: 1, -3
// failed to solve 0×x²+2x-3: error computing roots: division of zero by zero or infinity by infinity
}

0 comments on commit 4addc6f

Please sign in to comment.