mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 02:32:06 +00:00
Build everything as C++ (#1176)
This commit is contained in:
95
src/opmath.cpp
Normal file
95
src/opmath.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
// Mathematical operators that don't reuse C's behavior
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "opmath.hpp"
|
||||
|
||||
int32_t op_divide(int32_t dividend, int32_t divisor)
|
||||
{
|
||||
// Adjust division to floor toward negative infinity,
|
||||
// not truncate toward zero
|
||||
return dividend / divisor - ((dividend % divisor < 0) != (divisor < 0));
|
||||
}
|
||||
|
||||
int32_t op_modulo(int32_t dividend, int32_t divisor)
|
||||
{
|
||||
int32_t remainder = dividend % divisor;
|
||||
|
||||
// Adjust modulo to have the sign of the divisor,
|
||||
// not the sign of the dividend
|
||||
return remainder + divisor * ((remainder < 0) != (divisor < 0));
|
||||
}
|
||||
|
||||
int32_t op_exponent(int32_t base, uint32_t power)
|
||||
{
|
||||
int32_t result = 1;
|
||||
|
||||
for (;;) {
|
||||
if (power % 2)
|
||||
result *= base;
|
||||
power /= 2;
|
||||
if (!power)
|
||||
break;
|
||||
base *= base;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t op_shift_left(int32_t value, int32_t amount)
|
||||
{
|
||||
// Get the easy cases out of the way
|
||||
if (amount == 0)
|
||||
return value;
|
||||
if (value == 0 || amount >= 32)
|
||||
return 0;
|
||||
if (amount < -31)
|
||||
return (value < 0) ? -1 : 0;
|
||||
if (amount < 0)
|
||||
return op_shift_right(value, -amount);
|
||||
|
||||
// Use unsigned to force a bitwise shift
|
||||
// Casting back is OK because the types implement two's complement behavior
|
||||
return (uint32_t)value << amount;
|
||||
}
|
||||
|
||||
int32_t op_shift_right(int32_t value, int32_t amount)
|
||||
{
|
||||
// Repeat the easy cases here to avoid INT_MIN funny business
|
||||
if (amount == 0)
|
||||
return value;
|
||||
if (value == 0 || amount <= -32)
|
||||
return 0;
|
||||
if (amount > 31)
|
||||
return (value < 0) ? -1 : 0;
|
||||
if (amount < 0)
|
||||
return op_shift_left(value, -amount);
|
||||
|
||||
if (value > 0)
|
||||
return (uint32_t)value >> amount;
|
||||
|
||||
// Calculate an OR mask for sign extension
|
||||
// 1->0x80000000, 2->0xC0000000, ..., 31->0xFFFFFFFE
|
||||
uint32_t amount_high_bits = -(UINT32_C(1) << (32 - amount));
|
||||
|
||||
// The C standard leaves shifting right negative values
|
||||
// undefined, so use a left shift manually sign-extended
|
||||
return ((uint32_t)value >> amount) | amount_high_bits;
|
||||
}
|
||||
|
||||
int32_t op_shift_right_unsigned(int32_t value, int32_t amount)
|
||||
{
|
||||
// Repeat the easy cases here to avoid INT_MIN funny business
|
||||
if (amount == 0)
|
||||
return value;
|
||||
if (value == 0 || amount <= -32)
|
||||
return 0;
|
||||
if (amount > 31)
|
||||
return (value < 0) ? -1 : 0;
|
||||
if (amount < 0)
|
||||
return op_shift_left(value, -amount);
|
||||
|
||||
return (uint32_t)value >> amount;
|
||||
}
|
||||
Reference in New Issue
Block a user