From 696d39b922408b827b1232603f920848dc9ddc23 Mon Sep 17 00:00:00 2001 From: Lexi Date: Fri, 9 Aug 2024 16:54:26 -0400 Subject: [PATCH] Move safe_mul_div macro and make it generic on integer types (#1334) Move safe_mul_div macro and make it generic on integer types --- lib/std/math/math.c3 | 109 ++++++++++++++++++++++++++++++++++ lib/std/time/os/time_win32.c3 | 7 +-- test/unit/stdlib/math/math.c3 | 30 ++++++++++ 3 files changed, 141 insertions(+), 5 deletions(-) diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3 index ef6b3b48f..7fa119eef 100644 --- a/lib/std/math/math.c3 +++ b/lib/std/math/math.c3 @@ -1096,3 +1096,112 @@ macro overflow_mul_helper(x, y) @local if ($$overflow_mul(x, y, &res)) return MathError.OVERFLOW?; return res; } + + +macro char char.mult_div(self, char mul, char div) +{ + return mul * (self / div) + mul * (self % div) / div; +} + +macro ichar ichar.mult_div(self, ichar mul, ichar div) +{ + return mul * (self / div) + mul * (self % div) / div; +} + +macro short short.mult_div(self, short mul, short div) +{ + return mul * (self / div) + mul * (self % div) / div; +} + +macro ushort ushort.mult_div(self, ushort mul, ushort div) +{ + return mul * (self / div) + mul * (self % div) / div; +} + +macro int int.mult_div(self, int mul, int div) +{ + return mul * (self / div) + mul * (self % div) / div; +} + +macro uint uint.mult_div(self, uint mul, uint div) +{ + return mul * (self / div) + mul * (self % div) / div; +} + +macro long long.mult_div(self, long mul, long div) +{ + return mul * (self / div) + mul * (self % div) / div; +} + +macro ulong ulong.mult_div(self, ulong mul, ulong div) +{ + return mul * (self / div) + mul * (self % div) / div; +} + +macro bool @is_same_vector_or_scalar(#vector_value, #vector_or_scalar) @private { + return (values::@is_vector(#vector_or_scalar) &&& values::@is_same_vector_type(#vector_value, #vector_or_scalar)) ||| values::@is_int(#vector_or_scalar); +} + +/** + * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` + */ +macro char[<*>] char[<*>].mult_div(self, mul, div) { + return ($typeof(self))mul * (self / ($typeof(self))div) + ($typeof(self))mul * (self % ($typeof(self))div) / ($typeof(self))div; +} + +/** + * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` + */ +macro ichar[<*>] ichar[<*>].mult_div(self, mul, div) { + return ($typeof(self))mul * (self / ($typeof(self))div) + ($typeof(self))mul * (self % ($typeof(self))div) / ($typeof(self))div; +} + +/** + * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` + */ +macro short[<*>] short[<*>].mult_div(self, mul, div) { + return ($typeof(self))mul * (self / ($typeof(self))div) + ($typeof(self))mul * (self % ($typeof(self))div) / ($typeof(self))div; +} + +/** + * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` + */ +macro ushort[<*>] ushort[<*>].mult_div(self, mul, div) { + return ($typeof(self))mul * (self / ($typeof(self))div) + ($typeof(self))mul * (self % ($typeof(self))div) / ($typeof(self))div; +} + +/** + * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` + */ +macro int[<*>] int[<*>].mult_div(self, mul, div) { + return ($typeof(self))mul * (self / ($typeof(self))div) + ($typeof(self))mul * (self % ($typeof(self))div) / ($typeof(self))div; +} + +/** + * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` + */ +macro uint[<*>] uint[<*>].mult_div(self, mul, div) { + return ($typeof(self))mul * (self / ($typeof(self))div) + ($typeof(self))mul * (self % ($typeof(self))div) / ($typeof(self))div; +} + +/** + * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` + */ +macro long[<*>] long[<*>].mult_div(self, mul, div) { + return ($typeof(self))mul * (self / ($typeof(self))div) + ($typeof(self))mul * (self % ($typeof(self))div) / ($typeof(self))div; +} + +/** + * @require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar` + * @require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar` + */ +macro ulong[<*>] ulong[<*>].mult_div(self, mul, div) { + return ($typeof(self))mul * (self / ($typeof(self))div) + ($typeof(self))mul * (self % ($typeof(self))div) / ($typeof(self))div; +} \ No newline at end of file diff --git a/lib/std/time/os/time_win32.c3 b/lib/std/time/os/time_win32.c3 index f70e7ed6b..7a444c1fd 100644 --- a/lib/std/time/os/time_win32.c3 +++ b/lib/std/time/os/time_win32.c3 @@ -1,5 +1,6 @@ module std::time::os @if(env::WIN32); import std::os::win32; +import std::math; extern fn void win32_GetSystemTimeAsFileTime(Win32_FILETIME* time) @extern("GetSystemTimeAsFileTime"); extern fn Win32_BOOL win32_QueryPerformanceFrequency(Win32_LARGE_INTEGER* lpFrequency) @extern("QueryPerformanceFrequency"); @@ -8,10 +9,6 @@ extern fn Win32_BOOL win32_QueryPerformanceCounter(Win32_LARGE_INTEGER* lpPerfor const ulong WINDOWS_TICK_US @local = 10; const ulong WIN_TO_UNIX_EPOCH_US @local = 116444736000000000u64 / WINDOWS_TICK_US; -macro ulong safe_mul_div(ulong a, ulong b, ulong c) -{ - return b * (a / c) + b * (a % c) / c; -} fn Clock native_clock() { @@ -24,7 +21,7 @@ fn Clock native_clock() } Win32_LARGE_INTEGER counter @noinit; if (!win32_QueryPerformanceCounter(&counter)) return 0; - return (Clock)safe_mul_div(counter.quadPart, 1_000_000_000, freq.quadPart); + return (Clock)counter.quadPart.mult_div(1_000_000_000, freq.quadPart); } fn Time native_timestamp() diff --git a/test/unit/stdlib/math/math.c3 b/test/unit/stdlib/math/math.c3 index 630924c19..d4bab1ed1 100644 --- a/test/unit/stdlib/math/math.c3 +++ b/test/unit/stdlib/math/math.c3 @@ -164,4 +164,34 @@ fn void! test() @test assert(math::round_to_decimals(radians, 3) == 0.785); assert(math::round_to_decimals(radians_f, 3) == 0.785f); +} + +fn void! test_mult_div() +{ + char a = 20; + assert(a.mult_div(20, 10) == 40); + ichar b = 20; + assert(b.mult_div(20, -10) == -40); + short c = 16000; + assert(c.mult_div(4, 2) == 32000); + ushort d = 16000; + assert(d.mult_div(8, 2) == 64000); + int e = 1_000_000; + assert(e.mult_div(40000, 10000) == 4_000_000); + uint f = 3_000_000_000u; + assert(f.mult_div(110, 100) == 3_300_000_000u); + long g = 1_000_000_000_000i64; + assert(g.mult_div(2_000_000_000_000i64, 1_000_000_000i64) == 2_000_000_000_000_000i64); + ulong h = 1_000_000_000_000u64; + assert(h.mult_div(2_000_000_000_000u64, 1_000_000_000u64) == 2_000_000_000_000_000u64); + + char[<4>] i = {20, 30, 40, 50}; + assert(i.mult_div(12,10) == char[<4>] {24, 36, 48, 60}); + assert(i.mult_div(char[<4>]{11, 12, 13, 14}, char[<4>]{10,10,10,10}) == char[<4>]{22, 36, 52, 70}); + + long[<4>] j = {1_000_000_000_000i64, 2_000_000_000_000i64, 3_000_000_000_000i64, 4_000_000_000_000i64}; + assert(j.mult_div(2_000_000_000_000i64, 1_000_000_000i64) == long[<4>]{2_000_000_000_000_000i64, 4_000_000_000_000_000i64, 6_000_000_000_000_000i64, 8_000_000_000_000_000i64}); + + ichar[<4>] k = {20, 30, 40, 50}; + assert(k.mult_div(20,-10) == ichar[<4>]{-40,-60,-80,-100}); } \ No newline at end of file