Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

747 lines
24 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Contains macros for helping with floating point arithmetic.
  8. *
  9. * History:
  10. *
  11. * 07/08/1999 agodfrey
  12. * Remove MSVCRT dependency.
  13. * 12/06/1998 andrewgo
  14. * Created it.
  15. *
  16. \**************************************************************************/
  17. #ifndef _REAL_HPP_
  18. #define _REAL_HPP_
  19. // The following stuff is taken from Office code
  20. /*****************************************************************************
  21. Intrinsic functions - it is essential that these be used because there is
  22. no library implementation. Note that the intrinsic forms often have
  23. restricted behavior, e.g. the argument to a trignometric function must be
  24. less than 2^63 radians.
  25. ******************************************************************* JohnBo **/
  26. #pragma intrinsic(sin, cos, tan)
  27. #pragma intrinsic(atan, atan2)
  28. #pragma intrinsic(sqrt)
  29. #pragma intrinsic(log, log10, exp)
  30. #pragma intrinsic(fabs)
  31. #pragma intrinsic(fmod)
  32. namespace GpRuntime
  33. {
  34. /*
  35. [JohnBo]
  36. These in-line functions are required to force direct use of the
  37. instructions - without this the CI versions are used unless g optimization
  38. is switched on, with g optimization on the in-line function calls will be
  39. removed completely.
  40. */
  41. #pragma optimize("g", on)
  42. inline double InlineSin(double x) { return sin(x); }
  43. inline double InlineCos(double x) { return cos(x); }
  44. inline double InlineTan(double x) { return tan(x); }
  45. inline double InlineATan(double x) { return atan(x); }
  46. inline double InlineATan2(double y, double x) { return atan2(y, x); }
  47. inline double InlineSqrt(double x) { return sqrt(x); }
  48. inline double InlineLog(double x) { return log(x); }
  49. inline double InlineLog10(double x) { return log10(x); }
  50. inline double InlineExp(double x) { return exp(x); }
  51. /* Restore default optimization. */
  52. #pragma optimize("", on)
  53. // Out-of-line math functions
  54. // pow: We implemented it ourselves
  55. // exp: Because the inline version is so long, the compiler won't
  56. // inline it unless the original caller has 'generate fast code'
  57. // set. Instead, we use an out-of-line version.
  58. double Pow(double, double);
  59. double Exp(double);
  60. /*// Trying something:
  61. inline double FPX86InlineFmod(double x, double y) { return fmod(x,y); }
  62. #define fmod(x,y) FPX86InlineFmod(x,y)
  63. */
  64. };
  65. /* Force use of the in-line functions. */
  66. #define sin(x) GpRuntime::InlineSin(x)
  67. #define cos(x) GpRuntime::InlineCos(x)
  68. #define tan(x) GpRuntime::InlineTan(x)
  69. #define atan(x) GpRuntime::InlineATan(x)
  70. #define atan2(y,x) GpRuntime::InlineATan2(y,x)
  71. #define sqrt(x) GpRuntime::InlineSqrt(x)
  72. #define log(x) GpRuntime::InlineLog(x)
  73. #define log10(x) GpRuntime::InlineLog10(x)
  74. #define exp(x) GpRuntime::Exp(x)
  75. #define pow(x,y) GpRuntime::Pow(x,y)
  76. /* Integer interfaces */
  77. #pragma intrinsic(abs, labs)
  78. // End of Office code
  79. // Our pixel positioning uses 28.4 fixed point arithmetic and therefore
  80. // anything below the threshold of 1/32 should be irrelevant.
  81. // Our choice of PIXEL_EPSILON is 1/64 which should give us correct pixel
  82. // comparisons even in the event of accumulated floating point error.
  83. #define PIXEL_EPSILON 0.015625f // 1/64
  84. #ifndef REAL_EPSILON
  85. #define REAL_EPSILON FLT_EPSILON
  86. #endif
  87. // This is for computing the complexity of matrices. When you compose matrices
  88. // or scale them up by large factors, it's really easy to hit the REAL_EPSILON
  89. // limits without actually affecting the transform in any noticable way.
  90. // e.g. a matrix with a rotation of 1e-5 degrees is, for all practical purposes,
  91. // not a rotation.
  92. #define CPLX_EPSILON (REAL_EPSILON*5000.0f)
  93. // This is a tolerance error for the difference of each real coordinates.
  94. // This leaves some acurracy to calculate tangent or normal for the two points.
  95. #define POINTF_EPSILON (REAL_EPSILON*5000.0f)
  96. #define REALFMOD fmodf
  97. #define REALSQRT sqrtf
  98. #ifndef REALABS
  99. #define REALABS fabsf
  100. #endif
  101. #define REALSIN sinf
  102. #define REALCOS cosf
  103. #define REALATAN2 atan2f
  104. // #define REAL_EPSILON DBL_EPSILON
  105. // #define REALFMOD fmod
  106. // #define REALSQRT sqrt
  107. // #define REALABS fabs
  108. // #define REALSIN sin
  109. // #define REALCOS cos
  110. // #define REALATAN2 atan2
  111. // convert from unknown FLOAT type => REAL
  112. #define TOREAL(x) (static_cast<REAL>(x))
  113. // defined separately for possibly future optimization LONG to REAL
  114. #define LTOF(x) (static_cast<REAL>(x))
  115. // Return the positive integer remainder of a/b. b should not be zero.
  116. // note that a % b will return a negative number
  117. // for a<0 xor b<0 which is not suitable for texture mapping
  118. // or brush tiling.
  119. // This macro computes the remainder of a/b
  120. // correctly adjusted for tiling negative coordinates.
  121. #define RemainderI(a, b)\
  122. ((a) >= 0 ? (a) % (b) : \
  123. (b) - 1 - ((-(a) - 1) % (b)))
  124. // This definition assumes y > 0
  125. inline REAL GpModF(REAL x, REAL y)
  126. {
  127. if(x > 0)
  128. {
  129. return static_cast<REAL> (x - ((INT) (x/y))*y);
  130. }
  131. else if(x < 0)
  132. {
  133. REAL z;
  134. x = - x;
  135. z = static_cast<REAL> (x - ((INT) (x/y))*y);
  136. if(z > 0)
  137. z = y - z;
  138. return z;
  139. }
  140. else // x == 0
  141. return 0.0;
  142. /*
  143. // This assumes fmod(x, y) = - fmod(-x, y) when x < 0.
  144. REAL z = REALFMOD(x, y);
  145. if(z >= 0)
  146. return z;
  147. else
  148. return y + z;
  149. */
  150. }
  151. #if defined(_X86_) && !defined(_COMPLUS_GDI)
  152. #define _USE_X86_ASSEMBLY
  153. #else
  154. #undef _USE_X86_ASSEMBLY
  155. #endif
  156. #if defined(_USE_X86_ASSEMBLY)
  157. #define FPU_STATE() \
  158. UINT32 cwSave; \
  159. UINT32 cwTemp;
  160. #define FPU_GET_STATE() \
  161. UINT32 cwSave = this->cwSave; \
  162. UINT32 cwTemp = this->cwTemp;
  163. #define FPU_SAVE_STATE() \
  164. this->cwSave = cwSave; \
  165. this->cwTemp = cwTemp;
  166. #define FPU_SAVE_MODE() \
  167. UINT32 cwSave; \
  168. UINT32 cwTemp; \
  169. \
  170. __asm { \
  171. _asm fnstcw WORD PTR cwSave \
  172. _asm mov eax, cwSave \
  173. _asm mov cwTemp, eax \
  174. } \
  175. this->cwSave =
  176. #define FPU_RESTORE_MODE() \
  177. __asm { \
  178. _asm fldcw WORD PTR cwSave \
  179. }
  180. #define FPU_RESTORE_MODE_NO_EXCEPTIONS()\
  181. __asm { \
  182. _asm fnclex \
  183. _asm fldcw WORD PTR cwSave \
  184. }
  185. #define FPU_CHOP_ON() \
  186. __asm { \
  187. _asm mov eax, cwTemp \
  188. _asm or eax, 0x0c00 \
  189. _asm mov cwTemp, eax \
  190. _asm fldcw WORD PTR cwTemp \
  191. }
  192. #define FPU_ROUND_ON() \
  193. __asm { \
  194. _asm mov eax, cwTemp \
  195. _asm and eax,0xf3ff \
  196. _asm mov cwTemp, eax \
  197. _asm fldcw WORD PTR cwTemp \
  198. }
  199. #define FPU_ROUND_ON_PREC_HI() \
  200. __asm { \
  201. _asm mov eax, cwTemp \
  202. _asm and eax,0xf0ff \
  203. _asm or eax,0x0200 \
  204. _asm mov cwTemp, eax \
  205. _asm fldcw WORD PTR cwTemp \
  206. }
  207. #define FPU_PREC_LOW() \
  208. __asm { \
  209. _asm mov eax, cwTemp \
  210. _asm and eax, 0xfcff \
  211. _asm mov cwTemp, eax \
  212. _asm fldcw WORD PTR cwTemp \
  213. }
  214. #define FPU_PREC_LOW_MASK_EXCEPTIONS() \
  215. __asm { \
  216. _asm mov eax, cwTemp \
  217. _asm and eax, 0xfcff \
  218. _asm or eax, 0x3f \
  219. _asm mov cwTemp, eax \
  220. _asm fldcw WORD PTR cwTemp \
  221. }
  222. #define FPU_CHOP_ON_PREC_LOW() \
  223. __asm { \
  224. _asm mov eax, cwTemp \
  225. _asm or eax, 0x0c00 \
  226. _asm and eax, 0xfcff \
  227. _asm mov cwTemp, eax \
  228. _asm fldcw WORD PTR cwTemp \
  229. }
  230. #define FPU_CHOP_OFF_PREC_HI() \
  231. __asm { \
  232. _asm mov eax, cwTemp \
  233. _asm mov ah, 2 \
  234. _asm mov cwTemp, eax \
  235. _asm fldcw WORD PTR cwTemp \
  236. }
  237. #define CHOP_ROUND_ON()
  238. #define CHOP_ROUND_OFF()
  239. #if DBG
  240. #define ASSERT_CHOP_ROUND() \
  241. { \
  242. WORD cw; \
  243. __asm { \
  244. __asm fnstcw cw \
  245. } \
  246. ASSERT((cw & 0xc00) == 0xc00, "Chop round must be on"); \
  247. }
  248. #else
  249. #define ASSERT_CHOP_ROUND()
  250. #endif
  251. #else // _USE_X86_ASSEMBLY
  252. #define FLT_TO_FIX_SCALE(value_in, scale) \
  253. ((INT)((REAL)(value_in) * scale))
  254. #define FLT_TO_UCHAR_SCALE(value_in, scale) \
  255. ((UCHAR)((INT)((REAL)(value_in) * scale)))
  256. #define UNSAFE_FLT_TO_FIX(value_in) \
  257. FLT_TO_FIX(value_in)
  258. #define FPU_SAVE_MODE()
  259. #define FPU_RESTORE_MODE()
  260. #define FPU_RESTORE_MODE_NO_EXCEPTIONS()
  261. #define FPU_CHOP_ON()
  262. #define FPU_ROUND_ON()
  263. #define FPU_ROUND_ON_PREC_HI()
  264. #define FPU_PREC_LOW()
  265. #define FPU_PREC_LOW_MASK_EXCEPTIONS()
  266. #define FPU_CHOP_ON_PREC_LOW()
  267. #define FPU_CHOP_OFF_PREC_HI()
  268. #define CHOP_ROUND_ON()
  269. #define CHOP_ROUND_OFF()
  270. #define ASSERT_CHOP_ROUND()
  271. #endif //_USE_X86_ASSEMBLY
  272. #if defined(_USE_X86_ASSEMBLY)
  273. __inline INT __fastcall FLOOR(
  274. REAL a)
  275. {
  276. INT i;
  277. _asm {
  278. fld a
  279. fistp i
  280. }
  281. return i;
  282. }
  283. // Can cause overflow exceptions
  284. __inline INT __fastcall UNSAFE_FLOOR(
  285. REAL a)
  286. {
  287. INT l;
  288. _asm {
  289. fld a
  290. fistp l
  291. }
  292. return l;
  293. }
  294. #else
  295. #define FLOOR(a) ((INT) floor(a))
  296. #define UNSAFE_FLOOR(a) ((INT) floor(a))
  297. #endif
  298. //--------------------------------------------------------------------------
  299. // Class for invoking 'floor' mode, and restoring it afterwards
  300. //--------------------------------------------------------------------------
  301. // These define the bits in the FPU control word that we care about.
  302. // The high byte 0x0c is the rounding control and the low byte
  303. // 0x3F is the exception mask flags.
  304. #define FP_CTRL_MASK 0x0c3F
  305. // Set the rounding control and mask PE. DE is no longer masked because
  306. // taking the exception can be helpful in finding bugs. However, we should
  307. // probably turn on DE masking when we ship.
  308. // Round Down
  309. #define FP_CTRL_ROUNDDOWN 0x0400
  310. // Mask PE only.
  311. // Use this define to track down nasty FP bugs.
  312. // #define FP_CTRL_MASKEDEXCEPTIONS 0x0020
  313. // Mask all FP exceptions.
  314. #define FP_CTRL_MASKEDEXCEPTIONS 0x003F
  315. #define FP_CTRL_STATE (FP_CTRL_ROUNDDOWN | FP_CTRL_MASKEDEXCEPTIONS)
  316. class FPUStateSaver
  317. {
  318. private:
  319. UINT32 SavedState;
  320. #if DBG
  321. // For AssertMode, we use SaveLevel to keep track
  322. // of the nesting level of FPUState. This is not thread safe.
  323. // At worst, that could cause spurious asserts; more likely it could
  324. // fail to catch some errors. To prevent the spurious asserts,
  325. // used interlocked instructions to modify it. To fix it properly,
  326. // we'd need to use per-thread storage.
  327. static LONG SaveLevel;
  328. #endif
  329. public:
  330. FPUStateSaver()
  331. {
  332. // Here we set our thread's round mode to 'round down', and
  333. // save the old mode. 'Round to nearest' is actually the
  334. // default state for a process, but applications can set it
  335. // to whatever they like, and we should also respect and save
  336. // their preferred mode.
  337. #if defined(_USE_X86_ASSEMBLY)
  338. UINT32 tempState;
  339. UINT32 savedState;
  340. // clear the current exception state.
  341. // fnclex is a non-wait version of fclex - which means it clears
  342. // the exceptions without taking any pending unmasked exceptions.
  343. // We issue a fclex so that any unmasked exceptions are
  344. // triggered immediately. This indicates a bug in the caller
  345. // of the API.
  346. _asm fclex
  347. // Save control word:
  348. _asm fnstcw WORD PTR savedState
  349. this->SavedState = savedState;
  350. // Floor mode on & set up our prefered exception masks
  351. _asm mov eax, savedState
  352. _asm and eax, ~FP_CTRL_MASK
  353. _asm or eax, FP_CTRL_STATE
  354. _asm mov tempState, eax
  355. _asm fldcw WORD PTR tempState
  356. #endif
  357. #if DBG
  358. InterlockedIncrement(&SaveLevel);
  359. #endif
  360. }
  361. ~FPUStateSaver()
  362. {
  363. AssertMode();
  364. #if DBG
  365. InterlockedDecrement(&SaveLevel);
  366. #endif
  367. #if defined(_USE_X86_ASSEMBLY)
  368. UINT32 savedState = this->SavedState;
  369. // Clear the exception state.
  370. // Note: We issue the fwait and then an fnclex - which is equivalent
  371. // to the fclex instruction (9B DB E2) which causes us to
  372. // immediately take any unmasked pending exceptions.
  373. // Because we clear the exception state on the way in, hitting
  374. // an exception on this line means we generated an exception
  375. // in our code (or a call out to other code between the
  376. // FPUStateSaver constructor and destructor nesting) which was
  377. // pending and not handled.
  378. _asm fclex
  379. // Restore control word (rounding mode and exception masks):
  380. _asm fldcw WORD PTR savedState
  381. #endif
  382. }
  383. // AssertMode.
  384. //
  385. // AssertMode does nothing in Free builds, unless the FREE_BUILD_FP_BARRIER
  386. // define is set to 1. Debug builds always have FP barriers.
  387. // If exceptions are unmasked and you're getting delayed FP exceptions,
  388. // turn on the FP barriers and add FPUStateSaver::AssertMode() calls
  389. // bracketing all your calls. This will allow you to isolate the FP
  390. // exception generator.
  391. #define FREE_BUILD_FP_BARRIER 0
  392. #if DBG
  393. static VOID AssertMode();
  394. #else
  395. static VOID AssertMode()
  396. {
  397. #if defined(_USE_X86_ASSEMBLY)
  398. #if FREE_BUILD_FP_BARRIER
  399. _asm fwait
  400. #endif
  401. #endif
  402. }
  403. #endif
  404. //--------------------------------------------------------------------------
  405. // The following conversion routines are MUCH faster than the standard
  406. // C routines, because they assume that the FPU floating point state is
  407. // properly set.
  408. //
  409. // However, because they assume that the FPU floating point state has been
  410. // properly set, they can only be used if an instance of the
  411. // 'FPUStateSaver' class is in scope.
  412. //--------------------------------------------------------------------------
  413. static INT Floor(REAL x)
  414. {
  415. AssertMode();
  416. return((INT) FLOOR(x));
  417. }
  418. static INT Trunc(REAL x)
  419. {
  420. AssertMode();
  421. return (x>=0) ? FLOOR(x) : -FLOOR(-x);
  422. }
  423. static INT Ceiling(REAL x)
  424. {
  425. AssertMode();
  426. return((INT) -FLOOR(-x));
  427. }
  428. static INT Round(REAL x)
  429. {
  430. AssertMode();
  431. return((INT) FLOOR((x) + TOREAL(0.5)));
  432. }
  433. // Saturation versions of the above conversion routines. Don't test for
  434. // equality to INT_MAX because, when converted to floating-point for the
  435. // comparison, the value is (INT_MAX + 1):
  436. #define SATURATE(op) \
  437. static INT op##Sat(REAL x) \
  438. { \
  439. return (x >= INT_MIN) ? ((x < INT_MAX) ? op(x) \
  440. : INT_MAX) \
  441. : INT_MIN; \
  442. }
  443. SATURATE(Floor);
  444. SATURATE(Trunc);
  445. SATURATE(Ceiling);
  446. SATURATE(Round);
  447. #undef SATURATE
  448. };
  449. // FPUStateSandbox
  450. //
  451. // This object is designed to sandbox FPU unsafe code.
  452. // For example, many badly written printer drivers on win9x codebases
  453. // manipulate the FPU state without restoring it on exit. In order to
  454. // prevent code like that from hosing us, we wrap calls to potentially
  455. // unsafe code (like driver escapes) in an FPUStateSandbox.
  456. //
  457. // This will guarantee that after calling the unsafe code, the FPU state
  458. // (rounding mode and exceptions) are reset to our preferred state.
  459. // Because we assume that we're restoring to our preferred state, we
  460. // ASSERT on our preferred state being set on entry. This means that
  461. // the sandbox must be declared inside some top level FPUStateSaver block.
  462. // This condition is not strictly necessary and if there is a requirement
  463. // for an FPUStateSandbox not contained inside an FPUStateSaver, this
  464. // ASSERT can be removed. The sandbox saves the current state and restores
  465. // it on exit, so it can operate outside of our preferred state if required.
  466. //
  467. // So far we've found a number of printer drivers on win9x codebase that
  468. // require sandboxing - e.g. HP4500c pcl.
  469. //
  470. // Couple of caveats: This code is designed to wrap simple calls out of
  471. // GDI+ to the printer driver, such as Escape. It's not intended to be
  472. // nested or for use with GDI+ code. However, nesting will work. In
  473. // particular you should not call FPUStateSaver functions inside of
  474. // an FPUStateSandbox unless you've acquired another nested FPUStateSaver.
  475. // The only anticipated need for this is for sandboxing a callback function
  476. // that calls into our API again. In this case it's ok, because all the
  477. // GDI+ calls will be wrapped by a nested FPUStateSaver acquired at the
  478. // API.
  479. //
  480. // NOTE: The ASSERTs in GpRound will not catch the scenario when they're
  481. // called inside of a sandbox and not properly surrounded by a FPUStateSaver.
  482. // GpRound may work incorrectly inside of a sandbox because the unsafe code
  483. // could change the rounding mode. It could also generate exceptions.
  484. class FPUStateSandbox
  485. {
  486. private:
  487. UINT32 SavedState;
  488. public:
  489. FPUStateSandbox()
  490. {
  491. // it is assumed that this call is issued inside of an
  492. // FPUStateSaver block, so that the CTRL word is set to
  493. // our preferred state.
  494. // Lets not do this ASSERT - turns out that it gets called on the device
  495. // destructor durning InternalGdiplusShutdown and we don't want to wrap
  496. // that with an FPUStateSaver.
  497. // FPUStateSaver::AssertMode();
  498. #if defined(_USE_X86_ASSEMBLY)
  499. UINT32 savedState;
  500. // We must protect the sandboxed code from clearing the exception
  501. // masks and taking an exception generated by GDI+.
  502. // We do this by issuing fclex - which takes any unmasked exceptions
  503. // and clears all of the exceptions after that (masked and unmasked)
  504. // giving the sandboxed code a clean slate.
  505. _asm fclex
  506. // Save control word:
  507. _asm fnstcw WORD PTR savedState
  508. this->SavedState = savedState;
  509. #endif
  510. }
  511. ~FPUStateSandbox()
  512. {
  513. #if defined(_USE_X86_ASSEMBLY)
  514. UINT32 savedState = this->SavedState;
  515. // clear the current exception state.
  516. // fnclex is a non-wait version of fclex - which means it clears
  517. // the exceptions without taking any pending unmasked exceptions.
  518. // We issue an fnclex so that any unmasked exceptions are ignored.
  519. // This is designed to prevent the sandboxed code from blowing
  520. // up in code outside of the sandbox.
  521. _asm fnclex
  522. // Restore control word (rounding mode and exception masks):
  523. _asm fldcw WORD PTR savedState
  524. #endif
  525. }
  526. };
  527. //--------------------------------------------------------------------------
  528. // The following are simply handy versions that require less typing to
  529. // use (i.e., 'GpFloor(x)' instead of 'FPUStateSaver::Floor(x)').
  530. //
  531. // These functions require that a version of 'FPUStateSaver' has been
  532. // instantiated already for the current thread.
  533. //--------------------------------------------------------------------------
  534. inline INT GpFloor(REAL x) { return(FPUStateSaver::Floor(x)); }
  535. inline INT GpTrunc(REAL x) { return(FPUStateSaver::Trunc(x)); }
  536. inline INT GpCeiling(REAL x) { return(FPUStateSaver::Ceiling(x)); }
  537. inline INT GpRound(REAL x) { return(FPUStateSaver::Round(x)); }
  538. inline INT GpFloorSat(REAL x) { return(FPUStateSaver::FloorSat(x)); }
  539. inline INT GpTruncSat(REAL x) { return(FPUStateSaver::TruncSat(x)); }
  540. inline INT GpCeilingSat(REAL x) { return(FPUStateSaver::CeilingSat(x)); }
  541. inline INT GpRoundSat(REAL x) { return(FPUStateSaver::RoundSat(x)); }
  542. /**************************************************************************\
  543. *
  544. * Function Description:
  545. *
  546. * Return TRUE if two points are close. Close is defined as near enough
  547. * that the rounding to 32bit float precision could have resulted in the
  548. * difference. We define an arbitrary number of allowed rounding errors (10).
  549. * We divide by b to normalize the difference. It doesn't matter which point
  550. * we divide by - if they're significantly different, we'll return true, and
  551. * if they're really close, then a==b (almost).
  552. *
  553. * Arguments:
  554. *
  555. * a, b - input numbers to compare.
  556. *
  557. * Return Value:
  558. *
  559. * TRUE if the numbers are close enough.
  560. *
  561. * Created:
  562. *
  563. * 12/11/2000 asecchia
  564. *
  565. \**************************************************************************/
  566. inline BOOL IsCloseReal(const REAL a, const REAL b)
  567. {
  568. // if b == 0.0f we don't want to divide by zero. If this happens
  569. // it's sufficient to use 1.0 as the divisor because REAL_EPSILON
  570. // should be good enough to test if a number is close enough to zero.
  571. // NOTE: if b << a, this could cause an FP overflow. Currently we mask
  572. // these exceptions, but if we unmask them, we should probably check
  573. // the divide.
  574. // We assume we can generate an overflow exception without taking down
  575. // the system. We will still get the right results based on the FPU
  576. // default handling of the overflow.
  577. #if !(FP_CTRL_STATE & 0x8)
  578. // Ensure that anyone clearing the overflow mask comes and revisits this
  579. // assumption.
  580. #error #O exception cleared. Go check FP_CTRL_MASKEDEXCEPTIONS.
  581. #endif
  582. FPUStateSaver::AssertMode();
  583. return( REALABS( (a-b) / ((b==0.0f)?1.0f:b) ) < 10.0f*REAL_EPSILON );
  584. }
  585. inline BOOL IsClosePointF(const PointF &pt1, const PointF &pt2)
  586. {
  587. return (
  588. IsCloseReal(pt1.X, pt2.X) &&
  589. IsCloseReal(pt1.Y, pt2.Y)
  590. );
  591. }
  592. #endif // !_REAL_HPP_