Replace integer division algorithm

This commit is contained in:
Rerumu 2022-07-02 02:03:33 -04:00
parent 577fbf5926
commit 071b0877cf

View File

@ -1,6 +1,6 @@
local Numeric = {} local Numeric = {}
local NUM_ZERO, NUM_ONE, NUM_BIT_26 local NUM_ZERO, NUM_ONE, NUM_BIT_26, NUM_BIT_52
local bit_lshift = bit32.lshift local bit_lshift = bit32.lshift
local bit_rshift = bit32.rshift local bit_rshift = bit32.rshift
@ -11,22 +11,19 @@ local bit_or = bit32.bor
local bit_xor = bit32.bxor local bit_xor = bit32.bxor
local bit_not = bit32.bnot local bit_not = bit32.bnot
local bit_extract = bit32.extract
local bit_replace = bit32.replace local bit_replace = bit32.replace
local math_ceil = math.ceil
local math_floor = math.floor local math_floor = math.floor
local math_log = math.log
local math_max = math.max
local math_pow = math.pow
local table_freeze = table.freeze local table_freeze = table.freeze
local from_u32, into_u32, from_u64, into_u64 local from_u32, into_u32, from_u64, into_u64
local num_add, num_subtract, num_multiply, num_divide_unsigned, num_negate, num_not local num_add, num_subtract, num_divide_unsigned, num_negate
local num_is_negative, num_is_zero, num_is_equal, num_is_less_unsigned, num_is_greater_unsigned local num_not, num_or, num_shift_left
local num_is_negative, num_is_zero, num_is_less_unsigned
if Vector3 then if Vector3 then
local bit_extract = bit32.extract
local constructor = Vector3.new local constructor = Vector3.new
-- X: a[0 ..21] -- X: a[0 ..21]
@ -182,45 +179,40 @@ function Numeric.multiply(lhs, rhs)
return from_u32(data_1, data_2) return from_u32(data_1, data_2)
end end
local function get_approx_delta(rem, rhs)
local approx = math_max(1, math_floor(rem / rhs))
local log = math_ceil(math_log(approx, 2))
local delta = log <= 48 and 1 or math_pow(2, log - 48)
return approx, delta
end
function Numeric.divide_unsigned(lhs, rhs) function Numeric.divide_unsigned(lhs, rhs)
if num_is_zero(rhs) then if num_is_zero(rhs) then
error("division by zero") error("division by zero")
elseif num_is_zero(lhs) then elseif num_is_zero(lhs) then
return NUM_ZERO return NUM_ZERO
elseif num_is_less_unsigned(lhs, NUM_BIT_52) and num_is_less_unsigned(rhs, NUM_BIT_52) then
local result = math_floor(into_u64(lhs) / into_u64(rhs))
return from_u64(result)
end end
local rhs_number = into_u64(rhs) local quotient = NUM_ZERO
local rem = lhs local remainder = NUM_ZERO
local res = NUM_ZERO
while num_is_greater_unsigned(rem, rhs) or num_is_equal(rem, rhs) do local num_1, num_2 = into_u32(lhs)
local res_approx, delta = get_approx_delta(into_u64(rem), rhs_number)
local res_temp = from_u64(res_approx)
local rem_temp = num_multiply(res_temp, rhs)
while num_is_negative(rem_temp) or num_is_greater_unsigned(rem_temp, rem) do for i = 63, 0, -1 do
res_approx = res_approx - delta local rem_1, rem_2 = into_u32(num_shift_left(remainder, NUM_ONE))
res_temp = from_u64(res_approx)
rem_temp = num_multiply(res_temp, rhs) if i > 31 then
rem_1 = bit_or(rem_1, bit_extract(num_2, i - 32, 1))
else
rem_1 = bit_or(rem_1, bit_extract(num_1, i, 1))
end end
if num_is_zero(res_temp) then remainder = from_u32(rem_1, rem_2)
res_temp = NUM_ONE
if not num_is_less_unsigned(remainder, rhs) then
remainder = num_subtract(remainder, rhs)
quotient = num_or(quotient, num_shift_left(NUM_ONE, from_u32(i, 0)))
end
end end
res = num_add(res, res_temp) return quotient, remainder
rem = num_subtract(rem, rem_temp)
end
return res
end end
function Numeric.divide_signed(lhs, rhs) function Numeric.divide_signed(lhs, rhs)
@ -397,20 +389,21 @@ into_u64 = Numeric.into_u64
num_add = Numeric.add num_add = Numeric.add
num_subtract = Numeric.subtract num_subtract = Numeric.subtract
num_multiply = Numeric.multiply
num_divide_unsigned = Numeric.divide_unsigned num_divide_unsigned = Numeric.divide_unsigned
num_negate = Numeric.negate num_negate = Numeric.negate
num_not = Numeric.bit_not num_not = Numeric.bit_not
num_or = Numeric.bit_or
num_shift_left = Numeric.shift_left
num_is_negative = Numeric.is_negative num_is_negative = Numeric.is_negative
num_is_zero = Numeric.is_zero num_is_zero = Numeric.is_zero
num_is_equal = Numeric.is_equal
num_is_less_unsigned = Numeric.is_less_unsigned num_is_less_unsigned = Numeric.is_less_unsigned
num_is_greater_unsigned = Numeric.is_greater_unsigned
NUM_ZERO = from_u64(0) NUM_ZERO = from_u64(0)
NUM_ONE = from_u64(1) NUM_ONE = from_u64(1)
NUM_BIT_26 = from_u64(0x4000000) NUM_BIT_26 = from_u64(0x4000000)
NUM_BIT_52 = from_u64(0x10000000000000)
Numeric.ZERO = NUM_ZERO Numeric.ZERO = NUM_ZERO
Numeric.ONE = NUM_ONE Numeric.ONE = NUM_ONE