float类型转换
var f float32 = 3.1415926
// float32 转 float64
fmt.Printf("%v\n", float64(f)) // 输出:3.141592502593994,6位后的小数精度是错误的
// float64 转 float32
var f2 float64 = 3.141592653589793
fmt.Println("%v\n", float32(f2)) // 输出:3.1415927,6位后的小数精度是错误的
现象:
浮点类型在转换的时候会出现结果不精确的现象,出现浮点数不精确的原因是,浮点数储存至内存中时,2的-1、-2....-n次方不能精确的表示小数部分,所以再把这个数从地址中取出来进行计算就出现了偏差.
ps:不是所有的float相加减乘除都一定出现偏差,具体要根据golang实现IEEE 754的情况定
解决思路:
- 先将其他类型转为字符串
- 通过标准库strconv将改字符串转为对应的浮点类型
// float32Tofloat64 float32转float64
func float32Tofloat64(f float32) float64 {
str := fmt.Sprintf("%f", f)
v, err := strconv.ParseFloat(str, 64)
if err != nil {
fmt.Println("float32Tofloat64 err:", err, f)
}
return v
}
浮点类型转换为其他类型
思路:
- 先将浮点类型转换为字符串
- 再格式化为具体的类型
// float64ToUint16 float64转uint16
func float64ToUint16(f float64) uint16 {
s := strconv.FormatFloat(f,'f',-1,64)
// 第二个参数选项,含义如下:
// 'b' (-ddddp±ddd,二进制指数)
// 'e' (-d.dddde±dd,十进制指数)
// 'E' (-d.ddddE±dd,十进制指数)
// 'f' (-ddd.dddd,没有指数)
// 'g' ('e':大指数,'f':其它情况)
// 'G' ('E':大指数,'f':其它情况)
i, err := strconv.ParseInt(s, 10, 17)
// 这里注意 uint16的有效数字位是16,
// int16 有效数字位是 15,有一位是数字位
// 所以要转17位的
if err != nil {
fmt.Println("ParseInt err:", err, s)
}
return uint16(i)
}
float 类型计算
思路:
- 将float类型转换为精度不丢失的decimal进行计算
- 再将decimal转回float类型
import (
"github.com/shopspring/decimal"
)
// AddFloat decimal类型加法
// return d1 + d2
func AddFloat(d1, d2 float64) float64 {
decimalD1 := decimal.NewFromFloat(d1)
decimalD2 := decimal.NewFromFloat(d2)
decimalResult := decimalD1.Add(decimalD2)
float64Result, _ := decimalResult.Float64()
return float64Result
}
// SubtractFloat decimal类型减法
// return d1 - d2
func SubtractFloat(d1, d2 float64) float64 {
decimalD1 := decimal.NewFromFloat(d1)
decimalD2 := decimal.NewFromFloat(d2)
decimalResult := decimalD1.Sub(decimalD2)
float64Result, _ := decimalResult.Float64()
return float64Result
}
// MultiplyFloat decimal类型乘法
// return d1 * d2
func MultiplyFloat(d1, d2 float64) float64 {
decimalD1 := decimal.NewFromFloat(d1)
decimalD2 := decimal.NewFromFloat(d2)
decimalResult := decimalD1.Mul(decimalD2)
float64Result, _ := decimalResult.Float64()
return float64Result
}
// DivideFloat decimal类型除法
// return d1 / d2
func DivideFloat(d1, d2 float64) float64 {
decimalD1 := decimal.NewFromFloat(d1)
decimalD2 := decimal.NewFromFloat(d2)
decimalResult := decimalD1.Div(decimalD2)
float64Result, _ := decimalResult.Float64()
return float64Result
}
float类型保留精度
思路:
- 由于直接取整不会四舍五入,故将该值加上 0.5 / 10的n次方(n为精确到小数点后几位)
- 再将结果乘10的n次方取整后除于10的n次方
import (
"math"
"reflect"
)
// Round 浮点类型保留小数点后n位精度
func Round(f interface{}, n int) (r float64, err error) {
pow10N := math.Pow10(n)
switch f.(type) {
case float32:
v := reflect.ValueOf(f).Interface().(float32)
r = math.Trunc((float64(v) + 0.5 / pow10N) * pow10N) / pow10N
case float64:
v := reflect.ValueOf(f).Interface().(float64)
r = math.Trunc((v + 0.5 / pow10N) * pow10N) / pow10N
}
return r, err
}
有疑问加站长微信联系(非本文作者)