Skip to content

fix Issue 12412. CTFE-able math #2521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

fix Issue 12412. CTFE-able math #2521

wants to merge 1 commit into from

Conversation

9il
Copy link
Member

@9il 9il commented Sep 16, 2014

Issue:
https://issues.dlang.org/show_bug.cgi?id=12412

Make isNaN, isNormal, isSubnormal, isFinite, isInfinity CTFE-able.

@CyberShadow
Copy link
Member

Please rebase to remove the merge commit.

I see the function return value changed. This is technically a breaking change, however f() != 0 or f() == 0 seems to continue working if f returns bool.

@9il
Copy link
Member Author

9il commented Sep 16, 2014

@CyberShadow, rebased.

Previously this functions returned either 0 or 1. But with auto declarations it can be breaking change.
isNaN, isInfinity already returns bool.
I have changed return type for isFinite, isNormal and isSubnormal.

@quickfur
Copy link
Member

LGTM.

@schuetzm
Copy link
Contributor

Stupid question: Why can't the CTFE versions be used at runtime as well, instead of the bit testing? This would simplify the code greatly. Would it have bad performance?

@9il
Copy link
Member Author

9il commented Sep 16, 2014

@schuetzm Bad performance would be with isNormal and isSubnormal.
For other functions I don't now. I think if(someInt == otherInt && f.isFinity) can be optimized with bit testing.

@monarchdodra
Copy link
Collaborator

None of these functions need an else after the __ctfe block. IMO, it looks clearer to have a special case for CTFE, and then simply have the regular non-indented code if we haven't prematurely returned yet.

It also reduces the amount of diff we need to review, or the amount of code blame that gets assigned to you.

@9il
Copy link
Member Author

9il commented Sep 17, 2014

@monarchdodra PR rebased

foreach(T; TypeTuple!(float, double, real))
{
// CTFE-able tests
assert(isFinite(T(1.23)));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are these "CTFE-able" tests? Shouldn't those be static asserts?

BTW, you might be interested in assertCTFEable(alias dg)() in std.exception. This will run your entire "dg", both in runtime and ctfe time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I will use it.

@9il
Copy link
Member Author

9il commented Sep 17, 2014

@monarchdodra I will add CTFE signbit, frexp, isIdentical.
Should I create new PR or add new commits into this PR?

…unittests

minor update

remove else after ctfe

update unittests

remove line

remove line
@9il
Copy link
Member Author

9il commented Sep 17, 2014

Rebased

@9il
Copy link
Member Author

9il commented Sep 17, 2014

:-( I have no idea how make signbit, frexp, isIdentical CTFE-able .

@quickfur
Copy link
Member

Welcome to the club. :-P I've tried this before. I think the only solution is to use bit manipulation on the IEEE representation, but unfortunately that's not yet possible in CTFE. Basically, we need to implement support for type reinterpretation via unions in CTFE; once that is done, then actually most of the std.math functions will work as-is.

@9il
Copy link
Member Author

9il commented Sep 17, 2014

@quickfur I have tried:

int signbit(X)(X x) @nogc @trusted pure nothrow
{
    alias F = floatTraits!(X);
    static union Rep
    {
        X x;
        ubyte[X.sizeof] b;
    }
    Rep rep = Rep(x);
    return (rep.b[F.SIGNPOS_BYTE] & 0x80) != 0;
}

... without any hope, Error: rep.b[7] is used before initialized

@quickfur
Copy link
Member

Yes, because CTFE doesn't support that yet. The first thing to do would be to implement support in dmd, then we can proceed. Unfortunately, CTFE is one of the places I'm completely unfamiliar with, so I've no idea where to even begin.

@quickfur
Copy link
Member

Blocked on dmd limitation.

@9il 9il changed the title fix Issue 12412 fix Issue 12412. CTFE-able math Sep 17, 2014
@9il 9il mentioned this pull request Sep 18, 2014
@monarchdodra
Copy link
Collaborator

Blocked on dmd limitation.

Well, partially, right? What's currently in the pull works.

@quickfur
Copy link
Member

True. I suppose we could merge this first, and then do a followup PR once the dmd limitation is addressed.

@9il
Copy link
Member Author

9il commented Sep 18, 2014

Yes, the easy part done.

@monarchdodra
Copy link
Collaborator

Well, I don't see anything wrong with this pull, but I'm no numerics expert.

@@ -4525,76 +4533,24 @@ bool isInfinity(X)(X x) @nogc @trusted pure nothrow
}
else
{
return (x - 1) == x;
return x == x && x - x;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just trying to understand the change here: what was wrong with (x - 1) == x?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum M = 2.0L^^(real.max_exp-1) ;
static assert(M - 1 == M);//OK

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see.

Also, is there a performance hit associated with writing x == x && x - x != 0.0? I find that a little clearer, as it isn't obvious that x-x here is being implicitly cast to bool unless you're reading the code carefully.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think performance is same.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgn function for example uses implicite cast to bool. It is faster to understand the line of code. When I see f == 0.0 this really mean
f == 0.0 || f == -0.0 so I need to think about that.

@DmitryOlshansky
Copy link
Member

LGTM with the same notes as @monarchdodra I'm no numerics guy.

assert(!isNaN(-f));
f = cast(T)53.6;
assert(!isNaN(f));
assert(!isNaN(-f));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather that you don't remove the runtime tests. These were put here because the compiler - at least gdc - was able to const-fold the tests using literals above.

@9il
Copy link
Member Author

9il commented Sep 20, 2014

PR Closed.
Reasons:

  1. if(__ctfe) kills inlining in DMD.
  2. Other CTFE math can not be implemented until CTFE-able unions.

@9il 9il closed this Sep 20, 2014
@ibuclaw
Copy link
Member

ibuclaw commented Sep 20, 2014

  1. Other CTFE math can not be implemented until CTFE-able unions.

Has been on my todo list, but keeps being pushed back. ;)

@yebblies
Copy link
Member

Can some of these can have their current implementation replaced with the ctfe version without performance loss? I'd like to see all the bitmasking replaced eventually...

@9il
Copy link
Member Author

9il commented Sep 20, 2014

Need tests with LDC and GDC like

foreach(double a; ar)
{
   if(a.isNaN && some_int==other_int)
   {
    ...
   }
   else
   {
    ...
   }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants