当前位置: 首页 > news >正文

【Python Cookbook】数字日期和时间(一)

数字日期和时间(一)

  • 1.数字的四舍五入
  • 2.执行精确的浮点数运算
  • 3.数字的格式化输出
  • 4.二、八、十六进制整数

1.数字的四舍五入

你想对浮点数执行指定精度的舍入运算。

对于简单的舍入运算,使用内置的 round(value, ndigits) 函数即可。比如:

>>> round(1.23, 1)
1.2
>>> round(1.27, 1)
1.3
>>> round(-1.27, 1)
-1.3
>>> round(1.25361,3)
1.254
>>>

当一个值刚好在两个边界的中间的时候, round 函数返回离它最近的偶数。也就是说,对 1.5 1.5 1.5 或者 2.5 2.5 2.5 的舍入运算都会得到 2 2 2

传给 round() 函数的 ndigits 参数可以是负数,这种情况下,舍入运算会作用在十位、百位、千位等上面。比如:

>>> a = 1627731
>>> round(a, -1)
1627730
>>> round(a, -2)
1627700
>>> round(a, -3)
1628000
>>>

不要将舍入和格式化输出搞混淆了。如果你的目的只是简单的输出一定宽度的数,你不需要使用 round() 函数。而仅仅只需要在格式化的时候指定精度即可。比如:

>>> x = 1.23456
>>> format(x, '0.2f')
'1.23'
>>> format(x, '0.3f')
'1.235'
>>> 'value is {:0.3f}'.format(x)
'value is 1.235'
>>>

同样,不要试着去舍入浮点值来 “修正” 表面上看起来正确的问题。比如,你可能倾向于这样做:

>>> a = 2.1
>>> b = 4.2
>>> c = a + b
>>> c
6.300000000000001
>>> c = round(c, 2) # "Fix" result (???)
>>> c
6.3
>>>

对于大多数使用到浮点的程序,没有必要也不推荐这样做。尽管在计算的时候会有一点点小的误差,但是这些小的误差是能被理解与容忍的。如果不能允许这样的小误差(比如涉及到金融领域),那么就得考虑使用 decimal 模块了。

2.执行精确的浮点数运算

你需要对浮点数执行精确的计算操作,并且不希望有任何小误差的出现。

浮点数的一个普遍问题是它们并不能精确的表示十进制数。并且,即使是最简单的数学运算也会产生小的误差,比如:

>>> a = 4.2
>>> b = 2.1
>>> a + b
6.300000000000001
>>> (a + b) == 6.3
False
>>>

这些错误是由底层 CPU 和 IEEE 754 标准通过自己的浮点单位去执行算术时的特征。由于 Python 的浮点数据类型使用底层表示存储数据,因此你没办法去避免这样的误差。

如果你想更加精确(并能容忍一定的性能损耗),你可以使用 decimal 模块:

>>> from decimal import Decimal
>>> a = Decimal('4.2')
>>> b = Decimal('2.1')
>>> a + b
Decimal('6.3')
>>> print(a + b)
6.3
>>> (a + b) == Decimal('6.3')
True

初看起来,上面的代码好像有点奇怪,比如我们用字符串来表示数字。 然而,Decimal 对象会像普通浮点数一样的工作(支持所有的常用数学运算)。如果你打印它们或者在字符串格式化函数中使用它们,看起来跟普通数字没什么两样。

decimal 模块的一个主要特征是允许你控制计算的每一方面,包括数字位数和四舍五入运算。为了这样做,你先得创建一个本地上下文并更改它的设置,比如:

>>> from decimal import localcontext
>>> a = Decimal('1.3')
>>> b = Decimal('1.7')
>>> print(a / b)
0.7647058823529411764705882353
>>> with localcontext() as ctx:
...     ctx.prec = 3
...     print(a / b)
...
0.765
>>> with localcontext() as ctx:
...     ctx.prec = 50
...     print(a / b)
...
0.76470588235294117647058823529411764705882352941176
>>>

decimal 模块实现了 IBM 的 “通用小数运算规范”。不用说,有很多的配置选项这里没有提到。

Python 新手会倾向于使用 decimal 模块来处理浮点数的精确运算。然而,先理解你的应用程序目的是非常重要的。如果你是在做科学计算或工程领域的计算、电脑绘图,或者是科学领域的大多数运算,那么使用普通的浮点类型是比较普遍的做法。其中一个原因是,在真实世界中很少会要求精确到普通浮点数能提供的 17 位精度。因此,计算过程中的那么一点点的误差是被允许的。第二点就是,原生的浮点数计算要快的多(有时候你在执行大量运算的时候速度也是非常重要的)。

即便如此,你却不能完全忽略误差。数学家花了大量时间去研究各类算法,有些处理误差会比其他方法更好。你也得注意下减法删除以及大数和小数的加分运算所带来的影响。比如:

>>> nums = [1.23e+18, 1, -1.23e+18]
>>> sum(nums) # Notice how 1 disappears
0.0
>>>

上面的错误可以利用 math.fsum() 所提供的更精确计算能力来解决:

>>> import math
>>> math.fsum(nums)
1.0
>>>

然而,对于其他的算法,你应该仔细研究它并理解它的误差产生来源。

总的来说, decimal 模块主要用在涉及到金融的领域。在这类程序中,哪怕是一点小小的误差在计算过程中蔓延都是不允许的。 因此,
decimal 模块为解决这类问题提供了方法。当 Python 和数据库打交道的时候也通常会遇到 Decimal 对象,并且,通常也是在处理金融数据的时候。

3.数字的格式化输出

你需要将数字格式化后输出,并控制数字的位数、对齐、千位分隔符和其他的细节。

格式化输出单个数字的时候,可以使用内置的 format() 函数,比如:

>>> x = 1234.56789

>>> # Two decimal places of accuracy
>>> format(x, '0.2f')
'1234.57'

>>> # Right justified in 10 chars, one-digit accuracy
>>> format(x, '>10.1f')
'    1234.6'

>>> # Left justified
>>> format(x, '<10.1f')
'1234.6    '

>>> # Centered
>>> format(x, '^10.1f')
'  1234.6  '

>>> # Inclusion of thousands separator
>>> format(x, ',')
'1,234.56789'
>>> format(x, '0,.1f')
'1,234.6'
>>>

如果你想使用指数记法,将 f 改成 e 或者 E(取决于指数输出的大小写形式)。比如:

>>> format(x, 'e')
'1.234568e+03'
>>> format(x, '0.2E')
'1.23E+03'
>>>

同时指定宽度和精度的一般形式是 '[<>^]?width[,]?(.digits)?' , 其中 widthdigits 为整数,? 代表可选部分。 同样的格式也被用在字符串的 format() 方法中。比如:

>>> 'The value is {:0,.2f}'.format(x)
'The value is 1,234.57'
>>>

数字格式化输出通常是比较简单的。上面演示的技术同时适用于浮点数和 decimal 模块中的 Decimal 数字对象。

当指定数字的位数后,结果值会根据 round() 函数同样的规则进行四舍五入后返回。比如:

>>> x
1234.56789
>>> format(x, '0.1f')
'1234.6'
>>> format(-x, '0.1f')
'-1234.6'
>>>

包含千位符的格式化跟本地化没有关系。如果你需要根据地区来显示千位符,你需要自己去调查下 locale 模块中的函数了。你同样也可以使用字符串的 translate() 方法来交换千位符。例如,从英语格式 1,234.56789 转换为欧洲格式 1.234,56789

>>> swap_separators = { ord('.'):',', ord(','):'.' } # 创建替换规则字典
>>> format(x, ',').translate(swap_separators)
'1.234,56789'
>>>

在很多 Python 代码中会看到使用 % 来格式化数字的,比如:

>>> '%0.2f' % x
'1234.57'
>>> '%10.1f' % x
'    1234.6'
>>> '%-10.1f' % x
'1234.6    '
>>>

这种格式化方法也是可行的,不过比更加先进的 format() 要差一点。比如,在使用 % 操作符格式化数字的时候,一些特性(添加千位符)并不能被支持。

4.二、八、十六进制整数

你需要转换或者输出使用二进制,八进制或十六进制表示的整数。

为了将整数转换为二进制、八进制或十六进制的文本串,可以分别使用 bin()oct()hex() 函数:

>>> x = 1234
>>> bin(x)
'0b10011010010'
>>> oct(x)
'0o2322'
>>> hex(x)
'0x4d2'
>>>

另外,如果你不想输出 0b0o 或者 0x 的前缀的话,可以使用 format() 函数。比如:

>>> format(x, 'b')
'10011010010'
>>> format(x, 'o')
'2322'
>>> format(x, 'x')
'4d2'
>>>

整数是有符号的,所以如果你在处理负数的话,输出结果会包含一个负号。比如:

>>> x = -1234
>>> format(x, 'b')
'-10011010010'
>>> format(x, 'x')
'-4d2'
>>>

如果你想产生一个无符号值,你需要增加一个指示最大位长度的值。比如为了显示 32 位的值,可以像下面这样写:

>>> x = -1234
>>> format(2**32 + x, 'b')
'11111111111111111111101100101110'
>>> format(2**32 + x, 'x')
'fffffb2e'
>>>

🚀 上述代码演示了如何将负整数转换为无符号的二进制('b')和十六进制('x')字符串,利用了补码(Two's Complement)的原理。

为了以不同的进制转换整数字符串,简单的使用带有进制的 int() 函数即可:

>>> int('4d2', 16)
1234
>>> int('10011010010', 2)
1234
>>>

大多数情况下处理二进制、八进制和十六进制整数是很简单的。只要记住这些转换属于整数和其对应的文本表示之间的转换即可。永远只有一种整数类型。

最后,使用八进制的程序员有一点需要注意下。Python 指定八进制数的语法跟其他语言稍有不同。比如,如果你像下面这样指定八进制,会出现语法错误:

>>> import os
>>> os.chmod('script.py', 0755)
    File "<stdin>", line 1
        os.chmod('script.py', 0755)
                            ^
SyntaxError: invalid token
>>>

需确保八进制数的前缀是 0o ,就像下面这样:

>>> os.chmod('script.py', 0o755)
>>>

相关文章:

  • unity的dots中instantiate克隆对象后,对象会在原位置闪现的原因和解决
  • 吉卜力动画风格图像生成:Ghibli Diffusion
  • SDL中SDL_AudioSpec结构体参数
  • 23 MVC模式
  • Android学习总结之网络篇(HTTP请求流程)
  • Day82 | 灵神 | 快慢指针 重排链表
  • 科技赋能消防:无人机“挂弹灭火“构筑森林防火墙!
  • 生成式人工智能认证(GAI认证)如何推动就业市场的创新?
  • 【橘子大模型】关于记忆上下文Message History
  • Jenkins学习(B站教程)
  • [从零开始学习JAVA] 初学网络编程
  • 设计模式简述(十二)策略模式
  • [GN] sigrokdecode 模块学习指南 --- 准备阶段
  • COZE通关指南:工作流与插件开发
  • Go语言-初学者日记(四):包管理
  • 分组(二分查找)
  • GORM-Golang的ORM框架(1)
  • 2000-2019年 全国各省份GDP、人口、城镇化率统计数据
  • 深度研究deep-research优秀开源
  • Windows环境下开发pyspark程序
  • wordpress仿今日头条/seo搜索优化邵阳
  • 备案网站建设方案/常用的关键词优化策略有哪些
  • 找网络公司做网站需要注意/免费发布平台
  • vi设计百度百科/百度seo关键词优化软件
  • 调查问卷网站建设方案/无锡百度正规推广
  • 网站设计有哪几种设计方法/最近新闻头条