www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - CTFE fmod ?

reply userABCabc123 <userABCabc123 abc.ba> writes:
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 ?
Nov 20 2015
parent reply rumbu <rumbu rumbu.ro> writes:
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; }
Nov 20 2015
parent userABCabc123 <userABCabc123 ab.ba.ab> writes:
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.
Nov 20 2015