实现基于查表的三角函数

2024-03-03

对于我在业余时间实现的视频游戏,我尝试使用查找表实现我自己的 sinf()、cosf() 和 atan2f() 版本。目的是使实现速度更快,但准确性较低。

我的初步实现如下。这些函数可以工作,并返回良好的近似值。唯一的问题是他们是slower而不是调用标准 sinf()、cosf() 和 atan2f() 函数。

那么,我做错了什么?

// Geometry.h includes definitions of PI, TWO_PI, etc., as
// well as the prototypes for the public functions
#include "Geometry.h"

namespace {
    // Number of entries in the sin/cos lookup table
    const int SinTableCount = 512;

    // Angle covered by each table entry
    const float SinTableDelta = TWO_PI / (float)SinTableCount;

    // Lookup table for Sin() results
    float SinTable[SinTableCount];

    // This object initializes the contents of the SinTable array exactly once
    class SinTableInitializer {
    public:
        SinTableInitializer() {
            for (int i = 0; i < SinTableCount; ++i) {
                SinTable[i] = sinf((float)i * SinTableDelta);
            }
        }
    };
    static SinTableInitializer sinTableInitializer;

    // Number of entries in the atan lookup table
    const int AtanTableCount = 512;

    // Interval covered by each Atan table entry
    const float AtanTableDelta = 1.0f / (float)AtanTableCount;

    // Lookup table for Atan() results
    float AtanTable[AtanTableCount];

    // This object initializes the contents of the AtanTable array exactly once
    class AtanTableInitializer {
    public:
        AtanTableInitializer() {
            for (int i = 0; i < AtanTableCount; ++i) {
                AtanTable[i] = atanf((float)i * AtanTableDelta);
            }
        }
    };
    static AtanTableInitializer atanTableInitializer;

    // Lookup result in table.
    // Preconditions: y > 0, x > 0, y < x
    static float AtanLookup2(float y, float x) {
        assert(y > 0.0f);
        assert(x > 0.0f);
        assert(y < x);

        const float ratio = y / x;
        const int index = (int)(ratio / AtanTableDelta);
        return AtanTable[index];    
    }

}

float Sin(float angle) {
    // If angle is negative, reflect around X-axis and negate result
    bool mustNegateResult = false;
    if (angle < 0.0f) {
        mustNegateResult = true;
        angle = -angle;
    }

    // Normalize angle so that it is in the interval (0.0, PI)
    while (angle >= TWO_PI) {
        angle -= TWO_PI;
    }

    const int index = (int)(angle / SinTableDelta);
    const float result = SinTable[index];

    return mustNegateResult? (-result) : result;
}

float Cos(float angle) {
    return Sin(angle + PI_2);
}

float Atan2(float y, float x) {
    // Handle x == 0 or x == -0
    // (See atan2(3) for specification of sign-bit handling.)
    if (x == 0.0f) {
        if (y > 0.0f) {
            return PI_2;
        }
        else if (y < 0.0f) {
            return -PI_2;
        }
        else if (signbit(x)) {
            return signbit(y)? -PI : PI;
        }
        else {
            return signbit(y)? -0.0f : 0.0f;
        }
    }

    // Handle y == 0, x != 0
    if (y == 0.0f) {
        return (x > 0.0f)? 0.0f : PI;
    }

    // Handle y == x
    if (y == x) {
        return (x > 0.0f)? PI_4 : -(3.0f * PI_4);
    }

    // Handle y == -x
    if (y == -x) {
        return (x > 0.0f)? -PI_4 : (3.0f * PI_4);
    }

    // For other cases, determine quadrant and do appropriate lookup and calculation
    bool right = (x > 0.0f);
    bool top = (y > 0.0f);
    if (right && top) {
        // First quadrant
        if (y < x) {
            return AtanLookup2(y, x);
        }
        else {
            return PI_2 - AtanLookup2(x, y);
        }
    }
    else if (!right && top) {
        // Second quadrant
        const float posx = fabsf(x);
        if (y < posx) {
            return PI - AtanLookup2(y, posx);
        }
        else {
            return PI_2 + AtanLookup2(posx, y);
        }
    }
    else if (!right && !top) {
        // Third quadrant
        const float posx = fabsf(x);
        const float posy = fabsf(y);
        if (posy < posx) {
            return -PI + AtanLookup2(posy, posx);
        }
        else {
            return -PI_2 - AtanLookup2(posx, posy);
        }
    }
    else { // right && !top
        // Fourth quadrant
        const float posy = fabsf(y);
        if (posy < x) {
            return -AtanLookup2(posy, x);
        }
        else {
            return -PI_2 + AtanLookup2(x, posy);
        }
    }

    return 0.0f;
}

“过早的优化是万恶之源”——Donald Knuth

如今,编译器为三角函数提供了非常高效的内在函数,可以充分利用现代处理器(SSE 等),这解释了为什么你很难击败内置函数。不要在这些部分上浪费太多时间,而是专注于可以使用分析器发现的真正瓶颈。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实现基于查表的三角函数 的相关文章

  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 为什么 C# Array.BinarySearch 这么快?

    我已经实施了一个很简单用于在整数数组中查找整数的 C 中的 binarySearch 实现 二分查找 static int binarySearch int arr int i int low 0 high arr Length 1 mid
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 类模板参数推导 - clang 和 gcc 不同

    下面的代码使用 gcc 编译 但不使用 clang 编译 https godbolt org z ttqGuL template
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • 如何在 C 中调用采用匿名结构的函数?

    如何在 C 中调用采用匿名结构的函数 比如这个函数 void func struct int x p printf i n p x 当提供原型的函数声明在范围内时 调用该函数的参数必须具有与原型中声明的类型兼容的类型 其中 兼容 具有标准定
  • 这些作业之间是否存在顺序点?

    以下代码中的两个赋值之间是否存在序列点 f f x 1 1 x 2 不 没有 在这种情况下 标准确实是含糊不清的 如果你想确认这一点 gcc 有这个非常酷的选项 Wsequence point在这种情况下 它会警告您该操作可能未定义
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定

随机推荐

  • 不在异步方法中等待任务的注意事项

    我正在开发一个 Web API 项目 该项目使用 Azure 的托管缓存服务将数据库结果缓存在内存中 以缩短响应时间并减少数据库的重复流量 当尝试将新项目放入缓存时 有时会抛出特定于缓存的异常 代码为DataCacheErrorCode R
  • 如何使用 Paramiko 运行 sudo? (Python)

    我尝试过的 invoke shell then channel send su然后发送密码导致不是root invoke shell 进而channel exec command导致 通道已关闭 错误 transport open sess
  • python * 运算符的正确名称?

    操作员的正确名称是什么 as in function args 解压 解压 还有别的吗 在 Ruby 和 Perl 6 中 这被称为 splat 我认为大多数人 如果你这么称呼的话 那些社区会明白你的意思 The Python教程 docs
  • SQL Server 2000 - 调试死锁

    我正在寻找有关如何调试和解决 SQL Server 2000 数据库中的死锁问题的建议 有人建议我使用跟踪标志 1024 和 3605 我发现它们可以提供以下信息 1024 此跟踪标志返回参与死锁的锁的类型以及受影响的当前命令 3605 此
  • 如何让背景图像跨越网格布局

    我有一个网格布局 假设第一行有 2 行 2 列 第二行有 3 列 它们之间的网格间隙为 10px 给每个网格一个背景图像是没有问题的 但是 如果我希望它们都具有相同的背景图像 该背景图像从左上角网格开始并继续 跨越直到右下角网格 所有网格上
  • 递归Kaatsuba 乘法不起作用?

    我正在尝试实施唐叶乘法 https en wikipedia org wiki Karatsuba algorithm通过递归调用 下面的代码应该可以工作 但我一直得到错误的答案 有什么想法吗 public static long kara
  • Java RandomString类[重复]

    这个问题在这里已经有答案了 可能的重复 HangMan RandomString 类 https stackoverflow com questions 13818297 hangman randomstring class 以下是方向 创
  • 将 UITableView 添加到现有 ViewController

    我正在尝试添加一个UITableView到现有的UIViewController以编程方式 My run h文件有这个 interface runTests UIViewController
  • 将 process.env.NODE_ENV 与 String 进行比较

    为什么当我比较这两个时我得到false const production process env NODE ENV production 即使当我设置process env NODE ENV到生产我仍然得到false value Why E
  • 获取python项目使用的所有模块/包

    我有一个 python GUI 应用程序 现在我需要知道应用程序链接到的所有库 这样我就可以检查所有库的许可证兼容性 我尝试过使用 strace 但 strace 似乎会报告所有包 即使应用程序未使用它们 而且 我尝试了 python Mo
  • 如何更改 mysql 表列默认值?

    我有一个带有 type 列的表timestamp默认值current timestamp并更新至current timestamp每次更新时 我想删除此列上的 更新时 功能 怎样写alter语句呢 我尝试了以下方法 ALTER TABLE
  • 模块在角度模块中没有导出成员错误

    我想创建一个功能模块来处理上传的前端 上传组件 html没有错误
  • 从 Eclipse 插件使用 Jython

    当从 Eclipse 插件运行时 我很难让 jython 正常工作 我有一个简单的对象工厂 它加载符合 Java 接口的 python 模块 所有这些在独立模式下都可以正常工作 然而 当我将其打包为 Eclipse 插件时 我根据一些变量收
  • gnu sort - 默认缓冲区大小

    我已阅读全文文档 http www gnu org software coreutils manual html node sort invocation html sort invocation对于 gnu sort 并在线搜索 但我找不
  • JS 将 blob url 转换为 Base64 文件

    有如下代码 console log blob var reader new window FileReader reader onloadend function console log reader result reader readA
  • 如何在 Flutter 中点击其他小部件时打开 DropdownButton?

    我需要有一个DropdownButton当点击其他一些小部件时 选项列表会以编程方式打开 显示 我知道这可能不是 UI 最佳实践 但我需要这种行为 举个例子 在像下面这样的结构中 我可能需要用胶带固定Text every 来打开邻近的Dro
  • 在 php 下拉列表中设置默认选项并在提交查询时保留

    我有下面的代码 它从 php ini 创建下拉菜单 我想在这里实现两件事 1 我想将其中一个选项设置为默认 它可以是硬编码的或从查询中选择的 2 当按下按钮时 应保留所选选项 我可以使用会话数据检索所选选项 echo print versi
  • PostgreSQL 10 => 11.1 关于 Brew 更新问题

    试图找到一条迁移路线PostgreSQL 10 6 to postgreSQL 11 1 Using pg upgrade 从两个版本 给我错误 从11 1我认为这将用于将过时的表格转换为货币 usr local Cellar postgr
  • 检查 ipython 中最后一个命令的退出状态

    有谁知道如何在 ipython 中检查最后执行的命令 退出代码 的状态 它应该存储为 exit code运行命令后 至少在即将发布的 v0 11 版本中
  • 实现基于查表的三角函数

    对于我在业余时间实现的视频游戏 我尝试使用查找表实现我自己的 sinf cosf 和 atan2f 版本 目的是使实现速度更快 但准确性较低 我的初步实现如下 这些函数可以工作 并返回良好的近似值 唯一的问题是他们是slower而不是调用标