心血踩坑!Python保留指定位的小数

发布时间:2023年12月29日

需求:假定有一个小数,记作abc.defghhijk,其中a、b、c、d、e等代表0-9之间的数字,比如值可以是3.1415926354975。

目的:①以“截断”方式得到指定小数位的小数,②不进行舍入,③而且展示时需要有指定小数位数。

查阅了不少资料,遇到很多问题,这里记录解决的过程,分为3个部分。

1、现有的几个常见用法

2、踩坑

3、自己的最佳实践

一、现有的几个常见用法

1、python内置的round函数

In [107]: round(3.124, 2)
Out[107]: 3.12

In [108]: round(3.125, 2)
Out[108]: 3.12

In [109]: round(3.126, 2)
Out[109]: 3.13

结果:round函数会舍入处理,一般用于精确度要求不高的场景。

说明:round的“舍入”进位方式准确点应该叫“四舍六入五成双”,不是简单的四舍五入

2、字符串格式化

print("{:.2f}".format(3.124))
print("{:.2f}".format(3.125))
print("{:.2f}".format(3.126))

3.12
3.12
3.13
print("%.2f" % 3.124)
print("%.2f" % 3.125)
print("%.2f" % 3.126)

3.12
3.12
3.13
print(f"{3.124:.2f}")
print(f"{3.125:.2f}")
print(f"{3.126:.2f}")

3.12
3.12
3.13

结果:不同的字符串格式化方式均会舍入处理

3、decimal模块

decimal是Python核心库用于实现高精度小数运算模块。对比原生的float类型,Decimal类型能更好地保证计算精度,特别是货币计算或涉及其他高精度计算的场景。

首先导入decimal模块

from decimal import Decimal, ROUND_HALF_UP

rounding参数为ROUND_HALF_UP

In [127]: Decimal("3.124").quantize(Decimal("0.00"), rounding=ROUND_HALF_UP)
Out[127]: Decimal('3.12')

In [128]: Decimal("3.125").quantize(Decimal("0.00"), rounding=ROUND_HALF_UP)
Out[128]: Decimal('3.13')

In [129]: Decimal("3.126").quantize(Decimal("0.00"), rounding=ROUND_HALF_UP)
Out[129]: Decimal('3.13')

rounding参数缺省时,

In [130]: Decimal("3.124").quantize(Decimal("0.00"))
Out[130]: Decimal('3.12')

In [131]: Decimal("3.125").quantize(Decimal("0.00"))
Out[131]: Decimal('3.12')

In [132]: Decimal("3.126").quantize(Decimal("0.00"))
Out[132]: Decimal('3.13')

结果:会进行“舍入”处理,但当末尾为5时不进位,区别于rounding参数为ROUND_HALF_UP,末尾为5时会进位。

4、使用Numpy库的around函数

Numpy库广泛用于数据处理和科学计算领域,适用于高精度和复杂计算的场景,例如图像处理、机器学习和物理模拟等。

首先导入Numpy模块

import numpy as np

看下around的官方说明:

Signature: np.around(a, decimals=0, out=None)

Docstring:

Evenly round to the given number of decimals.

翻译就是:参数a表示需要保留小数位数的数组或数字,参数decimals表示要保留的小数位数

In [138]: np.around(3.124, 2)
Out[138]: 3.12

In [139]: np.around(3.125, 2)
Out[139]: 3.12

In [140]: np.around(3.126, 2)
Out[140]: 3.13

结果:会进行“舍入”处理

二、踩坑:

1、前4个常见方法(round函数、字符串格式化、decimal模块、numpy.around函数)均会“舍入”处理,不满足要求“截断”目的。

2、round函数、np.around,不仅会“舍入”操作,还会舍弃结果的末尾0。(想要的是3.10,但返回结果是3.1,舍弃了末尾的0。)

示例如下:

In [156]: round(3.103, 2)
Out[156]: 3.1
In [157]: "{:.2f}".format(3.103)
Out[157]: '3.10'

In [158]: "%.2f" % 3.103
Out[158]: '3.10'

In [159]: f"{3.103:.2f}"
Out[159]: '3.10'
In [160]: Decimal("3.103").quantize(Decimal("0.00"), rounding=ROUND_HALF_UP)
Out[160]: Decimal('3.10')
In [165]: np.around(3.103, 2)
Out[165]: 3.1

三、自己的最佳实践

思路:转为字符串进行序列切片,切出小数点前的数值、小数点后的指定位数值,最后拼装。

下面是自己实现的一个保留指定小数位的函数。

def custom_quantize(number, n_digits=0):
    """ 截断处理,不舍入 """
    number_lst = str(number).split(".")
    if n_digits > 0:
        if "." in str(number):
            new_number = number_lst[0] + "." + number_lst[1][:n_digits]
        else:
            new_number = number_lst[0] + "." + "0" * n_digits
    else:
        new_number = number_lst[0]
    return new_number

1、测试会不会“舍入”处理

In [135]: custom_quantize(3.124, 2)
Out[135]: 3.12

In [136]: custom_quantize(3.125, 2)
Out[136]: 3.12

In [137]: custom_quantize(3.126, 2)
Out[137]: 3.12

结果为不进行“舍入”处理

2、测试会不会保留末尾的数值0。

In [168]: custom_quantize(3.104, 2)
Out[168]: '3.10'

In [169]: custom_quantize(3.105, 2)
Out[169]: '3.10'

In [170]: custom_quantize(3.106, 2)
Out[170]: '3.10'

切片方式保留末尾的数值0。

本文原始版本发表链接:

https://mp.weixin.qq.com/s?__biz=MzI2Mjg3NTY5MQ==&mid=2247484480&idx=1&sn=a77de165ce5ea7c477bebf2befa5378b&chksm=ea453b04dd32b212d44a453aa90a51563bd920ea70b2feb6bdec3169849ec9588d6d592486f3#rd

kelly会在公众号「kelly学技术」不定期更新文章,感兴趣的朋友可以关注一下,期待与您交流。

--over--

文章来源:https://blog.csdn.net/qm5132/article/details/135289665
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。