556 changes: 529 additions & 27 deletions src/core/stdc/math.d
Original file line number Diff line number Diff line change
Expand Up @@ -215,65 +215,152 @@ version( CRuntime_DigitalMars )
}
}
}
else version( CRuntime_Microsoft )
else version( CRuntime_Microsoft ) // fully supported since MSVCRT 12 (VS 2013) only
{
version( all ) // legacy stuff to be removed in the future
{
enum
{
///
_FPCLASS_SNAN = 1,
///
_FPCLASS_QNAN = 2,
///
_FPCLASS_NINF = 4,
///
_FPCLASS_NN = 8,
///
_FPCLASS_ND = 0x10,
///
_FPCLASS_NZ = 0x20,
///
_FPCLASS_PZ = 0x40,
///
_FPCLASS_PD = 0x80,
///
_FPCLASS_PN = 0x100,
///
_FPCLASS_PINF = 0x200,
}

///
//deprecated("Please use the standard C99 function copysignf() instead.")
float _copysignf(float x, float s);
///

//deprecated("_chgsignf(x) is a non-standard MS extension. Please consider using -x instead.")
float _chgsignf(float x);

version( Win64 ) // not available in 32-bit runtimes
{
//deprecated("Please use the standard C99 function isfinite() instead.")
int _finitef(float x);

//deprecated("Please use the standard C99 function isnan() instead.")
int _isnanf(float x);

//deprecated("Please use the standard C99 function fpclassify() instead.")
int _fpclassf(float x);
}

//deprecated("Please use the standard C99 function copysign() instead.")
double _copysign(double x, double s);

//deprecated("_chgsign(x) is a non-standard MS extension. Please consider using -x instead.")
double _chgsign(double x);

//deprecated("Please use the standard C99 function isfinite() instead.")
int _finite(double x);

//deprecated("Please use the standard C99 function isnan() instead.")
int _isnan(double x);

//deprecated("Please use the standard C99 function fpclassify() instead.")
int _fpclass(double x);
}

enum
{
///
FP_SUBNORMAL = -2,
///
FP_NORMAL = -1,
///
FP_ZERO = 0,
///
FP_INFINITE = 1,
///
FP_NAN = 2,
}

private short _fdclass(float x);
private short _dclass(double x);

private int _fdsign(float x);
private int _dsign(double x);

extern(D)
{
//int fpclassify(real-floating x);
///
int _finitef(float x);
int fpclassify()(float x) { return _fdclass(x); }
///
version(Win64) int _isnanf(float x); // not available in Win32?
int fpclassify()(double x) { return _dclass(x); }
///
int _fpclassf(float x);
int fpclassify()(real x)
{
static if (real.sizeof == double.sizeof)
return _dclass(cast(double) x);
else
static assert(false, "fpclassify(real) not supported by MS C runtime");
}

//int isfinite(real-floating x);
///
double _copysign(double x, double s);
int isfinite()(float x) { return fpclassify(x) <= 0; }
///
double _chgsign(double x);
int isfinite()(double x) { return fpclassify(x) <= 0; }
///
int _finite(double x);
int isfinite()(real x) { return fpclassify(x) <= 0; }

//int isinf(real-floating x);
///
int _isnan(double x);
int isinf()(float x) { return fpclassify(x) == FP_INFINITE; }
///
int _fpclass(double x);
int isinf()(double x) { return fpclassify(x) == FP_INFINITE; }
///
int isinf()(real x) { return fpclassify(x) == FP_INFINITE; }

extern(D)
//int isnan(real-floating x);
version( none ) // requires MSVCRT 12+ (VS 2013)
{
///
version(Win64) int isnan(float x) { return _isnanf(x); }
int isnan(float x) { return fpclassify(x) == FP_NAN; }
///
version(Win32) int isnan(float x) { return _isnan(x); }
int isnan(double x) { return fpclassify(x) == FP_NAN; }
///
int isnan(real x) { return fpclassify(x) == FP_NAN; }
}
else // for backward compatibility with older runtimes
{
///
int isnan(double x) { return _isnan(x); }
int isnan(float x) { version(Win64) return _isnanf(x); else return _isnan(cast(double) x); }
///
int isnan(real x) { return _isnan(x); }
int isnan(double x) { return _isnan(x); }
///
int isnan(real x) { return _isnan(cast(double) x); }
}

//int isnormal(real-floating x);
///
int isnormal()(float x) { return fpclassify(x) == FP_NORMAL; }
///
int isnormal()(double x) { return fpclassify(x) == FP_NORMAL; }
///
int isnormal()(real x) { return fpclassify(x) == FP_NORMAL; }

//int signbit(real-floating x);
///
int signbit()(float x) { return _fdsign(x); }
///
int signbit()(double x) { return _dsign(x); }
///
int signbit()(real x)
{
static if (real.sizeof == double.sizeof)
return _dsign(cast(double) x);
else
return (cast(short*)&(x))[4] & 0x8000;
}
}
}
else version( linux )
{
Expand Down Expand Up @@ -874,6 +961,421 @@ extern (D)
int isunordered(real x, real y) { return isnan(x) || isnan(y); }
}

/* MS define some functions inline.
* Additionally, their *l functions work with a 64-bit long double and are thus
* useless for 80-bit D reals. So we use our own wrapper implementations working
* internally with reduced 64-bit precision.
* This also enables relaxing real to 64-bit double.
*/
version( CRuntime_Microsoft ) // fully supported since MSVCRT 12 (VS 2013) only
{
///
double acos(double x);
///
float acosf(float x);
///
extern(D) real acosl()(real x) { return acos(cast(double) x); }

///
double asin(double x);
///
float asinf(float x);
///
extern(D) real asinl()(real x) { return asin(cast(double) x); }

///
double atan(double x);
///
float atanf(float x);
///
extern(D) real atanl()(real x) { return atan(cast(double) x); }

///
double atan2(double y, double x);
///
float atan2f(float y, float x);
///
extern(D) real atan2l()(real y, real x) { return atan2(cast(double) y, cast(double) x); }

///
double cos(double x);
///
float cosf(float x);
///
extern(D) real cosl()(real x) { return cos(cast(double) x); }

///
double sin(double x);
///
float sinf(float x);
///
extern(D) real sinl()(real x) { return sin(cast(double) x); }

///
double tan(double x);
///
float tanf(float x);
///
extern(D) real tanl()(real x) { return tan(cast(double) x); }

///
double acosh(double x);
///
float acoshf(float x);
///
extern(D) real acoshl()(real x) { return acosh(cast(double) x); }

///
double asinh(double x);
///
float asinhf(float x);
///
extern(D) real asinhl()(real x) { return asinh(cast(double) x); }

///
double atanh(double x);
///
float atanhf(float x);
///
extern(D) real atanhl()(real x) { return atanh(cast(double) x); }

///
double cosh(double x);
///
float coshf(float x);
///
extern(D) real coshl()(real x) { return cosh(cast(double) x); }

///
double sinh(double x);
///
float sinhf(float x);
///
extern(D) real sinhl()(real x) { return sinh(cast(double) x); }

///
double tanh(double x);
///
float tanhf(float x);
///
extern(D) real tanhl()(real x) { return tanh(cast(double) x); }

///
double exp(double x);
///
float expf(float x);
///
extern(D) real expl()(real x) { return exp(cast(double) x); }

///
double exp2(double x);
///
float exp2f(float x);
///
extern(D) real exp2l()(real x) { return exp2(cast(double) x); }

///
double expm1(double x);
///
float expm1f(float x);
///
extern(D) real expm1l()(real x) { return expm1(cast(double) x); }

///
double frexp(double value, int* exp);
///
extern(D) float frexpf()(float value, int* exp) { return cast(float) frexp(value, exp); }
///
extern(D) real frexpl()(real value, int* exp) { return frexp(cast(double) value, exp); }

///
int ilogb(double x);
///
int ilogbf(float x);
///
extern(D) int ilogbl()(real x) { return ilogb(cast(double) x); }

///
double ldexp(double x, int exp);
///
extern(D) float ldexpf()(float x, int exp) { return cast(float) ldexp(x, exp); }
///
extern(D) real ldexpl()(real x, int exp) { return ldexp(cast(double) x, exp); }

///
double log(double x);
///
float logf(float x);
///
extern(D) real logl()(real x) { return log(cast(double) x); }

///
double log10(double x);
///
float log10f(float x);
///
extern(D) real log10l()(real x) { return log10(cast(double) x); }

///
double log1p(double x);
///
float log1pf(float x);
///
extern(D) real log1pl()(real x) { return log1p(cast(double) x); }

///
double log2(double x);
///
float log2f(float x);
///
extern(D) real log2l()(real x) { return log2(cast(double) x); }

///
double logb(double x);
///
float logbf(float x);
///
extern(D) real logbl()(real x) { return logb(cast(double) x); }

///
double modf(double value, double* iptr);
///
float modff(float value, float* iptr);
///
extern(D) real modfl()(real value, real* iptr)
{
double i;
double r = modf(cast(double) value, &i);
*iptr = i;
return r;
}

///
double scalbn(double x, int n);
///
float scalbnf(float x, int n);
///
extern(D) real scalbnl()(real x, int n) { return scalbn(cast(double) x, n); }

///
double scalbln(double x, c_long n);
///
float scalblnf(float x, c_long n);
///
extern(D) real scalblnl()(real x, c_long n) { return scalbln(cast(double) x, n); }

///
double cbrt(double x);
///
float cbrtf(float x);
///
extern(D) real cbrtl()(real x) { return cbrt(cast(double) x); }

///
double fabs(double x);
///
extern(D) float fabsf()(float x) { return cast(float) fabs(x); }
///
extern(D) real fabsl()(real x) { return fabs(cast(double) x); }

private double _hypot(double x, double y);
private float _hypotf(float x, float y);
///
extern(D) double hypot(double x, double y) { return _hypot(x, y); }
///
extern(D) float hypotf(float x, float y) { return _hypotf(x, y); }
///
extern(D) real hypotl(real x, real y) { return _hypot(cast(double) x, cast(double) y); }

///
double pow(double x, double y);
///
float powf(float x, float y);
///
extern(D) real powl()(real x, real y) { return pow(cast(double) x, cast(double) y); }

///
double sqrt(double x);
///
float sqrtf(float x);
///
extern(D) real sqrtl()(real x) { return sqrt(cast(double) x); }

///
double erf(double x);
///
float erff(float x);
///
extern(D) real erfl()(real x) { return erf(cast(double) x); }

///
double erfc(double x);
///
float erfcf(float x);
///
extern(D) real erfcl()(real x) { return erfc(cast(double) x); }

///
double lgamma(double x);
///
float lgammaf(float x);
///
extern(D) real lgammal()(real x) { return lgamma(cast(double) x); }

///
double tgamma(double x);
///
float tgammaf(float x);
///
extern(D) real tgammal()(real x) { return tgamma(cast(double) x); }

///
double ceil(double x);
///
float ceilf(float x);
///
extern(D) real ceill()(real x) { return ceil(cast(double) x); }

///
double floor(double x);
///
float floorf(float x);
///
extern(D) real floorl()(real x) { return floor(cast(double) x); }

///
double nearbyint(double x);
///
float nearbyintf(float x);
///
extern(D) real nearbyintl()(real x) { return nearbyint(cast(double) x); }

///
double rint(double x);
///
float rintf(float x);
///
extern(D) real rintl()(real x) { return rint(cast(double) x); }

///
c_long lrint(double x);
///
c_long lrintf(float x);
///
extern(D) c_long lrintl()(real x) { return lrint(cast(double) x); }

///
long llrint(double x);
///
long llrintf(float x);
///
extern(D) long llrintl()(real x) { return llrint(cast(double) x); }

///
double round(double x);
///
float roundf(float x);
///
extern(D) real roundl()(real x) { return round(cast(double) x); }

///
c_long lround(double x);
///
c_long lroundf(float x);
///
extern(D) c_long lroundl()(real x) { return lround(cast(double) x); }

///
long llround(double x);
///
long llroundf(float x);
///
extern(D) long llroundl()(real x) { return llround(cast(double) x); }

///
double trunc(double x);
///
float truncf(float x);
///
extern(D) real truncl()(real x) { return trunc(cast(double) x); }

///
double fmod(double x, double y);
///
float fmodf(float x, float y);
///
extern(D) real fmodl()(real x, real y) { return fmod(cast(double) x, cast(double) y); }

///
double remainder(double x, double y);
///
float remainderf(float x, float y);
///
extern(D) real remainderl()(real x, real y) { return remainder(cast(double) x, cast(double) y); }

///
double remquo(double x, double y, int* quo);
///
float remquof(float x, float y, int* quo);
///
extern(D) real remquol()(real x, real y, int* quo) { return remquo(cast(double) x, cast(double) y, quo); }

///
double copysign(double x, double y);
///
float copysignf(float x, float y);
///
extern(D) real copysignl()(real x, real y) { return copysign(cast(double) x, cast(double) y); }

///
double nan(char* tagp);
///
float nanf(char* tagp);
///
extern(D) real nanl()(char* tagp) { return nan(tagp); }

///
double nextafter(double x, double y);
///
float nextafterf(float x, float y);
///
extern(D) real nextafterl()(real x, real y) { return nextafter(cast(double) x, cast(double) y); }

///
double nexttoward(double x, real y);
///
float nexttowardf(float x, real y);
///
extern(D) real nexttowardl()(real x, real y) { return nexttoward(cast(double) x, cast(double) y); }

///
double fdim(double x, double y);
///
float fdimf(float x, float y);
///
extern(D) real fdiml()(real x, real y) { return fdim(cast(double) x, cast(double) y); }

///
double fmax(double x, double y);
///
float fmaxf(float x, float y);
///
extern(D) real fmaxl()(real x, real y) { return fmax(cast(double) x, cast(double) y); }

///
double fmin(double x, double y);
///
float fminf(float x, float y);
///
extern(D) real fminl()(real x, real y) { return fmin(cast(double) x, cast(double) y); }

///
double fma(double x, double y, double z);
///
float fmaf(float x, float y, float z);
///
extern(D) real fmal()(real x, real y, real z) { return fma(cast(double) x, cast(double) y, cast(double) z); }
}
/* NOTE: freebsd < 8-CURRENT doesn't appear to support *l, but we can
* approximate.
* A lot of them were added in 8.0-RELEASE, and so a lot of these workarounds
Expand All @@ -883,7 +1385,7 @@ extern (D)
// acoshl, asinhl, atanhl, coshl, sinhl, tanhl, cbrtl, powl, expl,
// expm1l, logl, log1pl, log10l, erfcl, erfl, lgammal, tgammal;
// but we can approximate.
version( FreeBSD )
else version( FreeBSD )
{
version (none) // < 8-CURRENT
{
Expand Down