Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 15, 2013 [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Don,
I'm in the middle of doing pure real implementations of the elementary math functions in std.math in D for the @safe/pure/nothrow routines that call impure extern(C) mathlib as a fallback if D_InlineAsm is not defined.
One nice side effect of this is that the functions are now CTFE-able - well... almost. :o)
The current blocker at the moment where CTFE support would be greatly appreciated is in the functions that require bit set/testing. In particular: isInfinity, floor, and ceil.
With isInfinity, could perhaps do an alternate test:
if (__ctfe)
return (x / 2) == x;
But for floor and ceil, at least one of the following must be available in CTFE to allow setting bits.
----
// Cannot convert &real to ushort* at compile time
real y = x;
ushort* sh = cast(ushort*)&y;
----
----
// Cannot convert &real to ushort[8LU]* at compile time
enum RSIZE_SHORT = real.sizeof/ushort.sizeof;
ushort[RSIZE_SHORT] sh = *cast(ushort[RSIZE_SHORT]*)&x; // _d_arraycopy
/* ... */
// reinterpreting cast from immutable(ushort[8LU]) to real* is not
supported in CTFE
real y = *cast(real*)&sh;
----
----
// Unions with overlapping fields are not yet supported in CTFE
union U
{
real y;
ushort[RSIZE_SHORT] sh;
}
U u = { x };
----
Now, the pressing question is, which method do you prefer / would like to see in CTFE first. :o)
Thanks,
--
Iain Buclaw
*(p < e ? p++ : p) = (c & 0x0f) + '0';
_______________________________________________
dmd-internals mailing list
dmd-internals@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-internals
|
July 15, 2013 Re: [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw | On 15 July 2013 10:46, Iain Buclaw <ibuclaw@ubuntu.com> wrote: > > Now, the pressing question is, which method do you prefer / would like to see in CTFE first. :o) > Alternatively, we could add BUILTINfloor and BUILTINceil into builtins.c, but I'd rather avoid this route if possible. :-) -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0'; _______________________________________________ dmd-internals mailing list dmd-internals@puremagic.com http://lists.puremagic.com/mailman/listinfo/dmd-internals |
July 16, 2013 Re: [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw Attachments:
| I would prefer to see (as either builtins or properties) a way to get/set the exponent/mantissa/sign of a float.
eg
float x;
x.sign = 1;
assert(x.exp == 123);
Easily ctfeable, no need for casting, no endianness problems.
I expect everything could be implemented from these?
On Mon, Jul 15, 2013 at 8:22 PM, Iain Buclaw <ibuclaw@ubuntu.com> wrote:
> On 15 July 2013 10:46, Iain Buclaw <ibuclaw@ubuntu.com> wrote:
> >
> > Now, the pressing question is, which method do you prefer / would like to see in CTFE first. :o)
> >
>
> Alternatively, we could add BUILTINfloor and BUILTINceil into builtins.c, but I'd rather avoid this route if possible. :-)
>
> --
> Iain Buclaw
>
> *(p < e ? p++ : p) = (c & 0x0f) + '0';
> _______________________________________________
> dmd-internals mailing list
> dmd-internals@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-internals
>
|
July 15, 2013 Re: [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | On Tue, Jul 16, 2013 at 12:04:08AM +1000, Daniel Murphy wrote: > I would prefer to see (as either builtins or properties) a way to get/set the exponent/mantissa/sign of a float. > > eg > float x; > x.sign = 1; > assert(x.exp == 123); > > Easily ctfeable, no need for casting, no endianness problems. [...] +1. IMO this is the right way to handle floating-point attributes. Direct knowledge about the binary representation should be restricted to the compiler as much as possible. Plus, having these attributes could potentially be useful in other contexts than std.math. T -- The best way to destroy a cause is to defend it poorly. _______________________________________________ dmd-internals mailing list dmd-internals@puremagic.com http://lists.puremagic.com/mailman/listinfo/dmd-internals |
July 15, 2013 Re: [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw Attachments:
| On 15 July 2013 11:46, Iain Buclaw <ibuclaw@ubuntu.com> wrote:
> But for floor and ceil, at least one of the following must be available in CTFE to allow setting bits.
>
> ----
> // Cannot convert &real to ushort* at compile time
> real y = x;
> ushort* sh = cast(ushort*)&y;
>
Yeah. The problem with this, is that what happens if somebody stores the pointer? It introduces loads of special cases.
The most minimal solution would be to explicitly allow:
ushort e = *(cast ushort *)&y;
*(cast ushort *)&y = e;
and likewise for getting the raw mantissa into a ulong.
Simply two permissible reads, and two permissible writes, and only for x86.
Essentially provides .exp | sign, and .mantissa as writable properties, but
without syntax sugar. We could wrap it in a library to create syntax sugar.
It's really a hack, but this is one of those low-level primitives that
needs to be provided as a special case, it's kind of an __asm feature.
I think the special case nature of this is unavoidable, it creates a host
of problems if you allow general casting.
We need it for doing atof() at compile-time, too, so providing built-in ceil and floor is not an option.
|
July 15, 2013 Re: [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | On 15 July 2013 15:04, Daniel Murphy <yebblies@gmail.com> wrote: > I would prefer to see (as either builtins or properties) a way to get/set the exponent/mantissa/sign of a float. > > eg > float x; > x.sign = 1; > assert(x.exp == 123); > > Easily ctfeable, no need for casting, no endianness problems. > > I expect everything could be implemented from these? > > There's also, MANTISSA_LSB and MANTISSA_MSB are used to peek into reals for 128bit real targets - but it can also apply to 80/96bit real targets (lsb/msb being of 32bit integers instead of 64bit). With floor, I've gone down the route of casting between real and ushort[real.sizeof / short.sizeof] as ushort* alternative was being optimised away by gcc backend. :o) I'd be happy to post it in all it's glory. Please note that the other functions implemented are not endianess specific (apart from the use of isNaN, isInfinity, frexp). ------------ real ceil(real x) @trusted pure nothrow { // Special cases. if (isNaN(x) || isInfinity(x)) return x; real y = floor(x); if (y < x) y += 1.0L; return y; } real floor(real x) @trusted pure nothrow { alias floatTraits!(real) F; enum REALSZ = real.sizeof / ushort.sizeof; static if (real.mant_dig == 53) { version (LittleEndian) enum FRACTPOS_SHORT = 0; else enum FRACTPOS_SHORT = 3; } else static if (real.mant_dig == 64) { version (LittleEndian) enum FRACTPOS_SHORT = 0; else enum FRACTPOS_SHORT = 4; } else if (real.mant_dig == 113) { version (LittleEndian) enum FRACTPOS_SHORT = 0; else enum FRACTPOS_SHORT = 7; } else static assert(false, "Only 64-bit, 80-bit, and 128-bit reals are supported"); // Bit clearing masks. static immutable ushort[17] BMASK = [ 0xffff, 0xfffe, 0xfffc, 0xfff8, 0xfff0, 0xffe0, 0xffc0, 0xff80, 0xff00, 0xfe00, 0xfc00, 0xf800, 0xf000, 0xe000, 0xc000, 0x8000, 0x0000, ]; // Special cases. if (isNaN(x) || isInfinity(x) || x == 0.0L) return x; // Find the exponent (power of 2) ushort[REALSZ] vu = *cast(ushort[REALSZ]*)&x; int exp = (vu[F.EXPPOS_SHORT] & 0x7fff) - 0x3fff; if (exp < 0) { if (x < 0) return -1.0L; else return 0.0L; } int j = FRACTPOS_SHORT; exp = (real.mant_dig - 1) - exp; // Clean out 16 bits at a time. while (exp >= 16) { version (LittleEndian) vu[j++] = 0; else vu[j--] = 0; exp -= 16; } // Clear the remaining bits. if (exp > 0) vu[j] &= BMASK[exp]; real y = *cast(real*)&vu; if ((x < 0.0L) && (y != x)) y -= 1.0L; return y; } Regards -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0'; _______________________________________________ dmd-internals mailing list dmd-internals@puremagic.com http://lists.puremagic.com/mailman/listinfo/dmd-internals |
July 15, 2013 Re: [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | On 15 July 2013 16:22, Don Clugston <dclugston@gmail.com> wrote: > > > On 15 July 2013 11:46, Iain Buclaw <ibuclaw@ubuntu.com> wrote: >> >> But for floor and ceil, at least one of the following must be available in CTFE to allow setting bits. >> >> ---- >> // Cannot convert &real to ushort* at compile time >> real y = x; >> ushort* sh = cast(ushort*)&y; > > > > Yeah. The problem with this, is that what happens if somebody stores the pointer? It introduces loads of special cases. > > The most minimal solution would be to explicitly allow: > > ushort e = *(cast ushort *)&y; > *(cast ushort *)&y = e; > Hmm, how about static arrays of the same size? This is safer because of copy semantics (e is a copy of y). ushort[8] e = *cast(ushort[8]*)&y; y = *cast(real *)&e; -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0'; _______________________________________________ dmd-internals mailing list dmd-internals@puremagic.com http://lists.puremagic.com/mailman/listinfo/dmd-internals |
July 16, 2013 Re: [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh Attachments:
| On 15 July 2013 16:54, H. S. Teoh <hsteoh@quickfur.ath.cx> wrote: > On Tue, Jul 16, 2013 at 12:04:08AM +1000, Daniel Murphy wrote: > > I would prefer to see (as either builtins or properties) a way to get/set the exponent/mantissa/sign of a float. > > > > eg > > float x; > > x.sign = 1; > > assert(x.exp == 123); > > > > Easily ctfeable, no need for casting, no endianness problems. > [...] > > +1. IMO this is the right way to handle floating-point attributes. Direct knowledge about the binary representation should be restricted to the compiler as much as possible. Plus, having these attributes could potentially be useful in other contexts than std.math. > No. You shouldn't be doing these kind of operations in normal code, you should be using normal arithmetic. If you need to know the exponent, you should use library functions like frexp(). You shouldn't be poking in the internals of a float unless you know the bit pattern exactly, and you need the extra speed. This issue only applies to 80-bit reals on x86, this is really a very special case. Floats and doubles already allow the necessary casts. > > > T > > -- > The best way to destroy a cause is to defend it poorly. > _______________________________________________ > dmd-internals mailing list > dmd-internals@puremagic.com > http://lists.puremagic.com/mailman/listinfo/dmd-internals > |
July 16, 2013 Re: [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw Attachments:
| On 15 July 2013 18:50, Iain Buclaw <ibuclaw@ubuntu.com> wrote:
> On 15 July 2013 16:22, Don Clugston <dclugston@gmail.com> wrote:
> >
> >
> > On 15 July 2013 11:46, Iain Buclaw <ibuclaw@ubuntu.com> wrote:
> >>
> >> But for floor and ceil, at least one of the following must be available in CTFE to allow setting bits.
> >>
> >> ----
> >> // Cannot convert &real to ushort* at compile time
> >> real y = x;
> >> ushort* sh = cast(ushort*)&y;
> >
> >
> >
> > Yeah. The problem with this, is that what happens if somebody stores the pointer? It introduces loads of special cases.
> >
> > The most minimal solution would be to explicitly allow:
> >
> > ushort e = *(cast ushort *)&y;
> > *(cast ushort *)&y = e;
> >
>
> Hmm, how about static arrays of the same size? This is safer because of copy semantics (e is a copy of y).
>
> ushort[8] e = *cast(ushort[8]*)&y;
> y = *cast(real *)&e;
>
True. But I don't think you would ever write runtime code that way, it
seems quite unnatural since it is so slow.
Could certainly be done.
|
July 16, 2013 Re: [dmd-internals] Pure CTFE-able std.math | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | On 16 July 2013 08:12, Don Clugston <dclugston@gmail.com> wrote: > On 15 July 2013 18:50, Iain Buclaw <ibuclaw@ubuntu.com> wrote: >> >> On 15 July 2013 16:22, Don Clugston <dclugston@gmail.com> wrote: >> > >> > >> > On 15 July 2013 11:46, Iain Buclaw <ibuclaw@ubuntu.com> wrote: >> >> >> >> But for floor and ceil, at least one of the following must be available in CTFE to allow setting bits. >> >> >> >> ---- >> >> // Cannot convert &real to ushort* at compile time >> >> real y = x; >> >> ushort* sh = cast(ushort*)&y; >> > >> > >> > >> > Yeah. The problem with this, is that what happens if somebody stores the pointer? It introduces loads of special cases. >> > >> > The most minimal solution would be to explicitly allow: >> > >> > ushort e = *(cast ushort *)&y; >> > *(cast ushort *)&y = e; >> > >> >> Hmm, how about static arrays of the same size? This is safer because of copy semantics (e is a copy of y). >> >> ushort[8] e = *cast(ushort[8]*)&y; >> y = *cast(real *)&e; > > > True. But I don't think you would ever write runtime code that way, it seems > quite unnatural since it is so slow. > Could certainly be done. > I wouldn't have thought it would be much different to using a union. -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0'; _______________________________________________ dmd-internals mailing list dmd-internals@puremagic.com http://lists.puremagic.com/mailman/listinfo/dmd-internals |
Copyright © 1999-2021 by the D Language Foundation