Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 55 additions & 47 deletions src/core/math.d
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,18 @@ module core.math;

public:
@nogc:
nothrow:
@safe:

/*****************************************
* Returns x rounded to a long value using the FE_TONEAREST rounding mode.
* If the integer value of x is
* greater than long.max, the result is
* indeterminate.
*/
extern (C) real rndtonl(real x);

pure:
/***********************************
* Returns cosine of x. x is in radians.
*
Expand All @@ -40,7 +51,9 @@ public:
* Results are undefined if |x| >= $(POWER 2,64).
*/

real cos(real x) @safe pure nothrow; /* intrinsic */
float cos(float x); /* intrinsic */
double cos(double x); /* intrinsic */ /// ditto
real cos(real x); /* intrinsic */ /// ditto

/***********************************
* Returns sine of x. x is in radians.
Expand All @@ -55,24 +68,20 @@ real cos(real x) @safe pure nothrow; /* intrinsic */
* Results are undefined if |x| >= $(POWER 2,64).
*/

real sin(real x) @safe pure nothrow; /* intrinsic */
float sin(float x); /* intrinsic */
double sin(double x); /* intrinsic */ /// ditto
real sin(real x); /* intrinsic */ /// ditto

/*****************************************
* Returns x rounded to a long value using the current rounding mode.
* If the integer value of x is
* greater than long.max, the result is
* indeterminate.
*/
long rndtol(real x) @safe pure nothrow; /* intrinsic */


/*****************************************
* Returns x rounded to a long value using the FE_TONEAREST rounding mode.
* If the integer value of x is
* greater than long.max, the result is
* indeterminate.
*/
extern (C) real rndtonl(real x);
long rndtol(float x); /* intrinsic */
long rndtol(double x); /* intrinsic */ /// ditto
long rndtol(real x); /* intrinsic */ /// ditto

/***************************************
* Compute square root of x.
Expand All @@ -85,42 +94,41 @@ extern (C) real rndtonl(real x);
* )
*/

@safe pure nothrow
{
float sqrt(float x); /* intrinsic */
double sqrt(double x); /* intrinsic */ /// ditto
real sqrt(real x); /* intrinsic */ /// ditto
}
float sqrt(float x); /* intrinsic */
double sqrt(double x); /* intrinsic */ /// ditto
real sqrt(real x); /* intrinsic */ /// ditto

/*******************************************
* Compute n * 2$(SUPERSCRIPT exp)
* References: frexp
*/

real ldexp(real n, int exp) @safe pure nothrow; /* intrinsic */
float ldexp(float n, int exp); /* intrinsic */
double ldexp(double n, int exp); /* intrinsic */ /// ditto
real ldexp(real n, int exp); /* intrinsic */ /// ditto

unittest {
static if (real.mant_dig == 113)
{
assert(ldexp(1, -16384) == 0x1p-16384L);
assert(ldexp(1, -16382) == 0x1p-16382L);
assert(ldexp(1.0L, -16384) == 0x1p-16384L);
assert(ldexp(1.0L, -16382) == 0x1p-16382L);
}
else static if (real.mant_dig == 106)
{
assert(ldexp(1, 1023) == 0x1p1023L);
assert(ldexp(1, -1022) == 0x1p-1022L);
assert(ldexp(1, -1021) == 0x1p-1021L);
assert(ldexp(1.0L, 1023) == 0x1p1023L);
assert(ldexp(1.0L, -1022) == 0x1p-1022L);
assert(ldexp(1.0L, -1021) == 0x1p-1021L);
}
else static if (real.mant_dig == 64)
{
assert(ldexp(1, -16384) == 0x1p-16384L);
assert(ldexp(1, -16382) == 0x1p-16382L);
assert(ldexp(1.0L, -16384) == 0x1p-16384L);
assert(ldexp(1.0L, -16382) == 0x1p-16382L);
}
else static if (real.mant_dig == 53)
{
assert(ldexp(1, 1023) == 0x1p1023L);
assert(ldexp(1, -1022) == 0x1p-1022L);
assert(ldexp(1, -1021) == 0x1p-1021L);
assert(ldexp(1.0L, 1023) == 0x1p1023L);
assert(ldexp(1.0L, -1022) == 0x1p-1022L);
assert(ldexp(1.0L, -1021) == 0x1p-1021L);
}
else
assert(false, "Only 128bit, 80bit and 64bit reals expected here");
Expand All @@ -135,7 +143,9 @@ unittest {
* $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) )
* )
*/
real fabs(real x) @safe pure nothrow; /* intrinsic */
float fabs(float x); /* intrinsic */
double fabs(double x); /* intrinsic */ /// ditto
real fabs(real x); /* intrinsic */ /// ditto

/**********************************
* Rounds x to the nearest integer value, using the current rounding
Expand All @@ -145,22 +155,29 @@ real fabs(real x) @safe pure nothrow; /* intrinsic */
* $(B nearbyint) performs
* the same operation, but does not set the FE_INEXACT exception.
*/
real rint(real x) @safe pure nothrow; /* intrinsic */
float rint(float x); /* intrinsic */
double rint(double x); /* intrinsic */ /// ditto
real rint(real x); /* intrinsic */ /// ditto

/***********************************
* Building block functions, they
* translate to a single x87 instruction.
*/

real yl2x(real x, real y) @safe pure nothrow; // y * log2(x)
real yl2xp1(real x, real y) @safe pure nothrow; // y * log2(x + 1)
// y * log2(x)
float yl2x(float x, float y); /* intrinsic */
double yl2x(double x, double y); /* intrinsic */ /// ditto
real yl2x(real x, real y); /* intrinsic */ /// ditto
// y * log2(x +1)
float yl2xp1(float x, float y); /* intrinsic */
double yl2xp1(double x, double y); /* intrinsic */ /// ditto
real yl2xp1(real x, real y); /* intrinsic */ /// ditto

unittest
{
version (INLINE_YL2X)
{
assert(yl2x(1024, 1) == 10);
assert(yl2xp1(1023, 1) == 10);
assert(yl2x(1024.0L, 1) == 10);
assert(yl2xp1(1023.0L, 1) == 10);
}
}

Expand All @@ -177,38 +194,29 @@ unittest
* Returns:
* f in precision of type `T`
*/
@safe pure nothrow
T toPrec(T:float)(float f) { pragma(inline, false); return f; }
/// ditto
@safe pure nothrow
T toPrec(T:float)(double f) { pragma(inline, false); return cast(T) f; }
/// ditto
@safe pure nothrow
T toPrec(T:float)(real f) { pragma(inline, false); return cast(T) f; }
/// ditto
@safe pure nothrow
T toPrec(T:double)(float f) { pragma(inline, false); return f; }
/// ditto
@safe pure nothrow
T toPrec(T:double)(double f) { pragma(inline, false); return f; }
/// ditto
@safe pure nothrow
T toPrec(T:double)(real f) { pragma(inline, false); return cast(T) f; }
/// ditto
@safe pure nothrow
T toPrec(T:real)(float f) { pragma(inline, false); return f; }
/// ditto
@safe pure nothrow
T toPrec(T:real)(double f) { pragma(inline, false); return f; }
/// ditto
@safe pure nothrow
T toPrec(T:real)(real f) { pragma(inline, false); return f; }

@safe unittest
{
static float f = 1.1f;
static double d = 1.1;
static real r = 1.1L;
float f = 1.1f;
double d = 1.1;
real r = 1.1L;
Comment on lines +217 to +219
Copy link
Contributor Author

@thewilsonator thewilsonator Apr 27, 2020

Choose a reason for hiding this comment

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

@ibuclaw was there any reason these need to be static? This makes the unittest impure.

Copy link
Member

Choose a reason for hiding this comment

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

To force the code generator (not CTFE) to do the work. Practically the same is done in the test suite, so could remove if you really must.

Copy link
Member

Choose a reason for hiding this comment

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

I'll remove it as part of #2871

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That PR seems to have offended the gods of continuous integration, so I'd rather that be done here.

Copy link
Member

Choose a reason for hiding this comment

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

I've added approxEqual, so the Win32 targets should now be happy with their inaccuracies.

f = toPrec!float(f + f);
f = toPrec!float(d + d);
f = toPrec!float(r + r);
Expand Down