Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "reference/decimal"]
path = reference/decimal
url = https://github.com/cppalliance/decimal.git
7 changes: 7 additions & 0 deletions d64/math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ func TestDecimalAddInf(t *testing.T) {
equal(t, QNaN, NegInf.Add(Inf))
}

func TestAddAdhoc(t *testing.T) {
t.Parallel()

// add := testBinop(Decimal.Add)
// t.Run("1", add("0.4164333216995441", "0.1628118190198403", "0.2536215026797038"))
}

func TestDecimalCmp(t *testing.T) {
t.Parallel()

Expand Down
14 changes: 14 additions & 0 deletions d64/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@
return equal(t, expected.String(), actual.String())
}

func testBinop(op func(a, b Decimal) Decimal) func(expected, a, b string) func(*testing.T) {

Check failure on line 61 in d64/util_test.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] d64/util_test.go#L61

func testBinop is unused (unused)
Raw output
d64/util_test.go:61:6: func testBinop is unused (unused)
func testBinop(op func(a, b Decimal) Decimal) func(expected, a, b string) func(*testing.T) {
     ^
7 issues:
* errcheck: 2
* staticcheck: 4
* unused: 1
return func(expected, a, b string) func(*testing.T) {
return func(t *testing.T) {
t.Helper()

e := MustParse(expected)
x := MustParse(a)
y := MustParse(b)
z := op(x, y)
equalD64(t, e, z)
}
}
}

func isnil(t *testing.T, a any) pass {
t.Helper()
if a != nil {
Expand Down
1 change: 1 addition & 0 deletions reference/decimal
Submodule decimal added at f34b02
44 changes: 44 additions & 0 deletions reference/decref/decref.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "decref.h"

#include <stdio.h>
#include <string.h>

#include <boost/decimal.hpp>
#include <iostream>
#include <sstream>

using namespace boost::decimal;

// Inline function to convert decimal64 to Dec64
inline Dec64 f64(decimal64 d) {
return *(Dec64*)&d;
}

// Inline function to convert Dec64 to decimal64
inline decimal64 t64(Dec64 d) {
return *(decimal64*)(&d);
}

Dec64 parse64(const char* str) {
decimal64 d;
std::istringstream(str) >> d;
return f64(d);
}

char* string64(Dec64 wrapper) {
std::ostringstream oss;
oss << std::scientific
<< std::setprecision(std::numeric_limits<double>::max_digits10)
<< t64(wrapper) << std::flush;
return strdup(oss.str().c_str());
}

Dec64 frombid64(uint64_t b) { return f64(from_bid<decimal64>(b)); }
uint64_t tobid64(Dec64 a) { return to_bid(t64(a)); }

int isNaN64(Dec64 a) { return isnan(t64(a)); }

Dec64 add64(Dec64 a, Dec64 b) { return f64(t64(a) + t64(b)); }
Dec64 sub64(Dec64 a, Dec64 b) { return f64(t64(a) - t64(b)); }
Dec64 mul64(Dec64 a, Dec64 b) { return f64(t64(a) * t64(b)); }
Dec64 quo64(Dec64 a, Dec64 b) { return f64(t64(a) / t64(b)); }
34 changes: 34 additions & 0 deletions reference/decref/decref.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package decref

/*
#cgo CXXFLAGS: -std=c++17 -I../decimal/include
#include "decref.h"
#include <stdlib.h>
*/
import "C"

import "unsafe"

type Dec64 C.Dec64

func Parse64(s string) Dec64 {
cstr := C.CString(s)
defer C.free(unsafe.Pointer(cstr))
return Dec64(C.parse64(cstr))
}

func (d Dec64) String() string {
cstr := C.string64(C.Dec64(d))
defer C.free(unsafe.Pointer(cstr))
return C.GoString(cstr)
}

func FromBid64(b uint64) Dec64 { return Dec64(C.frombid64(C.uint64_t(b))) }
func (d Dec64) ToBid() uint64 { return uint64(C.tobid64(C.Dec64(d))) }

func (d Dec64) IsNaN() bool { return C.isNaN64(C.Dec64(d)) != 0 }

func (d Dec64) Add(e Dec64) Dec64 { return Dec64(C.add64(C.Dec64(d), C.Dec64(e))) }
func (d Dec64) Sub(e Dec64) Dec64 { return Dec64(C.sub64(C.Dec64(d), C.Dec64(e))) }
func (d Dec64) Mul(e Dec64) Dec64 { return Dec64(C.mul64(C.Dec64(d), C.Dec64(e))) }
func (d Dec64) Quo(e Dec64) Dec64 { return Dec64(C.quo64(C.Dec64(d), C.Dec64(e))) }
26 changes: 26 additions & 0 deletions reference/decref/decref.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef uint64_t Dec64;

Dec64 parse64(const char* str);
char* string64(Dec64 wrapper);

Dec64 frombid64(uint64_t b);
uint64_t tobid64(Dec64 a);

int isNaN64(Dec64 a);

Dec64 add64(Dec64 a, Dec64 b);
Dec64 sub64(Dec64 a, Dec64 b);
Dec64 mul64(Dec64 a, Dec64 b);
Dec64 quo64(Dec64 a, Dec64 b);

#ifdef __cplusplus
}
#endif
82 changes: 82 additions & 0 deletions reference/decref/decref_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package decref_test

import (
"fmt"
"math/rand/v2"
"strings"
"testing"

"github.com/anz-bank/decimal/d64"
"github.com/anz-bank/decimal/reference/decref"
)

func TestParseString(t *testing.T) {
t.Parallel()

d := decref.Parse64("3.142")
if d.String() != "3.142" {
t.Errorf("expected 3.142, got %s", d.String())
}
}

func TestAdd(t *testing.T) {
t.Parallel()

rng := rand.New(rand.NewPCG(0, 0))
for i := range 1000000 {
decrefA := randDec(i, rng)
decrefB := randDec(i, rng)

aStr := formatDec(decrefA)
bStr := formatDec(decrefB)

d64A := d64.MustParse(aStr)
d64B := d64.MustParse(bStr)

// Perform addition
decrefResult := decrefA.Add(decrefB)
d64Result := d64A.Add(d64B)

d64Str := d64Result.Text('e', -1)
decrefStr := formatDec(decrefResult)

if d64Str != decrefStr {
t.Errorf("Mismatch: d64Result=%s, decrefResult=%s for a=%s, b=%s, %s", d64Str, decrefStr, aStr, bStr, decrefResult.String())
t.FailNow()
}
}
}

func formatDec(d decref.Dec64) string {
decrefStr := d.String()
// Trim mantissa trailing zeros.
if a, b, cut := strings.Cut(decrefStr, "0e"); cut {
decrefStr = strings.TrimRight(a, "0") + "e" + b
}
// Trim exponent leading zeros and all-zeros.
if a, b, cut := strings.Cut(decrefStr, "+0"); cut {
decrefStr = a[:len(a)-1]
if exp := strings.TrimLeft(b, "0"); exp != "" {
decrefStr += "e+" + exp
}
}
// Trim negative-exponent leading zeros.
if a, b, cut := strings.Cut(decrefStr, "-0"); cut {
decrefStr = a + "-" + strings.TrimLeft(b, "0")
}
return decrefStr
}

func randDec(i int, rng *rand.Rand) decref.Dec64 {
sign := [2]string{"", "-"}[rng.IntN(2)]
const explimit = 385
exp := rng.IntN(2*explimit+1) - (explimit - 1)
hidigit := rng.IntN(10)
lodigits := rng.Int64N(1_000_000_000_000_000)
s := fmt.Sprintf("%s%d.%dE%d", sign, hidigit, lodigits, exp)
d := decref.Parse64(s)
if d.IsNaN() {
panic(fmt.Errorf("[%d] unparsable: %s (d = %s)", i, s, d))
}
return d
}
5 changes: 5 additions & 0 deletions reference/decref/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/anz-bank/decimal/reference/decref

go 1.24.0

require github.com/anz-bank/decimal v1.15.0
2 changes: 2 additions & 0 deletions reference/decref/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/anz-bank/decimal v1.15.0 h1:wJ9X6XCVpBUqEwapFamKd0eTbCkJPQe9JJSOoShKykU=
github.com/anz-bank/decimal v1.15.0/go.mod h1:lSAX9MYcSaTIxYaII8tXEJbPom/njRKSAX2VMFVh434=