Thread overview
CTFE fmod ?
Nov 20, 2015
userABCabc123
Nov 20, 2015
rumbu
Nov 20, 2015
userABCabc123
November 20, 2015
Does someone have a good CTFE fmod() function ? The problem is that std.math.fmod() is itself not available at CT, neither do floor() or similar functions necessary to get the quotient when the input value is two times over/under the bounds.

Currently I have this one...

---
auto warp(T)(T x, T min, T max)
{
    if (x > max)
    {
        T rng = max - min;
        while (x > max + rng)
            x -= rng * 2;
        if (x > max)
            x -= rng;
    }
    else if (x < min)
    {
        T rng = max - min;
        while (x < min - rng)
            x += rng * 2;
        if (x < min)
            x += rng;
    }
    return x;
}
---

...but it fails to compile with certain float values. This example will consume a lot of memory ( I guess it's the while() loop in the CTFE VM who's responsible):

---
static assert(warp(2357136044, -5f, 5f).approxEqual(-1f));
---

Any suggestion ? Or maybe this is a limit ?

November 20, 2015
On Friday, 20 November 2015 at 11:16:13 UTC, userABCabc123 wrote:
> Does someone have a good CTFE fmod() function ? The problem is that std.math.fmod() is itself not available at CT, neither do floor() or similar functions necessary to get the quotient when the input value is two times over/under the bounds.
>

>
> Any suggestion ? Or maybe this is a limit ?

Not thoroughly tested and only works for doubles, but this must do the trick.

double ctfe_trunc(double x) @trusted pure nothrow @nogc
{
	ulong bits = *cast(ulong*)(&x);
	auto sign = bits & 0x8000000000000000;
	long exponent = (bits >> 52) & 0x7FF;
	auto mantissa = (bits & 0xFFFFFFFFFFFFF);
	
	if (exponent == 0 && mantissa == 0)
		return 0.0;
	else if (exponent == 0x7FF && mantissa == 0)
		return sign ? -double.infinity : double.infinity;
	else if (exponent == 0x7FF)
		return double.nan;

	exponent -= 1023;
	auto target = 52 - exponent;
	if (target >= 0 && target <= 51)
	{
		auto msb = mantissa & (1UL << target);
		auto lsb = mantissa & ~((1UL << target) - 1);
		bits = sign | ((exponent + 1023)) << 52 | lsb;
		mantissa += msb;
		return *cast(double*)&bits;
	}
	else
		return sign ? -0.0 : 0.0;
}

double ctfe_fmod(double x, double y) @safe pure nothrow @nogc
{
	return x - ctfe_trunc(x / y) * y;
}

November 20, 2015
On Friday, 20 November 2015 at 13:44:11 UTC, rumbu wrote:
> On Friday, 20 November 2015 at 11:16:13 UTC, userABCabc123 wrote:
>>[...]
>
>> [...]
>
> Not thoroughly tested and only works for doubles, but this must do the trick.
>
> [...]

Thx, it works, easy to adapt to float.