小数精度控制问题,ROUND函数的使用

SQL
ROUND函数是对数据进行制定精度的取值。

总结一下小数精度的处理问题

引言

图片 1

一、round()函数内置方法

      今天和测试沟通一个百分比计算方式时遇到一个问题,
我在存储过程里用到了强转CAST(32.678 AS DECIMAL(5,1)) 
我认为该方式只会保留一位小数,我给测试的回复是我并没有用到四舍五入函数,数据也没有四舍五入,而测试说他们自己验证后觉的数据是经过四舍五入了的。
想到这里于是我再试了试存储过程的每个计算点,才发现了这个问题。

 

  round(number,[ndigits]):round
对传入的数据进行四舍五入,但并不是传统意义上的四舍五入。number:需要被处理的参数;ndigits:保留的位数。

ROUND

第一个参数是取值的数据,第二个参数是精度,第三个参数是数据取值模式(四舍五入还是截断),其中第三个参数是可选参数,默认是四舍五入模式。

  ndigits:不取值,number的小数部分没有0.5的时候,则按照四舍五入进行取值;

     那么用到四舍五入并且保留小数点时我们肯定会首选ROUND函数, 
如果字段的数据类型是decimal(18,10)时那么四舍五入后还会有很多0出现。

图片 2

       
不取值,number的小数部分存在0.5的时候,round()取靠近的偶数;

CAST和CONVERT

 

      取值,number的小数部分没有.5的时候,则按照四舍五入进行取值;

   
其实我使用强转时并没有打算四舍五入结果,只是单纯为了得到符合我要求的数据,今天才发现这两个强转也会四舍五入结果,也就是说下面三个语句将会返回相同的结果值

 从上面结果可以看出,数据并非只保留两位小数,而是保留两位有效小数。

      取值,number的小数部分存在.5的时候,小数位前是奇数则舍弃,小数位前是偶数则向上取(意味着,一旦出现小数位后为.5的,则小数位前取值,无法取到偶数);

select ROUND(32.678,1)  --32.700
select CAST(32.678 as DECIMAL(5,1)) --32.7
select convert(NUMERIC(5,1),32.678) --32.7

图片 3

#  ndigits 不取值的时候
print("1:", round(2.5))  # 存在0.5,取值靠近偶数: 2
print("2:", round(2.55))  # 不存在0.5,取值按照四舍五入:3
print("3:", round(3.5))  # 存在0.5,取值靠近偶数:4
print("4:", round(4.5))  # 存在0.5,取值靠近偶数:4
print("5:", round(4.54))  # 不存在0.5,取值按照正常的四舍五入
print("6:", round(5.5))  # 存在0.5,取值靠近偶数:6

#  ndigits 取值的时候
print("7:", round(2.635, 2))  # 存在.5,小数位前奇数: 2.63
print("8:", round(2.645, 2))  # 存在.5,小数位前偶数:2.65
print("9:", round(2.655, 2))  # 存在.5,小数位前奇数:2.65
print("10:", round(2.665, 2))  # 存在.5,小数位前偶数:2.67
print("11:", round(2.675, 2))  # 存在.5,小数位前奇数:2.67
print("12:", round(2.634, 2))  # 不存在.5,按照四舍五入: 2.63
print("13:", round(2.636, 2))  # 不存在.5,按照四舍五入: 2.64

下面抽个空给大家介绍SQL的四舍五入ROUND函数

从上面两次可以看出,默认不使用第三个参数是四舍五入模式。

二、格式化处理

SQL四舍五入2007/11/01 16:35问题1:

图片 4

  输出格式%.mf:处理机制个round()函数一致,m指取得位数,f是指float数据类型

SELECT CAST('123.456' as decimal)

 

#  m不取值的时候
print("1: %.f" % 2.5)  # 存在0.5,取值靠近偶数: 2
print("2: %.f" % 3.5)  # 存在0.5,取值靠近偶数: 4
print("3: %.f" % 3.4)  # 不存在0.5,按照四色五入: 2
print("4: %.f" % 3.6)  # 不存在0.5,按照四舍五入: 2

#  m=2 取值的时候
print("4: %.2f" % 2.635)  # 存在.5,小数位前奇数: 2.63
print("5: %.2f" % 2.645)  # 存在.5,小数位前偶数:2.65
print("6: %.2f" % 2.655)  # 存在.5,小数位前奇数:2.65
print("7: %.2f" % 2.665)  # 存在.5,小数位前偶数:2.67
print("8: %.2f" % 2.675)  # 存在.5,小数位前奇数:2.67
print("9: %.2f" % 2.634)  # 不存在.5,按照四舍五入: 2.63

将会得到 123(小数点后面的将会被省略掉)。

第三个参数如果是0,则四舍五入,如果是非0,则截断

三、超过17位精度分析

如果希望得到小数点后面的两位。

图片 5

  python中默认的为17位小数精度,但如果我们需要使用更高精度的时候(意味着超过17位小数),如果处理?

则需要把上面的改为

通过结果发现,后面的5被截断,保留了两位有效小数。

  使用前面两种方法进行处理,查看一下处理结果:

SELECT CAST('123.456' as decimal(38, 2)) ===>123.46

另外,如果精度为负数,则为整数部分精确取值。

print("1: %.30f" % (1/3))  # 输出:1: 0.333333333333333314829616256247
print("2: %s" % round((1/3), 30))  # 输出:2: 0.3333333333333333

自动四舍五入了!

图片 6

显然前面两种方法是不适用的,round()内置函数其结果只能取到小数点后16位;而格式化处理虽然可以取到30位,但其精度是不准确的。

问题2:

 

下面介绍一种方法:高精度使用
decimal模块,配合getcontext

SELECT ROUND(123.75633, 2, 1), ROUND(123.75633, 2)

 

print(getcontext())
getcontext().prec = 50    # 设置全局精度
b = Decimal(1)/Decimal(3)
print(b)
c = Decimal(1)/Decimal(17)
print(float(c))

上面的SQL得到的2个值是不一样的,前一个是:123.75000,后一个是:123.76000。

SELECT ROUND(987.45,-2)

 四、关于小数和取整

因为前者在进行四舍五入之前,小数点后已经被截取,保留了2位。

图片 7

1.math模块下的ceil(x)函数:取大于或者等于x的最小整数

而后者则没有被截取,四舍五入时自然就会得到123.76000

出现错误是因为987.45为decimal(5,2),它无法表示1000.00,此时需要转换数据类型

2.math模块下的floor(x)函数:取小于或者等于x的最大整数

ROUND

图片 8

from math import ceil, floor

# ceil():取大于或等于x的最小整数
print("1: %s" % ceil(2.5))  # 1: 3
print("2: %s" % ceil(2.3))  # 2: 3
print("3: %s" % ceil(2.6))  # 3: 3

# floor():取小于或等于x的最大整数
print("4: %s" % floor(2.5))  # 4: 2
print("5: %s" % floor(2.3))  # 5: 2
print("6: %s" % floor(2.6))  # 6: 2

返回数字表达式并四舍五入为指定的长度或精度。

 

五、截取小数点后bit位

语法

参考: 

编写函数cut(self,bit)进行处理

ROUND ( numeric_e-xpression , length [ , function ] )

def cut(self, bit):
    str_sli = str(self).split('.', 1)
    sli = len(str_sli[0]) + bit + 1
    result = str(self)[:sli]
    return result

a = cut(3.1356, 2)
print(a)    #输出结果为: 3.13

参数

 

numeric_e-xpression

 

精确数字或近似数字数据类型类别的表达式(bit 数据类型除外)。

 

length

是 numeric_e-xpression 将要四舍五入的精度。length 必须是
tinyint、smallint 或int。当 length 为正数时,numeric_e-xpression
四舍五入为 length 所指定的小数位数。当 length
为负数时,numeric_e-xpression 则按 length
所指定的在小数点的左边四舍五入。

function

是要执行的操作类型。function 必须是 tinyint、smallint 或 int。如果省略
function 或 function 的值为 0(默认),numeric_e-xpression
将四舍五入。当指定 0 以外的值时,将截断 numeric_e-xpression。

返回类型

返回与 numeric_e-xpression 相同的类型。

注释

ROUND 始终返回一个值。如果 length 是负数且大于小数点前的数字个数,ROUND
将返回 0。

示例 结果

ROUND(748.58, -4) 0

当 length 是负数时,无论什么数据类型,ROUND 都将返回一个四舍五入的
numeric_e-xpression。

示例 结果

ROUND(748.58, -1) 750.00
ROUND(748.58, -2) 700.00
ROUND(748.58, -3) 1000.00

示例

A. 使用 ROUND 和估计值

下例显示两个表达式,说明使用 ROUND 函数且最后一个数字始终是估计值。

Select ROUND(123.9994, 3), ROUND(123.9995, 3) 
GO

下面是结果集:


123.9990    124.0000 

B. 使用 ROUND 和四舍五入的近似值

下例显示四舍五入和近似值。

语句 结果

Select ROUND(123.4545, 2)
123.4500
Select ROUND(123.45, -2)
100.00

C. 使用 ROUND 截断

下例使用两个 Select
语句说明四舍五入和截断之间的区别。第一个语句四舍五入结果。第二个语句截断结果。

语句 结果

Select ROUND(150.75, 0)
151.00
Select ROUND(150.75, 0, 1)
150.00

发表评论

电子邮件地址不会被公开。 必填项已用*标注