Skip to content

std.math: Add IEEE 128-bit implementation of lrint().#4036

Closed
redstar wants to merge 1 commit intodlang:masterfrom
redstar:lrint
Closed

std.math: Add IEEE 128-bit implementation of lrint().#4036
redstar wants to merge 1 commit intodlang:masterfrom
redstar:lrint

Conversation

@redstar
Copy link
Contributor

@redstar redstar commented Mar 2, 2016

This is one of the missing functions for 128-bit reals.

std/math.d Outdated

// Find the exponent and sign
ulong msb = vl[MANTISSA_MSB];
ulong lsb = vl[MANTISSA_LSB];
Copy link
Contributor

Choose a reason for hiding this comment

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

I realize you're just copying the names used above in the ieeeDouble section, but these really should be named something else like hi and lo.

msb generally stands for "Most Significant Byte" (or Bit), and lsb for "Least Significant Byte" (or Bit). Using that acronym for 64-bit values (quad words, I think, in Intel terminology?) is confusing.

@redstar redstar force-pushed the lrint branch 2 times, most recently from 094724c to 3ea49b2 Compare March 12, 2016 17:27
std/math.d Outdated
ulong hi = vl[MANTISSA_MSB];
ulong lo = vl[MANTISSA_LSB];
int exp = cast(int)((hi >> EXPSHIFT_ULONG) & F.EXPMASK) - F.EXPBIAS;
int sign = cast(int)(lo >> 63);
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be:

ulong hi = vl[MANTISSA_MSB];
int exp = cast(int)((hi >> EXPSHIFT_ULONG) & F.EXPMASK) - F.EXPBIAS;
int sign = cast(int)(hi >> 63);

The sign bit is in the hi part, which in turn means that you only actually need the lo part one place:

else
{
    const lo = vl[MANTISSA_LSB];
    result = (cast(long) hi << (exp - EXPSHIFT_ULONG)) | (lo >> (MANTISSE - exp));
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point.

This is one of the missing functions for 128-bit reals.

if (exp < 0)
result = 0;
else if (exp <= 48)
Copy link
Contributor

Choose a reason for hiding this comment

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

How about else if (exp <= EXPSHIFT_ULONG) ?

@9il 9il added the math label Mar 12, 2016
@tsbockman
Copy link
Contributor

This PR seems OK to me now, pending @9il 's approval.

@9il
Copy link
Member

9il commented Mar 12, 2016

I would like @redstar to reorganize this function to template (we should do it for all std.math).

@tsbockman
Copy link
Contributor

@9il I think we should plan on doing a clean-sheet std.math2. There are so many different things about the current module that could be improved, if we weren't bound by backwards compatibility.

Either way though, that can be done in a separate PR, yes?

@9il
Copy link
Member

9il commented Mar 12, 2016

@9il I think we should plan on doing a clean-sheet std.math2. There are so many different things about the current module that could be improved, if we weren't bound by backwards compatibility.

There is no significant problems with backwards compatibility for math functions, std.math would be upgraded step-by-step.

Either way though, that can be done in a separate PR, yes?

I would like to see the template version in this PR because lrint can be generalized with FloatTraits. FloatTraits can be extended itself.

@9il
Copy link
Member

9il commented Mar 12, 2016

32bit and 64bit should be converted to 64bit version
All other versions should have the same algorithm (except constants) like for extended.

@tsbockman
Copy link
Contributor

@9il

FloatTraits can be replaced itself.

Would it be worthwhile for me to try and turn this proof-of-concept I did a while ago into a real pull request? #3598 (comment)

I think part of the problem with floatTraits, is that it is too low-level. A wrapper like the one I sketched out in the linked comment would be much easier to use correctly. It should perform basically the same, with inlining.

@9il
Copy link
Member

9il commented Mar 12, 2016

FloatTraits can be replaced itself.
Would it be worthwhile for me to try and turn this proof-of-concept I did a while ago into a real pull request? #3598 (comment)

I think part of the problem with floatTraits, is that it is too low-level. A wrapper like the one I sketched out in the linked comment would be much easier to use correctly. It should perform basically the same, with inlining.

This should be extended instead of replaced. My bad.

Current FloatTraits looks OK for me, but if you have good ideas this would be interesting.

@tsbockman
Copy link
Contributor

@9il

Current FloatTraits looks OK for me, but if you have good ideas this would be interesting.

Check out FloatParts in the comment I linked.

@9il
Copy link
Member

9il commented Mar 12, 2016

@tsbockman Yes, we should have a union based version, because current pointer based algorithms are not CTFE-able. Anyway we need tests and disassembled code to see the performance issues.

@9il
Copy link
Member

9il commented Mar 12, 2016

But this is big work

@tsbockman
Copy link
Contributor

@9il

But this is big work

Indeed. I think it's time to just bite the bullet and do it, though, as otherwise we'll waste a lot of time refactoring std.math in ways that we aren't going to actually keep for very long.

@9il
Copy link
Member

9il commented Mar 12, 2016

Indeed. I think it's time to just bite the bullet and do it, though, as otherwise we'll waste a lot of time refactoring std.math in ways that we aren't going to actually keep for very long.
Hide all checks

In the same time you may port only few functions, so we can make a tests and review.

@tsbockman
Copy link
Contributor

In the same time you may port only few functions, so we can make a tests and review.

Yeah I wouldn't try to do everything in one go. The first step is just to get the prerequisites, like FloatParts, working.

ulong* vl = cast(ulong*)(&x);

enum EXPSHIFT_ULONG = 48;
enum MANTISSE = real.mant_dig - 1;
Copy link
Member

Choose a reason for hiding this comment

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

Are these strictly necessary? I don't think anyone would mind if you just use the numbers directly in the implementation, as they are very specific to this function.

The MANTISSE should always be 112, no?

@ibuclaw
Copy link
Member

ibuclaw commented Mar 13, 2016

Logic of the 128-bit implementation looks sound to me. I would expect this to pass our current tests on lrint.

@DmitryOlshansky
Copy link
Member

So anything holding this up? @ibuclaw @9il

@wilzbach
Copy link
Contributor

Ping @redstar - do you have time to "templatize" ?

@ibuclaw
Copy link
Member

ibuclaw commented Apr 23, 2016

So anything holding this up?

Waiting for response to my comments would be one.

{
// It is left implementation defined when the number is too large
// to fit in a 64bit long.
return cast(long) x;
Copy link
Contributor

Choose a reason for hiding this comment

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

sorry for the dumb question, but isn't there a chance that if we (will) have 128-bit floats, we might see 128-bit integers too?

Copy link
Member

Choose a reason for hiding this comment

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

128 bit floats are reality on Power64 I think

Copy link
Member

Choose a reason for hiding this comment

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

@wilzbach Yep, @redstar himself added support for cent/ucent in various places in Phobos and DMDFE.

Copy link
Contributor

Choose a reason for hiding this comment

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

so this function should return cent then?

Copy link
Member

Choose a reason for hiding this comment

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

No, the changes so far just moved errors relating to cent out of the parser and into the semantic pass.

Copy link
Contributor

Choose a reason for hiding this comment

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

@wilzbach

so this function should return cent then?

No - it should return long for now, to be compatible with algorithms that depend on the existing hard-coded return type.

Long-term, all these overly-similar rounding functions - round(), rint(), lrint(), and nearbyint() - could be replaced by a single template function. One of the template parameters can be the return type, allowing round!long() to directly replace lrint(). round!cent() would be supported as well.

@JackStouffer
Copy link
Contributor

Eight months of inactivity from the author. Closing.

@redstar Please reopen if you decide to come back to this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants