-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdecimator.py
202 lines (169 loc) · 6.42 KB
/
decimator.py
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
class Decimator:
def __init__(self, number):
assert isinstance(number, int) or isinstance(number, float) or self._is_number(number), 'number must be int or float'
self.number = number
self.positive_decimals = []
self.negative_decimals = []
self._set()
def _set(self):
if isinstance(self.number, int):
assert self.number >= 0, 'number must not be negative'
self.number_string = str(self.number)
self.integer_string = self.number_string
self.fraction_string = False
self.fraction_precision = 0
elif isinstance(self.number, float):
assert self.number >= 0, 'number must not be negative'
self.number_string = str(self.number)
n = self.number_string.find('.')
self.integer_string = self.number_string[0:n]
self.fraction_string = '0' + self.number_string[n:]
self.fraction_precision = len(self.fraction_string) - 2
elif isinstance(self.number, str):
assert '-' not in self.number, 'number must not be negative'
self.number_string = self.number
if '.' in self.number:
n = self.number_string.find('.')
self.integer_string = self.number_string[0:n]
self.fraction_string = '0' + self.number_string[n:]
self.fraction_precision = len(self.fraction_string) - 2
pass
else:
self.integer_string = self.number_string
self.fraction_precision = 0
self.fraction_string = False
self._get_positive_decimals_from_string(self.integer_string)
self._get_negative_decimals_from_string(self.fraction_string)
def _is_number(self, number):
if '.' in number:
try:
cast = float(number)
except:
return False
else:
try:
integer_cast = int(number)
except:
return False
return True
def _get_positive_decimals_from_string(self, integer):
index = len(integer)-1
while index >= 0:
value = self._get_digit_at_index(integer, index)
self.positive_decimals.append(value)
index -= 1
def _get_digit_at_index(self, number, index):
try:
value = number[index]
return int(value)
except:
return '0'
def _get_negative_decimals_from_string(self, fraction):
if not fraction:
self.negative_decimals.append(0)
return
index = 0
while index < self.fraction_precision:
value = self._get_digit_at_index(fraction, index+2)
self.negative_decimals.append(value)
index +=1
def add(self, number):
pass
def sub(self, number):
pass
def mul(self, number):
pass
def div(self, number):
pass
def pow(self, number):
pass
def shift(self, shift):
assert isinstance(shift, int), 'shift must be int'
decimator = Decimator(self.number)
decimator._shift(shift)
decimator._update_strings()
return decimator
def _update_strings(self):
self.integer_string = self._get_integer_string()
self._check_for_zero_fraction()
self.fraction_string = '0'+self._get_fraction_string()
self._update_fraction_precision()
def _check_for_zero_fraction(self):
if self.get_fractional_value() == 0.0:
self.negative_decimals = [0]
def _update_fraction_precision(self):
if self.negative_decimals == [0]:
self.fraction_precision = 0
else:
self.fraction_precision = len(self.negative_decimals)
def _shift(self, shift):
if shift > 0:
self._shift_positive(shift)
if shift < 0:
self._shift_negative(shift)
def _shift_positive(self, shift):
while shift > 0:
popped_value = self._pop_negative()
self._insert_positive(popped_value)
shift -= 1
def _shift_negative(self, shift):
while shift < 0:
popped_value = self._pop_positive()
self._insert_negative(popped_value)
shift += 1
def _insert_positive(self, value):
self.positive_decimals.insert(0, value)
def _insert_negative(self, value):
self.negative_decimals.insert(0, value)
def _pop_positive(self):
if len(self.positive_decimals) == 1:
pop = self.positive_decimals.pop(0)
self.positive_decimals.append(0)
return pop
return self.positive_decimals.pop(0)
def _pop_negative(self):
if len(self.negative_decimals) == 0:
return 0
return self.negative_decimals.pop(0)
def __str__(self):
number = self._get_integer_string()
if self.fraction_string:
number = number + self._get_fraction_string()
return number
def _get_integer_string(self):
integer = ''
for decimal in self.positive_decimals:
integer = str(decimal) + integer
return integer
def _get_fraction_string(self):
fraction = ''
fraction = fraction + '.'
if len(self.negative_decimals) > 0:
for decimal in self.negative_decimals:
fraction = fraction + str(decimal)
else:
fraction = fraction + '0'
return fraction
##########################################
#DO NEXT
def round(self, digits):
assert isinstance(digits, int), 'digits must be int'
assert digits >= 0, 'digits must be greater than or equal to'
decimator = Decimator(self.number)
return decimator
def _strip(self, digits):
if len(self.negative_decimals) > digits:
self.negative_decimals = self.negative_decimals[0:digits]
def get_value(self):
# I have found that the maximum floating point precision that can be trusted is 16
return float(self.__str__())
def get_integer_value(self):
value = 0
for i in range(len(self.positive_decimals)):
value += self.positive_decimals[i] * (10 ** i)
return value
def get_fractional_value(self):
value = 0.0
for i in range(len(self.negative_decimals)):
value += self.negative_decimals[i] * (10 ** ((-1)*(i+1)))
return value