News:

Herr Otto Partz says you're all nothing but pipsqueaks!

Main Menu

Restunts repository - Git mirror

Started by dreadnaut, March 19, 2021, 12:00:36 AM

Previous topic - Next topic

llm

#150
cleanuped version of the math.h usage with some tests

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "stunts_math.hpp"

namespace math_h_test
{
#define SCALE_BITS 14
#define SCALE (1 << SCALE_BITS)

// 0x400 steps = 2Pi
#define ANGLE_TO_RAD(a) ((a) * (M_PI / 512.0))
#define RAD_TO_ANGLE(r) ((r) * (512.0 / M_PI))

#define TO_FIXED(x)   ((int16_t)lround((x) * SCALE))
#define FROM_FIXED(x) ((double)(x) / SCALE)

    int16_t int_sin_math(uint16_t angle)
    {
        return TO_FIXED(sin(ANGLE_TO_RAD(angle)));
    }

    int16_t int_cos_math(uint16_t angle)
    {
        return TO_FIXED(cos(ANGLE_TO_RAD(angle)));
    }

    int16_t int_atan2_math(int16_t x, int16_t y)
    {
        double ang = atan2((double)x, (double)y);
        return (int16_t)lround(RAD_TO_ANGLE(ang));
    }

    int16_t int_hypot_math(int16_t x, int16_t y)
    {
        return TO_FIXED(hypot(FROM_FIXED(x), FROM_FIXED(y)));
    }

    int16_t int_hypot_3d_math(const VECTOR* v)
    {
        double dx = FROM_FIXED(v->x);
        double dy = FROM_FIXED(v->y);
        double dz = FROM_FIXED(v->z);
        return TO_FIXED(sqrt(dx * dx + dy * dy + dz * dz));
    }

    void test_sin_cos(void)
    {
        printf("=== SIN/COS compare ===\n");
        int max_diff_sin = 0, max_diff_cos = 0;

        for (int a = -0x400; a <= 0x400; ++a) {
            int16_t ref_sin = int_sin((uint16_t)a);
            int16_t ref_cos = int_cos((uint16_t)a);
            int16_t new_sin = int_sin_math((uint16_t)a);
            int16_t new_cos = int_cos_math((uint16_t)a);

            int diff_sin = abs(ref_sin - new_sin);
            assert(diff_sin == 0);

            int diff_cos = abs(ref_cos - new_cos);
            assert(diff_cos == 0);
        }
    }

    void test_atan2(void)
    {
        printf("=== ATAN2 Compare ===\n");
        int max_diff = 0;

        for (int y = -0x400; y <= 0x400; y += 64) {
            for (int x = -0x400; x <= 0x400; x += 64) {
                int16_t ref = int_atan2(x, y);
                int16_t newv = int_atan2_math(x, y);
                int diff = abs(ref - newv);

                assert(diff <= 1);
            }
        }
    }

    void test_hypot(void)
    {
        printf("=== HYPOT Compare ===\n");
        int max_diff = 0;

        for (int y = -0x400; y <= 0x400; y += 64) {
            for (int x = -0x400; x <= 0x400; x += 64) {
                int16_t ref = int_hypot(x, y);
                int16_t newv = int_hypot_math(x, y);
                int diff = abs(ref - newv);

                assert(diff <= 3);

                if (diff > 1)
                    printf("hypot(%4d,%4d): ref=%5d new=%5d diff=%3d\n",
                        x, y, ref, newv, diff);
            }
        }
    }

    void test_hypot3d(void)
    {
        printf("=== HYPOT_3D Compare ===\n");
        int max_diff = 0;
        VECTOR v;

        for (int z = -0x200; z <= 0x200; z += 64)
            for (int y = -0x200; y <= 0x200; y += 64)
                for (int x = -0x200; x <= 0x200; x += 64) {
                    v.x = x; v.y = y; v.z = z;
                    int16_t ref = int_hypot_3d(&v);
                    int16_t newv = int_hypot_3d_math(&v);
                    int diff = abs(ref - newv);

                    assert(diff <= 4);

                    if (diff > 1)
                        printf("hypot3d(%4d,%4d,%4d): ref=%5d new=%5d diff=%3d\n",
                            x, y, z, ref, newv, diff);
                }
    }

    int main(void)
    {
        test_sin_cos();
        test_atan2();
        test_hypot();
        test_hypot3d();
        return 0;
    }
}

llm

and wouldn't be a if-less vec_transform not faster?

or is failed branch prediction not a problem with older CPUs and multiply is much slower

    void vec_transform(const VECTOR* src, const MATRIX* mat, VECTOR* dst)
    {
        dst->x = ((int32_t)mat->m11 * src->x + (int32_t)mat->m12 * src->y + (int32_t)mat->m13 * src->z) >> SCALE_BITS;
        dst->y = ((int32_t)mat->m21 * src->x + (int32_t)mat->m22 * src->y + (int32_t)mat->m23 * src->z) >> SCALE_BITS;
        dst->z = ((int32_t)mat->m31 * src->x + (int32_t)mat->m32 * src->y + (int32_t)mat->m33 * src->z) >> SCALE_BITS;
    }

Cas

Hey!  As you guys know, I'm travelling. Soon will be back. Just wanted to clarify about my opinions on SDL. I do think SDL is a very good tool and I don't mean to say at all that programming for SDL is in any way easier than programming on a library that's built into the compiler. I just find that SDL is in itself like a language and programming for it in C is a very different experience from just making a C program (or C++). On the other hand, what I try to achieve with my programs is some portability (through time, more than from platform to platform, but both are good). I have not been very successful on that in GNU/Linux and I keep trying to improve that. SDL does not solve this. It solves other things. Still, I've been interesting in trying it many times, but well, I'd like to solve my portability problem first of all. So far, the only solution appears to be to program for DOS :P
Earth is my country. Science is my religion.