C或C++中乘法和除法的较高部分?

Jua*_*rez 10 c c++

当我在汇编中乘以一对4字节整数时,结果的下半部分在EAX中,而在EDX中则是较高部分.如果我使用的是C或C++并且我想获得更高的部分,是否有可能不使用内联汇编?

是否有可能从EAX获得整数除法结果和EDX的模数结果而不重复C或C++中的除法?我实际上只知道先做a/b,然后a%b在汇编程序中,两个结果都在同一个操作中给出.

chq*_*lie 10

您可以通过这种方式轻松完成:

#include <stdint.h>

uint32_t a, b;  // input
uint64_t val = (uint64_t)a * b;
uint32_t high = val >> 32, low = val;
Run Code Online (Sandbox Code Playgroud)

将它留给编译器以产生最好的代码.现代优化者真的很擅长.手动编码组件通常看起来更好,但性能更差.

正如Pete Becker评论的那样,上面依赖于类型uint32_t和类型的可用性uint64_t.如果你坚持难改便携性(比如你正在编写一个DS9K),你可以改用类型uint_least32_tuint_least64_tuint_fast32_tuint_fast64_t始终可用C99下,但你需要一个额外的面具,如果不需要的话,将被优化掉:

#include <stdint.h>

uint_fast32_t a, b;  // input
uint_fast64_t val = (uint_fast64_t)a * b;
uint_fast32_t high = (val >> 32) & 0xFFFFFFFF, low = val & 0xFFFFFFFF;
Run Code Online (Sandbox Code Playgroud)

关于除法,您可以使用C99库函数div,ldivlldiv在一次调用中执行有符号除法和余数运算.如果可能,在特定操作数类型的目标体系结构上,将在一个操作中实现除法/模组合.

编写两个表达式并依赖编译器检测模式并生成使用单个IDIV操作码的代码可能更有效:

struct divmod_t { int quo, rem; };
struct divmod_t divmod(int num, int denom) {
    struct divmod_t r = { num / denom, num % denom };
    return r;
}
Run Code Online (Sandbox Code Playgroud)

Matt上测试Godbolt的编译器浏览器显示clang和gcc都idiv为此代码生成一条指令-O3.

您可以将其中一个分区变为乘法:

struct divmod_t { int quo, rem; };
struct divmod_t divmod2(int num, int denom) {
    struct divmod_t r;
    r.quo = num / denom;
    r.rem = num - r.quo * denom;
    return r;
}
Run Code Online (Sandbox Code Playgroud)

请注意,上述函数不检查潜在的溢出,这会导致未定义的行为.如果denom = 0和如果num = INT_MIN和,则发生溢出denom = -1.

  • 这也是有效的C++ 11 (6认同)
  • 希望能用C++做到这一点 - 为什么C++必须*那么复杂?!! :P (2认同)
  • @PaulEvans因为你应该在*之后使用语言*它已被改进(即++ C),而不是之前;) (2认同)

Pau*_*ans 5

您不处理C或C++中的实现细节.这就是重点.如果您想要最重要的字节,只需使用该语言即可.右移>>旨在实现这一目标.就像是:

uint64_t i;
uint32_t a;
uint32_t b;
// input a, b and set i to a * b
// this should be done with (thanks to @nnn, pls see comment below):
// i = a; i *= b;
uint64_t msb = i >> 32;
Run Code Online (Sandbox Code Playgroud)

  • 为了避免任何不确定性,应该注意做`i = a*b;`是不行的,因为只存储32个LSBits.其中一个操作数应该具有转换为"uint64_t",或者具有类似于"i = a"的内容; 我*= b;` (2认同)