[OT] Re: Let's kill 80bit real at CTFE
Marco Leise via Digitalmars-d
digitalmars-d at puremagic.com
Sun Sep 11 07:31:23 PDT 2016
Am Sun, 11 Sep 2016 15:00:12 +1000
schrieb Manu via Digitalmars-d <digitalmars-d at puremagic.com>:
> On 9 September 2016 at 21:50, Stefan Koch via Digitalmars-d
> <digitalmars-d at puremagic.com> wrote:
> > Hi,
> >
> > In short 80bit real are a real pain to support cross-platform.
> > emulating them in software is prohibitively slow, and more importantly hard
> > to get right.
> > 64bit floating-point numbers are supported on more architectures and are
> > much better supported.
> > They are also trivial to use at ctfe.
> > I vote for killing the 80bit handling at constant folding.
> >
> > Destroy!
>
> I just want CTFE '^^'. Please, can we have that?
> It's impossible to CTFE any non-linear function. It's ridiculous, I
> constantly want to generate a curve at compile time!
I have experimented with a few iterative algorithms from
around the web that are now in my module for "random stuff not
in Phobos":
/*******************************************************************************
*
* Computes the arcus tangens at compile time.
*
**************************************/
enum ctfeAtan(real x)
in
{
assert(x == x && abs(x) != real.infinity);
}
body
{
if (abs(x) == 0)
return x;
// Reduce x to <0.5 for effective convergence of the Taylor series.
x /= 1 + sqrt(1 + x * x);
x /= 1 + sqrt(1 + x * x);
// Sum up Taylor series to compute atan().
immutable xSqr = -x * x;
real mul = x;
real div = 1;
real x_old;
do
{
x_old = x;
mul *= xSqr;
div += 2;
x += mul / div;
}
while (x !is x_old);
// Compensate for the initial reduction by multiplying by 4.
return 4 * x;
}
/*******************************************************************************
*
* Computes the arcs sinus at compile time.
*
**************************************/
enum ctfeAsin(real x)
in
{
assert(x.isWithin(-1,+1));
}
body
{
if (abs(x) == 0)
return x;
immutable div = 1 - x * x;
return x / abs(x) * (div == 0 ? PI / 2 : ctfeAtan(sqrt(x * x / div)));
}
/*******************************************************************************
*
* Computes `x` to the power of `y` at compile-time.
*
* Params:
* x = The base value.
* y = The power.
*
* Source:
* http://stackoverflow.com/a/7710097/4038614
*
**************************************/
@safe @nogc pure nothrow
real ctfePow(real x, real y)
{
if (y >= 1)
{
real temp = ctfePow( x, y / 2 );
return temp * temp;
}
real low = 0, high = 1;
real sqr = sqrt( x );
real acc = sqr;
real mid = high / 2;
while (mid != y)
{
sqr = sqrt( sqr );
if (mid <= y)
{
low = mid;
acc *= sqr;
}
else
{
high = mid;
acc *= 1 / sqr;
}
mid = (low + high) / 2;
}
return acc;
}
/*******************************************************************************
*
* Computes the natural logarithm of `x`at compile time.
*
**************************************/
@safe @nogc pure nothrow
FloatReg ctfeLog(FloatReg x)
{
if (x != x || x <= 0)
return -FloatReg.nan;
else if (x == 0)
return -FloatReg.infinity;
else if (x == FloatReg.infinity)
return +FloatReg.infinity;
uint m = 0;
while (x <= ulong.max)
{
x *= 2;
m++;
}
@safe @nogc pure nothrow
static FloatReg agm(FloatReg x, FloatReg y)
in
{
assert(x >= y);
}
body
{
real a, g;
do
{
a = x; g = y;
x = 0.5 * (a+g);
y = sqrt(a*g);
}
while(x != a || y != g);
return x;
}
return PI_2 / agm(1, 4/x) - m * LN2;
}
Especially the `log` function seemed like a good compromise
between execution speed and accuracy. FloatReg is "the native
float register type", but the way CTFE works it should be
`real` anyways. The code is mostly not by me, but from
StackOVerflow comments and Wikipedia. Most of it is common
knowledge to every mathematician.
--
Marco
More information about the Digitalmars-d
mailing list