Proposal for modifying gnucash to use exact quantities

Christopher Browne cbbrowne@hex.net
Wed, 02 Aug 2000 22:32:37 -0500


On Wed, 02 Aug 2000 12:54:52 -0400, the world broke into rejoicing as
Buddha Buck <bmbuck@14850.com>  said:
> At 11:25 AM 8/2/00 -0400, Jason Rennie wrote:
> 
> >bmbuck@14850.com said:
> > > I view "$/8 USD" and "$/100 USD" to be -similar- commodities.  You
> > > can't  add or subtract them, but comparison should be possible.
> >
> >Is it true that you would *never* want to add/subtract such
> >commodities?  I can't think of any cases where you would want to, but
> >should we building this assumption into our underlying data
> >representation?
> 
> Yes.
> 
> What is the result of $3/8 USD - $0.30 USD?  I can think of several 
> reasonable, but wrong (IMHO) answers:
> 
>    $0/8    (round down)
>    $1/8    (round up)
>    $0.07   (round down)
>    $0.08   (round up)
>    $15/200 (take LCD for denominator)
>    $60/800 (take product for denominator)
>    $0.075  (go to mills)
> 
> I don't think any of those make as much sense as saying that subtraction 
> just isn't defined between two similar or different commodities.

Thank you.

The "option" I'd prefer, if the addition were to be considered "legal,"
would be $3/40, but the fact that this isn't compatible with _either_
of the original denominators is pretty evocative that Something Is Wrong
With The Scenario.

The option that seems to make the most sense is to treat this as an
illegal operation, as you can't _have_ both $ 3/8 USD and $0.30 USD
and have USD be consistent with itself.

And I don't see this happening, in real life.

What happens in _real life_ is that you might have something priced at
$3/8 _per unit of whatever_, perhaps $3/8 "per candy bar," and then need
to turn that into $USD in order to add it into [say] an invoice.

The result is that you don't add $3/8 to $0.30, what you have is,
expressed in Scheme, thusly:

(define invoice-total
  (let ((candybars (make-quantity 1 'candy-bar))
        (gumsticks (make-quantity 1 'gum-stick))
        (cb-to-usd (make-price 'candy-bar 'USD 3 8)))
        (gum-to-usd (make-price 'gum-stick 'USD 3 10))))
    (quantity-add
        (convert candybars cb-to-usd)
        (convert gumsticks gum-to-usd))))

This assumes having:
a) make-quantity, which builds a structure containing quantity and
   commodity info
b) make-price, which takes two commodities, and the factors to describe
   the ratio between them, and builds a structure for that,
c) convert, which takes a quantity of a quantity and a price, and converts
   from the source commodity into the destination one.
   Rounding rules should be looked up based on the destination currency.
d) quantity-add, which takes a sequence of _compatible_ quantities,
   and adds them together, producing a quantity.

Simplifying the bit of code up above, we should get:
(quantity-add
   (make-quantity 'USD 37)  ;;; expressed in cents...
   (make-quantity 'USD -30))
which then resolves to be equivalent to:
(make-quantity 'USD 7)

It is unimportant to quibble over how the conversion of $0.375 should
have been resolved; I could as easily agree with the correct result being
$0.38, or (make-quantity 'USD 38).  The rounding policy should be embedded
in the function convert, and probably associated with the commodity, 'USD.

The above bit of code _ignores_ the important issue of what all
information is associated with the commodities that we see here, 
'(USD candy-bar gum-stick)

Note that the following would _FAIL_:
(quantity-add
  (make-quantity 'candy-bar 25) (make-quantity 'USD 255))

I'd expect there to be a (make-commodity) function that would allow
associating a variety of "policy" information with the commodity,
perhaps something like:

(make-commodity 'USD         ;; symbol
                "US Dollars" ;; Long name
                "USD"        ;; short name
                "$"          ;; symbol
                100          ;; denominator
                round-down-function  ;; rounding function
                display-usd) ;; Function to display US Dollars 

There would be some sort of "lookup table" for commodities and prices
so that you might try:
(coerce-add-quantities 'USD ;;; Common currency
  '((make-quantity 'candy-bar 25)  ;;; And now a list of quantities
    (make-quantity 'USD 255)       ;;; of diverse types
    (make-quantity 'soda-pop 50)))
where "coerce-add-quantities" would look up and thus resolve prices for
each of the commodities so as to turn them into 'USD quantities, so that
you _could_ add up a sequence of otherwise-incompatible quantities.

Does there need to be a C version of this?  Sure.  The fact that
the above gets rid of most of the syntax seems to me to make it a
simpler way to discuss and reason about it...
--
aa454@freenet.carleton.ca - <http://www.ntlug.org/~cbbrowne/linux.html>
"There  is no  psychiatrist in  the world  like a  puppy  licking your
face."  -- Ben Williams