rndint.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. /*******************************************************************************
  2. ** File: rndint.c
  3. **
  4. ** Contains: C source code for implementations of floating-point
  5. ** functions which round to integral value or format, as
  6. ** defined in header <fp.h>. In particular, this file
  7. ** contains implementations of functions rint, nearbyint,
  8. ** rinttol, round, roundtol, trunc, modf and modfl. This file
  9. ** targets PowerPC or Power platforms.
  10. **
  11. ** Written by: A. Sazegari, Apple AltiVec Group
  12. ** Created originally by Jon Okada, Apple Numerics Group
  13. **
  14. ** Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved
  15. **
  16. ** Change History (most recent first):
  17. **
  18. ** 13 Jul 01 ram replaced --setflm calls with inline assembly
  19. ** 03 Mar 01 ali first port to os x using gcc, added the crucial __setflm
  20. ** definition.
  21. ** 1. removed double_t, put in double for now.
  22. ** 2. removed iclass from nearbyint.
  23. ** 3. removed wrong comments intrunc.
  24. ** 4.
  25. ** 13 May 97 ali made performance improvements in rint, rinttol, roundtol
  26. ** and trunc by folding some of the taligent ideas into this
  27. ** implementation. nearbyint is faster than the one in taligent,
  28. ** rint is more elegant, but slower by %30 than the taligent one.
  29. ** 09 Apr 97 ali deleted modfl and deferred to AuxiliaryDD.c
  30. ** 15 Sep 94 ali Major overhaul and performance improvements of all functions.
  31. ** 20 Jul 94 PAF New faster version
  32. ** 16 Jul 93 ali Added the modfl function.
  33. ** 18 Feb 93 ali Changed the return value of fenv functions
  34. ** feclearexcept and feraiseexcept to their new
  35. ** NCEG X3J11.1/93-001 definitions.
  36. ** 16 Dec 92 JPO Removed __itrunc implementation to a
  37. ** separate file.
  38. ** 15 Dec 92 JPO Added __itrunc implementation and modified
  39. ** rinttol to include conversion from double
  40. ** to long int format. Modified roundtol to
  41. ** call __itrunc.
  42. ** 10 Dec 92 JPO Added modf (double) implementation.
  43. ** 04 Dec 92 JPO First created.
  44. **
  45. *******************************************************************************/
  46. #include <limits.h>
  47. #include <math.h>
  48. #if !defined(__ppc__)
  49. #define asm(x)
  50. #endif
  51. #define SET_INVALID 0x01000000UL
  52. typedef union
  53. {
  54. struct {
  55. #if defined(__BIG_ENDIAN__)
  56. unsigned long int hi;
  57. unsigned long int lo;
  58. #else
  59. unsigned long int lo;
  60. unsigned long int hi;
  61. #endif
  62. } words;
  63. double dbl;
  64. } DblInHex;
  65. static const unsigned long int signMask = 0x80000000ul;
  66. static const double twoTo52 = 4503599627370496.0;
  67. static const double doubleToLong = 4503603922337792.0; // 2^52
  68. static const DblInHex Huge = {{ 0x7FF00000, 0x00000000 }};
  69. static const DblInHex TOWARDZERO = {{ 0x00000000, 0x00000001 }};
  70. /*******************************************************************************
  71. * *
  72. * The function rint rounds its double argument to integral value *
  73. * according to the current rounding direction and returns the result in *
  74. * double format. This function signals inexact if an ordered return *
  75. * value is not equal to the operand. *
  76. * *
  77. ********************************************************************************
  78. * *
  79. * This function calls: fabs. *
  80. * *
  81. *******************************************************************************/
  82. /*******************************************************************************
  83. * First, an elegant implementation. *
  84. ********************************************************************************
  85. *
  86. *double rint ( double x )
  87. * {
  88. * double y;
  89. *
  90. * y = twoTo52.fval;
  91. *
  92. * if ( fabs ( x ) >= y ) // huge case is exact
  93. * return x;
  94. * if ( x < 0 ) y = -y; // negative case
  95. * y = ( x + y ) - y; // force rounding
  96. * if ( y == 0.0 ) // zero results mirror sign of x
  97. * y = copysign ( y, x );
  98. * return ( y );
  99. * }
  100. ********************************************************************************
  101. * Now a bit twidling version that is about %30 faster. *
  102. *******************************************************************************/
  103. #if defined(__ppc__)
  104. double rint ( double x )
  105. {
  106. DblInHex argument;
  107. register double y;
  108. unsigned long int xHead;
  109. register long int target;
  110. argument.dbl = x;
  111. xHead = argument.words.hi & 0x7fffffffUL; // xHead <- high half of |x|
  112. target = ( argument.words.hi < signMask ); // flags positive sign
  113. if ( xHead < 0x43300000ul )
  114. /*******************************************************************************
  115. * Is |x| < 2.0^52? *
  116. *******************************************************************************/
  117. {
  118. if ( xHead < 0x3ff00000ul )
  119. /*******************************************************************************
  120. * Is |x| < 1.0? *
  121. *******************************************************************************/
  122. {
  123. if ( target )
  124. y = ( x + twoTo52 ) - twoTo52; // round at binary point
  125. else
  126. y = ( x - twoTo52 ) + twoTo52; // round at binary point
  127. if ( y == 0.0 )
  128. { // fix sign of zero result
  129. if ( target )
  130. return ( 0.0 );
  131. else
  132. return ( -0.0 );
  133. }
  134. return y;
  135. }
  136. /*******************************************************************************
  137. * Is 1.0 < |x| < 2.0^52? *
  138. *******************************************************************************/
  139. if ( target )
  140. return ( ( x + twoTo52 ) - twoTo52 ); // round at binary pt.
  141. else
  142. return ( ( x - twoTo52 ) + twoTo52 );
  143. }
  144. /*******************************************************************************
  145. * |x| >= 2.0^52 or x is a NaN. *
  146. *******************************************************************************/
  147. return ( x );
  148. }
  149. #endif /* __ppc__ */
  150. /*******************************************************************************
  151. * *
  152. * The function nearbyint rounds its double argument to integral value *
  153. * according to the current rounding direction and returns the result in *
  154. * double format. This function does not signal inexact. *
  155. * *
  156. ********************************************************************************
  157. * *
  158. * This function calls fabs and copysign. *
  159. * *
  160. *******************************************************************************/
  161. double nearbyint ( double x )
  162. {
  163. double y;
  164. #if defined(__ppc__)
  165. double OldEnvironment;
  166. #endif /* __ppc__ */
  167. y = twoTo52;
  168. asm ("mffs %0" : "=f" (OldEnvironment)); /* get the environement */
  169. if ( fabs ( x ) >= y ) /* huge case is exact */
  170. return x;
  171. if ( x < 0 ) y = -y; /* negative case */
  172. y = ( x + y ) - y; /* force rounding */
  173. if ( y == 0.0 ) /* zero results mirror sign of x */
  174. y = copysign ( y, x );
  175. // restore old flags
  176. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment ));
  177. return ( y );
  178. }
  179. /*******************************************************************************
  180. * *
  181. * The function rinttol converts its double argument to integral value *
  182. * according to the current rounding direction and returns the result in *
  183. * long int format. This conversion signals invalid if the argument is a *
  184. * NaN or the rounded intermediate result is out of range of the *
  185. * destination long int format, and it delivers an unspecified result in *
  186. * this case. This function signals inexact if the rounded result is *
  187. * within range of the long int format but unequal to the operand. *
  188. * *
  189. *******************************************************************************/
  190. long int rinttol ( double x )
  191. {
  192. register double y;
  193. DblInHex argument, OldEnvironment;
  194. unsigned long int xHead;
  195. register long int target;
  196. argument.dbl = x;
  197. target = ( argument.words.hi < signMask ); // flag positive sign
  198. xHead = argument.words.hi & 0x7ffffffful; // high 32 bits of x
  199. if ( target )
  200. /*******************************************************************************
  201. * Sign of x is positive. *
  202. *******************************************************************************/
  203. {
  204. if ( xHead < 0x41dffffful )
  205. { // x is safely in long range
  206. y = ( x + twoTo52 ) - twoTo52; // round at binary point
  207. argument.dbl = y + doubleToLong; // force result into argument.words.lo
  208. return ( ( long ) argument.words.lo );
  209. }
  210. asm ("mffs %0" : "=f" (OldEnvironment.dbl)); // get environment
  211. if ( xHead > 0x41dffffful )
  212. { // x is safely out of long range
  213. OldEnvironment.words.lo |= SET_INVALID;
  214. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  215. return ( LONG_MAX );
  216. }
  217. /*******************************************************************************
  218. * x > 0.0 and may or may not be out of range of long. *
  219. *******************************************************************************/
  220. y = ( x + twoTo52 ) - twoTo52; // do rounding
  221. if ( y > ( double ) LONG_MAX )
  222. { // out of range of long
  223. OldEnvironment.words.lo |= SET_INVALID;
  224. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  225. return ( LONG_MAX );
  226. }
  227. argument.dbl = y + doubleToLong; // in range
  228. return ( ( long ) argument.words.lo ); // return result & flags
  229. }
  230. /*******************************************************************************
  231. * Sign of x is negative. *
  232. *******************************************************************************/
  233. if ( xHead < 0x41e00000ul )
  234. { // x is safely in long range
  235. y = ( x - twoTo52 ) + twoTo52;
  236. argument.dbl = y + doubleToLong;
  237. return ( ( long ) argument.words.lo );
  238. }
  239. asm ("mffs %0" : "=f" (OldEnvironment.dbl)); // get environment
  240. if ( xHead > 0x41e00000ul )
  241. { // x is safely out of long range
  242. OldEnvironment.words.lo |= SET_INVALID;
  243. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  244. return ( LONG_MIN );
  245. }
  246. /*******************************************************************************
  247. * x < 0.0 and may or may not be out of range of long. *
  248. *******************************************************************************/
  249. y = ( x - twoTo52 ) + twoTo52; // do rounding
  250. if ( y < ( double ) LONG_MIN )
  251. { // out of range of long
  252. OldEnvironment.words.lo |= SET_INVALID;
  253. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  254. return ( LONG_MIN );
  255. }
  256. argument.dbl = y + doubleToLong; // in range
  257. return ( ( long ) argument.words.lo ); // return result & flags
  258. }
  259. /*******************************************************************************
  260. * *
  261. * The function round rounds its double argument to integral value *
  262. * according to the "add half to the magnitude and truncate" rounding of *
  263. * Pascal's Round function and FORTRAN's ANINT function and returns the *
  264. * result in double format. This function signals inexact if an ordered *
  265. * return value is not equal to the operand. *
  266. * *
  267. *******************************************************************************/
  268. double round ( double x )
  269. {
  270. DblInHex argument, OldEnvironment;
  271. register double y, z;
  272. register unsigned long int xHead;
  273. register long int target;
  274. argument.dbl = x;
  275. xHead = argument.words.hi & 0x7fffffffUL; // xHead <- high half of |x|
  276. target = ( argument.words.hi < signMask ); // flag positive sign
  277. if ( xHead < 0x43300000ul )
  278. /*******************************************************************************
  279. * Is |x| < 2.0^52? *
  280. *******************************************************************************/
  281. {
  282. if ( xHead < 0x3ff00000ul )
  283. /*******************************************************************************
  284. * Is |x| < 1.0? *
  285. *******************************************************************************/
  286. {
  287. asm ("mffs %0" : "=f" (OldEnvironment.dbl)); // get environment
  288. if ( xHead < 0x3fe00000ul )
  289. /*******************************************************************************
  290. * Is |x| < 0.5? *
  291. *******************************************************************************/
  292. {
  293. if ( ( xHead | argument.words.lo ) != 0ul )
  294. OldEnvironment.words.lo |= 0x02000000ul;
  295. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  296. if ( target )
  297. return ( 0.0 );
  298. else
  299. return ( -0.0 );
  300. }
  301. /*******************************************************************************
  302. * Is 0.5 ² |x| < 1.0? *
  303. *******************************************************************************/
  304. OldEnvironment.words.lo |= 0x02000000ul;
  305. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  306. if ( target )
  307. return ( 1.0 );
  308. else
  309. return ( -1.0 );
  310. }
  311. /*******************************************************************************
  312. * Is 1.0 < |x| < 2.0^52? *
  313. *******************************************************************************/
  314. if ( target )
  315. { // positive x
  316. y = ( x + twoTo52 ) - twoTo52; // round at binary point
  317. if ( y == x ) // exact case
  318. return ( x );
  319. z = x + 0.5; // inexact case
  320. y = ( z + twoTo52 ) - twoTo52; // round at binary point
  321. if ( y > z )
  322. return ( y - 1.0 );
  323. else
  324. return ( y );
  325. }
  326. /*******************************************************************************
  327. * Is x < 0? *
  328. *******************************************************************************/
  329. else
  330. {
  331. y = ( x - twoTo52 ) + twoTo52; // round at binary point
  332. if ( y == x )
  333. return ( x );
  334. z = x - 0.5;
  335. y = ( z - twoTo52 ) + twoTo52; // round at binary point
  336. if ( y < z )
  337. return ( y + 1.0 );
  338. else
  339. return ( y );
  340. }
  341. }
  342. /*******************************************************************************
  343. * |x| >= 2.0^52 or x is a NaN. *
  344. *******************************************************************************/
  345. return ( x );
  346. }
  347. /*******************************************************************************
  348. * *
  349. * The function roundtol converts its double argument to integral format *
  350. * according to the "add half to the magnitude and chop" rounding mode of *
  351. * Pascal's Round function and FORTRAN's NINT function. This conversion *
  352. * signals invalid if the argument is a NaN or the rounded intermediate *
  353. * result is out of range of the destination long int format, and it *
  354. * delivers an unspecified result in this case. This function signals *
  355. * inexact if the rounded result is within range of the long int format but *
  356. * unequal to the operand. *
  357. * *
  358. *******************************************************************************/
  359. long int roundtol ( double x )
  360. {
  361. register double y, z;
  362. DblInHex argument, OldEnvironment;
  363. register unsigned long int xhi;
  364. register long int target;
  365. #if defined(__ppc__)
  366. const DblInHex kTZ = {{ 0x0, 0x1 }};
  367. const DblInHex kUP = {{ 0x0, 0x2 }};
  368. #endif /* __ppc__ */
  369. argument.dbl = x;
  370. xhi = argument.words.hi & 0x7ffffffful; // high 32 bits of x
  371. target = ( argument.words.hi < signMask ); // flag positive sign
  372. if ( xhi > 0x41e00000ul )
  373. /*******************************************************************************
  374. * Is x is out of long range or NaN? *
  375. *******************************************************************************/
  376. {
  377. asm ("mffs %0" : "=f" (OldEnvironment.dbl)); // get environment
  378. OldEnvironment.words.lo |= SET_INVALID;
  379. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  380. if ( target ) // pin result
  381. return ( LONG_MAX );
  382. else
  383. return ( LONG_MIN );
  384. }
  385. if ( target )
  386. /*******************************************************************************
  387. * Is sign of x is "+"? *
  388. *******************************************************************************/
  389. {
  390. if ( x < 2147483647.5 )
  391. /*******************************************************************************
  392. * x is in the range of a long. *
  393. *******************************************************************************/
  394. {
  395. y = ( x + doubleToLong ) - doubleToLong; // round at binary point
  396. if ( y != x )
  397. { // inexact case
  398. asm ("mffs %0" : "=f" (OldEnvironment.dbl)); // save environment
  399. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( kTZ.dbl )); // truncate rounding
  400. z = x + 0.5; // truncate x + 0.5
  401. argument.dbl = z + doubleToLong;
  402. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  403. return ( ( long ) argument.words.lo );
  404. }
  405. argument.dbl = y + doubleToLong; // force result into argument.words.lo
  406. return ( ( long ) argument.words.lo ); // return long result
  407. }
  408. /*******************************************************************************
  409. * Rounded positive x is out of the range of a long. *
  410. *******************************************************************************/
  411. asm ("mffs %0" : "=f" (OldEnvironment.dbl));
  412. OldEnvironment.words.lo |= SET_INVALID;
  413. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  414. return ( LONG_MAX ); // return pinned result
  415. }
  416. /*******************************************************************************
  417. * x < 0.0 and may or may not be out of the range of a long. *
  418. *******************************************************************************/
  419. if ( x > -2147483648.5 )
  420. /*******************************************************************************
  421. * x is in the range of a long. *
  422. *******************************************************************************/
  423. {
  424. y = ( x + doubleToLong ) - doubleToLong; // round at binary point
  425. if ( y != x )
  426. { // inexact case
  427. asm ("mffs %0" : "=f" (OldEnvironment.dbl)); // save environment
  428. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( kUP.dbl )); // round up
  429. z = x - 0.5; // truncate x - 0.5
  430. argument.dbl = z + doubleToLong;
  431. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  432. return ( ( long ) argument.words.lo );
  433. }
  434. argument.dbl = y + doubleToLong;
  435. return ( ( long ) argument.words.lo ); // return long result
  436. }
  437. /*******************************************************************************
  438. * Rounded negative x is out of the range of a long. *
  439. *******************************************************************************/
  440. asm ("mffs %0" : "=f" (OldEnvironment.dbl));
  441. OldEnvironment.words.lo |= SET_INVALID;
  442. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  443. return ( LONG_MIN ); // return pinned result
  444. }
  445. /*******************************************************************************
  446. * *
  447. * The function trunc truncates its double argument to integral value *
  448. * and returns the result in double format. This function signals *
  449. * inexact if an ordered return value is not equal to the operand. *
  450. * *
  451. *******************************************************************************/
  452. double trunc ( double x )
  453. {
  454. DblInHex argument,OldEnvironment;
  455. register double y;
  456. register unsigned long int xhi;
  457. register long int target;
  458. argument.dbl = x;
  459. xhi = argument.words.hi & 0x7fffffffUL; // xhi <- high half of |x|
  460. target = ( argument.words.hi < signMask ); // flag positive sign
  461. if ( xhi < 0x43300000ul )
  462. /*******************************************************************************
  463. * Is |x| < 2.0^53? *
  464. *******************************************************************************/
  465. {
  466. if ( xhi < 0x3ff00000ul )
  467. /*******************************************************************************
  468. * Is |x| < 1.0? *
  469. *******************************************************************************/
  470. {
  471. if ( ( xhi | argument.words.lo ) != 0ul )
  472. { // raise deserved INEXACT
  473. asm ("mffs %0" : "=f" (OldEnvironment.dbl));
  474. OldEnvironment.words.lo |= 0x02000000ul;
  475. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
  476. }
  477. if ( target ) // return properly signed zero
  478. return ( 0.0 );
  479. else
  480. return ( -0.0 );
  481. }
  482. /*******************************************************************************
  483. * Is 1.0 < |x| < 2.0^52? *
  484. *******************************************************************************/
  485. if ( target )
  486. {
  487. y = ( x + twoTo52 ) - twoTo52; // round at binary point
  488. if ( y > x )
  489. return ( y - 1.0 );
  490. else
  491. return ( y );
  492. }
  493. else
  494. {
  495. y = ( x - twoTo52 ) + twoTo52; // round at binary point.
  496. if ( y < x )
  497. return ( y + 1.0 );
  498. else
  499. return ( y );
  500. }
  501. }
  502. /*******************************************************************************
  503. * Is |x| >= 2.0^52 or x is a NaN. *
  504. *******************************************************************************/
  505. return ( x );
  506. }
  507. /*******************************************************************************
  508. * The modf family of functions separate a floating-point number into its *
  509. * fractional and integral parts, returning the fractional part and writing *
  510. * the integral part in floating-point format to the object pointed to by a *
  511. * pointer argument. If the input argument is integral or infinite in *
  512. * value, the return value is a zero with the sign of the input argument. *
  513. * The modf family of functions raises no floating-point exceptions. older *
  514. * implemenation set the INVALID flag due to signaling NaN input. *
  515. * *
  516. *******************************************************************************/
  517. /*******************************************************************************
  518. * modf is the double implementation. *
  519. *******************************************************************************/
  520. #if defined(__ppc__)
  521. double modf ( double x, double *iptr )
  522. {
  523. register double OldEnvironment, xtrunc;
  524. register unsigned long int xHead, signBit;
  525. DblInHex argument;
  526. argument.dbl = x;
  527. xHead = argument.words.hi & 0x7ffffffful; // |x| high bit pattern
  528. signBit = ( argument.words.hi & 0x80000000ul ); // isolate sign bit
  529. if (xHead == 0x7ff81fe0)
  530. signBit = signBit | 0;
  531. if ( xHead < 0x43300000ul )
  532. /*******************************************************************************
  533. * Is |x| < 2.0^53? *
  534. *******************************************************************************/
  535. {
  536. if ( xHead < 0x3ff00000ul )
  537. /*******************************************************************************
  538. * Is |x| < 1.0? *
  539. *******************************************************************************/
  540. {
  541. argument.words.hi = signBit; // truncate to zero
  542. argument.words.lo = 0ul;
  543. *iptr = argument.dbl;
  544. return ( x );
  545. }
  546. /*******************************************************************************
  547. * Is 1.0 < |x| < 2.0^52? *
  548. *******************************************************************************/
  549. asm ("mffs %0" : "=f" (OldEnvironment)); // save environment
  550. // round toward zero
  551. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( TOWARDZERO.dbl ));
  552. if ( signBit == 0ul ) // truncate to integer
  553. xtrunc = ( x + twoTo52 ) - twoTo52;
  554. else
  555. xtrunc = ( x - twoTo52 ) + twoTo52;
  556. // restore caller's env
  557. asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment ));
  558. *iptr = xtrunc; // store integral part
  559. if ( x != xtrunc ) // nonzero fraction
  560. return ( x - xtrunc );
  561. else
  562. { // zero with x's sign
  563. argument.words.hi = signBit;
  564. argument.words.lo = 0ul;
  565. return ( argument.dbl );
  566. }
  567. }
  568. *iptr = x; // x is integral or NaN
  569. if ( x != x ) // NaN is returned
  570. return x;
  571. else
  572. { // zero with x's sign
  573. argument.words.hi = signBit;
  574. argument.words.lo = 0ul;
  575. return ( argument.dbl );
  576. }
  577. }
  578. #endif /* __ppc__ */