trighypf.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /*++
  2. Copyright (c) 2017 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. trighypf.c
  9. Abstract:
  10. This module implements support for the hyperbolic trigonometric functions:
  11. sinh, cosh, and tanh.
  12. Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  13. Developed at SunPro, a Sun Microsystems, Inc. business.
  14. Permission to use, copy, modify, and distribute this
  15. software is freely granted, provided that this notice
  16. is preserved.
  17. Author:
  18. Chris Stevens 5-Jan-2017
  19. Environment:
  20. User Mode C Library
  21. --*/
  22. //
  23. // ------------------------------------------------------------------- Includes
  24. //
  25. #include "../libcp.h"
  26. #include "mathp.h"
  27. //
  28. // ---------------------------------------------------------------- Definitions
  29. //
  30. #define FLOAT_NINE_WORD 0x41100000
  31. #define FLOAT_SINH_TINY_WORD 0x39800000
  32. #define FLOAT_SINH_MID_RANGE_WORD 0x42B17217
  33. #define FLOAT_SINH_OVERFLOW_WORD 0x42B2d4FC
  34. #define FLOAT_COSH_HALF_LN_2_WORD 0x3EB17218
  35. #define FLOAT_COSH_TINY_WORD 0x39800000
  36. #define FLOAT_COSH_HUGE_WORD 0x42B17217
  37. #define FLOAT_COSH_HUGE_THRESHOLD_WORD 0x42B2D4FC
  38. #define FLOAT_TANH_TINY_WORD 0x39800000
  39. //
  40. // ------------------------------------------------------ Data Type Definitions
  41. //
  42. //
  43. // ----------------------------------------------- Internal Function Prototypes
  44. //
  45. float
  46. ClpFloatLoadExponentExpBig (
  47. float Value,
  48. int Exponent
  49. );
  50. float
  51. ClpFloatExpBig (
  52. float Value,
  53. int *Exponent
  54. );
  55. //
  56. // -------------------------------------------------------------------- Globals
  57. //
  58. const float ClFloatSinhHuge = 1.0e37;
  59. const ULONG ClFloatExpReductionConstant = 235;
  60. const float ClFloatExpReductionConstantTimesLn2 = 162.88958740;
  61. //
  62. // ------------------------------------------------------------------ Functions
  63. //
  64. LIBC_API
  65. float
  66. sinhf (
  67. float Value
  68. )
  69. /*++
  70. Routine Description:
  71. This routine computes the hyperbolic sine of the given value.
  72. Arguments:
  73. Value - Supplies the value to take the hyperbolic sine of.
  74. Return Value:
  75. Returns the hyperbolic sine on success.
  76. +/- HUGE_VAL (with the same sign as the value) if the result cannot be
  77. represented.
  78. NaN if the input is NaN.
  79. Returns the value itself if the given value is +/- 0 or +/- Infinity.
  80. --*/
  81. {
  82. LONG AbsoluteWord;
  83. float ExpMinusOne;
  84. float Half;
  85. LONG Word;
  86. FLOAT_PARTS Parts;
  87. Parts.Float= Value;
  88. Word = Parts.Ulong;
  89. AbsoluteWord = Word & ~FLOAT_SIGN_BIT;
  90. //
  91. // Handle Infinity or NaN.
  92. //
  93. if (AbsoluteWord >= FLOAT_NAN) {
  94. return Value + Value;
  95. }
  96. Half = 0.5;
  97. if (Word < 0) {
  98. Half = -Half;
  99. }
  100. //
  101. // If the |Value| is between [0,9], return
  102. // sign(Value) * 0.5 * (E + E / (E + 1)).
  103. //
  104. if (AbsoluteWord < FLOAT_NINE_WORD) {
  105. if (AbsoluteWord < FLOAT_SINH_TINY_WORD ) {
  106. if (ClFloatSinhHuge + Value > ClFloatOne) {
  107. //
  108. // With very tiny values, sinh(x) is x with an inexact
  109. // condition.
  110. //
  111. return Value;
  112. }
  113. }
  114. ExpMinusOne = expm1f(fabsf(Value));
  115. if (AbsoluteWord < FLOAT_ONE_WORD) {
  116. return Half *
  117. ((float)2.0 * ExpMinusOne - ExpMinusOne * ExpMinusOne /
  118. (ExpMinusOne + ClFloatOne));
  119. }
  120. return Half * (ExpMinusOne + ExpMinusOne / (ExpMinusOne + ClFloatOne));
  121. }
  122. //
  123. // For |Value| in [9, log(maxfloat)] return 0.5 * exp(|Value|).
  124. //
  125. if (AbsoluteWord < FLOAT_SINH_MID_RANGE_WORD) {
  126. return Half * expf(fabsf(Value));
  127. }
  128. //
  129. // For |Value| in [log(maxfloat), overflowthresold].
  130. //
  131. if (AbsoluteWord <= FLOAT_SINH_OVERFLOW_WORD) {
  132. return Half * (float)2.0 * ClpFloatLoadExponentExpBig(fabsf(Value), -1);
  133. }
  134. //
  135. // Finally, for absolute values greater than the overflow threshold, cause
  136. // an overflow.
  137. //
  138. return Value * ClFloatSinhHuge;
  139. }
  140. LIBC_API
  141. float
  142. coshf (
  143. float Value
  144. )
  145. /*++
  146. Routine Description:
  147. This routine computes the hyperbolic cosine of the given value.
  148. Arguments:
  149. Value - Supplies the value to take the hyperbolic cosine of.
  150. Return Value:
  151. Returns the hyperbolic cosine on success.
  152. +/- HUGE_VAL (with the same sign as the value) if the result cannot be
  153. represented.
  154. NaN if the input is NaN.
  155. 1.0 if the value is +/- 0.
  156. +Infinity if the value is +/- Infinity.
  157. --*/
  158. {
  159. LONG AbsoluteWord;
  160. float Exponential;
  161. float ExponentialPlusOne;
  162. FLOAT_PARTS Parts;
  163. Parts.Float = Value;
  164. AbsoluteWord = Parts.Ulong & ~FLOAT_SIGN_BIT;
  165. //
  166. // Handle Infinity or NaN.
  167. //
  168. if (AbsoluteWord >= FLOAT_NAN) {
  169. return Value * Value;
  170. }
  171. //
  172. // If |Value| is in [0, 0.5 * ln2], return
  173. // 1 * expm1f(|Value|)^2 / (2 * expf(|Value|))
  174. //
  175. if (AbsoluteWord <= FLOAT_COSH_HALF_LN_2_WORD) {
  176. Exponential = expm1f(fabsf(Value));
  177. ExponentialPlusOne = ClFloatOne + Exponential;
  178. //
  179. // The cosh of a tiny value is 1.
  180. //
  181. if (AbsoluteWord < FLOAT_COSH_TINY_WORD) {
  182. return ClFloatOne;
  183. }
  184. return ClFloatOne + (Exponential * Exponential) /
  185. (ExponentialPlusOne + ExponentialPlusOne);
  186. }
  187. //
  188. // If |Value| is in [0.5*ln2, 9], return
  189. // (expf(|Value|) + 1 / expf(|Value|) / 2.
  190. //
  191. if (AbsoluteWord < FLOAT_NINE_WORD) {
  192. Exponential = expf(fabsf(Value));
  193. return ClFloatOneHalf * Exponential + ClFloatOneHalf / Exponential;
  194. }
  195. //
  196. // If |Value| is in [9, log(maxdouble)] return 0.5 * exp(|Value|).
  197. //
  198. if (AbsoluteWord < FLOAT_COSH_HUGE_WORD) {
  199. return ClFloatOneHalf * expf(fabsf(Value));
  200. }
  201. //
  202. // If |Value| is in [log(maxdouble), overflowthresold].
  203. //
  204. if (AbsoluteWord <= FLOAT_COSH_HUGE_THRESHOLD_WORD) {
  205. return ClpFloatLoadExponentExpBig(fabsf(Value), -1);
  206. }
  207. //
  208. // The value is really big, return an overflow.
  209. //
  210. return ClFloatHugeValue * ClFloatHugeValue;
  211. }
  212. LIBC_API
  213. float
  214. tanhf (
  215. float Value
  216. )
  217. /*++
  218. Routine Description:
  219. This routine computes the hyperbolic tangent of the given value.
  220. Arguments:
  221. Value - Supplies the value to take the hyperbolic tangent of.
  222. Return Value:
  223. Returns the hyperbolic tangent on success.
  224. Returns the value itself if the value is +/- 0.
  225. Returns +/- 1 if the value is +/- Infinity.
  226. Returns the value itself with a range error if the value is subnormal.
  227. --*/
  228. {
  229. LONG AbsoluteWord;
  230. float ExpMinusOne;
  231. FLOAT_PARTS Parts;
  232. float Result;
  233. LONG Word;
  234. Parts.Float = Value;
  235. Word = Parts.Ulong;
  236. AbsoluteWord = Word & ~FLOAT_SIGN_BIT;
  237. //
  238. // Handle Inf or NaN.
  239. //
  240. if (AbsoluteWord >= FLOAT_NAN) {
  241. //
  242. // Tanh(+-Infinity) = +-1.
  243. //
  244. if (Word >= 0) {
  245. return ClFloatOne / Value + ClFloatOne;
  246. //
  247. // Tanh(NaN) = NaN.
  248. //
  249. } else {
  250. return ClFloatOne / Value - ClFloatOne;
  251. }
  252. }
  253. //
  254. // Handle |Values| < 9.
  255. //
  256. if (AbsoluteWord < FLOAT_NINE_WORD) {
  257. if (AbsoluteWord < FLOAT_TANH_TINY_WORD) {
  258. //
  259. // Tanh of a tiny value is a tiny value with inexact.
  260. //
  261. if (ClFloatHugeValue + Value > ClFloatOne) {
  262. return Value;
  263. }
  264. }
  265. if (AbsoluteWord >= FLOAT_ONE_WORD) {
  266. ExpMinusOne = expm1f((float)2.0 * fabsf(Value));
  267. Result = ClFloatOne - (float)2.0 / (ExpMinusOne + (float)2.0);
  268. } else {
  269. ExpMinusOne = expm1f((float)-2.0 * fabsf(Value));
  270. Result= -ExpMinusOne / (ExpMinusOne + (float)2.0);
  271. }
  272. //
  273. // If the |Value) is >= 9, return +-1.
  274. //
  275. } else {
  276. //
  277. // Raise the inexact flag.
  278. //
  279. Result = ClFloatOne - ClFloatTinyValue;
  280. }
  281. if (Word >= 0) {
  282. return Result;
  283. }
  284. return -Result;
  285. }
  286. //
  287. // --------------------------------------------------------- Internal Functions
  288. //
  289. float
  290. ClpFloatLoadExponentExpBig (
  291. float Value,
  292. int Exponent
  293. )
  294. /*++
  295. Routine Description:
  296. This routine computes exp(x) * 2^Exponent. They are intended for large
  297. arguments (real part >= ln(DBL_MAX)), where care is needed to avoid
  298. overflow. This implementation is narrowly tailored for the hyperbolic
  299. and exponential function; it assumes the exponent is small (0 or -1) and
  300. the caller has filtered out very large values for which the overflow would
  301. be inevitable.
  302. Arguments:
  303. Value - Supplies the input value of the computation.
  304. Exponent - Supplies the exponent.
  305. Return Value:
  306. Returns the exponential * 2^Exponent.
  307. --*/
  308. {
  309. int ExpExponent;
  310. float ExpResult;
  311. FLOAT_PARTS Parts;
  312. float Scale;
  313. ExpResult = ClpFloatExpBig(Value, &ExpExponent);
  314. Exponent += ExpExponent;
  315. Parts.Ulong = (FLOAT_EXPONENT_BIAS + Exponent) << FLOAT_EXPONENT_SHIFT;
  316. Scale = Parts.Float;
  317. return ExpResult * Scale;
  318. }
  319. float
  320. ClpFloatExpBig (
  321. float Value,
  322. int *Exponent
  323. )
  324. /*++
  325. Routine Description:
  326. This routine computes exp(x), scaled to avoid spurious overflow. An
  327. exponent is returned separately. The input is assumed to be >= ln(DBL_MAX)
  328. and < ln(2 * DBL_MAX / DBL_MIN_DENORM) ~= 129.7.
  329. Arguments:
  330. Value - Supplies the input value of the computation.
  331. Exponent - Supplies a pointer where the exponent will be returned.
  332. Return Value:
  333. Returns expf(Value), somewhere between 2^127 and 2^128.
  334. --*/
  335. {
  336. float ExpResult;
  337. ULONG Word;
  338. FLOAT_PARTS Parts;
  339. //
  340. // Use expf(Value) = expf(Value - kln2) * 2^k, carefully chosen to
  341. // minimize |expf(kln2) - 2^k|. Aalso scale the exponent to MAX_EXP so
  342. // that the result can be multiplied by a tiny number without losing
  343. // accuracy due to denormalization.
  344. //
  345. ExpResult = expf(Value - ClFloatExpReductionConstantTimesLn2);
  346. Parts.Float = ExpResult;
  347. Word = Parts.Ulong;
  348. *Exponent = (Word >> FLOAT_EXPONENT_SHIFT) -
  349. (FLOAT_EXPONENT_BIAS + 127) + ClFloatExpReductionConstant;
  350. Parts.Ulong = (Word & FLOAT_VALUE_MASK) |
  351. ((FLOAT_EXPONENT_BIAS + 127) << FLOAT_EXPONENT_SHIFT);
  352. return Parts.Float;
  353. }