1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 /*
  26  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 #if defined(ELFOBJ)
  31 #pragma weak nexttoward = __nexttoward
  32 #endif
  33 
  34 /*
  35  * nexttoward(x, y) delivers the next representable number after x
  36  * in the direction of y.  If x and y are both zero, the result is
  37  * zero with the same sign as y.  If either x or y is NaN, the result
  38  * is NaN.
  39  *
  40  * If x != y and the result is infinite, overflow is raised; if
  41  * x != y and the result is subnormal or zero, underflow is raised.
  42  * (This is wrong, but it's what C99 apparently wants.)
  43  */
  44 
  45 #include "libm.h"
  46 
  47 #if defined(__sparc)
  48 
  49 static union {
  50         unsigned i[2];
  51         double d;
  52 } C[] = {
  53         0x00100000, 0,
  54         0x7fe00000, 0,
  55         0x7fffffff, 0xffffffff
  56 };
  57 
  58 #define tiny    C[0].d
  59 #define huge    C[1].d
  60 #define qnan    C[2].d
  61 
  62 enum fcc_type {
  63         fcc_equal = 0,
  64         fcc_less = 1,
  65         fcc_greater = 2,
  66         fcc_unordered = 3
  67 };
  68 
  69 #ifdef __sparcv9
  70 #define _Q_cmp  _Qp_cmp
  71 #endif
  72 
  73 extern enum fcc_type _Q_cmp(const long double *, const long double *);
  74 
  75 double
  76 __nexttoward(double x, long double y) {
  77         union {
  78                 unsigned i[2];
  79                 double d;
  80         } xx;
  81         union {
  82                 unsigned i[4];
  83                 long double q;
  84         } yy;
  85         long double lx;
  86         unsigned hx;
  87         volatile double dummy;
  88         enum fcc_type rel;
  89 
  90         /*
  91          * It would be somewhat more efficient to check for NaN and
  92          * zero operands before converting x to long double and then
  93          * to code the comparison in line rather than calling _Q_cmp.
  94          * However, since this code probably won't get used much,
  95          * I'm opting in favor of simplicity instead.
  96          */
  97         lx = xx.d = x;
  98         hx = (xx.i[0] & ~0x80000000) | xx.i[1];
  99 
 100         /* check for each of four possible orderings */
 101         rel = _Q_cmp(&lx, &y);
 102         if (rel == fcc_unordered)
 103                 return (qnan);
 104 
 105         if (rel == fcc_equal) {
 106                 if (hx == 0) {  /* x is zero; return zero with y's sign */
 107                         yy.q = y;
 108                         xx.i[0] = yy.i[0];
 109                         return (xx.d);
 110                 }
 111                 return (x);
 112         }
 113 
 114         if (rel == fcc_less) {
 115                 if (hx == 0) {  /* x is zero */
 116                         xx.i[0] = 0;
 117                         xx.i[1] = 0x00000001;
 118                 } else if ((int)xx.i[0] >= 0) {      /* x is positive */
 119                         if (++xx.i[1] == 0)
 120                                 xx.i[0]++;
 121                 } else {
 122                         if (xx.i[1]-- == 0)
 123                                 xx.i[0]--;
 124                 }
 125         } else {
 126                 if (hx == 0) {  /* x is zero */
 127                         xx.i[0] = 0x80000000;
 128                         xx.i[1] = 0x00000001;
 129                 } else if ((int)xx.i[0] >= 0) {      /* x is positive */
 130                         if (xx.i[1]-- == 0)
 131                                 xx.i[0]--;
 132                 } else {
 133                         if (++xx.i[1] == 0)
 134                                 xx.i[0]++;
 135                 }
 136         }
 137 
 138         /* raise exceptions as needed */
 139         hx = xx.i[0] & ~0x80000000;
 140         if (hx == 0x7ff00000) {
 141                 dummy = huge;
 142                 dummy *= huge;
 143         } else if (hx < 0x00100000) {
 144                 dummy = tiny;
 145                 dummy *= tiny;
 146         }
 147 
 148         return (xx.d);
 149 }
 150 
 151 #elif defined(__x86)
 152 
 153 static union {
 154         unsigned i[2];
 155         double d;
 156 } C[] = {
 157         0, 0x00100000,
 158         0, 0x7fe00000,
 159 };
 160 
 161 #define tiny    C[0].d
 162 #define huge    C[1].d
 163 
 164 double
 165 __nexttoward(double x, long double y) {
 166         union {
 167                 unsigned i[2];
 168                 double d;
 169         } xx;
 170         unsigned hx;
 171         long double lx;
 172         volatile double dummy;
 173 
 174         lx = xx.d = x;
 175         hx = (xx.i[1] & ~0x80000000) | xx.i[0];
 176 
 177         /* check for each of four possible orderings */
 178         if (isunordered(lx, y))
 179                 return ((double) (lx + y));
 180 
 181         if (lx == y)
 182                 return ((double) y);
 183 
 184         if (lx < y) {
 185                 if (hx == 0) {  /* x is zero */
 186                         xx.i[0] = 0x00000001;
 187                         xx.i[1] = 0;
 188                 } else if ((int)xx.i[1] >= 0) {      /* x is positive */
 189                         if (++xx.i[0] == 0)
 190                                 xx.i[1]++;
 191                 } else {
 192                         if (xx.i[0]-- == 0)
 193                                 xx.i[1]--;
 194                 }
 195         } else {
 196                 if (hx == 0) {  /* x is zero */
 197                         xx.i[0] = 0x00000001;
 198                         xx.i[1] = 0x80000000;
 199                 } else if ((int)xx.i[1] >= 0) {      /* x is positive */
 200                         if (xx.i[0]-- == 0)
 201                                 xx.i[1]--;
 202                 } else {
 203                         if (++xx.i[0] == 0)
 204                                 xx.i[1]++;
 205                 }
 206         }
 207 
 208         /* raise exceptions as needed */
 209         hx = xx.i[1] & ~0x80000000;
 210         if (hx == 0x7ff00000) {
 211                 dummy = huge;
 212                 dummy *= huge;
 213         } else if (hx < 0x00100000) {
 214                 dummy = tiny;
 215                 dummy *= tiny;
 216         }
 217 
 218         return (xx.d);
 219 }
 220 
 221 #else
 222 #error Unknown architecture
 223 #endif