dinero.js icon indicating copy to clipboard operation
dinero.js copied to clipboard

How to divide by arbitrary integer (2.0-alpha)

Open chrisbenincasa opened this issue 2 years ago • 2 comments

I'm using dinero.js to calculate statistics for monetary values. I've opted to try out the alpha version but have run up against an issue where I cannot determine how to use the multiply or allocate APIs to express division by a variable value.

multiply seems like the correct choice here and makes sense when values are known ahead of time:

// Return 10% of amount
multiply(amount, { amount: 10, scale: 2 })

However, this seems more difficult if only the divisor is known, e.g. when calculating an average.

const zero = (currency: Currency<number> = USD) =>
  dinero({ amount: 0, currency });

const total = amounts.reduce((acc, amt) => add(acc, amt), zero());

// We want to divide by "amounts.length", i.e. multiply by "1/(amounts.length)"
const average = ??

I may be missing something, but is there a way to express this calculation without first doing floating point arithmetic in JS in order to obtain a scaled value to multiply by?

chrisbenincasa avatar Feb 05 '22 15:02 chrisbenincasa

Interim solution using allocate:

const x = Math.round(10000 * (1 / divisor));
return allocate(dividend, [x, 10000 - x])[0];

chrisbenincasa avatar Feb 05 '22 15:02 chrisbenincasa

Interim solution using allocate:

const x = Math.round(10000 * (1 / divisor));
return allocate(dividend, [x, 10000 - x])[0];

This solves my problem described #600

renepardon avatar Mar 16 '22 17:03 renepardon

Hey @chrisbenincasa, and sorry for the late reply.

Using allocate for splitting Dinero objects is the way to go. If you only know the divisor (e.g., divide an object into 3 equal objects), you can use ratios like this:

const total = amounts.reduce(add, dinero({ amount: 0, currency: USD }));
const ratios = Array.from({ length: amounts.length }).fill(1);

const [average] = allocate(total, ratios);

sarahdayan avatar Nov 05 '22 00:11 sarahdayan

And sorry for the late reply on my side!

Thanks for the code - that does in fact solve the average issue pretty well.

I'm wondering about arbitrary division, too, however.

For instance, in currency conversion, if I have rates only going one way (e.x. USD => EUR), but I want to do the reverse conversion. In other words, is there a standard way to calculate a reciprocal of a scaled value?

chrisbenincasa avatar Jun 22 '23 19:06 chrisbenincasa