分享
  1. 首页
  2. 文章

gloang 浮点类型计算,转换和保留精度处理

ming_a063 · · 11946 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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的情况定

解决思路:

  1. 先将其他类型转为字符串
  2. 通过标准库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
}

浮点类型转换为其他类型

思路:

  1. 先将浮点类型转换为字符串
  2. 再格式化为具体的类型
// 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 类型计算

思路:

  1. float类型转换为精度不丢失的decimal进行计算
  2. 再将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类型保留精度

思路:

  1. 由于直接取整不会四舍五入,故将该值加上 0.5 / 10的n次方(n为精确到小数点后几位)
  2. 再将结果乘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
}

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:ming_a063

查看原文:gloang 浮点类型计算,转换和保留精度处理

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
11946 次点击
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏