FAQ
Thanks for your reply. It is caused by the precision of float32 type.

Another question is how do I get 470, not 469 if I really have to let 4.7 *
100?

I mean is there a best practice to handle it?


在 2015年8月27日星期四 UTC+8上午12:56:23,bradfitz写道:
[-golang-dev, +golang-nuts]

You can read more about floating point numbers here:

https://en.wikipedia.org/wiki/Floating_point
and
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html



On Wed, Aug 26, 2015 at 7:35 AM, Timothy Ye <yexiaoz...@gmail.com
<javascript:>> wrote:
Hey guys,

I met a weird problem about the float32 type in Go.

This is my demo program: (You can run it via:
http://play.golang.org/p/dn4V4TcFtr)

package main

import "fmt"

func main() {
compute(4.8)
compute(4.7)
compute(4.6)
compute(4.5)
}

func compute(input float32) {
result := int64(input * 100)
fmt.Printf("Result is:%d\r\n", result)
result = int64(int(input *10)*10)
fmt.Printf("Result is:%d\r\n", result)
}

==================

The output is:

Result is:480
Result is:480
Result is:469
Result is:470
Result is:460
Result is:460
Result is:450
Result is:450


You may notice that all the results are as expected except when input is 4.7

I am confused about the float 4.7 * 100, why the result is 469?


But if I let 4.7 * 10 first, then convert it to int type and multiply by 10 again, the result is 470, not 469.


I don't know why, can anybody help to explain it? Thanks a lot!

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

Search Discussions

  • Ian Lance Taylor at Aug 26, 2015 at 5:28 pm

    On Wed, Aug 26, 2015 at 10:27 AM, Timothy Ye wrote:
    Thanks for your reply. It is caused by the precision of float32 type.

    Another question is how do I get 470, not 469 if I really have to let 4.7 *
    100?

    I mean is there a best practice to handle it?
    Don't use floating point?

    What are you really trying to do?

    Ian

    --
    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/d/optout.
  • Timothy Ye at Aug 27, 2015 at 1:57 am
    Hi Ian,

    Actually, 4.7 is the price of one product, 100 is the amount user ordered.
    I expect to get total price 470, not 469... -_-#


    在 2015年8月27日星期四 UTC+8上午1:28:44,Ian Lance Taylor写道:
    On Wed, Aug 26, 2015 at 10:27 AM, Timothy Ye <yexiaoz...@gmail.com
    <javascript:>> wrote:
    Thanks for your reply. It is caused by the precision of float32 type.

    Another question is how do I get 470, not 469 if I really have to let 4.7 *
    100?

    I mean is there a best practice to handle it?
    Don't use floating point?

    What are you really trying to do?

    Ian
    --
    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/d/optout.
  • Steven Blenkinsop at Aug 27, 2015 at 3:32 am
    Yeah, floating point is not good for financial computations. Computing
    costs in cents using integers could work, depending on your rounding
    strategy.
    On Wed, Aug 26, 2015 at 9:57 PM Timothy Ye wrote:

    Hi Ian,

    Actually, 4.7 is the price of one product, 100 is the amount user ordered.
    I expect to get total price 470, not 469... -_-#


    在 2015年8月27日星期四 UTC+8上午1:28:44,Ian Lance Taylor写道:
    On Wed, Aug 26, 2015 at 10:27 AM, Timothy Ye <yexiaoz...@gmail.com>
    wrote:
    Thanks for your reply. It is caused by the precision of float32 type.

    Another question is how do I get 470, not 469 if I really have to let 4.7 *
    100?

    I mean is there a best practice to handle it?
    Don't use floating point?

    What are you really trying to do?

    Ian
    --
    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/d/optout.
    --
    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/d/optout.
  • Wilhelmina Drengwitz at Aug 27, 2015 at 3:41 am
    You may want look into a fixed point decimal package, such as decnum[1].

    See this issue[2] for other potential (non)fixed point decimal
    packages to try out.

    [1] https://godoc.org/github.com/rin01/decnum
    [2] https://github.com/golang/go/issues/12332
    On Wed, Aug 26, 2015 at 9:57 PM, Timothy Ye wrote:
    Hi Ian,

    Actually, 4.7 is the price of one product, 100 is the amount user ordered.
    I expect to get total price 470, not 469... -_-#


    在 2015年8月27日星期四 UTC+8上午1:28:44,Ian Lance Taylor写道:
    On Wed, Aug 26, 2015 at 10:27 AM, Timothy Ye wrote:
    Thanks for your reply. It is caused by the precision of float32 type.

    Another question is how do I get 470, not 469 if I really have to let
    4.7 *
    100?

    I mean is there a best practice to handle it?
    Don't use floating point?

    What are you really trying to do?

    Ian
    --
    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/d/optout.
    --
    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/d/optout.
  • Dave Trombley at Aug 27, 2015 at 3:42 am
    As others have noted, you should use fixed-point numbers for prices or
    transactions in practice. That said, int conversion here will always
    round down - it's a truncation. You may want to round before truncating -
    use (x - math.Floor()), compare the result to 0.5, and adjust up as
    necessary...
    On Wednesday, August 26, 2015 at 12:56:23 PM UTC-4, bradfitz wrote:

    [-golang-dev, +golang-nuts]

    You can read more about floating point numbers here:

    https://en.wikipedia.org/wiki/Floating_point
    and
    http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html



    On Wed, Aug 26, 2015 at 7:35 AM, Timothy Ye <yexiaoz...@gmail.com
    <javascript:>> wrote:
    Hey guys,

    I met a weird problem about the float32 type in Go.

    This is my demo program: (You can run it via:
    http://play.golang.org/p/dn4V4TcFtr)

    package main

    import "fmt"

    func main() {
    compute(4.8)
    compute(4.7)
    compute(4.6)
    compute(4.5)
    }

    func compute(input float32) {
    result := int64(input * 100)
    fmt.Printf("Result is:%d\r\n", result)
    result = int64(int(input *10)*10)
    fmt.Printf("Result is:%d\r\n", result)
    }

    ==================

    The output is:

    Result is:480
    Result is:480
    Result is:469
    Result is:470
    Result is:460
    Result is:460
    Result is:450
    Result is:450


    You may notice that all the results are as expected except when input is 4.7

    I am confused about the float 4.7 * 100, why the result is 469?


    But if I let 4.7 * 10 first, then convert it to int type and multiply by 10 again, the result is 470, not 469.


    I don't know why, can anybody help to explain it? Thanks a lot!

    --
    You received this message because you are subscribed to the Google Groups
    "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-dev+...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/d/optout.
    --
    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/d/optout.
  • Xiiophen at Aug 27, 2015 at 11:45 am
    package main
    import "fmt"
    func main() {
      compute(4.8)
      compute(4.7)
      compute(4.6)
      compute(4.5)
    }
    func compute(input float32) {
      fmt.Println(input * 100)
    }


      http://play.golang.org/p/EgHj3nMX8E

    This shows explicity what is going wrong. As noted above there are other
    ways to round (https://en.wikipedia.org/wiki/Rounding#Rounding_to_integer)

    If working with currency use ints - with the lowest denomination as the
    base value (ie cents). For interest calculations on currency there's still
    a use for Binary Coded Decimal to avoid errors on 1/10ths 1/100ths etc -
    but this is a technical subject I'm not qualified to fully discuss.

    --
    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/d/optout.
  • Russ Cox at Aug 27, 2015 at 3:14 pm

    On Wed, Aug 26, 2015 at 1:27 PM, Timothy Ye wrote:

    Thanks for your reply. It is caused by the precision of float32 type.
    Another question is how do I get 470, not 469 if I really have to let 4.7
    * 100?
    I mean is there a best practice to handle it?
    >

    Abandoning floating point is the usual response to this kind of question,
    but it's really not necessary here. As others have pointed out, floating
    point numbers cannot represent decimal numbers exactly. There is a tiny bit
    of error due to rounding to a representable value. But that by itself does
    not explain your program's behavior.

    For a float32, the representation error is not more than 1 part in 2²⁴,
    or 0.000006%.
    For a float64, the representation error is not more than 1 part in 2⁵³, or
    0.00000000000001%.

    In your program, however, the error in your computation is 1 part in 470,
    or 0.2%. This is a good sign that the problem is *not* due to floating
    point representation error. Instead, the problem is just the conversion
    from float32 to int. In Go, like in C and other languages, the conversion
    from a floating point number to an integer discards the fractional part;
    that is, it truncates toward zero. The closest float32 representation for
    4.7 is actually 4.69999980926513671875; multiplying that by 100 gives the
    float32 469.999969482421875. Converting that to int with a Go conversion
    discards the fractional part, leaving 469.

    The way to keep tiny errors from becoming large errors during the
    conversion is to make the conversion round to the nearest integer instead
    of discarding the fractional part. The idiom for that is to use int(x+0.5)
    instead of int(x). If you make that simple change in your program,
    everything will work the way you expect. See
    http://play.golang.org/p/MVvelzhHVu, which prints:

    x = float32(4.7) = 4.69999980926513671875
    x*100 = 469.999969482421875
    int(x*100) = 469
    int(x*100+0.5) = 470


    It is worth a note of caution about float32. Although float32 is good
    enough for this particular computation, its range is very limited. That
    0.000006% means that for a given decimal number, a float32 only stores the
    first 7 digits accurately. In contrast, a float64 stores 15 digits
    accurately. In US dollars, assuming you care about pennies, that means a
    float32 fails to store $200,000.01 precisely while a float64 can precisely
    represent the current US national debt ($18,154,615,041,694.74). Unless you
    are squeezing space and know exactly what the tradeoff is that you're
    making, you should almost always use float64, not float32.

    Assuming you do use float64, floating point is perfectly fine for the vast
    majority of financial computations, and the various fixed point decimal or
    floating decimal packages are overkill. (In fact, again for most
    computations, a bug in the implementation of one of those seems more likely
    to me than an error caused by float64 precision.) Just make sure you round
    correctly when converting to integer.

    Russ

    --
    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/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedAug 26, '15 at 5:27p
activeAug 27, '15 at 3:14p
posts8
users7
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase