OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libm/] [powerpc/] [s_modf.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/*******************************************************************************
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
 
47
#include <limits.h>
48
#include <math.h>
49
 
50
#define      SET_INVALID      0x01000000UL
51
 
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
 
66
static const unsigned long int signMask = 0x80000000ul;
67
static const double twoTo52      = 4503599627370496.0;
68
static const double doubleToLong = 4503603922337792.0;              // 2^52
69
static const DblInHex Huge       = {{ 0x7FF00000, 0x00000000 }};
70
static const DblInHex TOWARDZERO = {{ 0x00000000, 0x00000001 }};
71
 
72
 
73
/*******************************************************************************
74
*                                                                              *
75
*     The function nearbyint rounds its double argument to integral value      *
76
*     according to the current rounding direction and returns the result in    *
77
*     double format.  This function does not signal inexact.                   *
78
*                                                                              *
79
********************************************************************************
80
*                                                                              *
81
*     This function calls fabs and copysign.                                     *
82
*                                                                              *
83
*******************************************************************************/
84
 
85
double nearbyint ( double x )
86
      {
87
        double y;
88
        double OldEnvironment;
89
 
90
        y = twoTo52;
91
 
92
        asm ("mffs %0" : "=f" (OldEnvironment));        /* get the environement */
93
 
94
      if ( fabs ( x ) >= y )                          /* huge case is exact */
95
            return x;
96
      if ( x < 0 ) y = -y;                                   /* negative case */
97
      y = ( x + y ) - y;                                    /* force rounding */
98
      if ( y == 0.0 )                        /* zero results mirror sign of x */
99
            y = copysign ( y, x );
100
//      restore old flags
101
        asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment ));
102
      return ( y );
103
        }
104
 
105
/*******************************************************************************
106
*                                                                              *
107
*     The function rinttol converts its double argument to integral value      *
108
*     according to the current rounding direction and returns the result in    *
109
*     long int format.  This conversion signals invalid if the argument is a   *
110
*     NaN or the rounded intermediate result is out of range of the            *
111
*     destination long int format, and it delivers an unspecified result in    *
112
*     this case.  This function signals inexact if the rounded result is       *
113
*     within range of the long int format but unequal to the operand.          *
114
*                                                                              *
115
*******************************************************************************/
116
 
117
long int rinttol ( double x )
118
      {
119
      register double y;
120
      DblInHex argument, OldEnvironment;
121
      unsigned long int xHead;
122
      register long int target;
123
 
124
      argument.dbl = x;
125
      target = ( argument.words.hi < signMask );        // flag positive sign
126
      xHead = argument.words.hi & 0x7ffffffful;         // high 32 bits of x
127
 
128
      if ( target )
129
/*******************************************************************************
130
*    Sign of x is positive.                                                    *
131
*******************************************************************************/
132
            {
133
            if ( xHead < 0x41dffffful )
134
                  {                                    // x is safely in long range
135
                  y = ( x + twoTo52 ) - twoTo52;       // round at binary point
136
                  argument.dbl = y + doubleToLong;     // force result into argument.words.lo
137
                  return ( ( long ) argument.words.lo );
138
                  }
139
 
140
                asm ("mffs %0" : "=f" (OldEnvironment.dbl));    // get environment
141
 
142
            if ( xHead > 0x41dffffful )
143
                  {                                    // x is safely out of long range
144
                  OldEnvironment.words.lo |= SET_INVALID;
145
                        asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
146
                  return ( LONG_MAX );
147
                  }
148
 
149
/*******************************************************************************
150
*     x > 0.0 and may or may not be out of range of long.                      *
151
*******************************************************************************/
152
 
153
            y = ( x + twoTo52 ) - twoTo52;             // do rounding
154
            if ( y > ( double ) LONG_MAX )
155
                  {                                    // out of range of long
156
                  OldEnvironment.words.lo |= SET_INVALID;
157
                        asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
158
                  return ( LONG_MAX );
159
                  }
160
            argument.dbl = y + doubleToLong;           // in range
161
            return ( ( long ) argument.words.lo );      // return result & flags
162
            }
163
 
164
/*******************************************************************************
165
*    Sign of x is negative.                                                    *
166
*******************************************************************************/
167
      if ( xHead < 0x41e00000ul )
168
            {                                          // x is safely in long range
169
            y = ( x - twoTo52 ) + twoTo52;
170
            argument.dbl = y + doubleToLong;
171
            return ( ( long ) argument.words.lo );
172
            }
173
 
174
        asm ("mffs %0" : "=f" (OldEnvironment.dbl));    // get environment
175
 
176
      if ( xHead > 0x41e00000ul )
177
            {                                          // x is safely out of long range
178
            OldEnvironment.words.lo |= SET_INVALID;
179
                asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
180
            return ( LONG_MIN );
181
            }
182
 
183
/*******************************************************************************
184
*    x < 0.0 and may or may not be out of range of long.                       *
185
*******************************************************************************/
186
 
187
      y = ( x - twoTo52 ) + twoTo52;                   // do rounding
188
      if ( y < ( double ) LONG_MIN )
189
            {                                          // out of range of long
190
            OldEnvironment.words.lo |= SET_INVALID;
191
                asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
192
            return ( LONG_MIN );
193
            }
194
      argument.dbl = y + doubleToLong;                       // in range
195
      return ( ( long ) argument.words.lo );           // return result & flags
196
      }
197
 
198
/*******************************************************************************
199
*                                                                              *
200
*     The function round rounds its double argument to integral value          *
201
*     according to the "add half to the magnitude and truncate" rounding of    *
202
*     Pascal's Round function and FORTRAN's ANINT function and returns the     *
203
*     result in double format.  This function signals inexact if an ordered    *
204
*     return value is not equal to the operand.                                *
205
*                                                                              *
206
*******************************************************************************/
207
 
208
double round ( double x )
209
      {
210
      DblInHex argument, OldEnvironment;
211
      register double y, z;
212
      register unsigned long int xHead;
213
      register long int target;
214
 
215
      argument.dbl = x;
216
      xHead = argument.words.hi & 0x7fffffffUL;      // xHead <- high half of |x|
217
      target = ( argument.words.hi < signMask );     // flag positive sign
218
 
219
      if ( xHead < 0x43300000ul )
220
/*******************************************************************************
221
*     Is |x| < 2.0^52?                                                        *
222
*******************************************************************************/
223
            {
224
            if ( xHead < 0x3ff00000ul )
225
/*******************************************************************************
226
*     Is |x| < 1.0?                                                           *
227
*******************************************************************************/
228
                  {
229
                        asm ("mffs %0" : "=f" (OldEnvironment.dbl));    // get environment
230
                  if ( xHead < 0x3fe00000ul )
231
/*******************************************************************************
232
*     Is |x| < 0.5?                                                           *
233
*******************************************************************************/
234
                        {
235
                        if ( ( xHead | argument.words.lo ) != 0ul )
236
                              OldEnvironment.words.lo |= 0x02000000ul;
237
                                asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
238
                        if ( target )
239
                              return ( 0.0 );
240
                        else
241
                              return ( -0.0 );
242
                        }
243
/*******************************************************************************
244
*     Is 0.5 ² |x| < 1.0?                                                      *
245
*******************************************************************************/
246
                  OldEnvironment.words.lo |= 0x02000000ul;
247
                        asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
248
                  if ( target )
249
                        return ( 1.0 );
250
                  else
251
                        return ( -1.0 );
252
                  }
253
/*******************************************************************************
254
*     Is 1.0 < |x| < 2.0^52?                                                   *
255
*******************************************************************************/
256
            if ( target )
257
                  {                                     // positive x
258
                  y = ( x + twoTo52 ) - twoTo52;        // round at binary point
259
                  if ( y == x )                         // exact case
260
                        return ( x );
261
                  z = x + 0.5;                          // inexact case
262
                  y = ( z + twoTo52 ) - twoTo52;        // round at binary point
263
                  if ( y > z )
264
                        return ( y - 1.0 );
265
                  else
266
                        return ( y );
267
                  }
268
 
269
/*******************************************************************************
270
*     Is x < 0?                                                                *
271
*******************************************************************************/
272
            else
273
                  {
274
                  y = ( x - twoTo52 ) + twoTo52;        // round at binary point
275
                  if ( y == x )
276
                        return ( x );
277
                  z = x - 0.5;
278
                  y = ( z - twoTo52 ) + twoTo52;        // round at binary point
279
                  if ( y < z )
280
                        return ( y + 1.0 );
281
                  else
282
                  return ( y );
283
                  }
284
            }
285
/*******************************************************************************
286
*      |x| >= 2.0^52 or x is a NaN.                                            *
287
*******************************************************************************/
288
      return ( x );
289
      }
290
 
291
/*******************************************************************************
292
*                                                                              *
293
*     The function roundtol converts its double argument to integral format    *
294
*     according to the "add half to the magnitude and chop" rounding mode of   *
295
*     Pascal's Round function and FORTRAN's NINT function.  This conversion    *
296
*     signals invalid if the argument is a NaN or the rounded intermediate     *
297
*     result is out of range of the destination long int format, and it        *
298
*     delivers an unspecified result in this case.  This function signals      *
299
*     inexact if the rounded result is within range of the long int format but *
300
*     unequal to the operand.                                                  *
301
*                                                                              *
302
*******************************************************************************/
303
 
304
long int roundtol ( double x )
305
        {
306
        register double y, z;
307
        DblInHex argument, OldEnvironment;
308
        register unsigned long int xhi;
309
        register long int target;
310
        const DblInHex kTZ = {{ 0x0, 0x1 }};
311
        const DblInHex kUP = {{ 0x0, 0x2 }};
312
 
313
        argument.dbl = x;
314
        xhi = argument.words.hi & 0x7ffffffful;                 // high 32 bits of x
315
        target = ( argument.words.hi < signMask );              // flag positive sign
316
 
317
        if ( xhi > 0x41e00000ul )
318
/*******************************************************************************
319
*     Is x is out of long range or NaN?                                        *
320
*******************************************************************************/
321
                {
322
                asm ("mffs %0" : "=f" (OldEnvironment.dbl));    // get environment
323
                OldEnvironment.words.lo |= SET_INVALID;
324
                asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
325
                if ( target )                                   // pin result
326
                        return ( LONG_MAX );
327
                else
328
                        return ( LONG_MIN );
329
                }
330
 
331
        if ( target )
332
/*******************************************************************************
333
*     Is sign of x is "+"?                                                     *
334
*******************************************************************************/
335
                {
336
                if ( x < 2147483647.5 )
337
/*******************************************************************************
338
*     x is in the range of a long.                                             *
339
*******************************************************************************/
340
                        {
341
                        y = ( x + doubleToLong ) - doubleToLong;        // round at binary point
342
                        if ( y != x )
343
                                {                                       // inexact case
344
                                asm ("mffs %0" : "=f" (OldEnvironment.dbl));    // save environment
345
                                asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( kTZ.dbl )); // truncate rounding
346
                                z = x + 0.5;                            // truncate x + 0.5
347
                                argument.dbl = z + doubleToLong;
348
                                asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
349
                                return ( ( long ) argument.words.lo );
350
                                }
351
 
352
                        argument.dbl = y + doubleToLong;                // force result into argument.words.lo
353
                        return ( ( long ) argument.words.lo );  // return long result
354
                        }
355
/*******************************************************************************
356
*     Rounded positive x is out of the range of a long.                        *
357
*******************************************************************************/
358
                asm ("mffs %0" : "=f" (OldEnvironment.dbl));
359
                OldEnvironment.words.lo |= SET_INVALID;
360
                asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
361
                return ( LONG_MAX );                            // return pinned result
362
                }
363
/*******************************************************************************
364
*     x < 0.0 and may or may not be out of the range of a long.                *
365
*******************************************************************************/
366
        if ( x > -2147483648.5 )
367
/*******************************************************************************
368
*     x is in the range of a long.                                             *
369
*******************************************************************************/
370
                {
371
                y = ( x + doubleToLong ) - doubleToLong;                // round at binary point
372
                if ( y != x )
373
                        {                                               // inexact case
374
                        asm ("mffs %0" : "=f" (OldEnvironment.dbl));    // save environment
375
                        asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( kUP.dbl )); // round up
376
                        z = x - 0.5;                            // truncate x - 0.5
377
                        argument.dbl = z + doubleToLong;
378
                        asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
379
                        return ( ( long ) argument.words.lo );
380
                        }
381
 
382
                argument.dbl = y + doubleToLong;
383
                return ( ( long ) argument.words.lo );          //  return long result
384
                }
385
/*******************************************************************************
386
*     Rounded negative x is out of the range of a long.                        *
387
*******************************************************************************/
388
        asm ("mffs %0" : "=f" (OldEnvironment.dbl));
389
        OldEnvironment.words.lo |= SET_INVALID;
390
        asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
391
        return ( LONG_MIN );                                    // return pinned result
392
        }
393
 
394
/*******************************************************************************
395
*                                                                              *
396
*     The function trunc truncates its double argument to integral value       *
397
*     and returns the result in double format.  This function signals          *
398
*     inexact if an ordered return value is not equal to the operand.          *
399
*                                                                              *
400
*******************************************************************************/
401
 
402
double trunc ( double x )
403
      {
404
        DblInHex argument,OldEnvironment;
405
        register double y;
406
        register unsigned long int xhi;
407
        register long int target;
408
 
409
        argument.dbl = x;
410
        xhi = argument.words.hi & 0x7fffffffUL;         // xhi <- high half of |x|
411
        target = ( argument.words.hi < signMask );              // flag positive sign
412
 
413
        if ( xhi < 0x43300000ul )
414
/*******************************************************************************
415
*     Is |x| < 2.0^53?                                                         *
416
*******************************************************************************/
417
                {
418
                if ( xhi < 0x3ff00000ul )
419
/*******************************************************************************
420
*     Is |x| < 1.0?                                                            *
421
*******************************************************************************/
422
                        {
423
                        if ( ( xhi | argument.words.lo ) != 0ul )
424
                                {                               // raise deserved INEXACT
425
                                asm ("mffs %0" : "=f" (OldEnvironment.dbl));
426
                                OldEnvironment.words.lo |= 0x02000000ul;
427
                                asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment.dbl ));
428
                                }
429
                        if ( target )                           // return properly signed zero
430
                                return ( 0.0 );
431
                        else
432
                                return ( -0.0 );
433
                        }
434
/*******************************************************************************
435
*     Is 1.0 < |x| < 2.0^52?                                                   *
436
*******************************************************************************/
437
                if ( target )
438
                        {
439
                        y = ( x + twoTo52 ) - twoTo52;          // round at binary point
440
                        if ( y > x )
441
                                return ( y - 1.0 );
442
                        else
443
                                return ( y );
444
                        }
445
 
446
                else
447
                        {
448
                        y = ( x - twoTo52 ) + twoTo52;          // round at binary point.
449
                        if ( y < x )
450
                                return ( y + 1.0 );
451
                        else
452
                                return ( y );
453
                        }
454
                }
455
/*******************************************************************************
456
*      Is |x| >= 2.0^52 or x is a NaN.                                         *
457
*******************************************************************************/
458
        return ( x );
459
        }
460
 
461
/*******************************************************************************
462
*     The modf family of functions separate a floating-point number into its   *
463
*     fractional and integral parts, returning the fractional part and writing *
464
*     the integral part in floating-point format to the object pointed to by a *
465
*     pointer argument.  If the input argument is integral or infinite in      *
466
*     value, the return value is a zero with the sign of the input argument.   *
467
*     The modf family of functions raises no floating-point exceptions. older  *
468
*     implemenation set the INVALID flag due to signaling NaN input.           *
469
*                                                                              *
470
*******************************************************************************/
471
 
472
/*******************************************************************************
473
*     modf is the double implementation.                                       *
474
*******************************************************************************/
475
 
476
double modf ( double x, double *iptr )
477
      {
478
      register double OldEnvironment, xtrunc;
479
      register unsigned long int xHead, signBit;
480
      DblInHex argument;
481
 
482
      argument.dbl = x;
483
      xHead = argument.words.hi & 0x7ffffffful;            // |x| high bit pattern
484
      signBit = ( argument.words.hi & 0x80000000ul );      // isolate sign bit
485
          if (xHead == 0x7ff81fe0)
486
                        signBit = signBit | 0;
487
 
488
      if ( xHead < 0x43300000ul )
489
/*******************************************************************************
490
*     Is |x| < 2.0^53?                                                         *
491
*******************************************************************************/
492
            {
493
            if ( xHead < 0x3ff00000ul )
494
/*******************************************************************************
495
*     Is |x| < 1.0?                                                            *
496
*******************************************************************************/
497
                  {
498
                  argument.words.hi = signBit;             // truncate to zero
499
                  argument.words.lo = 0ul;
500
                  *iptr = argument.dbl;
501
                  return ( x );
502
                  }
503
/*******************************************************************************
504
*     Is 1.0 < |x| < 2.0^52?                                                   *
505
*******************************************************************************/
506
                        asm ("mffs %0" : "=f" (OldEnvironment));        // save environment
507
                        // round toward zero
508
                        asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( TOWARDZERO.dbl ));
509
            if ( signBit == 0ul )                         // truncate to integer
510
                  xtrunc = ( x + twoTo52 ) - twoTo52;
511
            else
512
                  xtrunc = ( x - twoTo52 ) + twoTo52;
513
                // restore caller's env
514
                asm ("mtfsf 255,%0" : /*NULLOUT*/ : /*IN*/ "f" ( OldEnvironment ));
515
            *iptr = xtrunc;                               // store integral part
516
            if ( x != xtrunc )                            // nonzero fraction
517
                  return ( x - xtrunc );
518
            else
519
                  {                                       // zero with x's sign
520
                  argument.words.hi = signBit;
521
                  argument.words.lo = 0ul;
522
                  return ( argument.dbl );
523
                  }
524
            }
525
 
526
      *iptr = x;                                          // x is integral or NaN
527
      if ( x != x )                                       // NaN is returned
528
            return x;
529
      else
530
            {                                             // zero with x's sign
531
            argument.words.hi = signBit;
532
            argument.words.lo = 0ul;
533
            return ( argument.dbl );
534
            }
535
      }

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.