Comments (16)
Makes sense, there should be absolutely NO functions that loose any monetary value internally. That's the whole poit of package like this, to make mathematical operations with money lossless. Otherwise peopele can just use1+2...
from go-money.
I know the whole project is based on int64
but that does not invalidate my question.
If you have a Divide
function that returns a loss in precision with an int64
or a float
then why only allow int64
? There is always rounding occurring no matter which data type is used.
foo := money.New(100, "GBP")
bar := foo.Divide(3) // int64 loss in precision
bar := foo.Divide(1.2) // float loss in precision
You can never get a true lossless result from it so what's the difference? Just constraining it to int64
is so arbitrary.
This is probably why Divide
is not part of the money pattern.
from go-money.
As to increase precision, some financial institutions work with a hundred fraction of currency minor units. So for instance, US Dollars with cents as its minor units (2 digits) would use 1/10000 of a minor unit internally (4 digits). That would allow for more precise operations when working with $1.2345 for instance. Internally, using int64 as well, just that instead of a maximum of $92,233,720,368,547,758.07 (~92 quadrillions?) the maximum would be $922,337,203,685,477.5807 (~922 trillions?) that might be sufficient for money operations (unless we need more and then move into a big integer kind of internal implementation.
That could be an interesting addition to go-money, if one could specify extra precision (on top of minor units). We would be able to create an instance using m := money.New(12345, "USD")
and get the result of m.AsMajorUnits()
as 1.2345 instead of 123.45. Anyways that can be achieved by calling currency.AddCurrency(...)
with Fraction as 4.
from go-money.
The above can be achieved like this:
value := money.New(23485, "GBP")
taxPercent := 20.0
// We have to use large allocations to preserve precision.
netAlloc := int((100 / ((taxPercent / 100) + 1)) * 100)
taxAlloc := int(10000 - netAlloc)
buckets, _ := value.Allocate(netAlloc, taxAlloc)
fmt.Printf("Gross: %s\n", value.Display())
fmt.Printf("Net: %s\n", buckets[0].Display())
fmt.Printf("Tax: %s\n", buckets[1].Display())
Using Divide
would feel more natural.
from go-money.
Hi @nomad-software,
What result you expect to return by doing division here?
net := gross.Divide(1.2) // error
from go-money.
I would expect it to round (half up), so 499
.
gross := money.New(599, "GBP")
net := gross.Divide(1.2) // 499
tax, _ := gross.Subtract(net) // 100
gross = net.Add(tax) // 599
gross = net.Multiply(1.2) // 599
from go-money.
The problem with floats and division is that in some cases you will start loosing pennies because of rounding and removing decimals.
- If you're ok with that, you can always do calculations before creating Money object.
- If you're not ok with that, the best solution would be to use
Allocation
function.
By the definition of Fowler's Money pattern the ``Division``` operation shouldn't be include at all.
from go-money.
The problem with floats and division is that in some cases you will start loosing pennies because of rounding and removing decimals.
Yeah, that's always a problem but it looks like precision loss already exists in this library (not tested):
foo := money.New(100, "GBP")
bar := foo.Divide(3) // ?
from go-money.
There is two lossless functions Allocate, Split, using them you're sure that you will not loose any penny.
In order to split amount without losing use Split() operation.
pound := money.New(100, "GBP")
parties, err := pound.Split(3)
if err != nil {
log.Fatal(err)
}
parties[0].Display() // £0.34
parties[1].Display() // £0.33
parties[2].Display() // £0.33
Or you can use Allocate:
pound := money.New(100, "GBP")
// Allocate is variadic function which can receive ratios as
// slice (int[]{33, 33, 33}...) or separated by a comma integers
parties, err := pound.Allocate(33, 33, 33)
if err != nil {
log.Fatal(err)
}
parties[0].Display() // £0.34
parties[1].Display() // £0.33
parties[2].Display() // £0.33
from go-money.
There is two lossless functions Allocate, Split, using them you're sure that you will not loose any penny.
Yes, that's what I'm using at the minute. My point was that the Divide
function already loses precision in certain circumstances. So using an int
doesn't make it lossless.
from go-money.
@nomad-software yes you're totally right. Using float
it doesn't make it lossless too. Idea behind integer on divide and multiply functions was that the whole project is based on int64
and all conversions must be made outside go-money
.
If you want to divide number just use /
. You can always extract amount by using Money.Amount(). Do your division and create new Money structure.
from go-money.
Completely agree with previous man. If you library operating with floats (obviously it is) there is no reason not to accept float. I'll try this library in one project - and may be send pull request to maintainer.
from go-money.
Hello, Any plans on this, I noticed @Rhymond removed the divide method. I'll also love to have the ability to be able to do multiplications for floating-point numbers, Say I want to get what's 13%
of 79
I'll expect the answer to be 10
is this something you plan to support?
I'm aware that some rounding will need to be done when multiplying floats with ints but that's acceptable. This is kinda proof of concept. https://github.com/AchoArnold/ov-chipkaart-dashboard/blob/master/backend/money.go
from go-money.
Speaking of precision, what can I do if I need 3-digits precision (yes, some need it... look at price for Mouser electronic parts supply for example.
For instance, if I need to handle operations on $0.423
, with int64
, I need to round it to 49 cents
where I loose precision for operations... I can multiply any amouts by 10000 to get around that but at the end, I can't use formatter because amounts will be 100 times too high...
Maybe I missed something though ;)
from go-money.
@Rhymond what do you think, should this issue be closed since Divide has been removed and last comment is from 2 years ago.
from go-money.
@Rhymond what do you think, should this issue be closed since Divide has been removed and last comment is from 2 years ago.
Good point, I believe we can close it. If something is still missing from this issue, please create new issue.
from go-money.
Related Issues (20)
- Reminder: migrate master branch to main
- Split of small negative values doesn't work properly HOT 1
- Proposal: Add function NewFromFloat HOT 6
- Missing Currencies: West African Frank (XOF) and Malagasy Ariary (MGA) HOT 1
- KPW and HUF have incorrect ISO-4217 minor units HOT 2
- Add money comparisson HOT 1
- Wrong fraction for HUF HOT 1
- Question about the rounding for NewFromFloat HOT 5
- NewFromFloat trouble HOT 3
- Panic on money.Allocate() HOT 3
- NewFromFloat shifts the value of the amount in certain currencies. HOT 4
- Digit separation in INR amount
- There is no ZWL currency HOT 2
- How can I multiply a float number? HOT 4
- Integer overflow in the Allocate HOT 2
- Request support for Bolívar Soverano (VES) HOT 1
- wrong fraction length HOT 3
- Add Must* versions of methods that return error
- Use number of minor units in one major instead of a fraction
- Update the README.md HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from go-money.