1 // Compiler implementation of the D programming language 2 // Copyright (c) 1999-2016 by Digital Mars 3 // All Rights Reserved 4 // written by Walter Bright 5 // http://www.digitalmars.com 6 // Distributed under the Boost Software License, Version 1.0. 7 // http://www.boost.org/LICENSE_1_0.txt 8 9 module ddmd.root.ctfloat; 10 11 static import core.math, core.stdc.math; 12 import core.stdc.errno; 13 import core.stdc.stdio; 14 import core.stdc.stdlib; 15 import core.stdc..string; 16 17 // Type used by the front-end for compile-time reals 18 alias real_t = real; 19 20 private 21 { 22 version(CRuntime_DigitalMars) __gshared extern (C) extern const(char)* __locale_decpoint; 23 24 version(CRuntime_Microsoft) extern (C++) 25 { 26 struct longdouble { real_t r; } 27 size_t ld_sprint(char* str, int fmt, longdouble x); 28 longdouble strtold_dm(const(char)* p, char** endp); 29 } 30 } 31 32 // Compile-time floating-point helper 33 extern (C++) struct CTFloat 34 { 35 version(DigitalMars) 36 { 37 static __gshared bool yl2x_supported = true; 38 static __gshared bool yl2xp1_supported = true; 39 } 40 else 41 { 42 static __gshared bool yl2x_supported = false; 43 static __gshared bool yl2xp1_supported = false; 44 } 45 46 static void yl2x(const real_t* x, const real_t* y, real_t* res) 47 { 48 version(DigitalMars) 49 *res = core.math.yl2x(*x, *y); 50 else 51 assert(0); 52 } 53 54 static void yl2xp1(const real_t* x, const real_t* y, real_t* res) 55 { 56 version(DigitalMars) 57 *res = core.math.yl2xp1(*x, *y); 58 else 59 assert(0); 60 } 61 62 static real_t sin(real_t x) { return core.math.sin(x); } 63 static real_t cos(real_t x) { return core.math.cos(x); } 64 static real_t tan(real_t x) { return core.stdc.math.tanl(x); } 65 static real_t sqrt(real_t x) { return core.math.sqrt(x); } 66 static real_t fabs(real_t x) { return core.math.fabs(x); } 67 68 static bool isIdentical(real_t a, real_t b) 69 { 70 // don't compare pad bytes in extended precision 71 enum sz = (real_t.mant_dig == 64) ? 10 : real_t.sizeof; 72 return memcmp(&a, &b, sz) == 0; 73 } 74 75 static bool isNaN(real_t r) 76 { 77 return !(r == r); 78 } 79 80 static bool isSNaN(real_t r) 81 { 82 return isNaN(r) && !(((cast(ubyte*)&r)[7]) & 0x40); 83 } 84 85 // the implementation of longdouble for MSVC is a struct, so mangling 86 // doesn't match with the C++ header. 87 // add a wrapper just for isSNaN as this is the only function called from C++ 88 version(CRuntime_Microsoft) 89 static bool isSNaN(longdouble ld) 90 { 91 return isSNaN(ld.r); 92 } 93 94 static bool isInfinity(real_t r) 95 { 96 return r is real_t.infinity || r is -real_t.infinity; 97 } 98 99 static real_t parse(const(char)* literal, bool* isOutOfRange = null) 100 { 101 errno = 0; 102 version(CRuntime_DigitalMars) 103 { 104 auto save = __locale_decpoint; 105 __locale_decpoint = "."; 106 } 107 version(CRuntime_Microsoft) 108 auto r = strtold_dm(literal, null).r; 109 else 110 auto r = strtold(literal, null); 111 version(CRuntime_DigitalMars) __locale_decpoint = save; 112 if (isOutOfRange) 113 *isOutOfRange = (errno == ERANGE); 114 return r; 115 } 116 117 static int sprint(char* str, char fmt, real_t x) 118 { 119 version(CRuntime_Microsoft) 120 { 121 return cast(int)ld_sprint(str, fmt, longdouble(x)); 122 } 123 else 124 { 125 if (real_t(cast(ulong)x) == x) 126 { 127 // ((1.5 -> 1 -> 1.0) == 1.5) is false 128 // ((1.0 -> 1 -> 1.0) == 1.0) is true 129 // see http://en.cppreference.com/w/cpp/io/c/fprintf 130 char[5] sfmt = "%#Lg\0"; 131 sfmt[3] = fmt; 132 return sprintf(str, sfmt.ptr, x); 133 } 134 else 135 { 136 char[4] sfmt = "%Lg\0"; 137 sfmt[2] = fmt; 138 return sprintf(str, sfmt.ptr, x); 139 } 140 } 141 } 142 143 // Constant real values 0, 1, -1 and 0.5. 144 static __gshared real_t zero = real_t(0); 145 static __gshared real_t one = real_t(1); 146 static __gshared real_t minusone = real_t(-1); 147 static __gshared real_t half = real_t(0.5); 148 }