PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/dmd/root/longdouble.h

https://github.com/ldc-developers/ldc
C Header | 267 lines | 191 code | 50 blank | 26 comment | 9 complexity | 3696a51e048ed4c3966f27d58deed748 MD5 | raw file
  1. /* Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
  2. * written by Rainer Schuetze
  3. * https://www.digitalmars.com
  4. * Distributed under the Boost Software License, Version 1.0.
  5. * https://www.boost.org/LICENSE_1_0.txt
  6. * https://github.com/dlang/dmd/blob/master/src/dmd/root/longdouble.h
  7. */
  8. // 80 bit floating point value implementation for Microsoft compiler
  9. #pragma once
  10. #if !_MSC_VER // has native 10 byte doubles
  11. #include <stdio.h>
  12. typedef long double longdouble;
  13. typedef volatile long double volatile_longdouble;
  14. // also used from within C code, so use a #define rather than a template
  15. // template<typename T> longdouble ldouble(T x) { return (longdouble) x; }
  16. #define ldouble(x) ((longdouble)(x))
  17. #if __MINGW32__
  18. // MinGW supports 80 bit reals, but the formatting functions map to versions
  19. // from the MSVC runtime by default which don't.
  20. #define sprintf __mingw_sprintf
  21. #endif
  22. inline size_t ld_sprint(char* str, int fmt, longdouble x)
  23. {
  24. if (((longdouble)(unsigned long long)x) == x)
  25. { // ((1.5 -> 1 -> 1.0) == 1.5) is false
  26. // ((1.0 -> 1 -> 1.0) == 1.0) is true
  27. // see https://en.cppreference.com/w/cpp/io/c/fprintf
  28. char sfmt[5] = "%#Lg";
  29. sfmt[3] = fmt;
  30. return sprintf(str, sfmt, x);
  31. }
  32. else
  33. {
  34. char sfmt[4] = "%Lg";
  35. sfmt[2] = fmt;
  36. return sprintf(str, sfmt, x);
  37. }
  38. }
  39. #if __MINGW32__
  40. #undef sprintf
  41. #endif
  42. #else
  43. #include <float.h>
  44. #include <limits>
  45. struct longdouble_soft;
  46. // implemented in longdouble.d
  47. double ld_read(const longdouble_soft* const ld);
  48. long long ld_readll(const longdouble_soft* const ld);
  49. unsigned long long ld_readull(const longdouble_soft* const ld);
  50. void ld_set(longdouble_soft* ld, double d);
  51. void ld_setll(longdouble_soft* ld, long long d);
  52. void ld_setull(longdouble_soft* ld, unsigned long long d);
  53. int ld_statusfpu();
  54. void ld_clearfpu();
  55. int ld_initfpu(int bits, int mask);
  56. void ld_expl(longdouble_soft* ld, int exp);
  57. bool ld_cmpb(longdouble_soft ld1, longdouble_soft ld2);
  58. bool ld_cmpbe(longdouble_soft ld1, longdouble_soft ld2);
  59. bool ld_cmpa(longdouble_soft ld1, longdouble_soft ld2);
  60. bool ld_cmpae(longdouble_soft ld1, longdouble_soft ld2);
  61. bool ld_cmpe(longdouble_soft ld1, longdouble_soft ld2);
  62. bool ld_cmpne(longdouble_soft ld1, longdouble_soft ld2);
  63. int ld_cmp(longdouble_soft x, longdouble_soft y);
  64. longdouble_soft ld_add(longdouble_soft ld1, longdouble_soft ld2);
  65. longdouble_soft ld_sub(longdouble_soft ld1, longdouble_soft ld2);
  66. longdouble_soft ld_mul(longdouble_soft ld1, longdouble_soft ld2);
  67. longdouble_soft ld_div(longdouble_soft ld1, longdouble_soft ld2);
  68. longdouble_soft ld_mod(longdouble_soft ld1, longdouble_soft ld2);
  69. longdouble_soft ld_sqrt(longdouble_soft ld1);
  70. longdouble_soft ld_sin(longdouble_soft ld1);
  71. longdouble_soft ld_cos(longdouble_soft ld1);
  72. longdouble_soft ld_tan(longdouble_soft ld1);
  73. #pragma pack(push, 1)
  74. struct longdouble_soft
  75. {
  76. unsigned long long mantissa;
  77. unsigned short exponent:15; // bias 0x3fff
  78. unsigned short sign:1;
  79. // no constructor to be able to use this class in a union
  80. // use ldouble() to explicitly create a longdouble_soft value
  81. template<typename T> longdouble_soft& operator=(T x) { set(x); return *this; }
  82. void set(longdouble_soft ld) { mantissa = ld.mantissa; exponent = ld.exponent; sign = ld.sign; }
  83. // we need to list all basic types to avoid ambiguities
  84. void set(float d) { ld_set(this, d); }
  85. void set(double d) { ld_set(this, d); }
  86. void set(long double d) { ld_set(this, d); }
  87. void set(signed char d) { ld_set(this, d); }
  88. void set(short d) { ld_set(this, d); }
  89. void set(int d) { ld_set(this, d); }
  90. void set(long d) { ld_set(this, d); }
  91. void set(long long d) { ld_setll(this, d); }
  92. void set(unsigned char d) { ld_set(this, d); }
  93. void set(unsigned short d) { ld_set(this, d); }
  94. void set(unsigned int d) { ld_set(this, d); }
  95. void set(unsigned long d) { ld_set(this, d); }
  96. void set(unsigned long long d) { ld_setull(this, d); }
  97. void set(bool d) { ld_set(this, d); }
  98. operator float () const { return ld_read(this); }
  99. operator double () const { return ld_read(this); }
  100. operator signed char () const { return ld_read(this); }
  101. operator short () const { return ld_read(this); }
  102. operator int () const { return ld_read(this); }
  103. operator long () const { return ld_read(this); }
  104. operator long long () const { return ld_readll(this); }
  105. operator unsigned char () const { return ld_read(this); }
  106. operator unsigned short () const { return ld_read(this); }
  107. operator unsigned int () const { return ld_read(this); }
  108. operator unsigned long () const { return ld_read(this); }
  109. operator unsigned long long() const { return ld_readull(this); }
  110. operator bool () const { return mantissa != 0 || exponent != 0; } // correct?
  111. };
  112. #pragma pack(pop)
  113. // static_assert(sizeof(longdouble_soft) == 10, "bad sizeof longdouble_soft");
  114. inline longdouble_soft ldouble(unsigned long long mantissa, int exp, int sign = 0)
  115. {
  116. longdouble_soft d;
  117. d.mantissa = mantissa;
  118. d.exponent = exp;
  119. d.sign = sign;
  120. return d;
  121. }
  122. // codegen bug in VS2010/VS2012, if the set() function not inlined
  123. // (this passed on stack, but expected in ECX; RVO?)
  124. #if _MSC_VER >= 1600
  125. #define LDOUBLE_INLINE __declspec(noinline)
  126. #else
  127. #define LDOUBLE_INLINE inline
  128. #endif
  129. template<typename T> LDOUBLE_INLINE longdouble_soft ldouble(T x) { longdouble_soft d; d.set(x); return d; }
  130. #undef LDOUBLE_INLINE
  131. inline longdouble_soft operator+(longdouble_soft ld1, longdouble_soft ld2) { return ld_add(ld1, ld2); }
  132. inline longdouble_soft operator-(longdouble_soft ld1, longdouble_soft ld2) { return ld_sub(ld1, ld2); }
  133. inline longdouble_soft operator*(longdouble_soft ld1, longdouble_soft ld2) { return ld_mul(ld1, ld2); }
  134. inline longdouble_soft operator/(longdouble_soft ld1, longdouble_soft ld2) { return ld_div(ld1, ld2); }
  135. inline bool operator< (longdouble_soft ld1, longdouble_soft ld2) { return ld_cmpb(ld1, ld2); }
  136. inline bool operator<=(longdouble_soft ld1, longdouble_soft ld2) { return ld_cmpbe(ld1, ld2); }
  137. inline bool operator> (longdouble_soft ld1, longdouble_soft ld2) { return ld_cmpa(ld1, ld2); }
  138. inline bool operator>=(longdouble_soft ld1, longdouble_soft ld2) { return ld_cmpae(ld1, ld2); }
  139. inline bool operator==(longdouble_soft ld1, longdouble_soft ld2) { return ld_cmpe(ld1, ld2); }
  140. inline bool operator!=(longdouble_soft ld1, longdouble_soft ld2) { return ld_cmpne(ld1, ld2); }
  141. inline longdouble_soft operator-(longdouble_soft ld1) { ld1.sign ^= 1; return ld1; }
  142. inline longdouble_soft operator+(longdouble_soft ld1) { return ld1; }
  143. template<typename T> inline longdouble_soft operator+(longdouble_soft ld, T x) { return ld + ldouble(x); }
  144. template<typename T> inline longdouble_soft operator-(longdouble_soft ld, T x) { return ld - ldouble(x); }
  145. template<typename T> inline longdouble_soft operator*(longdouble_soft ld, T x) { return ld * ldouble(x); }
  146. template<typename T> inline longdouble_soft operator/(longdouble_soft ld, T x) { return ld / ldouble(x); }
  147. template<typename T> inline longdouble_soft operator+(T x, longdouble_soft ld) { return ldouble(x) + ld; }
  148. template<typename T> inline longdouble_soft operator-(T x, longdouble_soft ld) { return ldouble(x) - ld; }
  149. template<typename T> inline longdouble_soft operator*(T x, longdouble_soft ld) { return ldouble(x) * ld; }
  150. template<typename T> inline longdouble_soft operator/(T x, longdouble_soft ld) { return ldouble(x) / ld; }
  151. template<typename T> inline longdouble_soft& operator+=(longdouble_soft& ld, T x) { return ld = ld + x; }
  152. template<typename T> inline longdouble_soft& operator-=(longdouble_soft& ld, T x) { return ld = ld - x; }
  153. template<typename T> inline longdouble_soft& operator*=(longdouble_soft& ld, T x) { return ld = ld * x; }
  154. template<typename T> inline longdouble_soft& operator/=(longdouble_soft& ld, T x) { return ld = ld / x; }
  155. template<typename T> inline bool operator< (longdouble_soft ld, T x) { return ld < ldouble(x); }
  156. template<typename T> inline bool operator<=(longdouble_soft ld, T x) { return ld <= ldouble(x); }
  157. template<typename T> inline bool operator> (longdouble_soft ld, T x) { return ld > ldouble(x); }
  158. template<typename T> inline bool operator>=(longdouble_soft ld, T x) { return ld >= ldouble(x); }
  159. template<typename T> inline bool operator==(longdouble_soft ld, T x) { return ld == ldouble(x); }
  160. template<typename T> inline bool operator!=(longdouble_soft ld, T x) { return ld != ldouble(x); }
  161. template<typename T> inline bool operator< (T x, longdouble_soft ld) { return ldouble(x) < ld; }
  162. template<typename T> inline bool operator<=(T x, longdouble_soft ld) { return ldouble(x) <= ld; }
  163. template<typename T> inline bool operator> (T x, longdouble_soft ld) { return ldouble(x) > ld; }
  164. template<typename T> inline bool operator>=(T x, longdouble_soft ld) { return ldouble(x) >= ld; }
  165. template<typename T> inline bool operator==(T x, longdouble_soft ld) { return ldouble(x) == ld; }
  166. template<typename T> inline bool operator!=(T x, longdouble_soft ld) { return ldouble(x) != ld; }
  167. int _isnan(longdouble_soft ld);
  168. longdouble_soft fabsl(longdouble_soft ld);
  169. longdouble_soft sqrtl(longdouble_soft ld);
  170. longdouble_soft sinl (longdouble_soft ld);
  171. longdouble_soft cosl (longdouble_soft ld);
  172. longdouble_soft tanl (longdouble_soft ld);
  173. longdouble_soft fmodl(longdouble_soft x, longdouble_soft y);
  174. longdouble_soft ldexpl(longdouble_soft ldval, int exp); // see strtold
  175. inline longdouble_soft fabs (longdouble_soft ld) { return fabsl(ld); }
  176. inline longdouble_soft sqrt (longdouble_soft ld) { return sqrtl(ld); }
  177. #if !IN_LLVM
  178. #undef LDBL_DIG
  179. #undef LDBL_MAX
  180. #undef LDBL_MIN
  181. #undef LDBL_EPSILON
  182. #undef LDBL_MANT_DIG
  183. #undef LDBL_MAX_EXP
  184. #undef LDBL_MIN_EXP
  185. #undef LDBL_MAX_10_EXP
  186. #undef LDBL_MIN_10_EXP
  187. #define LDBL_DIG 18
  188. #define LDBL_MAX ldouble(0xffffffffffffffffULL, 0x7ffe)
  189. #define LDBL_MIN ldouble(0x8000000000000000ULL, 1)
  190. #define LDBL_EPSILON ldouble(0x8000000000000000ULL, 0x3fff - 63) // allow denormal?
  191. #define LDBL_MANT_DIG 64
  192. #define LDBL_MAX_EXP 16384
  193. #define LDBL_MIN_EXP (-16381)
  194. #define LDBL_MAX_10_EXP 4932
  195. #define LDBL_MIN_10_EXP (-4932)
  196. #endif // !IN_LLVM
  197. extern const longdouble_soft ld_qnan;
  198. extern const longdouble_soft ld_inf;
  199. extern const longdouble_soft ld_zero;
  200. extern const longdouble_soft ld_one;
  201. extern const longdouble_soft ld_pi;
  202. extern const longdouble_soft ld_log2t;
  203. extern const longdouble_soft ld_log2e;
  204. extern const longdouble_soft ld_log2;
  205. extern const longdouble_soft ld_ln2;
  206. extern const longdouble_soft ld_pi2;
  207. extern const longdouble_soft ld_piOver2;
  208. extern const longdouble_soft ld_piOver4;
  209. size_t ld_sprint(char* str, int fmt, longdouble_soft x);
  210. //////////////////////////////////////////////
  211. typedef longdouble_soft longdouble;
  212. // some optimizations are avoided by adding volatile to the longdouble_soft
  213. // type, but this introduces bad ambiguities when using the class implementation above
  214. // as we are going through asm these optimizations won't kick in anyway, so "volatile"
  215. // is not required.
  216. typedef longdouble_soft volatile_longdouble;
  217. #endif // !_MSC_VER