From ffa5a92ef09a41858355915ba3b66b4eff4dd071 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 17 Mar 2026 19:41:46 +0100 Subject: [PATCH] We're writing unit tests in Zig now I dunno what happened, I was just applying some FloatFree(tm) and then all of this appeared out of nowhere! --- .gitignore | 1 + build.zig | 27 ++++ src/console.c | 1 - src/console.h | 1 - src/d_main.cpp | 55 --------- src/k_items.c | 10 +- src/k_kart.h | 2 +- src/m_fixed.c | 258 --------------------------------------- src/m_fixed.h | 14 --- src/tests.zig | 35 ++++++ src/tests/CMakeLists.txt | 5 - src/tests/boolcompat.cpp | 9 -- src/tests/notnull.cpp | 31 ----- src/tests/testbase.hpp | 6 - 14 files changed, 65 insertions(+), 390 deletions(-) create mode 100644 build.zig create mode 100644 src/tests.zig delete mode 100644 src/tests/CMakeLists.txt delete mode 100644 src/tests/boolcompat.cpp delete mode 100644 src/tests/notnull.cpp delete mode 100644 src/tests/testbase.hpp diff --git a/.gitignore b/.gitignore index 14fe96ba4..c36abf649 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ Win32_LIB_ASM_Release /bin /build /CMakeUserPresets.json +/.zig-cache diff --git a/build.zig b/build.zig new file mode 100644 index 000000000..062edb673 --- /dev/null +++ b/build.zig @@ -0,0 +1,27 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // this is just unit tests for now, so the root source file is the tests file + const blankart = b.addModule("blankart", .{ + .root_source_file = b.path("src/tests.zig"), + .target = target, + .optimize = optimize, + }); + + blankart.addIncludePath(b.path("src")); // -Isrc + blankart.linkSystemLibrary("c", .{}); // -lc + blankart.addCSourceFiles(.{ + .root = b.path("src"), + // anything you need to test goes here + .files = &.{ "m_fixed.c", "tables.c" }, + }); + + const blantests = b.addTest(.{ + .root_module = blankart, + }); + const test_step = b.step("test", "Run tests"); + test_step.dependOn(&b.addRunArtifact(blantests).step); +} diff --git a/src/console.c b/src/console.c index 2f68864ab..145a0eca3 100644 --- a/src/console.c +++ b/src/console.c @@ -1661,7 +1661,6 @@ static const char *CON_LoadingStrings[LOADED_ALLDONE+1] = "Init rendering daemon...", //LOADED_RINIT "Init audio subsystem...", //LOADED_SINITSFXCHANNELS "Cache HUD...", //LOADED_STINIT - "Test fixed-point arithmetic...", //LOADED_MATHINIT "Init ACSVM...", //LOADED_ACSINIT "Check game status...", //LOADED_DCHECKNETGAME "Now starting..." diff --git a/src/console.h b/src/console.h index 21bb81aa5..ffb8d7932 100644 --- a/src/console.h +++ b/src/console.h @@ -52,7 +52,6 @@ typedef enum LOADED_RINIT, LOADED_SINITSFXCHANNELS, LOADED_STINIT, - LOADED_MATHINIT, LOADED_ACSINIT, LOADED_DCHECKNETGAME, LOADED_ALLDONE = LOADED_DCHECKNETGAME, diff --git a/src/d_main.cpp b/src/d_main.cpp index 302f1bbc2..8b00ef63c 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1873,61 +1873,6 @@ void D_SRB2Main(void) ST_Init(); CON_SetLoadingProgress(LOADED_STINIT); - CONS_Printf("FixedSqrt of 32767 fracunits: %d; FixedSqrt64: %" PRId64 "\n", - FixedSqrt(0x7FFF0000), - FixedSqrt64(0x7FFF0000)); - - if (FixedSqrt(0x7FFF0000) == FixedSqrt64(0x7FFF0000)) - { - CONS_Printf("\x83" "32767: Test OK!" "\x80" "\n"); - } - else - { - CONS_Printf("\x85" "32767: Test NG!" "\x80" "\n"); - } - - CONS_Printf("FixedSqrt of 4 fracunits: %d; FixedSqrt64: %" PRId64 "\n", - FixedSqrt(0x40000), - FixedSqrt64(0x40000)); - - if (FixedSqrt(0x40000) == FixedSqrt64(0x40000)) - { - CONS_Printf("\x83" "4: Test OK!" "\x80" "\n"); - } - else - { - CONS_Printf("\x85" "4: Test NG!" "\x80" "\n"); - } - - // You should probably generate the weird number with RANDOM.org -#define WEIRDNUMBER 3886284 /* 59.3 fracunits; this should approximate to around 7 */ - CONS_Printf("FixedSqrt of 59.3 fracunits: %d; FixedSqrt64: %" PRId64 "\n", - FixedSqrt(WEIRDNUMBER), - FixedSqrt64(WEIRDNUMBER)); - - if (FixedSqrt(WEIRDNUMBER) == FixedSqrt64(WEIRDNUMBER)) - { - CONS_Printf("\x83" "59.3: Test OK!" "\x80" "\n"); - } - else - { - CONS_Printf("\x85" "59.3: Test NG!" "\x80" "\n"); - } -#undef WEIRDNUMBER - - CONS_Printf("FixedSqrt64 of 65535 fracunits: %" PRId64 "(not possible at 32-bit scale)\n", - FixedSqrt64(0xFFFFFFFF)); - - CONS_Printf("IntSqrt of 32767: %d; IntSqrt64: %" PRId64 "\n", - IntSqrt(0x7FFF), - IntSqrt64(0x7FFF)); - - CONS_Printf("IntSqrt of 4: %d; IntSqrt64: %" PRId64 "\n", - IntSqrt(4), - IntSqrt64(4)); - - CON_SetLoadingProgress(LOADED_MATHINIT); - CONS_Printf("ACS_Init(): Init Action Code Script VM.\n"); ACS_Init(); CON_SetLoadingProgress(LOADED_ACSINIT); diff --git a/src/k_items.c b/src/k_items.c index 914be5f0e..26e432a04 100644 --- a/src/k_items.c +++ b/src/k_items.c @@ -509,16 +509,8 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush) static INT32 K_KartGetSMonitorOdds(UINT32 dist) { - // I'm tired; use floating-point distances for this fuckshit. - INT32 monitordist = SMONITORDIST; - - float fac_f = (float)(dist) / ((float)(monitordist)); - - if (fac_f < 1.0f) - return 0; - // If you're far enough for this to be in your item slot, you're far enough to SERIOUSLY need this. - return MAXSMONITORODDS; + return dist >= (UINT32)SMONITORDIST ? MAXSMONITORODDS : 0; } // updates all result cooldown timers, and sets cooldowns for "unique" items diff --git a/src/k_kart.h b/src/k_kart.h index ef0c552de..3b5eb9f15 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -278,7 +278,7 @@ extern boolean forcefullinvintheme; boolean K_PlayFullInvinTheme(void); void K_DoInvincibility(player_t *player, tic_t time); void K_DoSMonitor(player_t *player, tic_t time); -#define SMONITORWARNINGTIME (fixed_t)(0.833333333f * (float)(FRACUNIT)) +#define SMONITORWARNINGTIME (5*FRACUNIT/6) fixed_t K_SMonitorGradient(UINT16 time); fixed_t K_GetSMonitorSpeed(UINT16 time); fixed_t K_GetSMonitorAccel(UINT16 time); diff --git a/src/m_fixed.c b/src/m_fixed.c index 695ad4d93..7448f4f51 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -11,30 +11,12 @@ /// \file m_fixed.c /// \brief Fixed point implementation -#if 0 //#ifndef NO_M -#include -#define HAVE_SQRT - #if 0 //#ifndef _WIN32 // MSVCRT does not have *f() functions - #define HAVE_SQRTF - #endif -#endif - #include "doomdef.h" #include "m_fixed.h" #include "tables.h" // ANGLETOFINESHIFT fixed_t FixedSqrt(fixed_t x) { -#ifdef HAVE_SQRT - const float fx = FIXED_TO_FLOAT(x); - float fr; -#ifdef HAVE_SQRTF - fr = sqrtf(fx); -#else - fr = (float)sqrt(fx); -#endif - return FLOAT_TO_FIXED(fr); -#else // The neglected art of Fixed Point arithmetic // Jetro Lauha // Seminar Presentation @@ -58,22 +40,11 @@ fixed_t FixedSqrt(fixed_t x) } } while (count-- != 0); return root; -#endif } // Shitty 64-bit duplicate so certain distancing edgecases in k_odds die INT64 FixedSqrt64(INT64 x) { -#ifdef HAVE_SQRT - const float fx = FixedToFloat64(x); - float fr; -#ifdef HAVE_SQRTF - fr = sqrtf(fx); -#else - fr = (float)sqrt(fx); -#endif - return FloatToFixed64(fr); -#else // The neglected art of Fixed Point arithmetic // Jetro Lauha // Seminar Presentation @@ -97,7 +68,6 @@ INT64 FixedSqrt64(INT64 x) } } while (count-- != 0); return root; -#endif } fixed_t FixedHypot(fixed_t x, fixed_t y) @@ -1242,231 +1212,3 @@ fixed_t ApproachFixed(fixed_t current, fixed_t target, fixed_t inc, fixed_t dec) } return current; } - -/** \brief Returns the floating-point value 'current' after it tries to approach target, going up at - most 'inc' and going down at most 'dec'. - - \param current (float) current value - - \param target (float) target value - - \param inc (float) value to increment by - - \param dec (float) value to decrement by - - \return (float) current value after incrementing/decrementing -*/ -float ApproachFloat(float current, float target, float inc, float dec) -{ - if (current < target) - { - current += inc; - if (current > target) - { - current = target; - } - } - else - { - current -= dec; - if (current < target) - { - current = target; - } - } - return current; -} - -/** \brief Returns the double-precision floating-point value 'current' after it tries to approach - target, going up at most 'inc' and going down at most 'dec'. - - \param current (double) current value - - \param target (double) target value - - \param inc (double) value to increment by - - \param dec (double) value to decrement by - - \return (double) current value after incrementing/decrementing -*/ -double ApproachDouble(double current, double target, double inc, double dec) -{ - if (current < target) - { - current += inc; - if (current > target) - { - current = target; - } - } - else - { - current -= dec; - if (current < target) - { - current = target; - } - } - return current; -} - -#ifdef M_TESTCASE -//#define MULDIV_TEST -#define SQRT_TEST - -static inline void M_print(INT64 a) -{ - const fixed_t w = (a >> FRACBITS); - fixed_t f = a % FRACUNIT; - fixed_t d = FRACUNIT; - - if (f == 0) - { - printf("%d", (fixed_t)w); - return; - } - else while (f != 1 && f / 2 == f >> 1) - { - d /= 2; - f /= 2; - } - - if (w == 0) - printf("%d/%d", (fixed_t)f, d); - else - printf("%d+(%d/%d)", (fixed_t)w, (fixed_t)f, d); -} - -FUNCMATH FUNCINLINE static inline fixed_t FixedMulC(fixed_t a, fixed_t b) -{ - return (fixed_t)((((INT64)a * b)) / FRACUNIT); -} - -FUNCMATH FUNCINLINE static inline INT64 FixedMul64C(fixed_t a, fixed_t b) -{ - return (INt64)((((INT64)a * b)) / FRACUNIT); -} - -FUNCMATH FUNCINLINE static inline fixed_t FixedDivC2(fixed_t a, fixed_t b) -{ - INT64 ret; - - if (b == 0) - I_Error("FixedDiv: divide by zero"); - - ret = (((INT64)a * FRACUNIT)) / b; - - if ((ret > INT32_MAX) || (ret < INT32_MIN)) - I_Error("FixedDiv: divide by zero"); - return (fixed_t)ret; -} - -FUNCMATH FUNCINLINE static inline fixed_t FixedDivC(fixed_t a, fixed_t b) -{ - if ((abs(a) >> (FRACBITS - 2)) >= abs(b)) - return (a^b) < 0 ? INT32_MIN : INT32_MAX; - - return FixedDivC2(a, b); -} - -FUNCMATH FUNCINLINE static inline fixed_t FixedSqrtC(fixed_t x) -{ - const float fx = FIXED_TO_FLOAT(x); - float fr; -#ifdef HAVE_SQRTF - fr = sqrtf(fx); -#else - fr = (float)sqrt(fx); -#endif - return FLOAT_TO_FIXED(fr); -} -int main(int argc, char** argv) -{ - int n = 10; - INT64 a, b; - fixed_t c, d; - (void)argc; - (void)argv; - -#ifdef MULDIV_TEST - for (a = 1; a <= INT32_MAX; a += FRACUNIT) - for (b = 0; b <= INT32_MAX; b += FRACUNIT) - { - c = FixedMul(a, b); - d = FixedMulC(a, b); - if (c != d) - { - printf("("); - M_print(a); - printf(") * ("); - M_print(b); - printf(") = ("); - M_print(c); - printf(") != ("); - M_print(d); - printf(") \n"); - n--; - printf("%d != %d\n", c, d); - } - c = FixedDiv(a, b); - d = FixedDivC(a, b); - if (c != d) - { - printf("("); - M_print(a); - printf(") / ("); - M_print(b); - printf(") = ("); - M_print(c); - printf(") != ("); - M_print(d); - printf(")\n"); - n--; - printf("%d != %d\n", c, d); - } - if (n <= 0) - exit(-1); - } -#endif - -#ifdef SQRT_TEST - for (a = 0; a <= INT32_MAX; a += 1) - { - c = FixedSqrt(a); - d = FixedSqrtC(a); - b = abs(c - d); - if (b > 1) - { - printf("sqrt("); - M_print(a); - printf(") = {("); - M_print(c); - printf(") != ("); - M_print(d); - printf(")} \n"); - //n--; - printf("%d != %d {", c, d); - M_print(b); - printf("}\n"); - } - if (n <= 0) - exit(-1); - } -#endif - exit(0); -} - -static void *cpu_cpy(void *dest, const void *src, size_t n) -{ - return memcpy(dest, src, n); -} - -void *(*memcpy)(void* dest, const void* src, size_t n) = cpu_cpy; - -void I_Error(const char *error, ...) -{ - (void)error; - exit(-1); -} -#endif diff --git a/src/m_fixed.h b/src/m_fixed.h index b25d85107..c0c8ad7a0 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -57,21 +57,11 @@ FUNCMATH FUNCINLINE static ATTRINLINE float FixedToFloat(fixed_t x) return x / (float)FRACUNIT; } -FUNCMATH FUNCINLINE static ATTRINLINE float FixedToFloat64(INT64 x) -{ - return (float)x / (float)FRACUNIT; -} - FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f) { return (fixed_t)(f * FRACUNIT); } -FUNCMATH FUNCINLINE static ATTRINLINE INT64 FloatToFixed64(float f) -{ - return (INT64)(f * FRACUNIT); -} - /*! * \brief convert fixed_t into double-precision floating number */ @@ -469,8 +459,6 @@ void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z); INT32 ApproachINT32(INT32 current, INT32 target, INT32 inc, INT32 dec); UINT32 ApproachUINT32(UINT32 current, UINT32 target, UINT32 inc, UINT32 dec); fixed_t ApproachFixed(fixed_t current, fixed_t target, fixed_t inc, fixed_t dec); -float ApproachFloat(float current, float target, float inc, float dec); -double ApproachDouble(double current, double target, double inc, double dec); /** \brief Returns the INT32 value ``current`` after it tries to approach ``target``, going up or down at most ``delta``. @@ -505,8 +493,6 @@ double ApproachDouble(double current, double target, double inc, double dec); #define ApproachOneWayUINT32(current, target, delta) (ApproachUINT32(current, target, delta, delta)) #define ApproachOneWayFixed(current, target, delta) (ApproachFixed(current, target, delta, delta)) -#define ApproachOneWayFloat(current, target, delta) (ApproachFloat(current, target, delta, delta)) -#define ApproachOneWayDouble(current, target, delta) (ApproachDouble(current, target, delta, delta)) #ifdef __cplusplus } // extern "C" diff --git a/src/tests.zig b/src/tests.zig new file mode 100644 index 000000000..f109abe62 --- /dev/null +++ b/src/tests.zig @@ -0,0 +1,35 @@ +const std = @import("std"); + +const C = @cImport({ + // include the headers you need for testing here + // also make sure to add the corresponding source files in build.zig until + // the symbol errors go away :face_holding_back_tears: + @cInclude("m_fixed.h"); +}); + +const fixed_t = i32; +const FRACUNIT: fixed_t = 65536; +const FRACBITS = 16; + +test "FixedSqrt d_main.cpp" +{ + try std.testing.expectEqual(C.FixedSqrt(0x7FFF0000), C.FixedSqrt64(0x7FFF0000)); + try std.testing.expectEqual(C.FixedSqrt(0x40000), C.FixedSqrt64(0x40000)); + + // You should probably generate the weird number with RANDOM.org + const WEIRDNUMBER = 3886284; // 59.3 fracunits; this should approximate to around 7 + try std.testing.expectEqual(C.FixedSqrt(WEIRDNUMBER), C.FixedSqrt64(WEIRDNUMBER)); +} + + +test "FixedSqrt m_fixed.c" +{ + var a: i64 = 0; + // not enough time in the world for all 2 billion values... + // prime numbers to the rescue + while (a <= std.math.maxInt(i32)) : (a += 97) { + const c: fixed_t = C.FixedSqrt(@intCast(a)); + const d: fixed_t = @intFromFloat(@sqrt(@as(f64, @floatFromInt(a)) / FRACUNIT) * FRACUNIT); + try std.testing.expect(@abs(c - d) <= 1); + } +} diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt deleted file mode 100644 index 59c64ae00..000000000 --- a/src/tests/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -target_sources(srb2tests PRIVATE - boolcompat.cpp - notnull.cpp - testbase.hpp -) diff --git a/src/tests/boolcompat.cpp b/src/tests/boolcompat.cpp deleted file mode 100644 index 72e2ccba7..000000000 --- a/src/tests/boolcompat.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "testbase.hpp" -#include - -#include "../doomtype.h" - -TEST_CASE("C++ bool is convertible to doomtype.h boolean") { - REQUIRE(static_cast(true) == 1); - REQUIRE(static_cast(false) == 0); -} diff --git a/src/tests/notnull.cpp b/src/tests/notnull.cpp deleted file mode 100644 index 282ef9e57..000000000 --- a/src/tests/notnull.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "testbase.hpp" -#include - -#include "../cxxutil.hpp" - -namespace { -class A { -public: - virtual bool foo() = 0; -}; -class B : public A { -public: - virtual bool foo() override final { return true; }; -}; -} // namespace - -TEST_CASE("NotNull is constructible from int*") { - int a = 0; - REQUIRE(srb2::NotNull(static_cast(&a))); -} - -TEST_CASE("NotNull is constructible from B* where B inherits from A") { - B b; - REQUIRE(srb2::NotNull(static_cast(&b))); -} - -TEST_CASE("NotNull dereferences to B& to call foo") { - B b; - srb2::NotNull a {static_cast(&b)}; - REQUIRE(a->foo()); -} diff --git a/src/tests/testbase.hpp b/src/tests/testbase.hpp deleted file mode 100644 index 39ce223a0..000000000 --- a/src/tests/testbase.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __SRB2_TESTS_TESTBASE_HPP__ -#define __SRB2_TESTS_TESTBASE_HPP__ - -#define SRB2_ASSERT_HANDLER srb2::NoOpAssertHandler - -#endif // __SRB2_TESTS_TESTBASE_HPP__