mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 23:11:38 +00:00
Implement true modulo in the engine
This commit is contained in:
parent
4269c8cb07
commit
b4fd804e4e
3 changed files with 52 additions and 0 deletions
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue