Giter Site home page Giter Site logo

Comments (16)

 avatar commented on May 14, 2024 5

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.

nomad-software avatar nomad-software commented on May 14, 2024 1

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.

caiomeemo avatar caiomeemo commented on May 14, 2024 1

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.

nomad-software avatar nomad-software commented on May 14, 2024

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.

Rhymond avatar Rhymond commented on May 14, 2024

Hi @nomad-software,

What result you expect to return by doing division here?

net := gross.Divide(1.2) // error

from go-money.

nomad-software avatar nomad-software commented on May 14, 2024

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.

Rhymond avatar Rhymond commented on May 14, 2024

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.

image

from go-money.

nomad-software avatar nomad-software commented on May 14, 2024

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.

Rhymond avatar Rhymond commented on May 14, 2024

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.

nomad-software avatar nomad-software commented on May 14, 2024

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.

Rhymond avatar Rhymond commented on May 14, 2024

@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.

splokhikh avatar splokhikh commented on May 14, 2024

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.

AchoArnold avatar AchoArnold commented on May 14, 2024

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.

nmaupu avatar nmaupu commented on May 14, 2024

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.

edtsech avatar edtsech commented on May 14, 2024

@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 avatar Rhymond commented on May 14, 2024

@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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.