Proposal for modifying gnucash to use exact quantities

Richard Wackerbarth rkw@dataplex.net
Fri, 28 Jul 2000 09:14:31 -0500


On Fri, 28 Jul 2000, Christopher Browne wrote:

> Unfortunately, all Bill has provided is a way of representing and
> manipulating rational values.  There's nothing particularly _wrong_ or
> awful about having that.

> But I don't think it represents what people really need to do with
> _financial amounts_.

This is exactly what I have been trying to say all along.

> Once we get that library, the conclusion is liable to be:
> "Well, now let's build something that works with transactions, and
> adds, prices, and values them."
>
> I'd rather put the emphasis on that next higher level library, which
> might look more like:
>
> struct finamt {
>   numerator Q;   /* Might be a rational value, if need be... */
>   commodity C;
> };
I would be more inclined to use
struct finamt {
  numerator Q;
  commodity *CP;
};
Or pass CP as a separate argument where it is needed.
In most cases, the caller will know the "units" of the result and the "math" 
doesn't care what they are as long as they are consistent.

>
> struct commodity {
>   string IDENTIFIER;
>   string NAME;
>   integer DENOMINATOR /* for $USD, $CDN, 100, as $1.00 is expressed
>                          as 100 */
>   integer MULTIPLIER  /* for Lira, where the minimum quanta is
>                          something like 1000, this is 1000 */
>   /* the two amounts here allow scaling up and down */
> };

I would also add display formatting functions here.
Off hand, rather than expressing DENOMINATOR & NUMERATOR, we might use 
    rational DISPLAY_SCALE_FACTOR;
and we also need
    ?  DISPLAY_FORMATTING;
Please observe that although numerically equivalent, we might wish to display
40/32 as "1.25", "1 1/4", "1 8/32", or in some other way depending upon the 
usage.

>
> struct price {
>   numerator N;
>   denominator D;
>   commodity *FROM;
>   commodity *TO;
> }:
>
> We then have:
>
> finamt add_amounts ( finamt a, finamt b );
> finamt sub_amounts ( finamt a, finamt b );
> finamt sum_amt_seq ( finamt *SEQ );
> finamt translate_value ( finamt amt, price p );
>
> Note that there would need to be some preconditions here.  For instance,
> you can only add amounts for compatible commodities.  Adding dollars to
> soybeans doesn't work.  Unless we introduce:
>
> finamt add_amounts_with_coercion ( finamt result, finamt addition )
>   where inside the function, it looks for a conversion rate so that
>   "addition" may be coerced into the commodity that "result" references.

It probably makes more sense to have an "exchange" function that converts to 
the common unit and then apply the regular add_amounts.

> This set of operators came off the top of my head, and there is a bit
> of an assumption that amounts are integers, and that the denominators
> sit in the commodity.  Relax/strengthen that as needed.
>
> People shouldn't and won't be coding using the "rational division"
> operator; they should be writing financial code that sums up sequences
> of transaction values.  Or converting a value from one commodity to
> another.

The only "division" that I see is in the apportion operation where an amount 
is divided into two (or more) parts in proportion to some set of amounts.

basis_sold = units_sold * total_basis / total_units

With the appropriate integer rounding of the result.

In fact, I think we need only implement the MATH function r(a,b,c) = a * b / c
for "numerator" (some kind of integer) amounts.

Your translate_value then becomes r(amt, n(p), d(p));

> It may be that we could use the API that Bill has described to help
> implement the next one, but I think it's the operators to work with
> commodities and quantities thereof that need the attention.

That's what I have been asking people to address. It is my opinion that once 
they do so, they will see that translating their requirements into Bill's API 
is more obfuscating that using a simpler API similar to the one you describe.