Implement true modulo in the engine

This commit is contained in:
Bill Currie 2020-02-16 11:53:56 +09:00
parent 4269c8cb07
commit b4fd804e4e
3 changed files with 52 additions and 0 deletions

View file

@ -391,6 +391,10 @@ typedef enum {
OP_LOADB_D,
OP_LOADBI_D,
OP_ADDRESS_D,
OP_MOD_I,
OP_MOD_F,
OP_MOD_D,
} pr_opcode_e;
typedef struct opcode_s {

View file

@ -318,6 +318,8 @@ signal_hook (int sig, void *data)
else
OPC.integer_var = 0x7fffffff;
return 1;
case OP_MOD_I:
case OP_MOD_F:
case OP_REM_I:
case OP_REM_F:
OPC.integer_var = 0x00000000;
@ -1429,9 +1431,35 @@ op_call:
case OP_DIV_I:
OPC.integer_var = OPA.integer_var / OPB.integer_var;
break;
case OP_MOD_I:
{
// implement true modulo for integers:
// 5 mod 3 = 2
// -5 mod 3 = 1
// 5 mod -3 = -1
// -5 mod -3 = -2
int a = OPA.integer_var;
int b = OPB.integer_var;
int c = a % b;
// % is really remainder and so has the same sign rules
// as division: -5 % 3 = -2, so need to add b (3 here)
// if c's sign is incorrect, but only if c is non-zero
int mask = (a ^ b) >> 31;
mask &= ~!!c + 1;
OPC.integer_var = c + (mask & b);
}
break;
case OP_REM_I:
OPC.integer_var = OPA.integer_var % OPB.integer_var;
break;
case OP_MOD_D:
{
double a = OPA_double_var;
double b = OPB_double_var;
// floating point modulo is so much easier :P
OPC_double_var = a - b * floor (a / b);
}
break;
case OP_REM_D:
{
double a = OPA_double_var;
@ -1439,6 +1467,13 @@ op_call:
OPC_double_var = a - b * trunc (a / b);
}
break;
case OP_MOD_F:
{
float a = OPA.float_var;
float b = OPB.float_var;
OPC.float_var = a - b * floorf (a / b);
}
break;
case OP_REM_F:
{
float a = OPA.float_var;

View file

@ -175,6 +175,10 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"%%", "mod.d", OP_MOD_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"+", "add.d", OP_ADD_D, false,
ev_double, ev_double, ev_double,
@ -1040,6 +1044,10 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_integer, ev_integer, ev_integer,
PROG_VERSION,
},
{"%%", "mod.i", OP_MOD_I, false,
ev_integer, ev_integer, ev_integer,
PROG_VERSION,
},
{"&", "bitand.i", OP_BITAND_I, false,
ev_integer, ev_integer, ev_integer,
PROG_VERSION,
@ -1054,6 +1062,11 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
},
{"%%", "mod.f", OP_MOD_F, false,
ev_float, ev_float, ev_float,
PROG_VERSION,
},
{">=", "ge.i", OP_GE_I, false,
ev_integer, ev_integer, ev_integer,
PROG_VERSION,