diff --git a/src/core/stdc/math.d b/src/core/stdc/math.d
index 2bdb3e621e..05ac543746 100644
--- a/src/core/stdc/math.d
+++ b/src/core/stdc/math.d
@@ -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 )
 {
@@ -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
@@ -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
   {