python里的数值类型

Published On March 31, 2017

category python


不像其他语言需要借助专门的库,python天生支持大数计算。如果要说python有什么优点的话,这个绝对算是其中一点。numpy等科学计算库也从python这个特性受益。正是因为很多诸如此类的特性,使得python成为科研领域炙手可热的语言。 今天在做题的时候需要用到超大数的除法,我就傻傻的实现了针对字符串的四则运算,因为我计算除法用到乘法和减法,而乘法需要加法。后来想起来python里的数值可以是任意大,于是就好好看了一下文档。下面让我们来认识python的数值类型。

python有四种基本的数值类型,integer,long,float,complex,此外还有两种高级的类型,分别是固定精度的十进制数decimal和分数(有理数)fraction,下面分别进行介绍。

integer,整形,boolean是它的子类型

使用c语言的long实现,至少有32位精度。最大值是sys.maxint,最小值是-sys.maxint - 1。

常数sys.maxsize,表示Py_ssize_t类型的最大值,对于32位机器是2**31-1,对于64位机器是2**63-1,也是list, string, dict的最大size。 虽然文档上对sys.maxint和sys.maxsize的表述不一样,但事实上,它们是相等的。 python3里移除了sys.maxint,保留了sys.maxsize,所以为了兼容,尽量使用sys.maxsize。

>>> import sys
>>> sys.maxint
9223372036854775807
>>> sys.maxint == 2**63-1
True
>>> sys.maxsize == sys.maxint
True

整数可以写成十进制,十六进制(0x或0X开头,后接0~9和A~E,大小写都可以),八进制(以0o或0O开头,以0开头的写法容易产生混淆,在python3中被淘汰了)和二进制(以0b或0B开头)

>>> 0x1a
26
>>> 0X1a
26
>>> 0o11
9
>>> 0o11==9
True
>>> 0b111
7
>>> bin(7)
'0b111'

因为bool是integer的子类行,所以True相当于1,False相当于0:

>>> isinstance(True,bool)
True
>>> isinstance(True,int)
True
>>> True+1
2
>>> True==1
True
>>> True is 1
False

位操作只针对整形,优先级高于比较,低于其他数值运算。 下面两个表达式等效,但明显加了括号的看起来更容易,所以强烈建议不要省:

>>> 2 ** 2 + 1 < 1<<2+1
True
>>> (2 ** 2 + 1) < (1<<(2+1))
True

long,长整型,具有无限精度

只要内存空间允许,长整型可以增长到任意大 在整形的后面加l或L会转换成长整型,建议用L,l和1有时分不清。

>>> type(100l)
<type 'long'>
>>> 100L
100L

字面数字无法用integer表示的时候会产生long

>>> 12345678901234567890
12345678901234567890L

注意print的时候不会显示L,因为print相当于调要对象的__str__方法,通常是对用户更加友好的格式;而交互模式下调用对象的__repr__,一般__repr__的表示会更像代码。

>>> print(2*100)
200
>>> print(2**100)
1267650600228229401496703205376

integer计算的结果超出表示范围后会自动转换成Long integer,这就允许我们放心大胆地进行大数运算。

>>> type(sys.maxsize)
<type 'int'>
>>> sys.maxsize+1
9223372036854775808L
>>> type(sys.maxsize+1)
<type 'long'>
>>> 2 ** 100
1267650600228229401496703205376L

python3中已经将一般整形和长整型合二为一了,也就是说没有long这种类型了。不能在常数末尾加l或L,交互模式下也不会显示这个字符。

float,浮点数

使用c语言里的double实现,它的精度也是机器相关的,可以通过sys.float_info查看float类型的精度和内部表示等底层信息。

  • sys.float_info.dig是float能精确表示的十进制数字的位数
  • sys.float_info.radix是科学计数法里的exponent部分的底数

浮点数字面值可以写成科学计数法的形式,底数是10

>>> 1.2
1.2
>>> .2
0.2
>>> 1.
1.0
>>> -1e-2
-0.01
>>> 3.14e-10
3.14e-10
>>> 2E10
20000000000.0

在比较的时候经常用到无穷大和无穷小:

  • float('nan')表示Not a Number (NaN)
  • float('inf')表示正无穷大
  • float('-inf')表示负无穷大
>>> 2**200<float('inf')
True
>>> -2**10000 > float('-inf')
True

说到浮点数就不得不提0.1+0.2的问题。这个问题的根本原因计算机里的数都是二进制表示的,而二进制数无法精确表示浮点数。 和c,java等大多数编程语言一样,python的float是用二进制分数(binary fraction)存储的,因为现在的计算机都是使用IEEE-754浮点运算标准。 就像十进制分数无法用有限的位数精确表示1/3一样,二进制分数也无法精确的表示大部分十进制的小数,比如0.1

python在显示的时候会进行舍入以提供一种用户友好的显示,但在运算的时候需要我们清楚它是不精确的。使用decimal库可以看到一个浮点数是怎么存储的。

>>> 0.1
0.1
>>> 0.1 + 0.2
0.30000000000000004
>>> from decimal import Decimal
>>> Decimal(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')

complex,实部和虚部都是float

常写成实部+虚部的形式,虚部以j或J结尾,实部可有可无:

>>> 1+2j
(1+2j)
>>> type(1+2j)
<type 'complex'>
>>> complex(1,2)
(1+2j)

实部和虚部分别保存在复数对象的real 和 imag属性中

>>> c=1+2j
>>> c.real
1.0
>>> c.imag
2.0

decimal,有固定精度的浮点数

使用字符串创建Decimal的时候精度就是传给它的字符串的小数位数,不同精度的小数的+-运算结果自动升级为小数位数最多的

>>> from decimal import Decimal
>>> Decimal('0.1')+Decimal('0.2')
Decimal('0.3')
>>> Decimal('0.1')+Decimal('0.20')
Decimal('0.30')

使用数值常量创建的时候,Decimal的精度是浮点数的最大精度

>>> Decimal(1.)
Decimal('1')
>>> Decimal(0.5)
Decimal('0.5')
>>> Decimal(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')

用户可以自定义精度

>>> import decimal
>>> decimal.Decimal(2)/decimal.Decimal(3)
Decimal('0.6666666666666666666666666667')
>>> decimal.getcontext().prec=2
>>> decimal.Decimal(2)/decimal.Decimal(3)
Decimal('0.67')

fraction,分数,精确的表示任何有理数

任何有理数都可以用分数表示。 通过传入两个整数作为分子和分母创建分数,分数会自动约分到最简的形式。

>>> from fractions import Fraction
>>> x=Fraction(1,10)
>>> x
Fraction(1, 10)
>>> y=Fraction(2,10)
>>> y
Fraction(1, 5)
>>> x+y
Fraction(3, 10)

通过浮点数的字符串表示创建分数

>>> Fraction('.125')
Fraction(1, 8)

和浮点数相互转换

>>> 0.5.as_integer_ratio()
(1, 2)
>>> Fraction(*0.5.as_integer_ratio())
Fraction(1, 2)
>>> Fraction.from_float(0.5)
Fraction(1, 2)
>>> float(Fraction(1,3))
0.3333333333333333

Fraction和浮点数运算的结果是浮点数

>>> Fraction(1,3)+0.5
0.8333333333333333

运算和比较

python支持不同的数值类型直接进行运算和比较,运算遵循的原则是“小”类型提升为另外一种类型。按范围大小排序有:

integer<long<float<complex

有一个例外,long可以是任意大,而float是有限的,所以float类型并不能表示所有的long。

连续比较

python允许多个比较连续起来执行,相当于用and连接起来,下面的两条比较语句是等价的:

>>> 1==2<3
False
>>> 1==2 and 2<3
False

除法

在c语言里5/2=2,5/-2=-2,不支持5/2.0 在python2里

>>> 5/2
2
>>> 5/-2
-3
>>> 5/2.0
2.5

在python3里面/总是真除

>>> 5/2
2.5
>>> 5/-2
-2.5
>>> 5/2.0
2.5

python2和3支持截断除法(floor除法),他总是返回(向下)截断后的整数部分,操作数有浮点数就是浮点数类型,否则是整形:

>>> 5//2
2
>>> 5//-2
-3
>>> 5//2.0
2.0
5/-2的结果是-2.5,向下截断是-3

注意:python不是弱类型的语言,它不允许用字符串表示的数字和数值类型直接进行运算,但有两个例外:

  • 字符串乘法表示重复

    >>> 'he' * 2
    'hehe'
    

  • python2里数值和其他类型比较的时候总是比其他类型小,python3则不允许不同类型之间的比较

    >>> 100 < '10'
    True
    >>> 1.2 > '0'
    False
    

参考


qq email facebook github
© 2018 - Xurui Yan. All rights reserved
Built using pelican