Thread overview
How to muldiv in D?
Nov 21, 2016
Kagamin
Nov 21, 2016
Ali Çehreli
Nov 22, 2016
Kagamin
Nov 22, 2016
rumbu
November 21, 2016
Can't find a function for it.
November 21, 2016
On 11/21/2016 11:16 AM, Kagamin wrote:
> Can't find a function for it.

Here is a draft adapted from the following page


http://stackoverflow.com/questions/14872499/is-there-an-equivalent-to-muldiv-for-linux

This draft works for signed types:

T mulDiv(T)(T number, T numerator, T denominator) {
    static if (is (T == long)) {
        static assert("Sorry, can't support long");
    }
    else static if (is (T == int)) {
        alias InterimT = long;
    }
    else {
        alias InterimT = int;
    }

    InterimT ret = number;
    ret *= numerator;
    ret /= denominator;
    return cast(T)ret;
}

void main() {
    int number = int.max / 2;
    int numerator = 42;
    int denominator = numerator * 2;

    const correctResult = int.max / 4;
    const wrongResult = number * numerator / denominator;

    assert(mulDiv(number, numerator, denominator) == correctResult);
    assert(wrongResult != correctResult);
}

Ali

November 22, 2016
Yep, I need muldiv for long values on x86-64.
November 22, 2016
On Tuesday, 22 November 2016 at 08:54:36 UTC, Kagamin wrote:
> Yep, I need muldiv for long values on x86-64.

Quick and dirty assembler:

version(D_InlineAsm_X86_64):

long muldiv(long a, long b, long c)
{
    //windows RCX, RDX, R8
    //linux RDI, RSI, RDX

    version(Windows)
    {
        asm
        {
            naked;
            mov RAX, RCX;   //RAX = a
            imul RDX;       //RDX:RAX = a * b
            idiv R8;        //RAX = a * b / c
            ret;
        }
    }
    else version(linux)
    {
        asm
        {
            naked;
            mov RAX, RDI;   //RAX = a;
            mov R8, RDX;    //R8 = b
            imul RSI;       //RDX:RAX = a * b
            idiv R8;        //RAX = a * b / c
            ret;
        }
    }
    else
        static assert(0);
}