FAQ
(Note you're ignoring all but the last error in that big block of
fmt.Sscans.)

Disclaimer: I've never written any financial software. However, thinking
about it it seems that just using int64 to represent a base unit (say,
cents or 1/1000 of cents) would be a reasonable way to go unless you
actually need to represent arbitrarily large currency amounts.

Taking inspiration from the time package, I came up with this:

http://play.golang.org/p/v5mP-_KEce

-Caleb

On Sun, Dec 29, 2013 at 3:16 PM, John Whitton wrote:

Hi all,

I'm trying to work with currencies in go. I'm using a simple shopping cart
example where someone is buying some hamburgers and milkshakes, calculating
tax and the total amount.
You can see the code here http://play.golang.org/p/LevYw2DU7R and below
It took me about 40 lines of code to do this and it did not seem
intuitive.
I know there's been some discussion regarding whether to make the amounts
as integers using cents vs big.Rat
If anyone can show me a simpler way to do this, I'd appreciate it.
I'm at the stage where I'm starting to define my types and datastore
elements and would like to have a sound approach for currency before
continuing.

Regards,

John

// Currency Example
//I want to buy 4 Hamburgers ($5.50 each) and 2 Milkshakes ($2.86 each)
// Calcualte the Total Price Before Tax = $27.72 = 4 * $5.50 + 2 * $2.86
// Calculate the Tax (7.65%) amount $2.12 = $27.72 * 0.765
// Calculate the Total Price $29.84 = $27.72 + $2.12

package main

import (
"fmt"
"math/big"
)

func main() {

//Define all the variables
HamburgerPrice := new(big.Rat)
HamburgerQty := new(big.Rat)
HamburgerTotPrice := new(big.Rat)
MilkshakePrice := new(big.Rat)
MilshakeQty := new(big.Rat)
MilkshakeTotPrice := new(big.Rat)
Tax := new(big.Rat)
TotalPriceBeforeTax := new(big.Rat)
TaxAmount := new(big.Rat)
TotalPrice := new(big.Rat)

//Scan all the Variables
_, err := fmt.Sscan("5.50", HamburgerPrice)
_, err = fmt.Sscan("4", HamburgerQty)
_, err = fmt.Sscan("2.86", MilkshakePrice)
_, err = fmt.Sscan("2", MilshakeQty)
_, err = fmt.Sscan("0.0765", Tax)
if err != nil {
fmt.Println("error scanning value:", err)
}
//Do the Calculation
HamburgerTotPrice.Mul(HamburgerPrice, HamburgerQty)
MilkshakeTotPrice.Mul(MilkshakePrice, MilshakeQty)
TotalPriceBeforeTax.Add(HamburgerTotPrice, MilkshakeTotPrice)
TaxAmount.Mul(TotalPriceBeforeTax, Tax)
TotalPrice.Add(TotalPriceBeforeTax, TaxAmount)
//Print the result
fmt.Println("Total Price : $", TotalPrice.FloatString(2))
}

--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • John Whitton at Dec 30, 2013 at 12:06 am
    Thanks Caleb,

    That looks a lot more intuitive and a lot cleaner.
    I appreciate the help.

    Regards,

    John
    On Sunday, December 29, 2013 3:37:54 PM UTC-8, Caleb Spare wrote:

    (Note you're ignoring all but the last error in that big block of
    fmt.Sscans.)

    Disclaimer: I've never written any financial software. However, thinking
    about it it seems that just using int64 to represent a base unit (say,
    cents or 1/1000 of cents) would be a reasonable way to go unless you
    actually need to represent arbitrarily large currency amounts.

    Taking inspiration from the time package, I came up with this:

    http://play.golang.org/p/v5mP-_KEce

    -Caleb


    On Sun, Dec 29, 2013 at 3:16 PM, John Whitton <john.a....@gmail.com<javascript:>
    wrote:
    Hi all,

    I'm trying to work with currencies in go. I'm using a simple shopping
    cart example where someone is buying some hamburgers and milkshakes,
    calculating tax and the total amount.
    You can see the code here http://play.golang.org/p/LevYw2DU7R and below
    It took me about 40 lines of code to do this and it did not seem
    intuitive.
    I know there's been some discussion regarding whether to make the amounts
    as integers using cents vs big.Rat
    If anyone can show me a simpler way to do this, I'd appreciate it.
    I'm at the stage where I'm starting to define my types and datastore
    elements and would like to have a sound approach for currency before
    continuing.

    Regards,

    John

    // Currency Example
    //I want to buy 4 Hamburgers ($5.50 each) and 2 Milkshakes ($2.86 each)
    // Calcualte the Total Price Before Tax = $27.72 = 4 * $5.50 + 2 * $2.86
    // Calculate the Tax (7.65%) amount $2.12 = $27.72 * 0.765
    // Calculate the Total Price $29.84 = $27.72 + $2.12

    package main

    import (
    "fmt"
    "math/big"
    )

    func main() {

    //Define all the variables
    HamburgerPrice := new(big.Rat)
    HamburgerQty := new(big.Rat)
    HamburgerTotPrice := new(big.Rat)
    MilkshakePrice := new(big.Rat)
    MilshakeQty := new(big.Rat)
    MilkshakeTotPrice := new(big.Rat)
    Tax := new(big.Rat)
    TotalPriceBeforeTax := new(big.Rat)
    TaxAmount := new(big.Rat)
    TotalPrice := new(big.Rat)

    //Scan all the Variables
    _, err := fmt.Sscan("5.50", HamburgerPrice)
    _, err = fmt.Sscan("4", HamburgerQty)
    _, err = fmt.Sscan("2.86", MilkshakePrice)
    _, err = fmt.Sscan("2", MilshakeQty)
    _, err = fmt.Sscan("0.0765", Tax)
    if err != nil {
    fmt.Println("error scanning value:", err)
    }
    //Do the Calculation
    HamburgerTotPrice.Mul(HamburgerPrice, HamburgerQty)
    MilkshakeTotPrice.Mul(MilkshakePrice, MilshakeQty)
    TotalPriceBeforeTax.Add(HamburgerTotPrice, MilkshakeTotPrice)
    TaxAmount.Mul(TotalPriceBeforeTax, Tax)
    TotalPrice.Add(TotalPriceBeforeTax, TaxAmount)
    //Print the result
    fmt.Println("Total Price : $", TotalPrice.FloatString(2))
    }

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Gerard at Dec 30, 2013 at 7:52 am
    Using floats in financial software is a big nono (rounding issues).

    There are several decimal packages (including this<http://code.google.com/p/godec/>one) around there and there has also been some discussion about this
    subject in this newsgroup.

    Best,
    Gerard
    On Monday, December 30, 2013 12:16:26 AM UTC+1, John Whitton wrote:

    Hi all,

    I'm trying to work with currencies in go. I'm using a simple shopping cart
    example where someone is buying some hamburgers and milkshakes, calculating
    tax and the total amount.
    You can see the code here http://play.golang.org/p/LevYw2DU7R and below
    It took me about 40 lines of code to do this and it did not seem
    intuitive.
    I know there's been some discussion regarding whether to make the amounts
    as integers using cents vs big.Rat
    If anyone can show me a simpler way to do this, I'd appreciate it.
    I'm at the stage where I'm starting to define my types and datastore
    elements and would like to have a sound approach for currency before
    continuing.

    Regards,

    John

    // Currency Example
    //I want to buy 4 Hamburgers ($5.50 each) and 2 Milkshakes ($2.86 each)
    // Calcualte the Total Price Before Tax = $27.72 = 4 * $5.50 + 2 * $2.86
    // Calculate the Tax (7.65%) amount $2.12 = $27.72 * 0.765
    // Calculate the Total Price $29.84 = $27.72 + $2.12

    package main

    import (
    "fmt"
    "math/big"
    )

    func main() {

    //Define all the variables
    HamburgerPrice := new(big.Rat)
    HamburgerQty := new(big.Rat)
    HamburgerTotPrice := new(big.Rat)
    MilkshakePrice := new(big.Rat)
    MilshakeQty := new(big.Rat)
    MilkshakeTotPrice := new(big.Rat)
    Tax := new(big.Rat)
    TotalPriceBeforeTax := new(big.Rat)
    TaxAmount := new(big.Rat)
    TotalPrice := new(big.Rat)

    //Scan all the Variables
    _, err := fmt.Sscan("5.50", HamburgerPrice)
    _, err = fmt.Sscan("4", HamburgerQty)
    _, err = fmt.Sscan("2.86", MilkshakePrice)
    _, err = fmt.Sscan("2", MilshakeQty)
    _, err = fmt.Sscan("0.0765", Tax)
    if err != nil {
    fmt.Println("error scanning value:", err)
    }
    //Do the Calculation
    HamburgerTotPrice.Mul(HamburgerPrice, HamburgerQty)
    MilkshakeTotPrice.Mul(MilkshakePrice, MilshakeQty)
    TotalPriceBeforeTax.Add(HamburgerTotPrice, MilkshakeTotPrice)
    TaxAmount.Mul(TotalPriceBeforeTax, Tax)
    TotalPrice.Add(TotalPriceBeforeTax, TaxAmount)
    //Print the result
    fmt.Println("Total Price : $", TotalPrice.FloatString(2))
    }
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Shkarupin at Dec 30, 2013 at 3:04 pm
    It would be nice to have full (native) support for decimals in GO with
    overloaded operators. With current implementation not only it is hard to
    read but you still have to take care of rounding issues
    val1:= new (big.Rat)
    val1 = val1.SetFloat64(1.1)
    val2 := new (big.Rat)
    val2.SetFloat64(0.1)
    two := big.NewRat(2,1)
    avg := val1.Add(val1, val2).Quo(val1, two)
    fmt.Println(avg.Float64())
    On Monday, December 30, 2013 1:52:49 AM UTC-6, Gerard wrote:

    Using floats in financial software is a big nono (rounding issues).

    There are several decimal packages (including this<http://code.google.com/p/godec/>one) around there and there has also been some discussion about this
    subject in this newsgroup.

    Best,
    Gerard
    On Monday, December 30, 2013 12:16:26 AM UTC+1, John Whitton wrote:

    Hi all,

    I'm trying to work with currencies in go. I'm using a simple shopping
    cart example where someone is buying some hamburgers and milkshakes,
    calculating tax and the total amount.
    You can see the code here http://play.golang.org/p/LevYw2DU7R and below
    It took me about 40 lines of code to do this and it did not seem
    intuitive.
    I know there's been some discussion regarding whether to make the amounts
    as integers using cents vs big.Rat
    If anyone can show me a simpler way to do this, I'd appreciate it.
    I'm at the stage where I'm starting to define my types and datastore
    elements and would like to have a sound approach for currency before
    continuing.

    Regards,

    John

    // Currency Example
    //I want to buy 4 Hamburgers ($5.50 each) and 2 Milkshakes ($2.86 each)
    // Calcualte the Total Price Before Tax = $27.72 = 4 * $5.50 + 2 * $2.86
    // Calculate the Tax (7.65%) amount $2.12 = $27.72 * 0.765
    // Calculate the Total Price $29.84 = $27.72 + $2.12

    package main

    import (
    "fmt"
    "math/big"
    )

    func main() {

    //Define all the variables
    HamburgerPrice := new(big.Rat)
    HamburgerQty := new(big.Rat)
    HamburgerTotPrice := new(big.Rat)
    MilkshakePrice := new(big.Rat)
    MilshakeQty := new(big.Rat)
    MilkshakeTotPrice := new(big.Rat)
    Tax := new(big.Rat)
    TotalPriceBeforeTax := new(big.Rat)
    TaxAmount := new(big.Rat)
    TotalPrice := new(big.Rat)

    //Scan all the Variables
    _, err := fmt.Sscan("5.50", HamburgerPrice)
    _, err = fmt.Sscan("4", HamburgerQty)
    _, err = fmt.Sscan("2.86", MilkshakePrice)
    _, err = fmt.Sscan("2", MilshakeQty)
    _, err = fmt.Sscan("0.0765", Tax)
    if err != nil {
    fmt.Println("error scanning value:", err)
    }
    //Do the Calculation
    HamburgerTotPrice.Mul(HamburgerPrice, HamburgerQty)
    MilkshakeTotPrice.Mul(MilkshakePrice, MilshakeQty)
    TotalPriceBeforeTax.Add(HamburgerTotPrice, MilkshakeTotPrice)
    TaxAmount.Mul(TotalPriceBeforeTax, Tax)
    TotalPrice.Add(TotalPriceBeforeTax, TaxAmount)
    //Print the result
    fmt.Println("Total Price : $", TotalPrice.FloatString(2))
    }
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jan Mercl at Dec 30, 2013 at 3:12 pm

    On Mon, Dec 30, 2013 at 4:04 PM, wrote:
    It would be nice to have full (native) support for decimals in GO with
    overloaded operators. With current implementation not only it is hard to
    read but you still have to take care of rounding issues
    val1:= new (big.Rat)
    val1 = val1.SetFloat64(1.1)
    val2 := new (big.Rat)
    val2.SetFloat64(0.1)
    two := big.NewRat(2,1)
    avg := val1.Add(val1, val2).Quo(val1, two)
    fmt.Println(avg.Float64())
    The four basic arithmetic operations are performed exactly for
    big.{Int,Rat} typed values. There's nothing to gain here wrt a decimal
    type.

    Rounding issues are introduced only by using inexact (floating point)
    numbers (for no good reason). And, the very same would happen using a
    decimal type.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Shkarupin at Dec 30, 2013 at 3:20 pm
    Yes there is. This is how this formula looks in c#
      var avg = (0.1d + 1.1d)/2
    printing avg would return 0.6 (something that I expect with decimals)
    On Monday, December 30, 2013 9:11:40 AM UTC-6, Jan Mercl wrote:

    On Mon, Dec 30, 2013 at 4:04 PM, <shka...@gmail.com <javascript:>>
    wrote:
    It would be nice to have full (native) support for decimals in GO with
    overloaded operators. With current implementation not only it is hard to
    read but you still have to take care of rounding issues
    val1:= new (big.Rat)
    val1 = val1.SetFloat64(1.1)
    val2 := new (big.Rat)
    val2.SetFloat64(0.1)
    two := big.NewRat(2,1)
    avg := val1.Add(val1, val2).Quo(val1, two)
    fmt.Println(avg.Float64())
    The four basic arithmetic operations are performed exactly for
    big.{Int,Rat} typed values. There's nothing to gain here wrt a decimal
    type.

    Rounding issues are introduced only by using inexact (floating point)
    numbers (for no good reason). And, the very same would happen using a
    decimal type.

    -j
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Michael Jones at Dec 30, 2013 at 4:52 pm
    ...same works with int64 using values*1000:

    var avg = (100 + 1100)/2

    John von Neumann did it this way. So can you.

    On Mon, Dec 30, 2013 at 7:20 AM, wrote:

    Yes there is. This is how this formula looks in c#
    var avg = (0.1d + 1.1d)/2
    printing avg would return 0.6 (something that I expect with decimals)
    On Monday, December 30, 2013 9:11:40 AM UTC-6, Jan Mercl wrote:
    On Mon, Dec 30, 2013 at 4:04 PM, wrote:
    It would be nice to have full (native) support for decimals in GO with
    overloaded operators. With current implementation not only it is hard to
    read but you still have to take care of rounding issues
    val1:= new (big.Rat)
    val1 = val1.SetFloat64(1.1)
    val2 := new (big.Rat)
    val2.SetFloat64(0.1)
    two := big.NewRat(2,1)
    avg := val1.Add(val1, val2).Quo(val1, two)
    fmt.Println(avg.Float64())
    The four basic arithmetic operations are performed exactly for
    big.{Int,Rat} typed values. There's nothing to gain here wrt a decimal
    type.

    Rounding issues are introduced only by using inexact (floating point)
    numbers (for no good reason). And, the very same would happen using a
    decimal type.

    -j
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | mtj@google.com | +1
    650-335-5765
    *(Note: this email has been shared with you under the terms of Regulation
    23 <http://go/cory-eula>)*

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Shkarupin at Dec 30, 2013 at 5:38 pm
    I can, but it doesn't make developer's work easier, nor it makes
    calculations more precise. They way I see it right now is: GO does support decimal
    (Rat) if you really need it, but it is rather painful to use it for any
    (serious) financial/accounting software. I agree for some scenarios
    suggested method or even floats would be enough.
    On Monday, December 30, 2013 10:51:54 AM UTC-6, Michael Jones wrote:

    ...same works with int64 using values*1000:

    var avg = (100 + 1100)/2

    John von Neumann did it this way. So can you.

    On Mon, Dec 30, 2013 at 7:20 AM, <shka...@gmail.com <javascript:>> wrote:

    Yes there is. This is how this formula looks in c#
    var avg = (0.1d + 1.1d)/2
    printing avg would return 0.6 (something that I expect with decimals)
    On Monday, December 30, 2013 9:11:40 AM UTC-6, Jan Mercl wrote:
    On Mon, Dec 30, 2013 at 4:04 PM, wrote:
    It would be nice to have full (native) support for decimals in GO with
    overloaded operators. With current implementation not only it is hard to
    read but you still have to take care of rounding issues
    val1:= new (big.Rat)
    val1 = val1.SetFloat64(1.1)
    val2 := new (big.Rat)
    val2.SetFloat64(0.1)
    two := big.NewRat(2,1)
    avg := val1.Add(val1, val2).Quo(val1, two)
    fmt.Println(avg.Float64())
    The four basic arithmetic operations are performed exactly for
    big.{Int,Rat} typed values. There's nothing to gain here wrt a decimal
    type.

    Rounding issues are introduced only by using inexact (floating point)
    numbers (for no good reason). And, the very same would happen using a
    decimal type.

    -j
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | m...@google.com<javascript:>
    +1 650-335-5765
    *(Note: this email has been shared with you under the terms of Regulation
    23 <http://go/cory-eula>)*
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Gerard at Dec 30, 2013 at 7:18 pm
    As I said before, you can also look at other decimal packages. If you
    search you will find them. Or create your own. It's not that hard.
    On Monday, December 30, 2013 6:38:01 PM UTC+1, shka...@gmail.com wrote:

    I can, but it doesn't make developer's work easier, nor it makes
    calculations more precise. They way I see it right now is: GO does support decimal
    (Rat) if you really need it, but it is rather painful to use it for any
    (serious) financial/accounting software. I agree for some scenarios
    suggested method or even floats would be enough.
    On Monday, December 30, 2013 10:51:54 AM UTC-6, Michael Jones wrote:

    ...same works with int64 using values*1000:

    var avg = (100 + 1100)/2

    John von Neumann did it this way. So can you.

    On Mon, Dec 30, 2013 at 7:20 AM, wrote:

    Yes there is. This is how this formula looks in c#
    var avg = (0.1d + 1.1d)/2
    printing avg would return 0.6 (something that I expect with decimals)
    On Monday, December 30, 2013 9:11:40 AM UTC-6, Jan Mercl wrote:
    On Mon, Dec 30, 2013 at 4:04 PM, wrote:
    It would be nice to have full (native) support for decimals in GO with
    overloaded operators. With current implementation not only it is hard to
    read but you still have to take care of rounding issues
    val1:= new (big.Rat)
    val1 = val1.SetFloat64(1.1)
    val2 := new (big.Rat)
    val2.SetFloat64(0.1)
    two := big.NewRat(2,1)
    avg := val1.Add(val1, val2).Quo(val1, two)
    fmt.Println(avg.Float64())
    The four basic arithmetic operations are performed exactly for
    big.{Int,Rat} typed values. There's nothing to gain here wrt a decimal
    type.

    Rounding issues are introduced only by using inexact (floating point)
    numbers (for no good reason). And, the very same would happen using a
    decimal type.

    -j
    --
    You received this message because you are subscribed to the Google
    Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send
    an email to golang-nuts...@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | m...@google.com | +1
    650-335-5765
    *(Note: this email has been shared with you under the terms of Regulation
    23 <http://go/cory-eula>)*
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Simon place at Dec 30, 2013 at 7:58 pm
    from memory, when working with actual money, what is done is to use
    integers, of (for USD) 1/1000 of a cent.

    so 1 dollar is represented by 100,000.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Francesc Campoy Flores at Dec 30, 2013 at 8:16 pm
    I would probably use something really simple as in
    http://play.golang.org/p/DJGVtMFYJf

    You can probably add a parsing method too if you need it.

    On Mon, Dec 30, 2013 at 11:58 AM, simon place wrote:

    from memory, when working with actual money, what is done is to use
    integers, of (for USD) 1/1000 of a cent.

    so 1 dollar is represented by 100,000.

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    --
    Francesc Campoy
    http://campoy.cat

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Sugu Sougoumarane at Dec 31, 2013 at 1:26 am
    Financial institutions don't like fractional pennies:
    http://youtu.be/orGNl-S2IoE?t=37s
    So, it'll be easier if you used an int64 to represent whole pennies.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Caleb Doxsey at Dec 31, 2013 at 1:49 am
    C#'s decimal type is 128 bit and follows this spec:

    http://en.wikipedia.org/wiki/Decimal128_floating-point_format

    It's significantly more complicated than just using an int64 to represent
    fractions of a penny.
    On Mon, Dec 30, 2013 at 6:25 PM, Sugu Sougoumarane wrote:

    Financial institutions don't like fractional pennies:
    http://youtu.be/orGNl-S2IoE?t=37s
    So, it'll be easier if you used an int64 to represent whole pennies.

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • John Waycott at Dec 31, 2013 at 2:16 am
    The company I work for interfaces to dozens of payment transaction
    processing companies. There is no real standard for the format payment
    processors require - int, BCD, ASCII with spaces on the left or right,
    fixed and variable widths, etc. I am not aware of any that use float (for
    hopefully obvious reasons).

    Internally, we use 64-bit integers representing cents and convert to the
    appropriate format for the payment processor. We have not had a need yet to
    provide fractions of cents, and indeed, most processors don't even support
    them yet. Hever it is just as easy to represent fractional cents. Even
    going to 1/1,000,000th cent accuracy there would still be plenty of room
    for the dollar amount.

    The complexity of a general decimal type seems overkill to me. I think
    Caleb's example of using ideas similar to the Time Duration type is a good
    way to handle currency in Go.

    On Sunday, December 29, 2013 4:16:26 PM UTC-7, John Whitton wrote:

    Hi all,

    I'm trying to work with currencies in go. I'm using a simple shopping cart
    example where someone is buying some hamburgers and milkshakes, calculating
    tax and the total amount.
    You can see the code here http://play.golang.org/p/LevYw2DU7R and below
    It took me about 40 lines of code to do this and it did not seem
    intuitive.
    I know there's been some discussion regarding whether to make the amounts
    as integers using cents vs big.Rat
    If anyone can show me a simpler way to do this, I'd appreciate it.
    I'm at the stage where I'm starting to define my types and datastore
    elements and would like to have a sound approach for currency before
    continuing.

    Regards,

    John

    // Currency Example
    //I want to buy 4 Hamburgers ($5.50 each) and 2 Milkshakes ($2.86 each)
    // Calcualte the Total Price Before Tax = $27.72 = 4 * $5.50 + 2 * $2.86
    // Calculate the Tax (7.65%) amount $2.12 = $27.72 * 0.765
    // Calculate the Total Price $29.84 = $27.72 + $2.12

    package main

    import (
    "fmt"
    "math/big"
    )

    func main() {

    //Define all the variables
    HamburgerPrice := new(big.Rat)
    HamburgerQty := new(big.Rat)
    HamburgerTotPrice := new(big.Rat)
    MilkshakePrice := new(big.Rat)
    MilshakeQty := new(big.Rat)
    MilkshakeTotPrice := new(big.Rat)
    Tax := new(big.Rat)
    TotalPriceBeforeTax := new(big.Rat)
    TaxAmount := new(big.Rat)
    TotalPrice := new(big.Rat)

    //Scan all the Variables
    _, err := fmt.Sscan("5.50", HamburgerPrice)
    _, err = fmt.Sscan("4", HamburgerQty)
    _, err = fmt.Sscan("2.86", MilkshakePrice)
    _, err = fmt.Sscan("2", MilshakeQty)
    _, err = fmt.Sscan("0.0765", Tax)
    if err != nil {
    fmt.Println("error scanning value:", err)
    }
    //Do the Calculation
    HamburgerTotPrice.Mul(HamburgerPrice, HamburgerQty)
    MilkshakeTotPrice.Mul(MilkshakePrice, MilshakeQty)
    TotalPriceBeforeTax.Add(HamburgerTotPrice, MilkshakeTotPrice)
    TaxAmount.Mul(TotalPriceBeforeTax, Tax)
    TotalPrice.Add(TotalPriceBeforeTax, TaxAmount)
    //Print the result
    fmt.Println("Total Price : $", TotalPrice.FloatString(2))
    }
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Shkarupin at Dec 31, 2013 at 6:33 pm
    Consider this simple example:
    This formula (if you use int64) $100/$339*$10000 in our case would result
    in 0 regardless of precision, but should be 2949.8525
    With decimals (or Rat) you will get correct result with ints you don't
    (unless you complicate the formula to work with reminders too)
    For this reason major db vendors implement decimal/numeric support
    On Monday, December 30, 2013 8:16:06 PM UTC-6, John Waycott wrote:

    The company I work for interfaces to dozens of payment transaction
    processing companies. There is no real standard for the format payment
    processors require - int, BCD, ASCII with spaces on the left or right,
    fixed and variable widths, etc. I am not aware of any that use float (for
    hopefully obvious reasons).

    Internally, we use 64-bit integers representing cents and convert to the
    appropriate format for the payment processor. We have not had a need yet to
    provide fractions of cents, and indeed, most processors don't even support
    them yet. Hever it is just as easy to represent fractional cents. Even
    going to 1/1,000,000th cent accuracy there would still be plenty of room
    for the dollar amount.

    The complexity of a general decimal type seems overkill to me. I think
    Caleb's example of using ideas similar to the Time Duration type is a good
    way to handle currency in Go.

    On Sunday, December 29, 2013 4:16:26 PM UTC-7, John Whitton wrote:

    Hi all,

    I'm trying to work with currencies in go. I'm using a simple shopping
    cart example where someone is buying some hamburgers and milkshakes,
    calculating tax and the total amount.
    You can see the code here http://play.golang.org/p/LevYw2DU7R and below
    It took me about 40 lines of code to do this and it did not seem
    intuitive.
    I know there's been some discussion regarding whether to make the amounts
    as integers using cents vs big.Rat
    If anyone can show me a simpler way to do this, I'd appreciate it.
    I'm at the stage where I'm starting to define my types and datastore
    elements and would like to have a sound approach for currency before
    continuing.

    Regards,

    John

    // Currency Example
    //I want to buy 4 Hamburgers ($5.50 each) and 2 Milkshakes ($2.86 each)
    // Calcualte the Total Price Before Tax = $27.72 = 4 * $5.50 + 2 * $2.86
    // Calculate the Tax (7.65%) amount $2.12 = $27.72 * 0.765
    // Calculate the Total Price $29.84 = $27.72 + $2.12

    package main

    import (
    "fmt"
    "math/big"
    )

    func main() {

    //Define all the variables
    HamburgerPrice := new(big.Rat)
    HamburgerQty := new(big.Rat)
    HamburgerTotPrice := new(big.Rat)
    MilkshakePrice := new(big.Rat)
    MilshakeQty := new(big.Rat)
    MilkshakeTotPrice := new(big.Rat)
    Tax := new(big.Rat)
    TotalPriceBeforeTax := new(big.Rat)
    TaxAmount := new(big.Rat)
    TotalPrice := new(big.Rat)

    //Scan all the Variables
    _, err := fmt.Sscan("5.50", HamburgerPrice)
    _, err = fmt.Sscan("4", HamburgerQty)
    _, err = fmt.Sscan("2.86", MilkshakePrice)
    _, err = fmt.Sscan("2", MilshakeQty)
    _, err = fmt.Sscan("0.0765", Tax)
    if err != nil {
    fmt.Println("error scanning value:", err)
    }
    //Do the Calculation
    HamburgerTotPrice.Mul(HamburgerPrice, HamburgerQty)
    MilkshakeTotPrice.Mul(MilkshakePrice, MilshakeQty)
    TotalPriceBeforeTax.Add(HamburgerTotPrice, MilkshakeTotPrice)
    TaxAmount.Mul(TotalPriceBeforeTax, Tax)
    TotalPrice.Add(TotalPriceBeforeTax, TaxAmount)
    //Print the result
    fmt.Println("Total Price : $", TotalPrice.FloatString(2))
    }
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Michael Jones at Dec 31, 2013 at 7:12 pm
    One always multiplies before dividing in scaled integer arithmetic.
    http://en.wikipedia.org/wiki/Fixed-point_arithmetic

    In Forth, there is a special "MulDiv" operator "a b c */" that computes a*b
    in doubled integer precision and then divides the high precision result by
    c. It turns out that almost everything can be solved using MulDiv.

    On Tue, Dec 31, 2013 at 10:33 AM, wrote:

    Consider this simple example:
    This formula (if you use int64) $100/$339*$10000 in our case would result
    in 0 regardless of precision, but should be 2949.8525
    With decimals (or Rat) you will get correct result with ints you don't
    (unless you complicate the formula to work with reminders too)
    For this reason major db vendors implement decimal/numeric support
    On Monday, December 30, 2013 8:16:06 PM UTC-6, John Waycott wrote:

    The company I work for interfaces to dozens of payment transaction
    processing companies. There is no real standard for the format payment
    processors require - int, BCD, ASCII with spaces on the left or right,
    fixed and variable widths, etc. I am not aware of any that use float (for
    hopefully obvious reasons).

    Internally, we use 64-bit integers representing cents and convert to the
    appropriate format for the payment processor. We have not had a need yet to
    provide fractions of cents, and indeed, most processors don't even support
    them yet. Hever it is just as easy to represent fractional cents. Even
    going to 1/1,000,000th cent accuracy there would still be plenty of room
    for the dollar amount.

    The complexity of a general decimal type seems overkill to me. I think
    Caleb's example of using ideas similar to the Time Duration type is a good
    way to handle currency in Go.

    On Sunday, December 29, 2013 4:16:26 PM UTC-7, John Whitton wrote:

    Hi all,

    I'm trying to work with currencies in go. I'm using a simple shopping
    cart example where someone is buying some hamburgers and milkshakes,
    calculating tax and the total amount.
    You can see the code here http://play.golang.org/p/LevYw2DU7R and below
    It took me about 40 lines of code to do this and it did not seem
    intuitive.
    I know there's been some discussion regarding whether to make the
    amounts as integers using cents vs big.Rat
    If anyone can show me a simpler way to do this, I'd appreciate it.
    I'm at the stage where I'm starting to define my types and datastore
    elements and would like to have a sound approach for currency before
    continuing.

    Regards,

    John

    // Currency Example
    //I want to buy 4 Hamburgers ($5.50 each) and 2 Milkshakes ($2.86 each)
    // Calcualte the Total Price Before Tax = $27.72 = 4 * $5.50 + 2 * $2.86
    // Calculate the Tax (7.65%) amount $2.12 = $27.72 * 0.765
    // Calculate the Total Price $29.84 = $27.72 + $2.12

    package main

    import (
    "fmt"
    "math/big"
    )

    func main() {

    //Define all the variables
    HamburgerPrice := new(big.Rat)
    HamburgerQty := new(big.Rat)
    HamburgerTotPrice := new(big.Rat)
    MilkshakePrice := new(big.Rat)
    MilshakeQty := new(big.Rat)
    MilkshakeTotPrice := new(big.Rat)
    Tax := new(big.Rat)
    TotalPriceBeforeTax := new(big.Rat)
    TaxAmount := new(big.Rat)
    TotalPrice := new(big.Rat)

    //Scan all the Variables
    _, err := fmt.Sscan("5.50", HamburgerPrice)
    _, err = fmt.Sscan("4", HamburgerQty)
    _, err = fmt.Sscan("2.86", MilkshakePrice)
    _, err = fmt.Sscan("2", MilshakeQty)
    _, err = fmt.Sscan("0.0765", Tax)
    if err != nil {
    fmt.Println("error scanning value:", err)
    }
    //Do the Calculation
    HamburgerTotPrice.Mul(HamburgerPrice, HamburgerQty)
    MilkshakeTotPrice.Mul(MilkshakePrice, MilshakeQty)
    TotalPriceBeforeTax.Add(HamburgerTotPrice, MilkshakeTotPrice)
    TaxAmount.Mul(TotalPriceBeforeTax, Tax)
    TotalPrice.Add(TotalPriceBeforeTax, TaxAmount)
    //Print the result
    fmt.Println("Total Price : $", TotalPrice.FloatString(2))
    }

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | mtj@google.com | +1
    650-335-5765
    *(Note: this email has been shared with you under the terms of Regulation
    23 <http://go/cory-eula>)*

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Shkarupin at Dec 31, 2013 at 7:32 pm
    I doubt anyone writing financial software would consider first option. It
    is error prone. It changes formulas e.g. (100/339 + 1)*10000 would result
    in 100*10000/339 + 1*10000. So far big.Rat is the winner but it is not easy
    to work with that either. I'm not familiar with MulDiv operator
    On Tuesday, December 31, 2013 1:11:44 PM UTC-6, Michael Jones wrote:

    One always multiplies before dividing in scaled integer arithmetic.
    http://en.wikipedia.org/wiki/Fixed-point_arithmetic

    In Forth, there is a special "MulDiv" operator "a b c */" that computes
    a*b in doubled integer precision and then divides the high precision result
    by c. It turns out that almost everything can be solved using MulDiv.

    On Tue, Dec 31, 2013 at 10:33 AM, <shka...@gmail.com <javascript:>> wrote:

    Consider this simple example:
    This formula (if you use int64) $100/$339*$10000 in our case would result
    in 0 regardless of precision, but should be 2949.8525
    With decimals (or Rat) you will get correct result with ints you don't
    (unless you complicate the formula to work with reminders too)
    For this reason major db vendors implement decimal/numeric support
    On Monday, December 30, 2013 8:16:06 PM UTC-6, John Waycott wrote:

    The company I work for interfaces to dozens of payment transaction
    processing companies. There is no real standard for the format payment
    processors require - int, BCD, ASCII with spaces on the left or right,
    fixed and variable widths, etc. I am not aware of any that use float (for
    hopefully obvious reasons).

    Internally, we use 64-bit integers representing cents and convert to the
    appropriate format for the payment processor. We have not had a need yet to
    provide fractions of cents, and indeed, most processors don't even support
    them yet. Hever it is just as easy to represent fractional cents. Even
    going to 1/1,000,000th cent accuracy there would still be plenty of room
    for the dollar amount.

    The complexity of a general decimal type seems overkill to me. I think
    Caleb's example of using ideas similar to the Time Duration type is a good
    way to handle currency in Go.

    On Sunday, December 29, 2013 4:16:26 PM UTC-7, John Whitton wrote:

    Hi all,

    I'm trying to work with currencies in go. I'm using a simple shopping
    cart example where someone is buying some hamburgers and milkshakes,
    calculating tax and the total amount.
    You can see the code here http://play.golang.org/p/LevYw2DU7R and below
    It took me about 40 lines of code to do this and it did not seem
    intuitive.
    I know there's been some discussion regarding whether to make the
    amounts as integers using cents vs big.Rat
    If anyone can show me a simpler way to do this, I'd appreciate it.
    I'm at the stage where I'm starting to define my types and datastore
    elements and would like to have a sound approach for currency before
    continuing.

    Regards,

    John

    // Currency Example
    //I want to buy 4 Hamburgers ($5.50 each) and 2 Milkshakes ($2.86 each)
    // Calcualte the Total Price Before Tax = $27.72 = 4 * $5.50 + 2 * $2.86
    // Calculate the Tax (7.65%) amount $2.12 = $27.72 * 0.765
    // Calculate the Total Price $29.84 = $27.72 + $2.12

    package main

    import (
    "fmt"
    "math/big"
    )

    func main() {

    //Define all the variables
    HamburgerPrice := new(big.Rat)
    HamburgerQty := new(big.Rat)
    HamburgerTotPrice := new(big.Rat)
    MilkshakePrice := new(big.Rat)
    MilshakeQty := new(big.Rat)
    MilkshakeTotPrice := new(big.Rat)
    Tax := new(big.Rat)
    TotalPriceBeforeTax := new(big.Rat)
    TaxAmount := new(big.Rat)
    TotalPrice := new(big.Rat)

    //Scan all the Variables
    _, err := fmt.Sscan("5.50", HamburgerPrice)
    _, err = fmt.Sscan("4", HamburgerQty)
    _, err = fmt.Sscan("2.86", MilkshakePrice)
    _, err = fmt.Sscan("2", MilshakeQty)
    _, err = fmt.Sscan("0.0765", Tax)
    if err != nil {
    fmt.Println("error scanning value:", err)
    }
    //Do the Calculation
    HamburgerTotPrice.Mul(HamburgerPrice, HamburgerQty)
    MilkshakeTotPrice.Mul(MilkshakePrice, MilshakeQty)
    TotalPriceBeforeTax.Add(HamburgerTotPrice, MilkshakeTotPrice)
    TaxAmount.Mul(TotalPriceBeforeTax, Tax)
    TotalPrice.Add(TotalPriceBeforeTax, TaxAmount)
    //Print the result
    fmt.Println("Total Price : $", TotalPrice.FloatString(2))
    }

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | m...@google.com<javascript:>
    +1 650-335-5765
    *(Note: this email has been shared with you under the terms of Regulation
    23 <http://go/cory-eula>)*
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • John Waycott at Jan 1, 2014 at 4:29 pm

    On Tuesday, December 31, 2013 12:32:01 PM UTC-7, shka...@gmail.com wrote:
    I doubt anyone writing financial software would consider first option. It
    is error prone. It changes formulas e.g. (100/339 + 1)*10000 would result
    in 100*10000/339 + 1*10000. So far big.Rat is the winner but it is not easy
    to work with that either. I'm not familiar with MulDiv operator
    On Tuesday, December 31, 2013 1:11:44 PM UTC-6, Michael Jones wrote:

    One always multiplies before dividing in scaled integer arithmetic.
    http://en.wikipedia.org/wiki/Fixed-point_arithmetic

    In Forth, there is a special "MulDiv" operator "a b c */" that computes
    a*b in doubled integer precision and then divides the high precision result
    by c. It turns out that almost everything can be solved using MulDiv.
      All of the programmers I've known who have written financial software
    dealing with division and multiplication are well aware of the pitfalls of
    dividing before multiplying. It is a well-studied problem.

    I think you mean $100/339*10000. I can't imagine any case where you would
    multiply two currency values. The results are nonsensical. $10/$5 is an
    untyped number which might be useful, but the result is not currency. Is
    $20 * $30 = 600 square-dollars? Seriously, using a decimal package might
    make sense for complex calculations such as compounding interest, but I'd
    wager most programmers need to just add up a bunch of prices on an invoice.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedDec 29, '13 at 11:38p
activeJan 1, '14 at 4:29p
posts18
users11
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase