数值修约程序(包括运算过程有效数字保留,Python3实现)
2022.09更新:考虑到需要用到这个程序的朋友很可能没有计算机基础(这也是我只放在csdn而没有放github的原因),我稍微加了一点注释,并且稍微重构了一下以提高可读性。
分割线后是2020原文
今年疫情期间应物理系的朋友要求做了一个做所谓数值和运算修约的程序。
具体包括数值修约(说得简单些就是舍入,参考GB/T 8170-1987)和运算过程的有效数字的保留(就是加减乘除过程中对数值保留位数有要求。具体看我朋友给我提供的这份文件吧:https://shimo.im/docs/PH3hvV6CygW3wK36/)
不说废话了,下面直接贴完整代码吧,Python 3.7和3.8测试过是可以直接跑的。代码使用Python语言实现,所以需要Python解释器。限于篇幅,我在这里就不说怎么安装Python了。
-
如果你也在找数值运算修约程序,为什么不试试呢?我试过,这个东西手算实在是太费脑筋了,还特别容易错。
-
如果你看不懂
class
或者self
是什么,那就直接划到最底下看一下示范的用法,然后copy, paste and run吧。 -
如果本程序使用的修约规则与你所需要的不同,你可以进行更改,毕竟很多基本的逻辑里面都已经实现好了。
等我有时间再考虑要不要把实现思路给写出来吧。
# %%
import math
from warnings import warn
from decimal import *
from typing import Union
# Ver 0.5, Copyleft 2020.6 - 2022.6 Peng Lingbo
# The documentation is written in CHINESE, since the program is based on GB/T 8170-1987
# if you can read Chinese but the following docs doesn't make sense, try to reopen file with UTF-8 encoding.
# v0.3 增加debug功能,可以用于查看追踪过程
# v0.4 支持用任何类型的数字来进行初始化,然而浮点类型本身存在精度问题,所以会收到一个警告要求你使用str()或者Decimal()
# 此外,现在已经支持运算中加入非Number类对象(内置数字),不过出于上面的原因,还是
# 建议用str类型--显式的str()转换或者是直接用'单引号'括起来--或者用Decimal类型.
# v0.5 优化程序逻辑和debug的呈现方式。初始化时可以直接指定精度了。
# 由于使用者所在单位采取的运算修约标准可能与本程序所使用的有轻微不同,建议使用者先用几个测例打开debug=True检查各类运算是否符合期望
# 然后对于不符合的部分做自己的修改再使用。
# 使用本程序,即代表你已经同意程序作者对由于使用本程序所带来的一切可能后果不负任何责任。
class Number:
"""
帮你自动完成数值运算修约!
"""
def __init__(self, value:Union[Decimal, str, int, float], precision:int = None, debug:bool = False):
"""初始化
参数 value: 一个Decimal对象或一个数字的字符串形式,比如:\n
a = Number('3.51E2')\n
b = Number('-8.000') <-注意这里的引号\n
x = Decimal('3.14159')\n
c = Number(x)\n
注意:从程序的角度,直接使用浮点型小数也没问题,但是可能数值会和输入的不一样\n
参数 precision: 整数型,指定精度到 10 ^ precision 位。默认为无,会根据value自动计算\n
参数 debug: 布尔型,指定是否查看追踪过程。默认值 False,即不查看\n
"""
if isinstance(value, Number):
for attr in dir(value):
if attr[:2] != '__':
setattr(self, attr, getattr(value, attr))
if precision is not None and precision != self.effective_digits:
self.round_inplace(precision)
return
if isinstance(value, float):
warn(f"Floating type can cause numerical problems. Use '{
value}' or str({
value}) to initialize to suppress this warning.")
self.value = Decimal(value)
self.effective_digits = Number._eff(self.value.__str__())
self.debug = debug
self.debugger = lambda x: print('[Debug]', x) if debug else lambda x: x
if self.value != 0:
# 这个数字的最高位的log10值,也就是它最高位的幂数
self.highest_digit = math.floor(math.log10(abs(self.value)))
# 这个数字的最低位的log10值,也就是它最低位的幂数
self.lowest_digit = self.highest_digit - self.effective_digits