x86 上两个 128 位整数的高效乘法/除法(无 64 位)

2023-12-28

编译器:明威/海湾合作委员会
Issues:不允许使用 GPL/LGPL 代码(GMP 或任何 bignum 库对于这个问题来说都太过分了,因为我已经实现了该类)。

我已经构建了自己的128-bit固定大小的大整数类(旨在用于游戏引擎,但可以推广到任何使用情况),我发现当前乘法和除法运算的性能非常糟糕(是的,我已经对它们进行了计时,见下文) , 和我想改进(或更改)进行低级数字运算的算法。


当涉及乘法和除法运算符时,与类中的其他所有运算符相比,它们慢得难以忍受。

这些是相对于我自己的计算机的近似测量值:

Raw times as defined by QueryPerformanceFrequency:
1/60sec          31080833u
Addition:              ~8u
Subtraction:           ~8u
Multiplication:      ~546u
Division:           ~4760u (with maximum bit count)

正如您所看到的,仅进行乘法比加法或减法慢很多很多倍。除法比乘法慢大约 10 倍。

我想提高这两个运算符的速度,因为每帧可能需要进行大量计算(点积、各种碰撞检测方法等)。


结构(省略方法)看起来有点像:

class uint128_t
{
    public:
        unsigned long int dw3, dw2, dw1, dw0;
  //...
}

乘法目前使用典型的长乘法方法(在汇编中,以便我可以捕获EDX输出),同时忽略超出范围的单词(也就是说,我只做了 10mull与 16 相比)。

Division使用移位减法算法(速度取决于操作数的位数)。然而,它不是在装配中完成的。我发现这有点太难了,决定让编译器优化它。


我在谷歌上搜索了几天,查看描述算法的页面,例如唐叶乘法 http://en.wikipedia.org/wiki/Karatsuba_algorithm,高基数除法,以及牛顿-拉夫逊分部 http://en.wikipedia.org/wiki/Division_%28digital%29#Newton.E2.80.93Raphson_division但数学符号有点超出我的理解范围。我想使用其中一些高级方法来加速我的代码,但我必须首先将“希腊语”翻译成可以理解的内容。

对于那些可能认为我的努力“过早优化”的人;我认为这段代码是一个瓶颈,因为非常基本的数学运算本身变得很慢。我可以忽略对更高级别代码的此类优化,但该代码将被足够多的调用/使用以使其发挥作用。

我想要关于应该使用哪种算法来改进乘法和除法(如果可能)的建议,以及关于建议算法如何工作的基本(希望易于理解)解释highly赞赏。


编辑:乘以改进

我能够通过将代码内联到运算符 *= 中来改进乘法运算,并且它看起来尽可能快。

Updated raw times:
1/60sec          31080833u
Addition:              ~8u
Subtraction:           ~8u
Multiplication:      ~100u (lowest ~86u, highest around ~256u)
Division:           ~4760u (with maximum bit count)

这里有一些简单的代码供您检查(请注意,我的类型名称实际上不同,为了简单起见,对其进行了编辑):

//File: "int128_t.h"
class int128_t
{
    uint32_t dw3, dw2, dw1, dw0;

    // Various constrctors, operators, etc...

    int128_t& operator*=(const int128_t&  rhs) __attribute__((always_inline))
    {
        int128_t Urhs(rhs);
        uint32_t lhs_xor_mask = (int32_t(dw3) >> 31);
        uint32_t rhs_xor_mask = (int32_t(Urhs.dw3) >> 31);
        uint32_t result_xor_mask = (lhs_xor_mask ^ rhs_xor_mask);
        dw0 ^= lhs_xor_mask;
        dw1 ^= lhs_xor_mask;
        dw2 ^= lhs_xor_mask;
        dw3 ^= lhs_xor_mask;
        Urhs.dw0 ^= rhs_xor_mask;
        Urhs.dw1 ^= rhs_xor_mask;
        Urhs.dw2 ^= rhs_xor_mask;
        Urhs.dw3 ^= rhs_xor_mask;
        *this += (lhs_xor_mask & 1);
        Urhs += (rhs_xor_mask & 1);

        struct mul128_t
        {
            int128_t dqw1, dqw0;
            mul128_t(const int128_t& dqw1, const int128_t& dqw0): dqw1(dqw1), dqw0(dqw0){}
        };

        mul128_t data(Urhs,*this);
        asm volatile(
        "push      %%ebp                            \n\
        movl       %%eax,   %%ebp                   \n\
        movl       $0x00,   %%ebx                   \n\
        movl       $0x00,   %%ecx                   \n\
        movl       $0x00,   %%esi                   \n\
        movl       $0x00,   %%edi                   \n\
        movl   28(%%ebp),   %%eax #Calc: (dw0*dw0)  \n\
        mull             12(%%ebp)                  \n\
        addl       %%eax,   %%ebx                   \n\
        adcl       %%edx,   %%ecx                   \n\
        adcl       $0x00,   %%esi                   \n\
        adcl       $0x00,   %%edi                   \n\
        movl   24(%%ebp),   %%eax #Calc: (dw1*dw0)  \n\
        mull             12(%%ebp)                  \n\
        addl       %%eax,   %%ecx                   \n\
        adcl       %%edx,   %%esi                   \n\
        adcl       $0x00,   %%edi                   \n\
        movl   20(%%ebp),   %%eax #Calc: (dw2*dw0)  \n\
        mull             12(%%ebp)                  \n\
        addl       %%eax,   %%esi                   \n\
        adcl       %%edx,   %%edi                   \n\
        movl   16(%%ebp),   %%eax #Calc: (dw3*dw0)  \n\
        mull             12(%%ebp)                  \n\
        addl       %%eax,   %%edi                   \n\
        movl   28(%%ebp),   %%eax #Calc: (dw0*dw1)  \n\
        mull              8(%%ebp)                  \n\
        addl       %%eax,   %%ecx                   \n\
        adcl       %%edx,   %%esi                   \n\
        adcl       $0x00,   %%edi                   \n\
        movl   24(%%ebp),   %%eax #Calc: (dw1*dw1)  \n\
        mull              8(%%ebp)                  \n\
        addl       %%eax,   %%esi                   \n\
        adcl       %%edx,   %%edi                   \n\
        movl   20(%%ebp),   %%eax #Calc: (dw2*dw1)  \n\
        mull              8(%%ebp)                  \n\
        addl       %%eax,   %%edi                   \n\
        movl   28(%%ebp),   %%eax #Calc: (dw0*dw2)  \n\
        mull              4(%%ebp)                  \n\
        addl       %%eax,   %%esi                   \n\
        adcl       %%edx,   %%edi                   \n\
        movl   24(%%ebp),  %%eax #Calc: (dw1*dw2)   \n\
        mull              4(%%ebp)                  \n\
        addl       %%eax,   %%edi                   \n\
        movl   28(%%ebp),   %%eax #Calc: (dw0*dw3)  \n\
        mull               (%%ebp)                  \n\
        addl       %%eax,   %%edi                   \n\
        pop        %%ebp                            \n"
        :"=b"(this->dw0),"=c"(this->dw1),"=S"(this->dw2),"=D"(this->dw3)
        :"a"(&data):"%ebp");

        dw0 ^= result_xor_mask;
        dw1 ^= result_xor_mask;
        dw2 ^= result_xor_mask;
        dw3 ^= result_xor_mask;
        return (*this += (result_xor_mask & 1));
    }
};

至于除法,检查代码是毫无意义的,因为我需要更改数学算法才能看到任何实质性的好处。唯一可行的选择似乎是高基数除法,但我还没有解决(在我看来)how它会起作用的。


我不会太担心乘法。你正在做的事情看起来非常有效。我并没有真正遵循希腊语的唐叶乘法,但我的感觉是,只有比你正在处理的数字大得多时,它才会更有效。

我的一个建议是尝试使用最小的内联汇编块,而不是在汇编中编码逻辑。你可以写一个函数:

struct div_result { u_int x[2]; };
static inline void mul_add(int a, int b, struct div_result *res);

该函数将在内联汇编中实现,您将从 C++ 代码中调用它。它应该与纯汇编一样高效,并且更容易编码。

至于分工,我不知道。我看到的大多数算法都谈论渐近效率,这可能意味着它们仅对非常高的位数有效。

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

x86 上两个 128 位整数的高效乘法/除法(无 64 位) 的相关文章

  • 单元测试验证失败

    我正在运行我的单元测试PostMyModel路线 然而 在PostMyModel 我用的是线Validate
  • C++ 长 switch 语句还是用地图查找?

    在我的 C 应用程序中 我有一些值充当代表其他值的代码 为了翻译代码 我一直在争论使用 switch 语句还是 stl 映射 开关看起来像这样 int code int value switch code case 1 value 10 b
  • CSharpRepl emacs 集成?

    我碰巧知道莫诺CSharpRepl http www mono project com CsharpRepl 是否有 emacs csharp 模式使用它在一个窗口中运行 REPL 并像 python 模式一样在另一个窗口中编译 运行 C
  • 检测到堆栈崩溃

    我正在执行我的 a out 文件 执行后 程序运行一段时间 然后退出并显示消息 stack smashing detected a out terminated Backtrace lib tls i686 cmov libc so 6 f
  • Gwan C#,如何获取HTTP标头?

    我需要它来重写 url 以了解我正在处理哪个友好的 url 用于用户代理和其他东西 EDIT public class Gwan MethodImplAttribute MethodImplOptions InternalCall exte
  • 循环中的递归算法复杂度(运行时间)

    我想了解您对如何检测以下递归算法的 T n 运行时间 的意见 Charm 是一种用于发现事务数据库中频繁闭项集的算法 频繁闭项集列表是在一组交易 tids 中多次出现的频繁项 例如面包和牛奶是经常一起购买的物品 它们是通过将索引为 i 的当
  • 获取 boost Spirit 语法中的当前行

    我正在尝试使用 boostspirit 获取正在解析的文件的当前行 我创建了一个语法类和结构来解析我的命令 我还想跟踪在哪一行找到命令并将其解析到我的结构中 我将 istream 文件迭代器包装在 multi pass 迭代器中 然后将其包
  • 访问 ascx 文件中的母版页控件

    我有一个母版页文件 其中包含 2 个面板控件中的 2 个菜单 我还使用控件来检查用户是否登录并获取用户类型 根据我想要显示 隐藏面板的类型 控件本身不在母版页中引用 而是通过 CMS 系统动态引用 我想在用户控件中使用findcontrol
  • 使用查询表达式对 List 进行排序

    我在使用 Linq 订购这样的结构时遇到问题 public class Person public int ID get set public List
  • C#6 中的长字符串插值行

    我发现 虽然字符串插值在应用于现有代码库的字符串 Format 调用时非常好 但考虑到通常首选的列限制 字符串对于单行来说很快就会变得太长 特别是当被插值的表达式很复杂时 使用格式字符串 您将获得一个可以拆分为多行的变量列表 var str
  • 使用具有抗锯齿功能的 C# 更改抗锯齿图像的背景颜色

    我有一个图像需要更改背景颜色 例如 将下面示例图像的背景更改为蓝色 然而 图像是抗锯齿的 所以我不能简单地用不同的颜色替换背景颜色 我尝试过的一种方法是创建第二个图像 仅作为背景 并更改其颜色并将两个图像合并为一个图像 但是这不起作用 因为
  • 为什么 Cdecl 调用在“标准”P/Invoke 约定中经常不匹配?

    我正在开发一个相当大的代码库 其中 C 功能是从 C P Invoked 的 我们的代码库中有很多调用 例如 C extern C int stdcall InvokedFunction int 使用相应的 C DllImport CPlu
  • 如何使用 NPOI 按地址(A1、A2)获取 Excel 单元格值

    我有一个 Excel 单元格地址 例如 A1 A2 如何使用 C 中的 NPOI 框架以编程方式访问此单元格 我找到的一些 Java POI 示例代码 CellReference cr new CellReference A1 row my
  • 从BackgroundWorker线程更新图像UI属性

    在我正在编写的 WPF 应用程序中 我有一个 TransformedBitmap 属性 该属性绑定到 UI 上的 Image 对象 每当我更改此属性时 图像就会更新 因此显示在屏幕上的图像也会更新 为了防止在检索下一张图像时 UI 冻结或变
  • 从浏览器访问本地文件?

    您好 我想从浏览器访问系统的本地文件 由于涉及大量安全检查 是否可以通过某种方式实现这一目标 或使用 ActiveX 或 Java Applet 的任何其他工作环境 请帮帮我 要通过浏览器访问本地文件 您可以使用签名的 Java Apple
  • 逆向工程 ASP.NET Web 应用程序

    我有一个 ASP NET Web 应用程序 我没有源代码 该 bin 包含 10 个程序集和一个 compiled 文件 我在 App Code dll 上使用 Reflector 它向我显示了类和命名空间之类的东西 但它太混乱了 有没有什
  • 如何停止无限循环?

    我正在编写一个程序 该程序将计算三角形或正方形的面积 然后提示用户是否希望计算另一个 我的代码已经运行到可以计算任一形状的面积的程度 但随后不再继续执行代码的其余部分 例如 如果选择了正方形 则计算面积 然后返回到正方形边长的提示 我假设这
  • C++ 中 void(*)() 和 void(&)() 之间的区别[重复]

    这个问题在这里已经有答案了 在此示例代码中 func1是类型void int double and funky是类型void int double include
  • 对产品列表进行分类的算法? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个代表或多或少相同的产品的列表 例如 在下面的列表中 它们都是希捷硬盘 希捷硬盘 500Go 适用于笔记本电脑的希捷硬盘 120
  • 为什么匹配模板类上的部分类模板特化与没有模板匹配的另一个部分特化不明确?

    这个问题可能很难用标题中的句子来描述 但这里有一个最小的例子 include

随机推荐

  • 从服务器 Objective C 或 Swift 下载文件

    如何将音频文件从我的服务器下载到用户的手机以在应用程序中使用 当我访问网站链接时 JSON 代码如下所示 name Lets Party path http domain us audios Lets Party wav name Let
  • MongoEngine:关闭连接

    我花了很长时间试图找到一个简单的例子 其中使用了 MongoEngine 并且关闭了连接 终于弄清楚并发布我的代码 我知道这是一个老问题 但如果其他人正在搜索 我想我会给出一个替代答案 close 实际上并没有从 MongoEngine 的
  • 理解浮点变量

    有问题 无论如何我都无法理解 请看一下这段代码
  • Swift Playgrounds 中的链接页面 [Xcode]

    我是 Swift Playgrounds 的新手 在 Xcode 中制作 Swift Playground 时遇到了一些问题 这是我的 Playground 主页面 import UIKit import PlaygroundSupport
  • Python lambda函数根据字典对列表进行排序

    下面的示例代码检索所有正在运行的进程并打印它们 他们是按照第三个例子写的here http www programcreek com python example 53869 psutil process iter最后一张来自here ht
  • Visual Studio 2017 中适用于 JavaScript 和 TypeScript 文件的 Visual Studio Code 颜色主题

    正如主题所示 我想在 Visual Studio 2017 中为 JavaScript 和 TypeScript 文件导入 设置 Visual Studio Code 颜色主题 因此 我想为其设置颜色主题的文件是 js jsx ts and
  • jQuery Colorbox,iframe 内容在 iPad 中不滚动

    在 iPad 上查看时 Colorbox iframe 内容不会滚动 请阅读以下内容 https github com jackmoore colorbox issues 41 issuecomment 5244379 https gith
  • 为什么当 GMSMarker 与 GMSOverlay 重叠时我需要点击两次 GMSMarker 才能显示其信息窗口?

    我有一个GMS覆盖在 GMSMapView 中 所以我用以下方法监听对它的点击 func mapView mapView GMSMapView didTap overlay GMSOverlay Overlay was tapped 然后我
  • WAMP 上的 Mysqli,错误 - 连接尝试失败

    添加信息 我尝试了全新安装的 codeigniter 只需添加 this gt load gt database 默认控制器会触发相同的错误 我检查了 phpinfo 并且 mysqli 已安装 我用下面的代码检查了它并且它正在工作 当我打
  • 复制文件,保留权限和所有者

    Shutil 的文档告诉我 即使是更高级别的文件复制函数 shutil copy shutil copy2 也无法复制所有文件元数据 在 POSIX 平台上 这意味着文件所有者和组以及 ACL 都会丢失 如果我需要在python中复制文件
  • 检查视图是否自午夜以来已加载

    我有一个 ViewController 它对数组执行随机洗牌并将文本吐出到标签 在viewDidLoad方法 问题是 每当我导航到同一个 ViewController 时 它都会再次执行随机播放 而我每天只需要它随机播放一次 因此 我需要检
  • 从 iOS 应用内购买收据中检索订单 ID/文档编号

    目前 我们的系统的工作方式是 当用户购买应用内订阅时 购买的收据数据会发送到服务器 验证后我们将相应地更改用户的权利 有时 由于各种原因 我们可能会遇到这样的问题 用户可能没有获得应有的权利 在这种情况下 他们会通过电子邮件向我们发送从 A
  • 在 GSON 中使用泛型

    我正在使用 GSON 将 JSON 解码为 T 类型的对象 例如 public T decode String json Gson gson new Gson return gson fromJson json new TypeToken
  • 禁用 XAML 预览

    在 Visual Studio 2008 中 当我从项目中打开 XAML 文件时 它会显示水平分割 预览位于顶部 XAML 位于底部 大多数时候 我们的 XAML 不会在预览中呈现 因此我只需等待它尝试呈现 然后关闭预览 有没有办法让它默认
  • 如何安装我自己的扩展? VS代码

    我使用 Yeoman Generator 制作了自己的扩展包 但我不知道如何将其安装在我的 vscode 上 也许如果我将扩展包导出到市场 这是可能的 但我不想这样做 You can 将扩展打包到 vsix 文件中 https code v
  • bash——在运行之间存储变量的更好方法?

    我制作了一个 bash 脚本 我使用 crontab 每小时运行一次 并且我需要存储一个变量 以便下次运行它时可以访问它 该脚本每次运行时都会更改变量 因此我无法对其进行硬编码 现在我将其写入 txt 文件 然后读回 还有比这更好的方法吗
  • 在数据库的未知表中查找特定列?

    我试图在包含 125 个表的数据库中找到未知的特定列 我正在寻找一个通配符 例如 watcher 这可能吗 SELECT TABLE NAME COLUMN NAME DATA TYPE IS NULLABLE COLUMN DEFAULT
  • Java/HTML 编码问题(破折号变成 -)

    情况 我正在尝试修复一些使用 Java 后端通过 Velocity Mail Manager 发送自动电子邮件的代码 问题 主题在Java代码中设置如下String subject Hello what s next 然后将其设置为消息对象
  • 重复将数据从 Windows 服务传输到控制台应用程序

    这是我的场景 我有一个 Windows 服务 每 20 分钟运行一次任务 任务是 从远程网站托管的 API 请求更新 响应是 JSON 对象列表 当服务收到该列表时 它会执行一组操作 然后附加更多 JSON 对象 最后服务必须将该列表推送到
  • x86 上两个 128 位整数的高效乘法/除法(无 64 位)

    编译器 明威 海湾合作委员会 Issues 不允许使用 GPL LGPL 代码 GMP 或任何 bignum 库对于这个问题来说都太过分了 因为我已经实现了该类 我已经构建了自己的128 bit固定大小的大整数类 旨在用于游戏引擎 但可以推