整数除法和浮点除法C语言,关于c ++:整数除法还是浮点乘法?

博客探讨了在编程中使用整数除法与浮点数乘法的性能差异,指出整数运算通常比浮点运算更快,尤其是在涉及移位和简单除法的情况下。文章强调了编译器优化、硬件特性和上下文对性能的影响,并建议在实际环境中进行基准测试以确定最佳实践。同时,提到了转换成本、溢出行为和精度问题在选择运算方式时的重要性。
摘要由CSDN通过智能技术生成

如果必须计算给定int值的一小部分,请说:

int j = 78;

int i = 5* j / 4;

这比做的更快:

int i = 1.25*j; // ?

如果是,是否存在可用于决定使用哪个转换因子的转换因子,因为在一次float乘法的同时可以完成多少int个除法?

编辑:我认为评论清楚表明浮点数学会慢一点,但问题是,多少? 如果我需要用$ N $ int除法替换每个float乘法,那么$ N $将不再值得吗?

你有基准吗?

这些数字中有多少是动态的?

@KerrekSB指的是编译器为您优化所有这些。因此,为什么基准测试很重要。

@KerrekSB - 所有数字都是动态的。这个例子只是一个例子,实际上这些都是动态的。

我会说如果你有三个整数a,b和c,你想要计算a * b / c,那么你应该写int compute(int a, int b, int c) { return a * b / c; }。我怀疑你能做得更好。

这似乎是过早优化,还要注意1.25文字实际上是double,而不是float。

您展示的两种替代方案可能产生不同的结果。首先根据所需结果进行选择,然后根据性能进行选择。

是否正确舍入结果值可能的问题?

我也看不到你希望实现的目标。如果所有三个输入都是动态的,那么你最多可以将浮点乘数计算为static_cast(a) / static_cast(c),那么你需要将b转换为浮点,乘以,然后使用C ++舍入,强制舍入,全部和任何一个这不可能比两个整数运算更快。

你也可以进行整数移位和加法而不是乘法(取决于你的硬件有什么)。使用C和编译器有转换开销等,你不会保持固定点。但答案是不确定的,你只需要测试它......

你确定你的程序的性能瓶颈是这个操作吗? (我敢打赌它不是。)测量它,然后优化瓶颈。

@pts - 当这是唯一的操作,并且你重复它10 ^ 7次,这是一个瓶颈。

你的前提实际上有些缺陷。如果您能够在5/4和1.25之间切换,则不可能使所有数字都是动态的。如果分子和分母不是编译时常数,你怎么知道乘以1.25? (没有实际进行你试图避免的分裂)

基本算术性能无关紧要我不知道为什么你关心优化这个。你打算在烤面包机里运行这个代码吗?

只是为了清除事物,在单个操作中在CPU级别执行乘法,并且除法是最昂贵的CPU基本操作之一。是否使用多个操作而不是仅包含一个除法,即使您只使用整数,它也会更快?我真诚地怀疑它。

你已经说过所有的价值都是动态的,这会产生不同。对于特定值5 * j / 4,整数运算将会非常快,因为最糟糕的情况是编译器将它们优化为两个班次和一个加法,加上一些搞乱来应对j的可能性是否定的。如果CPU可以做得更好(单周期整数乘法或其他),那么编译器通常会知道它。当您编译一大类CPU(例如,生成最低公分母ARM代码)时,编译器优化此类事物的能力的限制基本上就会出现,编译器对此并不太了解硬件,因此不能总是做出好的选择。

我想如果a和b固定一段时间(但在编译时不知道),则可能是计算k = double(a) / b一次然后int(k * x)对于许多不同的x值,可能是对于x的许多不同值,比计算a * x / b更快。我不会指望它。

如果所有值每次都变化,那么计算1.25的浮点除法,接着是浮点乘法,似乎不会比整数乘法后跟整数除法更快。但你永远不知道,测试它。

在现代处理器上为此提供简单的相对时序是不可能的,它实际上很大程度上取决于周围的代码。代码中的主要成本通常不是"实际"操作:它是"不可见"的东西,比如指令管道停止依赖,或者将寄存器溢出到堆栈或函数调用开销。是否可以内联执行此功能的功能可能比功能实际执行的功能更容易产生差异。就性能的确定性陈述而言,您基本上可以测试实际代码或关闭。但是,如果你的值以整数开始,那么对它们进行整数运算将比转换为double并执行类似数量的double运算更快。

不可能脱离背景地回答这个问题。另外,5*j/4通常不会产生与(int) (1.25*j)相同的结果,这是由于整数和浮点算法的属性,包括舍入和溢出。

如果你的程序主要执行整数运算,那么j到浮点的转换,乘以1.25,并且转换回整数可能是免费的,因为它使用了没有其他参与的浮点单元。

或者,在某些处理器上,操作系统可能会将浮点状态标记为无效,因此第一次进程使用它时,有一个例外,操作系统会保存浮点寄存器(包含来自另一个的值)进程),恢复或初始化进程的寄存器,并从异常中返回。相对于正常的指令执行,这将花费大量时间。

答案还取决于程序正在执行的特定处理器模型的特性,以及操作系统,编译器如何将源转换为汇编,甚至可能取决于系统上的其他进程正在执行的操作。

此外,5*j/4和(int) (1.25*j)之间的性能差异通常太小而不能在程序中引人注意,除非它或类似的操作重复很多次。 (并且,如果它们是,那么对代码进行矢量化可能会带来巨大的好处,也就是说,使用许多现代处理器的单指令多数据[SIMD]功能可以同时执行多个操作。)

对于您的情况,5*j/4将比1.25*j快得多,因为通过右移可以轻松地除以2的幂,并且5*j可以通过某些体系结构(例如LEA)上的单个指令来完成。支持ARM的x86或ADD。大多数其他指令最多需要2条指令,如j + j >> 2,但这些指令可能仍然比浮点乘法更快。此外,通过执行int i = 1.25*j,您需要在double和int之间进行2次转换,以及2次跨域移动,这可能非常昂贵(这就是为什么有不同的SSE或AVX指令执行完全相同的操作,只是在不同的域)。使用int multiply / divide也允许编译器通过常数优化除法

对于其他情况,当分数不能用浮点表示时(比如3*j/10)那么使用int multiply / divide会更正确(因为0.3在二进制浮点中不完全是0.3),并且最可能更快(因为编译器可以通过将其转换为乘法乘法的乘法来优化除以常数。看到

将数字除以3而不使用*,/,+, - ,%运算符

使用位移除以10?

不使用%和/运算符的5的可分性

对于i和j属于浮点类型的情况,乘以另一个浮点值可能会更快。因为在float和int域之间移动值需要时间,并且int和float之间的转换也需要时间,如上所述

一个重要的区别是,如果j太大,5*j/4将溢出,但1.25*j不会

也就是说,对于"更快"和"速度更快"的问题,没有一般性的答案,因为它取决于特定的架构和特定的环境。您必须在系统上进行测量并做出决定。但是如果表达式重复执行很多值,那么就该转到SIMD了

也可以看看

为什么int * float比int / int快?

我应该使用乘法还是除法?

浮点除法与浮点乘法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值