简介
Go 属于强类型语言,各种数值类型不允许直接进行运算,和PHP、Python、JavaScript等弱类型而言,在运算过程中比较麻烦,需要对数据进行转换成同类型才可以运算,若是遇到整型的除法运算(10 / 3 = 3),会丢失掉小数点之后数值,精度会大大降低,要想可以保留小数点,就需要对数据类型进行转换成Float64或Float32,才能进行操作,若是每次运算都是如此操作的话,对编程就比较麻烦,所以一般都会对加减乘除这样的简单运算做逻辑封装,后期只需调用对应的方法函数即可。
代码示例
针对加减乘除做了以下封装
加法
// Add 加法,两数及以上的数值累计相加之和,并保留小数点后两位
// Example:
// Add(100, 2000, 2, 100.01111)
// Output: 2200.01
func Add(x, y interface{}, decimal float64, z ...interface{}) float64 {
sum := Float64(x) + Float64(y)
if len(z) > 0 {
for _, v := range z {
sum += Float64(v)
}
}
return Scale(sum, decimal)
}
减法
// Sub 减法,两数及以上的数值累计之差,并保留小数点后两位
// Example:
// Sub(100, 2000, 2, 100.01111)
// Output: -2000.01
func Sub(x, y interface{}, decimal float64, z ...interface{}) float64 {
s := Float64(x) - Float64(y)
if len(z) > 0 {
for _, v := range z {
s -= Float64(v)
}
}
return Scale(s, decimal)
}
乘法
// Mul 乘法,两数及以上的数值乘积,并保留小数点后两位
// Example:
// Mul(100, 2000, 2, 100.01111)
// Output: 2.0002222e+07
func Mul(x, y interface{}, decimal float64, z ...interface{}) float64 {
s := Float64(x) * Float64(y)
if len(z) > 0 {
for _, v := range z {
s *= Float64(v)
}
}
if s == 0 {
return 0
}
return Scale(s, decimal)
}
除法
// Div 除法, 两数相除
// Example:
// Sub(999, 8989.5645, 2)
// Output: 0.11
func Div(x, y interface{}, decimal float64) float64 {
if Float64(y) == 0 || Float64(x) == 0 {
return 0
}
s := Float64(x) / Float64(y)
return Scale(s, decimal)
}
转换函数
- 小数点保留转换设置函数
// Scale 保留小数点-四舍五入算法
// Example:
// Scale(98.88888, 2) 保留两位小数
// Output: 98.89
func Scale(s, decimal float64) float64 {
// 保留小数点,注:避免小数点小于等于0,计算错误
var d float64 = 1
if decimal > 1 {
d = math.Pow(10, decimal) // 10的N次方
}
return math.Round(s*d) / d
}
- 数据类型浮点型内部转换函数
// Float64 转换float64
func Float64(any interface{}) float64 {
if any == nil {
return 0
}
switch value := any.(type) {
case float64:
return value
case float32:
return float64(value)
case uint:
return float64(value)
case uint8:
return float64(value)
case uint32:
return float64(value)
case uint16:
return float64(value)
case int:
return float64(value)
case int8:
return float64(value)
case int16:
return float64(value)
case int32:
return float64(value)
case int64:
return float64(value)
case string:
v, _ := strconv.ParseFloat(value, 64)
return v
default:
return 0
}
}
逻辑解析:
- 定义Add、Sub、Mul、Div函数,x,y参数定义interface接口类型,允许接收整型、浮点型、字符串类型,采用内部类型转换逻辑,把所有参数转成浮点型进行运算,decimal:设置允许保留多少位小数,z:为可变函数,同样设置为interface接口类型,允许多个数值进行运算,但不强制输入(除法除外);
- Float64函数,把interface接口类型,统一转成float64类型进行运算,输出的数据类型也是float64,减少外部手动转的麻烦
- Scale函数:设置本次运算需要保留的小数点位数,为避免出现输入,小于等于0的情况下,默认不保留小数点,返回float64类型结果
完整代码示例
package util
import (
"math"
"strconv"
)
// Add 加法,两数及以上的数值累计相加之和,并保留小数点后两位
// Example:
// Add(100, 2000, 2, 100.01111)
// Output: 2200.01
func Add(x, y interface{}, decimal float64, z ...interface{}) float64 {
sum := Float64(x) + Float64(y)
if len(z) > 0 {
for _, v := range z {
sum += Float64(v)
}
}
return Scale(sum, decimal)
}
// Sub 减法,两数及以上的数值累计之差,并保留小数点后两位
// Example:
// Sub(100, 2000, 2, 100.01111)
// Output: -2000.01
func Sub(x, y interface{}, decimal float64, z ...interface{}) float64 {
s := Float64(x) - Float64(y)
if len(z) > 0 {
for _, v := range z {
s -= Float64(v)
}
}
return Scale(s, decimal)
}
// Mul 乘法,两数及以上的数值乘积,并保留小数点后两位
// Example:
// Mul(100, 2000, 2, 100.01111)
// Output: 2.0002222e+07
func Mul(x, y interface{}, decimal float64, z ...interface{}) float64 {
s := Float64(x) * Float64(y)
if len(z) > 0 {
for _, v := range z {
s *= Float64(v)
}
}
if s == 0 {
return 0
}
return Scale(s, decimal)
}
// Div 除法, 两数相除
// Example:
// Sub(999, 8989.5645, 2)
// Output: 0.11
func Div(x, y interface{}, decimal float64) float64 {
if Float64(y) == 0 || Float64(x) == 0 {
return 0
}
s := Float64(x) / Float64(y)
return Scale(s, decimal)
}
// Scale 保留小数点-四舍五入算法
// Example:
// Scale(98.88888, 2) 保留两位小数
// Output: 98.89
func Scale(s, decimal float64) float64 {
// 保留小数点,注:避免小数点小于等于0,计算错误
var d float64 = 1
if decimal > 1 {
d = math.Pow(10, decimal) // 10的N次方
}
return math.Round(s*d) / d
}
// Float64 转换float64
func Float64(any interface{}) float64 {
if any == nil {
return 0
}
switch value := any.(type) {
case float64:
return value
case float32:
return float64(value)
case uint:
return float64(value)
case uint8:
return float64(value)
case uint32:
return float64(value)
case uint16:
return float64(value)
case int:
return float64(value)
case int8:
return float64(value)
case int16:
return float64(value)
case int32:
return float64(value)
case int64:
return float64(value)
case string:
v, _ := strconv.ParseFloat(value, 64)
return v
default:
return 0
}
}
总结
- 以上代码,可以根据自己业务实际情况进行修改使用,只是提供一个逻辑供大家参考,本次操作用到库(math、strconv),返回的数据以四舍五入后的float64值返回,支持所有数值类型和数字字符串类型使用,注:若是涉及大数字运算,需用引用bigMath进行处理,但一般情况下根本不会有大额数字运算的方法,所以以上函数基本可以处理大部分运算场景,可以直接使用,若是传入非数字字符串或其他非数值类型,默认返回0,请根据实际业务修改;
- 转换返回0的示例如下:
a := "12312321321"
b := "24234234234.44"
c := "242342423dd"
d := "dd348783434.44"
// Output:调用Float64(输出如下)
// a = 12312321321
// b = 24234234234.44
// c和d = 0
只有全数字类型才能转换成float64类型,所以请注意字符串类型的数字,不能含有不能转换的特殊字符