mruby/c VM Source Code master (2026/08/06)
Loading...
Searching...
No Matches
c_numeric.c
Go to the documentation of this file.
1
14
15/***** Feature test switches ************************************************/
16/***** System headers *******************************************************/
17//@cond
18#include "vm_config.h"
19#include <stdio.h>
20#include <limits.h>
21#if MRBC_USE_FLOAT
22#include <math.h>
23#endif
24//@endcond
25
26/***** Local headers ********************************************************/
27#include "mrubyc.h"
28
29/***** Constat values *******************************************************/
30/***** Macros ***************************************************************/
31#if MRBC_USE_FLOAT == 1
32#define MRBC_POW powf
33#else
34#define MRBC_POW pow
35#endif
36
37/***** Typedefs *************************************************************/
38/***** Function prototypes **************************************************/
39/***** Local variables ******************************************************/
40/***** Global variables *****************************************************/
41/***** Signal catching functions ********************************************/
42/***** Local functions ******************************************************/
43
44/***** Integer class ********************************************************/
45//================================================================
48static void c_integer_bitref(mrbc_vm *vm, mrbc_value v[], int argc)
49{
50 const int INT_BITS = sizeof(mrbc_int_t) * CHAR_BIT;
51
52 if( mrbc_integer(v[1]) < 0 || mrbc_integer(v[1]) >= INT_BITS ||
53 (argc != 1 && mrbc_integer(v[2]) <= 0) ) {
54 SET_INT_RETURN( 0 );
55 } else {
56 mrbc_uint_t mask;
57 if( argc == 1 ) {
58 mask = 1;
59 } else if( mrbc_integer(v[2]) >= INT_BITS ) {
60 mask = (mrbc_uint_t)-1;
61 } else {
62 mask = ((mrbc_uint_t)1 << mrbc_integer(v[2])) - 1;
63 }
64 mrbc_uint_t ret = (mrbc_uint_t)(mrbc_integer(v[0]) >> mrbc_integer(v[1]));
65 SET_INT_RETURN( (mrbc_int_t)(ret & mask) );
66 }
67}
68
69
70//================================================================
73static void c_integer_positive(mrbc_vm *vm, mrbc_value v[], int argc)
74{
75 // do nothing
76}
77
78
79//================================================================
82static void c_integer_negative(mrbc_vm *vm, mrbc_value v[], int argc)
83{
84 mrbc_int_t num = mrbc_integer(v[0]);
85 SET_INT_RETURN( -num );
86}
87
88
89//================================================================
92static void c_integer_power(mrbc_vm *vm, mrbc_value v[], int argc)
93{
94 if( mrbc_type(v[1]) == MRBC_TT_INTEGER ) {
95 mrbc_int_t x = 1;
96
97 if( mrbc_integer(v[1]) < 0 ) x = 0;
98 for( int i = 0; i < mrbc_integer(v[1]); i++ ) {
99 x *= mrbc_integer(v[0]);
100 }
101 SET_INT_RETURN( x );
102 }
103
104#if MRBC_USE_FLOAT && MRBC_USE_MATH
105 else if( mrbc_type(v[1]) == MRBC_TT_FLOAT ) {
107 }
108#endif
109}
110
111
112//================================================================
115static void c_integer_mod(mrbc_vm *vm, mrbc_value v[], int argc)
116{
117 if( mrbc_type(v[1]) != MRBC_TT_INTEGER ) {
118 mrbc_raise(vm, MRBC_CLASS(TypeError), 0 );
119 return;
120 }
121
122 mrbc_int_t v0 = v[0].i;
123 mrbc_int_t v1 = v[1].i;
124
125 if( v1 == 0 ) {
126 mrbc_raise(vm, MRBC_CLASS(ZeroDivisionError), 0 );
127 return;
128 }
129
130 mrbc_int_t ret = v0 % v1;
131
132 if( (ret != 0) && ((v0 ^ v1) < 0) ) ret += v1;
133 SET_INT_RETURN( ret );
134}
135
136
137//================================================================
140static void c_integer_and(mrbc_vm *vm, mrbc_value v[], int argc)
141{
142 mrbc_int_t num = mrbc_integer(v[1]);
143 SET_INT_RETURN(v->i & num);
144}
145
146
147//================================================================
150static void c_integer_or(mrbc_vm *vm, mrbc_value v[], int argc)
151{
152 mrbc_int_t num = mrbc_integer(v[1]);
153 SET_INT_RETURN(v->i | num);
154}
155
156
157//================================================================
160static void c_integer_xor(mrbc_vm *vm, mrbc_value v[], int argc)
161{
162 mrbc_int_t num = mrbc_integer(v[1]);
163 SET_INT_RETURN( v->i ^ num );
164}
165
166
167//================================================================
170static void c_integer_not(mrbc_vm *vm, mrbc_value v[], int argc)
171{
172 mrbc_int_t num = mrbc_integer(v[0]);
173 SET_INT_RETURN( ~num );
174}
175
176
177//----------------------------------------------------------------
181{
182 // Don't support environments that include padding in int.
183 const int INT_BITS = sizeof(mrbc_int_t) * CHAR_BIT;
184
185 if( y >= INT_BITS ) return 0;
186 if( y >= 0 ) return x << y;
187 if( y <= -INT_BITS ) return 0;
188 return x >> -y;
189}
190
191
192//================================================================
195static void c_integer_lshift(mrbc_vm *vm, mrbc_value v[], int argc)
196{
197 mrbc_int_t num = mrbc_integer(v[1]);
198 SET_INT_RETURN( shift(v->i, num) );
199}
200
201
202//================================================================
205static void c_integer_rshift(mrbc_vm *vm, mrbc_value v[], int argc)
206{
207 mrbc_int_t num = mrbc_integer(v[1]);
208 SET_INT_RETURN( shift(v->i, -num) );
209}
210
211
212//================================================================
215static void c_integer_plus(mrbc_vm *vm, mrbc_value v[], int argc)
216{
217 assert( mrbc_type(v[1]) == MRBC_TT_INTEGER );
218
220}
221
222
223//================================================================
226static void c_integer_minus(mrbc_vm *vm, mrbc_value v[], int argc)
227{
228 assert( mrbc_type(v[1]) == MRBC_TT_INTEGER );
229
231}
232
233
234//================================================================
237static void c_integer_gt_eq(mrbc_vm *vm, mrbc_value v[], int argc)
238{
239 assert( mrbc_type(v[1]) == MRBC_TT_INTEGER );
240
241 SET_BOOL_RETURN( mrbc_integer(v[0]) >= mrbc_integer(v[1]) );
242}
243
244
245//================================================================
248static void c_integer_abs(mrbc_vm *vm, mrbc_value v[], int argc)
249{
250 if( mrbc_integer(v[0]) < 0 ) {
251 mrbc_integer(v[0]) = -mrbc_integer(v[0]);
252 }
253}
254
255
256//================================================================
262static void c_numeric_clamp(mrbc_vm *vm, mrbc_value v[], int argc)
263{
264 if (argc != 2) {
265 mrbc_raise(vm, MRBC_CLASS(ArgumentError), "wrong number of arguments");
266 return;
267 }
268 mrbc_value min = v[1];
269 mrbc_value max = v[2];
270 if (
271 (mrbc_type(min) != MRBC_TT_INTEGER && mrbc_type(min) != MRBC_TT_FLOAT) ||
273 ) {
274 mrbc_raise(vm, MRBC_CLASS(ArgumentError), "comparison failed");
275 return;
276 }
277 if (mrbc_compare(&max, &min) < 0) {
278 mrbc_raise(vm, MRBC_CLASS(ArgumentError), "min argument must be smaller than max argument");
279 return;
280 }
281 if (mrbc_compare(&v[0], &min) < 0) {
282 SET_RETURN(min);
283 return;
284 }
285 if (mrbc_compare(&max, &v[0]) < 0) {
286 SET_RETURN(max);
287 return;
288 }
289 SET_RETURN(v[0]); /* return self */
290}
291
292
293#if MRBC_USE_FLOAT
294//================================================================
297static void c_integer_to_f(mrbc_vm *vm, mrbc_value v[], int argc)
298{
299 mrbc_float_t f = mrbc_integer(v[0]);
300 SET_FLOAT_RETURN( f );
301}
302#endif
303
304
305#if MRBC_USE_STRING
306//================================================================
310#if MRBC_USE_STRING_UTF8
311int mrbc_utf8_encode(int32_t codepoint, char *buf)
312{
313 if( codepoint < 0 || codepoint > 0x10FFFF ) {
314 return 0; // out of range
315 }
316 if( codepoint >= 0xD800 && codepoint <= 0xDFFF ) {
317 return 0; // surrogate pair - invalid in UTF-8
318 }
319
320 if( codepoint <= 0x7F ) {
321 buf[0] = (char)codepoint;
322 return 1;
323 } else if( codepoint <= 0x7FF ) {
324 buf[0] = (char)(0xC0 | (codepoint >> 6));
325 buf[1] = (char)(0x80 | (codepoint & 0x3F));
326 return 2;
327 } else if( codepoint <= 0xFFFF ) {
328 buf[0] = (char)(0xE0 | (codepoint >> 12));
329 buf[1] = (char)(0x80 | ((codepoint >> 6) & 0x3F));
330 buf[2] = (char)(0x80 | (codepoint & 0x3F));
331 return 3;
332 } else {
333 buf[0] = (char)(0xF0 | (codepoint >> 18));
334 buf[1] = (char)(0x80 | ((codepoint >> 12) & 0x3F));
335 buf[2] = (char)(0x80 | ((codepoint >> 6) & 0x3F));
336 buf[3] = (char)(0x80 | (codepoint & 0x3F));
337 return 4;
338 }
339}
340#endif
341
342//================================================================
345static void c_integer_chr(mrbc_vm *vm, mrbc_value v[], int argc)
346{
347#if MRBC_USE_STRING_UTF8
348 mrbc_int_t codepoint = mrbc_integer(v[0]);
349 char buf[5];
350 int len;
351
352 if( codepoint < 0 ) {
353 mrbc_raise(vm, MRBC_CLASS(RangeError), "out of char range");
354 return;
355 }
356 if( codepoint >= 0xD800 && codepoint <= 0xDFFF ) {
357 mrbc_raise(vm, MRBC_CLASS(RangeError), "invalid codepoint in UTF-8");
358 return;
359 }
360 if( codepoint > 0x10FFFF ) {
361 mrbc_raise(vm, MRBC_CLASS(RangeError), "out of char range");
362 return;
363 }
364
365 // chr without encoding argument only accepts 0..255
366 if( codepoint > 0xFF ) {
367 mrbc_raise(vm, MRBC_CLASS(RangeError), "out of char range");
368 return;
369 }
370
371 buf[0] = (char)codepoint;
372 len = 1;
373 mrbc_value value = mrbc_string_new(vm, buf, len);
374 SET_RETURN(value);
375#else
376 char buf[2] = { mrbc_integer(v[0]) };
377
378 mrbc_value value = mrbc_string_new(vm, buf, 1);
379 SET_RETURN(value);
380#endif
381}
382
383
384//================================================================
387static void c_integer_inspect(mrbc_vm *vm, mrbc_value v[], int argc)
388{
389 if( mrbc_type(v[0]) == MRBC_TT_CLASS ) {
390 mrbc_object_inspect(vm, v, argc);
391 return;
392 }
393
394 int base = 10;
395 if( argc ) {
396 base = mrbc_integer(v[1]);
397 if( base < 2 || base > 36 ) {
398 mrbc_raisef(vm, MRBC_CLASS(ArgumentError), "invalid radix %d", base);
399 return;
400 }
401 }
402
403 mrbc_printf_t pf;
404 char buf[16];
405 mrbc_printf_init( &pf, buf, sizeof(buf), NULL );
406 pf.fmt.type = 'd';
407 mrbc_printf_int( &pf, v->i, base );
408 mrbc_printf_end( &pf );
409
410 mrbc_value value = mrbc_string_new_cstr(vm, buf);
411 SET_RETURN(value);
412}
413#endif
414
415
416/* MRBC_AUTOGEN_METHOD_TABLE
417
418 CLASS("Integer")
419 FILE("_autogen_class_integer.h")
420
421 METHOD( "[]", c_integer_bitref )
422 METHOD( "+@", c_integer_positive )
423 METHOD( "-@", c_integer_negative )
424 METHOD( "**", c_integer_power )
425 METHOD( "%", c_integer_mod )
426 METHOD( "&", c_integer_and )
427 METHOD( "|", c_integer_or )
428 METHOD( "^", c_integer_xor )
429 METHOD( "~", c_integer_not )
430 METHOD( "<<", c_integer_lshift )
431 METHOD( ">>", c_integer_rshift )
432 METHOD( "+", c_integer_plus )
433 METHOD( "-", c_integer_minus )
434 METHOD( ">=", c_integer_gt_eq )
435 METHOD( "abs", c_integer_abs )
436 METHOD( "to_i", c_ineffect )
437 METHOD( "clamp", c_numeric_clamp )
438#if MRBC_USE_FLOAT
439 METHOD( "to_f", c_integer_to_f )
440#endif
441#if MRBC_USE_STRING
442 METHOD( "chr", c_integer_chr )
443 METHOD( "inspect", c_integer_inspect )
444 METHOD( "to_s", c_integer_inspect )
445#endif
446*/
447#include "_autogen_class_integer.h"
448
449
450
451/***** Float class **********************************************************/
452#if MRBC_USE_FLOAT
453
454//================================================================
457static void c_float_positive(mrbc_vm *vm, mrbc_value v[], int argc)
458{
459 // do nothing
460}
461
462
463//================================================================
466static void c_float_negative(mrbc_vm *vm, mrbc_value v[], int argc)
467{
468 mrbc_float_t num = mrbc_float(v[0]);
469 SET_FLOAT_RETURN( -num );
470}
471
472
473#if MRBC_USE_MATH
474//================================================================
477static void c_float_power(mrbc_vm *vm, mrbc_value v[], int argc)
478{
479 mrbc_float_t n = 0;
480 switch( mrbc_type(v[1]) ) {
481 case MRBC_TT_INTEGER: n = mrbc_integer(v[1]); break;
482 case MRBC_TT_FLOAT: n = mrbc_float(v[1]); break;
483 default: break;
484 }
485
487}
488#endif
489
490
491//================================================================
494static void c_float_abs(mrbc_vm *vm, mrbc_value v[], int argc)
495{
496 if( mrbc_float(v[0]) < 0 ) {
497 mrbc_float(v[0]) = -mrbc_float(v[0]);
498 }
499}
500
501
502//================================================================
505static void c_float_to_i(mrbc_vm *vm, mrbc_value v[], int argc)
506{
508 SET_INT_RETURN( i );
509}
510
511
512#if MRBC_USE_STRING
513//================================================================
516static void c_float_inspect(mrbc_vm *vm, mrbc_value v[], int argc)
517{
518 if( mrbc_type(v[0]) == MRBC_TT_CLASS ) {
519 mrbc_object_inspect(vm, v, argc);
520 return;
521 }
522
523 char buf[32];
524 mrbc_format_float(buf, sizeof(buf), v->d);
525 mrbc_value value = mrbc_string_new_cstr(vm, buf);
526 SET_RETURN(value);
527}
528#endif
529
530
531/* MRBC_AUTOGEN_METHOD_TABLE
532
533 CLASS("Float")
534 FILE("_autogen_class_float.h")
535
536 METHOD( "+@", c_float_positive )
537 METHOD( "-@", c_float_negative )
538#if MRBC_USE_MATH
539 METHOD( "**", c_float_power )
540#endif
541 METHOD( "abs", c_float_abs )
542 METHOD( "to_i", c_float_to_i )
543 METHOD( "to_f", c_ineffect )
544 METHOD( "clamp", c_numeric_clamp )
545#if MRBC_USE_STRING
546 METHOD( "inspect", c_float_inspect )
547 METHOD( "to_s", c_float_inspect )
548#endif
549*/
550#include "_autogen_class_float.h"
551
552#endif // MRBC_USE_FLOAT
#define mrbc_type(o)
Definition boxing_no.h:57
struct RObject mrbc_value
Value object. Default version.
#define mrbc_float(o)
Definition boxing_no.h:60
#define mrbc_integer(o)
Definition boxing_no.h:58
static mrbc_int_t shift(mrbc_int_t x, mrbc_int_t y)
Definition c_numeric.c:180
#define MRBC_POW
Definition c_numeric.c:32
void mrbc_object_inspect(mrbc_vm *vm, mrbc_value v[], int argc)
Definition c_object.c:91
mrbc_value mrbc_string_new(mrbc_vm *vm, const void *src, int len)
Definition c_string.c:64
static mrbc_value mrbc_string_new_cstr(mrbc_vm *vm, const char *src)
Definition c_string.h:91
#define MRBC_CLASS(cls)
Definition class.h:55
int mrbc_printf_int(mrbc_printf_t *pf, mrbc_int_t value, unsigned int base)
Definition console.c:792
static void mrbc_printf_end(mrbc_printf_t *pf)
Definition console.h:150
struct RPrintf mrbc_printf_t
printf tiny (mruby/c) version data container.
static void mrbc_printf_init(mrbc_printf_t *pf, char *buf, int size, const char *fstr)
Definition console.h:124
void mrbc_raise(struct VM *vm, struct RClass *exc_cls, const char *msg)
Definition error.c:145
void mrbc_raisef(struct VM *vm, struct RClass *exc_cls, const char *fstr,...)
Definition error.c:168
Include at once the necessary header files.
mrbc_float_t d
Definition boxing_no.h:24
mrbc_int_t i
Definition boxing_no.h:22
char type
format char. (e.g. 'd','f','x'...)
Definition console.h:51
struct RPrintfFormat fmt
Definition console.h:70
int mrbc_compare(const mrbc_value *v1, const mrbc_value *v2)
Definition value.c:68
void mrbc_format_float(char *buf, int bufsiz, mrbc_float_t flo)
Definition value.c:264
float mrbc_float_t
Definition value.h:52
int32_t mrbc_int_t
Definition value.h:47
#define SET_BOOL_RETURN(n)
Definition value.h:238
#define SET_INT_RETURN(n)
Definition value.h:243
@ MRBC_TT_FLOAT
Float.
Definition value.h:88
@ MRBC_TT_INTEGER
Integer.
Definition value.h:86
@ MRBC_TT_CLASS
Class.
Definition value.h:90
uint32_t mrbc_uint_t
Definition value.h:48
#define SET_RETURN(n)
Definition value.h:221
#define SET_FLOAT_RETURN(n)
Definition value.h:248
struct VM mrbc_vm
Virtual Machine.
Global configuration of mruby/c VM's.