有效地乘以 7

2024-03-24

我最近遇到了以下面试问题:

如何以高效且优化的方式将数字乘以 7?

我知道我可以乘以 8(或左移三位),然后减去原始值:

num = (num << 3) - num;

但还有其他解决方案吗?


对于有限范围,您可以使用查找表:

static unsigned int mult7[] = {0, 7, 14, 21, ...};
unsigned int three = 3;
unsigned int twenty_one = mult7[three];

这可能sound愚蠢(这可能是针对这个特定情况的),但对于有的事情来说它通常很方便real成本来计算。我只是不确定乘以七是否算作其中一种情况。

首先,乘以x7(或移位x剩下三位然后减去x)是完全可以在CPU内部完成的操作。通过表查找,您可能会看到乘以四(左移两位),然后进行加法以获得正确的地址,但随后您必须访问内存才能进行实际查找 - 即使使用缓存和所有其他方法当前 CPU 具有的奇妙技巧,这可能会减慢速度。

There's also a good chance that your compiler will already know all the tricks about how to multiply fast. If your seven is a constant (or const int or equivalent), the compiler will probably already have chosen the fastest way and there's a good chance the compiler writers know a lot more about this sort of stuff than mere mortals :-) (a)

但对于计算成本的情况is相对较高,计算一次值并将它们作为查找表嵌入到代码中是标准优化策略之一(以时间换取空间)。


(a) Examine the following code:

#include <stdio.h>

static int mult7 (int num) {
    return num * 7;
}

int main (int argc, char *argv[]) {
    printf ("%d\n", mult7 (atoi (argv[1])));
    return 0;
}

通过正常编译gcc, mult7左移三位并减去技巧:

_mult7:
    pushl   %ebp             ; stack frame setup.
    movl    %esp, %ebp
    movl    8(%ebp), %edx    ; get value to edx
    movl    %edx, %eax       ;    and eax.
    sall    $3, %eax         ; eax <- eax * 8.
    subl    %edx, %eax       ; eax <- eax - edx.
    popl    %ebp             ; stack frame teardown and return.
    ret

At -O3(我喜欢称之为疯狂的优化级别),整个事情都内联到main with:

call    _atoi
movl    $LC0, (%esp)

leal    0(,%eax,8), %edx     ; these two are the relevant instructions.
subl    %eax, %edx

movl    %edx, 4(%esp)
call    _printf

请注意,此内联操作仅由于函数的静态性质而可能 - 如果它对链接器可见,则必须将其维护为单独的函数,以防另一个对象文件需要调用它。

如果您脱下static,它确实使其与所有堆栈帧设置和拆卸保持非内联,但它至少仍然使用下面提到的(大概)更有效的技巧。你can摆脱堆栈帧代码gcc如果你使用-fomit-frame-pointer前提是这不会对代码产生不利影响,但这已经开始深入研究黑暗面了:-)

这个技巧是使用LEA设置指令edx to eax * 8然后减去eax从那。与理论相同sall/subl在正常优化时,只是机制略有不同。

底线,相信你的编译器。如果你想乘法num到 7 时,使用以下命令:

num *= 7;

很可能,无论您从这种尝试的微观优化中获得什么改进,您都可以通过查看宏观层面(算法和数据结构选择等)获得更好的改进。

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

有效地乘以 7 的相关文章

  • Asp.net core默认路由

    简化版Startup code public void ConfigureServices IServiceCollection services services AddMvc public void Configure IApplica
  • 在 Mac OS X 上安装 libxml2 时出现问题

    我正在尝试在我的 Mac 操作系统 10 6 4 上安装 libxml2 我实际上正在尝试在 Python 中运行 Scrapy 脚本 这需要我安装 Twisted Zope 现在还需要安装 libxml2 我已经下载了最新版本 2 7 7
  • 以下 PLINQ 代码没有改进

    我没有看到使用以下代码的处理速度有任何改进 IEnumerable
  • 从时间列表中查找最接近的时间

    所以 这是场景 我有一个带有创建时间的文件 我想从该文件的创建时间最接近或相等的时间列表中选择一个时间 完成此操作的最佳方法是什么 var closestTime listOfTimes OrderBy t gt Math Abs t fi
  • 如何调试在发布版本中优化的变量

    我用的是VS2010 我的调试版本工作正常 但我的发布版本不断崩溃 因此 在发布版本模式下 我右键单击该项目 选择 调试 然后选择 启动新实例 此时我看到我声明的一个数组 int ma 4 1 2 8 4 永远不会被初始化 关于可能发生的事
  • 虚拟并行端口模拟器

    在我的计算机网络课程中 我们应该通过使用本机寄存器 例如使用 outportb 等命令 来学习并行端口编程 我没有并行端口 因为我住在 2011 年 但想练习这些程序 我使用 dosbox 安装了旧的 Turboc 3 IDE 有没有一个程
  • Nhibernate:连接表并从其他表获取单列

    我有以下表格 create table Users Id uniqueidentifier primary key InfoId uniqueidentifier not null unique Password nvarchar 255
  • 关闭整数的最右边设置位

    我只需要关闭最右边的设置位即可 我的方法是找到最右边位的位置 然后离开该位 我编写这段代码是为了这样做 int POS int n int p 0 while n if n 2 0 p else break n n 2 return p i
  • 名称查找、实例化点 (POI) 和基本类型

    以下代码针对 X 进行编译 但不适用于 double struct X void foo double void foo X namespace NN struct A void foo A foo double error foo not
  • 检测 TextBox 中的 Tab 键按下

    I am trying to detect the Tab key press in a TextBox I know that the Tab key does not trigger the KeyDown KeyUp or the K
  • 无法获取本地或参数的值,因为它在此指令指针处不可用,可能是因为它已被优化掉

    Visual Studio 2010 会删除 没有其他词 不安全块中函数参数之一中的数据 什么可能导致此错误 调试器显示以下消息 Cannot obtain value of local or argument as it is not a
  • 如何在新窗口中打开图像或pdf文件?

    我有一个 gridview 它包含文件名和文件路径 图像和 pdf 格式文件 其中我使用了模板字段 在该字段下放置了 1 个图像按钮 单击该图像按钮 即 查看 按钮 时 我想在新窗口中打开所选文件 这是我的代码 protected void
  • 如何使用 C# 查询远程 MS ACCESS .mdb 数据库

    我正在尝试使用 C 查询 mote MS ACCESS 数据库 mdb 文件 将文件复制到本地计算机时可以成功查询它 我只想远程放置文件 所以我的客户端程序不包含原始数据 static string m path http www xyz
  • MSChart 控件中的自定义 X/Y 网格线

    我有一个带有简单 2D 折线图的 C Windows 窗体 我想向其中添加自定义 X 或 Y 轴标记 并绘制自定义网格线 例如 以突出显示的颜色 虚线 我查看了 customLabels 属性 但这似乎覆盖了我仍然想显示的默认网格 这是为了
  • 在 C++ 代码 gdb 中回溯指针

    我在运行 C 应用程序时遇到段错误 在 gdb 中 它显示我的一个指针位置已损坏 但我在应用程序期间创建了 10 万个这样的对象指针 我怎样才能看到导致崩溃的一个 我可以在 bt 命令中执行任何操作来查看该指针的生命周期吗 谢谢 鲁奇 据我
  • 用数组或向量实现多维数组

    我想使用单个数组或向量实现多维数组 可以像通常的多维数组一样访问它 例如 a 1 2 3 我陷入困境的是如何实施 操作员 如果数组的维数为 1 则 a 1 应该返回位于索引 1 处的元素 但是如果维数大于一怎么办 对于嵌套向量 例如 3 维
  • 解释这段代码的工作原理;子进程如何返回值以及在哪里返回值?

    我不明白子进程如何返回该值以及返回给谁 输出为 6 7 问题来源 http www cs utexas edu mwalfish classes s11 cs372h hw sol1 html http www cs utexas edu
  • 值和类型的简洁双向静态 1:1 映射

    我将从我想象如何使用我想要创建的代码开始 它不必完全像这样 但它是我在标题中所说的 简洁 的一个很好的例子 就我而言 它是将类型映射到相关的枚举值 struct bar foo
  • 对多个对象使用事件处理程序

    我有 20 件物品List
  • 在 C 中使用 #define 没有任何价值

    If a define没有任何价值地使用 例如 define COMMAND SPI 默认值是0吗 不 它的评估结果为零 从字面上看 该符号被替换为空 然而 一旦你有了 define FOO 预处理器条件 ifdef FOO现在将是真的 另

随机推荐