简体   繁体   English

Go:使用乘数将float64转换为int

[英]Go: Converting float64 to int with multiplier

I want to convert a float64 number, let's say it 1.003 to 1003 (integer type). 我想转换一个float64号码,比方说1.0031003 (整数类型)。 My implementation is simply multiply the float64 with 1000 and cast it to int . 我的实现只是将float641000相乘并将其转换为int

package main

import "fmt"


func main() {
  var f float64 = 1.003
  fmt.Println(int(f * 1000))
}

But when I run that code, what I got is 1002 not 1003 . 但是当我运行该代码时,我得到的是1002而不是1003 Because Go automatically stores 1.003 as 1.002999... in the variable. 因为Go会自动将1.003存储为1.002999...在变量中。 What is the correct approach to do this kind of operation on Golang? 在Golang上进行这种操作的正确方法是什么?

Go spec: Conversions: 转到规格:转换:

Conversions between numeric types 数字类型之间的转换

When converting a floating-point number to an integer, the fraction is discarded (truncation towards zero). 将浮点数转换为整数时,将丢弃该分数(截断为零)。

So basically when you convert a floating-point number to an integer, only the integer part is kept. 所以基本上当你将浮点数转换为整数时,只保留整数部分。

If you just want to avoid errors arising from representing with finite bits, just add 0.5 to the number before converting it to int . 如果您只是想避免因使用有限位表示而产生的错误,只需在将数字转换为int之前将数字加0.5即可。 No external libraries or function calls (from standard library) required. 无需外部库或函数调用(来自标准库)。

Since float -> int conversion is not rounding but keeping the integer part , this will give you the desired result. 由于float -> int转换不是舍入而是保留整数部分 ,因此这将为您提供所需的结果。 Taking into consideration both the possible smaller and greater representation: 考虑到可能的更小和更大的代表性:

1002.9999 + 0.5 = 1003.4999;     integer part: 1003
1003.0001 + 0.5 = 1003.5001;     integer part: 1003

So simply just write: 所以简单地写一下:

var f float64 = 1.003
fmt.Println(int(f * 1000 + 0.5))

To wrap this into a function: 将它包装成一个函数:

func toint(f float64) int {
    return int(f + 0.5)
}

// Using it:
fmt.Println(toint(f * 1000))

Try them on the Go Playground . Go Playground上试试

Note: 注意:

Be careful when you apply this in case of negative numbers! 如果是负数,请小心使用! For example if you have a value of -1.003 , then you probably want the result to be -1003 . 例如,如果您的值为-1.003 ,那么您可能希望结果为-1003 But if you add 0.5 to it: 但是如果你加0.5

-1002.9999 + 0.5 = -1002.4999;     integer part: -1002
-1003.0001 + 0.5 = -1002.5001;     integer part: -1002

So if you have negative numbers, you have to either: 因此,如果您有负数,则必须:

  • subtract 0.5 instead of adding it 减去0.5而不是添加它
  • or add 0.5 but subtract 1 from the result 或者添加0.5但从结果中减去1

Incorporating this into our helper function: 将此结合到我们的辅助函数中:

func toint(f float64) int {
    if f < 0 {
        return int(f - 0.5)
    }
    return int(f + 0.5)
}

As Will mentions, this comes down to how floats are represented on various platforms. 正如威尔所提到的,这归结为浮动在各种平台上的表现方式。 Essentially you need to round the float rather than let the default truncating behavior to happen. 基本上你需要对浮点数进行舍入而不是让默认的截断行为发生。 There's no standard library function for this, probably because there's a lot of possible behavior and it's trivial to implement. 这没有标准的库函数,可能是因为有很多可能的行为,实现起来很简单。

If you knew you'd always have errors of the sort described, where you're slightly below (1299.999999) the value desired (1300.00000) you could use the math library's Ceil function: 如果你知道你总是有所描述类型的错误,你所需的值(130099000)略低于(1299.999999)你可以使用数学库的Ceil函数:

f := 1.29999
n := math.Ceil(f*1000)

But if you have different kinds of floating error and want a more general sorting behavior? 但是,如果您有不同类型的浮动错误并想要更通用的排序行为? Use the math library's Modf function to separate the your floating point value by the decimal point: 使用数学库的Modf函数将浮点值与小数点分开:

f := 1.29999

f1,f2 := math.Modf(f*1000)
n := int(f1) // n = 1299   
if f2 > .5 { 
    n++
}
fmt.Println(n)

You can run a slightly more generalized version of this code in the playground yourself. 您可以自己在游乐场中运行此代码的稍微更通用的版本。

This is probably likely a problem with floating points in general in most programming languages though some have different implementations than others. 在大多数编程语言中,这通常可能是浮点问题,尽管有些实现与其他编程语言不同。 I wouldn't go into the intricacies here but most languages usually have a "decimal" approach either as a standard library or a third party library to get finer precision. 我不会在这里讨论复杂的问题,但是大多数语言通常采用“十进制”方法作为标准库或第三方库来获得更精确的。

For instance, I've found the inf.v0 package largely useful. 例如,我发现inf.v0包非常有用。 Underlying the library is a Dec struct that holds the exponents and the integer value. 该库的底层是一个Dec结构,它包含指数和整数值。 Therefore, it's able to hold 1.003 as 1003 * 10^-3 . 因此,它能够将1.003保持为1003 * 10^-3 See below for an example: 请参阅下面的示例:

package main

import (
    "fmt"

    "gopkg.in/inf.v0"
)

func main() {
    // represents 1003 * 10^-3
    someDec := inf.NewDec(1003, 3)

    // multiply someDec by 1000 * 10^0
    // which translates to 1003 * 10^-3 * 1000 * 10^0
    someDec.Mul(someDec, inf.NewDec(1000, 0))

    // inf.RoundHalfUp rounds half up in the 0th scale, eg. 0.5 rounds to 1
    value, ok := someDec.Round(someDec, 0, inf.RoundHalfUp).Unscaled()
    fmt.Println(value, ok)
}

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM