python四舍五入(round精度不够,有时不能实现四舍五入)

devtools/2024/10/19 2:25:15/
round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">
Python 所有文章传送门
【Python】所有文章传送门

目录

  • 简述 / 前言
  • 1. Python 实验
  • 2. 自定义函数
  • 3. 总结

简述 / 前言

最近心血来潮,刚复习到折半插入排序时,发现算法的mid(中间点)选择的公式是:(low + high)/2,那么当(low + high)出现奇数时怎么办呢,比如(low + high)/2 = 1.5,那么是取 1 还是 2 呢?于是我在 Python 中实验了一下,由于 Python 中浮点数运算结果还是浮点数,因此我用了内置函数 round(number, ndigits) 来实现小数转整数运算。

1. Python 实验

python">>>> round(1.5, 0)
2.0

看样子好像是四舍五入的取法,但是换了一个数字之后,就发现新大陆了!

python">>>> round(2.5, 0)
2.0

这个运算发现round其实就是直接截取了整数部分,那么事实果真如此吗?文末会给出解答~

2. 自定义函数

第一反应就是官方的函数是不是有问题,于是找了几篇博客(参考的一个博客解答,但并没有完全解决)看看怎么回事,发现给出的解决方法都不能解决问题,实验如下:

python">>>> from decimal import Decimal
>>>
>>> print(round(Decimal("1.5"),0))
2
>>> print(round(Decimal("2.5"),0))
2
>>> print(Decimal("1.5").quantize(Decimal("0.")))
2
>>> print(Decimal("2.5").quantize(Decimal("0.")))
2

于是一股脑的自己花了十几分钟写了一个函数来实现:

python">def round_Pro(number, ndigits):"""实现四舍五入:param number: 要四舍五入的数字:param ndigits: 要保留的位数:return: 以 float 形式输出"""flag = ''       # 用于记录 number 的正负性if number < 0:flag = '-'number_abs = abs(number)    # 一律采用正数的四舍五入进行操作number_abs_str = str(number_abs)if '.' in number_abs_str:       # 如果给的数字是小数的话integer = int(number_abs_str.split('.')[0])     # 数字的整数部分decimal_str = number_abs_str.split('.')[1]      # 数字的小数部分decimal_cnt = len(decimal_str)      # 小数位数if ndigits >= decimal_cnt:      # 如果要保留的小数位数 >= 整个小数位数,则直接输出原数字return numberelse:       # 要保留的小数位数 < 整个小数位数,需要进行四舍五入judge_num = int(decimal_str[ndigits])   # 舍入位数字(根据此数字判断是否需要进位)if ndigits == 0:    # 只保留整数decimal = 0     # 小数设为 0if judge_num >= 5:  # 如果小数第一位 > 5,则整数进一位integer += 1else:       # 保留指定小数位数decimal = int(decimal_str[:ndigits])        # 要保留的小数(直接截断转为整数,便于后续直接计算进位)decimal_cnt = len(decimal_str[:ndigits])    # 要保留的小数位数if judge_num >= 5:      # 如果判断位(指定保留小数位数后一位的小数数字,比如:number=1.234,ndigits=2,那么判断位就是数字"4") > 5decimal += 1        # 小数进一位if len(str(decimal)) > decimal_cnt:     # 如果进位导致小数位最高位也进位了integer += 1        # 整数部分也要进位decimal = str(decimal)[1:]      # 小数部分去掉最高位(由于进位多出来的数据)decimal = str(decimal)return float(flag + str(integer) + '.' + decimal)else:       # 给的数字是一个整数,直接输出return number

测试如下:

python">print(round_Pro(2.9897, 5))
print(round_Pro(2.4497, 1))
print(round_Pro(2.4497, 0))
print(round_Pro(2.5597, 0))
print(round_Pro(2.5597, 10))
print(round_Pro(0, 0))
print(round_Pro(0, 10))
print(round_Pro(-1.5, 0))
print(round_Pro(-1.5, 1))
print(round_Pro(-1.56, 1))
print(round_Pro(-1.56, 2))
print(round_Pro(-1.999, 2))

输出如下:

python">2.9897
2.4
2.0
3.0
2.5597
0
0
-2.0
-1.5
-1.6
-1.56
-2.0

写完之后发现我的逻辑其实有点复杂(先转为字符串进行分割,再分别转成数字进行计算),于是又找找看有没有其它的解决方法,因为我坚信我不可能是第一个遇到这种问题的人,于是很快发现了另一篇博客(能够解决此问题的一篇博客),完全解决了这个问题,即用到一个库:decimal,只保留整数就是 Decimal("1."),保留1位小数就是 Decimal(".1"),2位小数就是 Decimal(".01")Decimal(".89") 也是一样的,本质就是看你给的字符串中小数占了多少位而已】。

python">>>> from decimal import Decimal
>>> print(Decimal(1.5).quantize(Decimal("1."), rounding="ROUND_HALF_UP"))
2
>>> print(Decimal(2.5).quantize(Decimal("1."), rounding="ROUND_HALF_UP"))
3

3. 总结

解决方法,使用第三方库函数,格式是:Decimal(要进行四舍五入的数字).quantize(Decimal("保留多少位小数"), rounding="ROUND_HALF_UP")

python">>>> from decimal import Decimal
>>> num = 1.5
>>> print(Decimal(num).quantize(Decimal("1."), rounding="ROUND_HALF_UP"))
2

那么回到文章开头提出的问题,round为什么不能进行四舍五入呢? 其实round本质就是四舍五入,但是由于我们的计算机存储数字的精度有问题,才导致了这种情况发生:

python">>>> from decimal import Decimal
>>> print(Decimal(1.535))
1.5349999999999999200639422269887290894985198974609375
>>> print(Decimal(1.725))
1.725000000000000088817841970012523233890533447265625

详见 python3 小数位的四舍五入(用两种方法解决round 遇5不进),文中给出了两种解决方法。


http://www.ppmy.cn/devtools/43673.html

相关文章

在树莓派3B+中下载opencv(遇到的各种问题及解决)

目录 前言 1、删除原版本下新版本 2、python虚拟环境 3、python版本共存换链接——给版本降低 4、烧录之前版本的文件&#xff08;在清华源中可以找&#xff0c;不用官网的烧录文件就行&#xff1b; 比如&#xff1a;&#xff08;balenaEtcher&#xff09;重新烧录有问题…

vue中获取dom高度

vue中获取dom高度 在 Vue 中获取 DOM 元素的高度可以通过以下几种方式&#xff1a;1、通过ref来获取节点&#xff0c;通过offsetHeight来获取节点的高度2、通过js获取节点&#xff0c;本次演示的是document.querySelectorAll3、获取到节点的高度动态赋值 offsetHeight 属性可以…

[9] CUDA性能测量与错误处理

CUDA性能测量与错误处理 讨论如何通过CUDA事件来测量它的性能如何通过CUDA代码进行调试 1.测量CUDA程序的性能 1.1 CUDA事件 CPU端的计时器可能无法给出正确的内核执行时间CUDA事件等于是在你的CUDA应用运行的特定时刻被记录的时间戳&#xff0c;通过使用CUDA事件API&#…

大模型面试--大模型(LLMs)基础面

大模型&#xff08;LLMs&#xff09;基础面 1. 目前主流的开源模型体系有哪些&#xff1f; 目前主流的开源大模型体系有以下几种&#xff1a; 1. Transformer 系列 Transformer 模型是深度学习中的一类重要模型&#xff0c;尤其在自然语言处理&#xff08;NLP&#xff09;领…

WebSocket

WebSocket 一、简介1.HTTP协议和WebSocket协议对比2.思考&#xff08;1&#xff09;WebSocket缺点&#xff08;2&#xff09;WebSocket应用场景 二、入门案例1.案例分析2.代码开发3.功能测试 三、参考 一、简介 WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器…

【设计模式】JAVA Design Patterns——Circuit Breaker(断路器模式)

&#x1f50d;目的 以这样一种方式处理昂贵的远程服务调用&#xff0c;即单个服务/组件的故障不会导致整个应用程序宕机&#xff0c;我们可以尽快重新连接到服务 &#x1f50d;解释 真实世界例子 想象一个 Web 应用程序&#xff0c;它同时具有用于获取数据的本地文件/图像和远程…

Java 18 新特性详解:提升开发效率与性能

Java 18 新特性详解 Java 18 是 Oracle 于 2022 年发布的最新版本,带来了许多新的特性和改进。本文将深入探讨 Java 18 的主要新特性及其应用场景,帮助开发者更好地理解和利用这些新功能。 1. 简单的 Web 服务器 Java 18 引入了一个简单的 HTTP 文件服务器,旨在为开发和测…

基于jeecgboot-vue3的Flowable增加表单功能(二)

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 接上一节 6、增加一个types.ts 类型 export interface FormForm {id: number | string | undefined;formName: string;formContent?: string;remark: string; } 7、api增加一个getForm…