Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

"""Rational number type based on Python integers. """ 

 

from __future__ import print_function, division 

 

import operator 

 

from sympy.polys.polyutils import PicklableWithSlots 

from sympy.polys.domains.domainelement import DomainElement 

 

from sympy.core.compatibility import integer_types 

from sympy.core.sympify import converter 

from sympy.core.numbers import Rational 

from sympy.printing.defaults import DefaultPrinting 

from sympy.utilities import public 

 

@public 

class PythonRational(DefaultPrinting, PicklableWithSlots, DomainElement): 

""" 

Rational number type based on Python integers. 

 

This was supposed to be needed for compatibility with older Python 

versions which don't support Fraction. However, Fraction is very 

slow so we don't use it anyway. 

 

Examples 

======== 

 

>>> from sympy.polys.domains import PythonRational 

 

>>> PythonRational(1) 

1 

>>> PythonRational(2, 3) 

2/3 

>>> PythonRational(14, 10) 

7/5 

 

""" 

 

__slots__ = ['p', 'q'] 

 

def parent(self): 

from sympy.polys.domains import PythonRationalField 

return PythonRationalField() 

 

def __init__(self, p, q=1): 

if not q: 

raise ZeroDivisionError('rational number') 

elif q < 0: 

p, q = -p, -q 

 

if not p: 

self.p = 0 

self.q = 1 

elif p == 1 or q == 1: 

self.p = p 

self.q = q 

else: 

x, y = p, q 

 

while y: 

x, y = y, x % y 

 

if x != 1: 

p //= x 

q //= x 

 

self.p = p 

self.q = q 

 

@classmethod 

def new(cls, p, q): 

obj = object.__new__(cls) 

obj.p = p 

obj.q = q 

return obj 

 

def __hash__(self): 

if self.q == 1: 

return hash(self.p) 

else: 

return hash((self.p, self.q)) 

 

def __int__(self): 

p, q = self.p, self.q 

if p < 0: 

return -(-p//q) 

return p//q 

 

def __float__(self): 

return float(self.p)/self.q 

 

def __abs__(self): 

return self.new(abs(self.p), self.q) 

 

def __pos__(self): 

return self.new(+self.p, self.q) 

 

def __neg__(self): 

return self.new(-self.p, self.q) 

 

def __add__(self, other): 

if isinstance(other, PythonRational): 

p = self.p*other.q + self.q*other.p 

q = self.q*other.q 

elif isinstance(other, integer_types): 

p = self.p + self.q*other 

q = self.q 

else: 

return NotImplemented 

 

return self.__class__(p, q) 

 

def __radd__(self, other): 

if not isinstance(other, integer_types): 

return NotImplemented 

 

p = self.p + self.q*other 

q = self.q 

 

return self.__class__(p, q) 

 

def __sub__(self, other): 

if isinstance(other, PythonRational): 

p = self.p*other.q - self.q*other.p 

q = self.q*other.q 

elif isinstance(other, integer_types): 

p = self.p - self.q*other 

q = self.q 

else: 

return NotImplemented 

 

return self.__class__(p, q) 

 

def __rsub__(self, other): 

if not isinstance(other, integer_types): 

return NotImplemented 

 

p = self.q*other - self.p 

q = self.q 

 

return self.__class__(p, q) 

 

def __mul__(self, other): 

if isinstance(other, PythonRational): 

p = self.p*other.p 

q = self.q*other.q 

elif isinstance(other, integer_types): 

p = self.p*other 

q = self.q 

else: 

return NotImplemented 

 

return self.__class__(p, q) 

 

def __rmul__(self, other): 

if not isinstance(other, integer_types): 

return NotImplemented 

 

p = self.p*other 

q = self.q 

 

return self.__class__(p, q) 

 

def __div__(self, other): 

if isinstance(other, PythonRational): 

p = self.p*other.q 

q = self.q*other.p 

elif isinstance(other, integer_types): 

p = self.p 

q = self.q*other 

else: 

return NotImplemented 

 

return self.__class__(p, q) 

 

__truediv__ = __div__ 

 

def __rdiv__(self, other): 

if not isinstance(other, integer_types): 

return NotImplemented 

 

p = self.q*other 

q = self.p 

 

return self.__class__(p, q) 

 

__rtruediv__ = __rdiv__ 

 

def __mod__(self, other): 

return self.__class__(0) 

 

def __divmod__(self, other): 

return (self//other, self % other) 

 

def __pow__(self, exp): 

p, q = self.p, self.q 

 

if exp < 0: 

p, q, exp = q, p, -exp 

 

return self.new(p**exp, q**exp) 

 

def __nonzero__(self): 

return self.p != 0 

 

__bool__ = __nonzero__ 

 

def __eq__(self, other): 

if isinstance(other, PythonRational): 

return self.q == other.q and self.p == other.p 

elif isinstance(other, integer_types): 

return self.q == 1 and self.p == other 

else: 

return False 

 

def __ne__(self, other): 

return not self.__eq__(other) 

 

def _cmp(self, other, op): 

try: 

diff = self - other 

except TypeError: 

return NotImplemented 

else: 

return op(diff.p, 0) 

 

def __lt__(self, other): 

return self._cmp(other, operator.lt) 

 

def __le__(self, other): 

return self._cmp(other, operator.le) 

 

def __gt__(self, other): 

return self._cmp(other, operator.gt) 

 

def __ge__(self, other): 

return self._cmp(other, operator.ge) 

 

@property 

def numer(self): 

return self.p 

 

@property 

def denom(self): 

return self.q 

 

numerator = numer 

denominator = denom 

 

 

def sympify_pythonrational(arg): 

return Rational(arg.p, arg.q) 

converter[PythonRational] = sympify_pythonrational