划分而不会遗失余数

Nul*_*lik 14 c

在C中,是否可以将一个被除数除以常数并同时得到结果和余数?

我想避免执行2个除法指令,如下例所示:

val=num / 10;
mod=num % 10;
Run Code Online (Sandbox Code Playgroud)

sas*_*ang 14

我不担心指令计数,因为x86指令集将提供一条idivl指令来计算一条指令中的被除数和余数.任何体面的编译器都会使用此指令.这里的文档http://programminggroundup.blogspot.com/2007/01/appendix-b-common-x86-instructions.html描述了如下指令:

执行无符号除法.将组合的%edx:%eax寄存器中包含的双字的内容除以指定的寄存器或存储单元中的值.%eax寄存器包含结果商,%edx寄存器包含结果余数.如果商太大而不适合%eax,则会触发类型0中断.

例如,编译此示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  int x = 39;
  int divisor = 1;
  int div = 0;
  int rem = 0;

  printf("Enter the divisor: ");
  scanf("%d", &divisor);
  div = x/divisor;
  rem = x%divisor;

  printf("div = %d, rem = %d\n", div, rem);
}
Run Code Online (Sandbox Code Playgroud)

使用gcc -S -O2(-S保存创建的显示asm列表的临时文件),显示以下行中的除法和mod

div = x/divisor;
rem = x%divisor;
Run Code Online (Sandbox Code Playgroud)

有效地减少到以下指令:

idivl   28(%esp)
Run Code Online (Sandbox Code Playgroud)

正如您可以看到执行除法和mod计算的一条指令.在idivl即使MOD计算在C程序被移除指令保持.之后idivl有电话mov:

movl    $.LC2, (%esp)
movl    %edx, 8(%esp)
movl    %eax, 4(%esp)
call    printf
Run Code Online (Sandbox Code Playgroud)

这些调用将商和余数复制到堆栈上以调用printf.

更新

有趣的div是,除了在函数调用中包装/和%运算符之外,该函数没有做任何特殊操作.因此,从性能的角度来看,它不会通过替换线来改善性能

 val=num / 10;       
 mod=num % 10;
Run Code Online (Sandbox Code Playgroud)

只需一个电话div.


Joh*_*ess 5

div():

div_t result = div(num, 10);
// quotient is result.quot
// remainder is result.rem
Run Code Online (Sandbox Code Playgroud)

  • 见这里:http://sourceware.org/git/?p = glibc.git; a = blob; f = stdlib/div.c; h = 5268f4c49440c936e23049d7eda4fde68f650369; hb = HEAD.div的实现只包含对%和/的调用. (2认同)

Dav*_*ave 5

不要浪费你的时间与div()Like Nemo说,编译器将很容易地优化使用除法,然后使用模数运算合二为一.编写具有最佳意义的代码,让计算机删除残缺.


Gab*_*abe 3

您始终可以使用该div功能。