quagmt / udecimal

A high-performance, high precision, zero allocation fixed-point decimal library for financial applications
https://quagmt.github.io/udecimal/
BSD 3-Clause "New" or "Revised" License
111 stars 4 forks source link

Reduce size of Decimal type #4

Closed zolstein closed 1 month ago

zolstein commented 1 month ago

The Decimal type is 48 bytes on a 64-bit machine. Even though this is not "large" per se, it seems likely that users would construct large slices of Decimal values, so it's worth trying to reduce the size to pack more values into less memory. There are two relatively easy ways to do this:

First, you can reorder the Decimal fields from this:

type Decimal struct {
    neg bool
    coef bint
    prec uint8 // 0 <= prec <= 19
}

to this:

type Decimal struct {
    coef bint
    neg bool
    prec uint8 // 0 <= prec <= 19
}

Putting neg and prec together after the coef reduces the padding used for alignment, saving 8 bytes.

Second, unless I'm missing something, you could refactor bint to remove the overflow bool. It looks like you could implicitly infer that overflow == (bigint != nil). This saves an additional 8 bytes, since Go pads the boolean to make bint a multiple of 8 bytes. Unlike Decimal, in this case there's no way to reorder the fields to reduce the size.

(You could alternately reduce the size by removing bint, rolling the fields into Decimal, and placing overflow alongside neg and prec, but doing this loses the encapsulation of bint and requires a larger refactor than just replacing all instances of overflow with bint != nil.)

quagmt commented 1 month ago

The actual implementation of Decimal type is already your suggestion, I'll update the README to match it. As for overflow, agree that it can be removed and checked by bigint != nil instead. I'll craft a fix for it. Thanks