[英]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.003
到1003
(整数类型)。 My implementation is simply multiply the float64
with 1000
and cast it to int
. 我的实现只是将
float64
与1000
相乘并将其转换为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: 因此,如果您有负数,则必须:
0.5
instead of adding it 0.5
而不是添加它 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.