强基初中数学&学Python——第202课 数字和数学模块之一: numbers数字的抽象基类


  该模块定义了数字的层级结构抽象基类,逐级添加一些特性已适应各种数字对称操作的需要。

  

  class Number

  数字的顶层,是其它所有数字层次的基础,可Number()实例化,但这样的实例无用。本模块中它之下的所有类型都不能实例化。如果你只想确认参数x是不是数字而不关心其类型,则使用内置函数isinstance(x, Number)

>>>from numbers import Number

>>>n = Number()

>>>n

<numbers.Number object at 0x000001357370BAE0>

>>>isinstance(1, Number)

True

 

  第一层class Complex(复数类型)

  这是Number的抽象子类,描述了复数抽象要求和功能,适用于内置 complex 类型的操作。这些操作有: 转换为complex bool, real, imag, +, -, *, /, **, abs(), conjugate(), == 以及 !=。除取反(-)和不等于( != )之外所有操作都是抽象的。

  Complex.real该复数的实数部分,抽象,只有复数对象才可以调用。

  Complex.imag复数的虚数部分,抽象。

  abstractmethod Complex.conjugate(),抽象。返回共轭复数。例如 (1+3j).conjugate() == (1-3j)

>>>from numbers import Complex

>>>n = Complex()

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

TypeError: Can't instantiate abstract class Complex with abstract methods __abs__, __add__, __complex__, __eq__, __mul__, __neg__, __pos__, __pow__, __radd__, __rmul__, __rpow__, __rtruediv__, __truediv__, conjugate, imag, real

>>>isinstance(1+1J, Complex)

True

>>>cmp=complex("1+1j")

>>>cmp

1+1j

>>>bool(cmp)

True

>>>cmp.real

1.0

>>>cmp.imag

1.0

>>>cmp.conjugate()

(1-1j)

>>>abs(cmp)

1.4142135623730951

 

  第二层class Real(实数类型)

  这是Complex的抽象子类,虚部为0,继承复数的所有属性和方法外,增加了只适合实数的操作,它们包括:float()、math.trunc()、 round()、 math.floor()、 math.ceil()、 divmod()、 //、 %、 <、 <=、 >、 和 >=。

>>>from numbers import Real

>>>real = Real()

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

TypeError: Can't instantiate abstract class Real with abstract methods __abs__, __add__, __ceil__, __eq__, __float__, __floor__, __floordiv__, __le__, __lt__, __mod__, __mul__, __neg__, __pos__, __pow__, __radd__, __rfloordiv__, __rmod__, __rmul__, __round__, __rpow__, __rtruediv__, __truediv__, __trunc__

>>>f=float("1.23e12")

>>>f

1230000000000.0

>>>from math import trunc,floor,ceil

>>>f=trunc(1.23e12)

>>>f

1230000000000

>>>round(2.3501,2)

2.35

>>>floor(1.995)

1

>>>ceil(1.021)

2

>>>divmod(123,11)

(11,2)

>>>complex("1.23")

(1.23+0j)

>>>r=1.23

>>>r.real

1.23

>>>r.imag

0.0

>>>r.conjugate()

1.23

 

  第三层class Rational(比,有理数类型)

  这是Real的抽象子类,增加了numerator(分子)和denominator(分母)两种抽象属性,这两种属性为float()提供底层支持。

>>>from numbers import Rational

>>>r = Rational()

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

TypeError: Can't instantiate abstract class Rational with abstract methods __abs__, __add__, __ceil__, __eq__, __floor__, __floordiv__, __le__, __lt__, __mod__, __mul__, __neg__, __pos__, __pow__, __radd__, __rfloordiv__, __rmod__, __rmul__, __round__, __rpow__, __rtruediv__, __truediv__, __trunc__, denominator, numerator

>>>from fractions import Fraction

>>>fr=Fraction(1,2)

>>>isinstance(fr,Rational)

True

>>>fr.numerator

1

>>>fr.denominator

2

>>>f=1.23

>>>isinstance(f,Rational)

False

>>>f.as_integer_ratio()

(2769713770832855, 2251799813685248)

 

  第四层class Integral(整数类型)

  这是Rational的抽象子类,增加int()转换操作支持,为 float(), numerator 和 denominator 提供了默认支持。为 pow() 方法增加了求余,即pow(base, exp, mod)。二进制按位运算的抽象方法: <<(左移), >>(右移), &(按位与), ^(按位异或), |(按位或), ~(按位取反)。 右移 n 位被定义为被pow(2,n)整除。左移n位被定义为乘以 pow(2,n)。

>>>from numbers import Integral

>>>it = Integral()

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

TypeError: Can't instantiate abstract class Integral with abstract methods __abs__, __add__, __and__, __ceil__, __eq__, __floor__, __floordiv__, __int__, __invert__, __le__, __lshift__, __lt__, __mod__, __mul__, __neg__, __or__, __pos__, __pow__, __radd__, __rand__, __rfloordiv__, __rlshift__, __rmod__, __rmul__, __ror__, __round__, __rpow__, __rrshift__, __rshift__, __rtruediv__, __rxor__, __truediv__, __trunc__, __xor__

>>>n=123

isinstance(n,Integral)

True

>>>n.numerator

123

>>>n.denominator

1

>>>pow(12,3,10)

8

>>>bin(0b110101110101>>8), bin(0b110101110101//pow(2,8))

('0b1101', '0b1101')

>>>bin(-0b110101110101>>8), bin(-0b110101110101//pow(2,8))

('-0b1110', '-0b1110')

>>>bin(0b110101110101<<8), bin(0b110101110101*pow(2,8))

('0b11010111010100000000', '0b11010111010100000000')

>>>bin(-0b110101110101<<8), bin(-0b110101110101*pow(2,8))

('-0b11010111010100000000', '-0b11010111010100000000')

>>>bin(1 & 0b110101), bin(-1 & 0b110101)

('0b1', '0b110101')

>>>bin(1 ^ 0b110101), bin(-1 ^ 0b110101)

('0b110100', '-0b110110')

>>>bin(1 | 0b110101), bin(-1 | 0b110101)

('0b110101', '-0b1')

>>>bin(~0b110101), bin(~-0b110101)

('-0b110110', '0b110100')

>>>~123 | 123, ~-123 | -123

(-1, -1)

 

  位移(>>和<<)

  整数左移填入0,右移填入符合位(正0负1)。由上面的计算可以看出,绝对值相同,右移后同样位数后,负数的绝对值比正数大1,这是怎么回事呢?

  假如用16位表示一个整数,最高位(左起第一位)是符号位,0代表正数,1代表负数。正数是数的本身,负数除了符号位,其它位是这个数绝对值的补数+1。下图第三行是-1的储存结构。

 

  下图是-0b110101110101>>8的过程,储存码移去右边红色部分,左边填充1,然后减1后除了符号位外取反得到移位后的原码。可见这个数的移位操作使相应位置由1101变为1110,在数学上显然是错误的。关于这个问题下一课再讨论。

 

  按位与(&)

  “按位与”不区分符号位,把整个数当作0、1序列处理。由于-1的储存码所有位都是1,所以与-1“按位与”操作是数的本身。

  利用“按位与”这种特性,查看数的储存码(按位提取数值),例如,查看-1的最后(右)8位是什么数字。

>>>bin(-1 & 0xFF)

'0b11111111'

  计算机内储存整数外(最高位是符号位)还可以储存无符号整数(即自然数,最高位也是数位)。最常见的例子是32位IP地址,由于它是无符号整数,所以范围是0x0(0)到0xFFFFFFFF(2^32-1=4294967295)。注意:Python默认不支持无符号整数,但这个不影响与正整数的按位与操作。因为正整数的符号位都是0,所以与正整数的按位与操作一定是正整数。

  IP=4054568328转化为*.*.*.*形式。

  分析:就是把这个整数的最后4个字节分开成4个无符号整数。把一个字节看做是无符号整数,它的范围是0到255。

  程序代码(文本代码附录1):

 

  运行结果:

 

 

  按位或(|)

  只有对应两个位都是0,结果才是0,否则是1,所以-1与所有的整数“按位或”都是-1。

  例2 把IP=“241.171.205.136”转化为整数。

  分析:把四个整数分别左移24、16、8、0位后“按位或”就行。

  程序代码(文本代码附录2):

 

  运行结果:

 

 

  按位异或(^)

  对应位相同(同是0或1)结果是0,否则是1。

1^1=0,0^1=1;

1^0=1,1^0=1;

0^1=1,1^1=0;

0^0=0,0^0=0。

可见,一个数与另个数“异或”两次,值不变。

a^b^b=a。

  a=123b=-123,不使用临时变量交换它们的值,即交换后a=-123b=123

  分析:a放a和b的异或值,那么a再和b异或就是原来a值,放入b中,a和原来的a值“异或”就是b值,放入a中。

  程序代码(文本代码附录3):

 

  运行结果:

 

 

  按位取反(~)

  0变1,1变0。一个数按位取反后与这个数相或等于-1,即两个数互补。按位取反与相反数有差别,看下面运算

>>>~0,~1,~2,~3,~4

(-1, -2, -3, -4, -5)

>>>~-1, ~-2, ~-3, ~-4, ~-5

(0, 1, 2, 3, 4)

 

 

  练习题:

1、从父类到子类的顺序排列下面的类。

Real、Rational、Complex、Integral、Number。

2、手算-213右移四位是多少?运行验证。

3、把IP=2857487分成*.*.*.*形式,然后合成整数验证。

4、不用中间变量,交换a=9123,b=4536的值。

5、1234567按位取反是什么数,并验证。

 

附录1:

#按位与分解ip地址

IP=4054568328

print(IP>>24 & 0xFF, end=".")

print(IP>>16 & 0xFF, end=".")

print(IP>>8 & 0xFF, end=".")

print(IP & 0xFF)

附录2:

#按位或合并ip地址

IP="241.171.205.136"

ips = IP.split(".")

ip = (int(ips[0])<<24) | \

     (int(ips[1])<<16) | \

     (int(ips[2])<<8)  | \

     (int(ips[3]))

print(ip)

附录3:

#异或交换变量值

a=123

b=-123

print("a=%d, b=%d" % (a,b))

a=a^b #aab的异或值

b=a^b #b放原a

a=a^b #a放原b

print("a=%d, b=%d" % (a,b))

 

 

收录于合集 #强基初中数学

 125个

上一篇强基初中数学&学Python——外加课 负整数向右位移的系统错误与纠正方法下一篇强基初中数学&学Python——第201课 浮点计算“怪”的根源