Vita
int.h
Go to the documentation of this file.
1
13#if !defined(VITA_INT_PRIMITIVE_H)
14#define VITA_INT_PRIMITIVE_H
15
16#include <climits>
17#include <limits>
18#include <string>
19
20#include "kernel/gp/function.h"
22#include "kernel/random.h"
23#include "kernel/gp/terminal.h"
25
35{
36
37using base_t = D_INT;
38
44inline base_t cast(const value_t &v)
45{
46 return std::get<base_t>(v);
47}
48
54class number : public terminal
55{
56public:
57 explicit number(const cvect &c, int m = -128, int u = 127)
58 : terminal("INT", c[0]), min(m), upp(u)
59 {
60 Expects(c.size() == 1);
61 Expects(m < u);
62 }
63
64 bool parametric() const final { return true; }
65
66 terminal_param_t init() const final { return random::between(min, upp); }
67
68 std::string display(terminal_param_t v, format) const final
69 { return std::to_string(v); }
70
71 value_t eval(symbol_params &p) const final
72 {
73 return static_cast<base_t>(p.fetch_param());
74 }
75
76private:
77 const int min, upp;
78};
79
81class add : public function
82{
83public:
84 explicit add(const cvect &c) : function("ADD", c[0], {c[0], c[0]})
85 {
86 Expects(c.size() == 1);
87 }
88
89 bool associative() const final { return true; }
90
91 value_t eval(symbol_params &args) const final
92 {
93 const auto v0(integer::cast(args[0]));
94 const auto v1(integer::cast(args[1]));
95
96 if (v0 > 0 && v1 > 0 && (v0 > std::numeric_limits<base_t>::max() - v1))
97 return std::numeric_limits<base_t>::max();
98 if (v0 < 0 && v1 < 0 && (v0 < std::numeric_limits<base_t>::min() - v1))
99 return std::numeric_limits<base_t>::min();
100
101 return v0 + v1;
102 }
103};
104
106class div : public function
107{
108public:
109 explicit div(const cvect &c) : function("DIV", c[0], {c[0], c[0]})
110 { Expects(c.size() == 1); }
111
112 value_t eval(symbol_params &args) const final
113 {
114 const auto v0(integer::cast(args[0]));
115 const auto v1(integer::cast(args[1]));
116
117 if (v1 == 0 || (v0 == std::numeric_limits<base_t>::min() && (v1 == -1)))
118 return v0;
119
120 return v0 / v1;
121 }
122};
123
124class ife : public function
125{
126public:
127 explicit ife(const cvect &c)
128 : function("IFE", c[1], {c[0], c[0], c[1], c[1]})
129 { Expects(c.size() == 2); }
130
131 value_t eval(symbol_params &args) const final
132 {
133 const auto v0(integer::cast(args[0]));
134 const auto v1(integer::cast(args[1]));
135
136 if (v0 == v1)
137 return args[2];
138
139 return args[3];
140 }
141
142 double penalty_nvi(core_interpreter *ci) const final
143 {
145 }
146};
147
148class ifl : public function
149{
150public:
151 explicit ifl(const cvect &c)
152 : function("IFL", c[1], {c[0], c[0], c[1], c[1]})
153 { Expects(c.size() == 2); }
154
155 value_t eval(symbol_params &args) const final
156 {
157 const auto v0(integer::cast(args[0]));
158 const auto v1(integer::cast(args[1]));
159
160 if (v0 < v1)
161 return args[2];
162
163 return args[3];
164 }
165
166 double penalty_nvi(core_interpreter *ci) const final
167 {
169 }
170};
171
172class ifz : public function
173{
174public:
175 explicit ifz(const cvect &c) : function("IFZ", c[0], {c[0], c[0], c[0]})
176 { Expects(c.size() == 1); }
177
178 value_t eval(symbol_params &args) const final
179 {
180 const auto v0(integer::cast(args[0]));
181
182 if (v0 == 0)
183 return args[1];
184
185 return args[2];
186 }
187
188 double penalty_nvi(core_interpreter *ci) const final
189 {
191 }
192};
193
195class mod : public function
196{
197public:
198 explicit mod(const cvect &c) : function("MOD", c[0], {c[0], c[0]})
199 { Expects(c.size() == 1); }
200
201 value_t eval(symbol_params &args) const final
202 {
203 const auto v0(integer::cast(args[0]));
204 const auto v1(integer::cast(args[1]));
205
206 if (v1 == 0 || (v0 == std::numeric_limits<base_t>::min() && (v1 == -1)))
207 return v1;
208
209 return v0 % v1;
210 }
211};
212
214class mul : public function
215{
216public:
217 explicit mul(const cvect &c) : function("MUL", c[0], {c[0], c[0]})
218 { Expects(c.size() == 1); }
219
220 bool associative() const final { return true; }
221
222 value_t eval(symbol_params &args) const final
223 {
224 static_assert(sizeof(std::intmax_t) >= 2 * sizeof(base_t),
225 "Unable to detect overflow after multiplication");
226
227 const std::intmax_t v0(integer::cast(args[0]));
228 const std::intmax_t v1(integer::cast(args[1]));
229
230 const auto tmp(v0 * v1);
231 if (tmp > std::numeric_limits<base_t>::max())
232 return std::numeric_limits<base_t>::max();
233 if (tmp < std::numeric_limits<base_t>::min())
234 return std::numeric_limits<base_t>::min();
235
236 return static_cast<base_t>(tmp);
237
238 /*
239 // On systems where the above relationship does not hold, the following
240 // compliant solution may be used to ensure signed overflow does not
241 // occur.
242 if (v0 > 0)
243 if (v1 > 0)
244 {
245 assert(v0 > 0 && v1 > 0);
246 if (v0 > std::numeric_limits<base_t>::max() / v1)
247 return std::numeric_limits<base_t>::max();
248 }
249 else // v0 is positive, v1 is non-positive
250 {
251 assert(v0 > 0 && v1 <= 0);
252 if (v1 < std::numeric_limits<base_t>::min() / v0)
253 return std::numeric_limits<base_t>::min();
254 }
255 else // v0 is non-positive
256 if (v1 > 0)
257 {
258 assert(v0 <= 0 && v1 > 0);
259 if (v0 < std::numeric_limits<base_t>::min() / v1)
260 return std::numeric_limits<base_t>::min();
261 }
262 else // v0 is non-positive, v1 is non-positive
263 {
264 assert(v0 <= 0 && v1 <= 0);
265 if (v0 != 0 && v1 < std::numeric_limits<base_t>::max() / v0)
266 return std::numeric_limits<base_t>::max();
267 }
268
269 return v0 * v1;
270 */
271 }
272};
273
275class shl : public function
276{
277public:
278 explicit shl(const cvect &c) : function("SHL", c[0], {c[0], c[0]})
279 { Expects(c.size() == 1); }
280
281 value_t eval(symbol_params &args) const final
282 {
283 const auto v0(integer::cast(args[0]));
284 const auto v1(integer::cast(args[1]));
285
286 if (v0 < 0 || v1 < 0 ||
287 v1 >= static_cast<base_t>(sizeof(base_t) * CHAR_BIT) ||
288 v0 > std::numeric_limits<base_t>::max() >> v1)
289 return v0;
290
291 return v0 << v1;
292 }
293};
294
296class sub : public function
297{
298public:
299 explicit sub(const cvect &c) : function("SUB", c[0], {c[0], c[0]})
300 { Expects(c.size() == 1); }
301
302 value_t eval(symbol_params &args) const final
303 {
304 const auto v0(integer::cast(args[0]));
305 const auto v1(integer::cast(args[1]));
306
307 if (v0 < 0 && v1 > 0 && (v0 < std::numeric_limits<base_t>::min() + v1))
308 return std::numeric_limits<base_t>::min();
309 if (v0 > 0 && v1 < 0 && (v0 > std::numeric_limits<base_t>::max() + v1))
310 return std::numeric_limits<base_t>::max();
311
312 return v0 - v1;
313 }
314};
315
316} // namespace vita::integer
317
318#endif // include guard
Minimum interface of an interpreter.
A symbol with arity() > 0.
Definition: function.h:35
function(const std::string &, category_t, cvect)
Definition: function.cc:25
bool associative() const final
Is the symbol subject to the associative law of arithmetic?
Definition: int.h:89
value_t eval(symbol_params &args) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:91
value_t eval(symbol_params &args) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:112
value_t eval(symbol_params &args) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:131
double penalty_nvi(core_interpreter *ci) const final
Definition: int.h:142
value_t eval(symbol_params &args) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:155
double penalty_nvi(core_interpreter *ci) const final
Definition: int.h:166
double penalty_nvi(core_interpreter *ci) const final
Definition: int.h:188
value_t eval(symbol_params &args) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:178
value_t eval(symbol_params &args) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:201
bool associative() const final
Is the symbol subject to the associative law of arithmetic?
Definition: int.h:220
value_t eval(symbol_params &args) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:222
Integer ephemeral random constant.
Definition: int.h:55
value_t eval(symbol_params &p) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:71
bool parametric() const final
A parametric terminal needs an additional parameter to be evaluated.
Definition: int.h:64
terminal_param_t init() const final
Used to initialize the internal parameter of the terminal.
Definition: int.h:66
std::string display(terminal_param_t v, format) const final
Definition: int.h:68
value_t eval(symbol_params &args) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:281
value_t eval(symbol_params &args) const final
Calculates the value of / performs the action associated with the symbol (it's implementation specifi...
Definition: int.h:302
An interface for parameter passing to functions / terminals.
format
Symbol rendering format.
Definition: symbol.h:39
bool terminal() const
Definition: symbol.h:153
A symbol with zero-arity.
Definition: terminal.h:27
Integer overflow is undefined behaviour.
Definition: int.h:35
base_t cast(const value_t &v)
Just a simple shortcut.
Definition: int.h:44
double comparison_function_penalty(core_interpreter *ci)
A simple, convenient function for the penalty score of the typical four-terms comparison.
Definition: comp_penalty.h:29
std::variant< D_VOID, D_INT, D_DOUBLE, D_STRING > value_t
A variant containing the data types used by the interpreter for internal calculations / output value ...
Definition: value.h:45