oh wow I missed when this started to happen
In many common cases shift and masking can replace integer division (i.e. hash tables) and you avoid division altogether, and that probably has about the cost of converting an int to a float.
Recently I have been investigating what operations modern compilers for modern CPUs can optimize. I fond, that for floating-point types there are vector division instructions (which compilers use if they can vectorize), but for integers there are still only scalar instructions. It's unclear for me why no vector instructions exist for such basic arithmetic.
When you code simd it's best to assume the integer divide instruction does not exist. Just an impossibility, if you need to divide ints, rethink your whole program.
Integer multiply is also pretty universally 3 cycles of latency, i.e. basically the same as float multiply (or even add!).
What float div definitely has over int div is throughput, as float div comes in vectorized versions on x86 & ARM, and it usually is actually parallelized.
On top of generally fp div generally having higher throughput (M1 gets down to 1 instr/cycle! though int div isn't bad either at 0.5 instrs/cycle; x86 numbers are messy but even 32-bit int div is never better than f64 div, though they're close; also an annoying aspect is that x86 division instrs actually always take a 128-bit divisor, though hopefully a sign-/zero-extended 64-bit value skips the extra work)
> d = trunc(x/y); // floor works for unsigned
>
> // NOTE: if only want 'd' and it's being converted to an
> // integer then the truncate or floor operation is
> // free in the float to integer conversion.
Please show me how to portably truncate or floor a floating point value to an int in C for "free".{within float-to-integer conversion} trunc or floor is free
that is, if you are converting, you already get it by default
This sort of limitation has a long pedigree and is surprisingly common. For instance, the CDC 6000 series had no general purpose integer arithmetic unit. The DEC Alpha had no integer divide and the standard RISC-5 spec also omits it. Same for low-end ARM chips.
For latency:
- DIV/IDIV r32: 12 cycles
- DIV/IDIV r64: 15 cycles
- FDIV: 14–16 cycles
Throughput:
- DIV/IDIV r32: 6 cycles
- DIV/IDIV r64: 10 cycles
- FDIV: 4–5 cycles
I didn't check for a more recent CPU.
[1] https://www.agner.org/optimize/instruction_tables.pdf page 366 & 369
Use this instead of x87’s FDIV