2015-10-19 122 views
1

我想轉換一個float64數字,我們假設它是1.0031003(整數類型)。我的實現是將float641000相乘,然後將其轉換爲int轉:將float64轉換爲帶有乘數的int

package main 

import "fmt" 


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

但是當我運行的代碼,我得到了什麼是10021003。由於Go自動將1.003作爲1.002999...存儲在變量中。在Golang上進行這種操作的正確方法是什麼?

回答

5

Go spec: Conversions:

換算數值類型

當浮點數轉換爲整數之間,則該部分將被丟棄(向零截斷)。

所以基本上當你將一個浮點數轉換爲一個整數時,只保留整數部分。

如果您只是想避免由於使用有限位進行表示而出現錯誤,只需在將其轉換爲int之前將該數字加上0.5即可。不需要外部庫或函數調用(來自標準庫)。

由於float -> int轉換不四捨五入保持整數部分,這會給你想要的結果。同時考慮到可能更小和更大的代表性:

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

所以只是簡單地寫:

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

爲了結束這種成一個函數:

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

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

試戴的Go Playground

注:

要小心,當你申請這個在負數的情況下!例如,如果您的值爲-1.003,那麼您可能希望結果爲-1003。但是,如果你添加0.5它:

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

所以,如果你有負數,你必須要麼:中

  • 0.5,而不是將它添加
  • 或從加0.5但減去1結果

將此結合到我們的幫助函數中:

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

在大多數編程語言中,這可能是浮點問題,儘管一些實現方式與其他實現方式不同。我不想在這裏錯綜複雜,但大多數語言通常都有一個「十進制」方法,可以作爲標準庫或第三方庫來獲得更高的精度。

例如,我發現inf.v0包在很大程度上是有用的。庫的底層是一個Dec結構,它保存指數和整數值。因此,它能夠將1.003作爲1003 * 10^-3。看下面的例子:

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

希望這有助於!

+1

我以前沒使用的包,但在看文檔,它肯定看起來好像四捨五入以後,你可以調用無格式()直接提取int值,而不是抓住一個字符串,並通過將其轉換strcon再次。 – AndrewN

+0

啊,你是對的。完全忘記了。將更新代碼!謝謝! –

2

正如Will提到的,這涉及到如何在各種平臺上呈現花車。基本上,你需要將float浮起來,而不是讓默認的截斷行爲發生。這沒有標準的庫函數,可能是因爲有很多可能的行爲,並且實現起來很微不足道。

如果你知道你總是有那種錯誤的描述,在這裏你稍低於(1299.999999)(1300.00000)所需的值時,您可以使用數學庫的Ceil功能:

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

但如果你有不同類型的浮動錯誤並想要更普遍的排序行爲?使用數學庫的Modf功能由小數點到您的浮點值分開:

f := 1.29999 

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

可以在playground自己運行此代碼的一個稍微更廣義的版本。