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 #pragma weak nexttoward = __nexttoward
  31 
  32 /*
  33  * nexttoward(x, y) delivers the next representable number after x
  34  * in the direction of y.  If x and y are both zero, the result is
  35  * zero with the same sign as y.  If either x or y is NaN, the result
  36  * is NaN.
  37  *
  38  * If x != y and the result is infinite, overflow is raised; if
  39  * x != y and the result is subnormal or zero, underflow is raised.
  40  * (This is wrong, but it's what C99 apparently wants.)
  41  */
  42 
  43 #include "libm.h"
  44 
  45 #if defined(__sparc)
  46 
  47 static union {
  48         unsigned i[2];
  49         double d;
  50 } C[] = {
  51         0x00100000, 0,
  52         0x7fe00000, 0,
  53         0x7fffffff, 0xffffffff
  54 };
  55 
  56 #define tiny    C[0].d
  57 #define huge    C[1].d
  58 #define qnan    C[2].d
  59 
  60 enum fcc_type {
  61         fcc_equal = 0,
  62         fcc_less = 1,
  63         fcc_greater = 2,
  64         fcc_unordered = 3
  65 };
  66 
  67 #ifdef __sparcv9
  68 #define _Q_cmp  _Qp_cmp
  69 #endif
  70 
  71 extern enum fcc_type _Q_cmp(const long double *, const long double *);
  72 
  73 double
  74 __nexttoward(double x, long double y) {
  75         union {
  76                 unsigned i[2];
  77                 double d;
  78         } xx;
  79         union {
  80                 unsigned i[4];
  81                 long double q;
  82         } yy;
  83         long double lx;
  84         unsigned hx;
  85         volatile double dummy;
  86         enum fcc_type rel;
  87 
  88         /*
  89          * It would be somewhat more efficient to check for NaN and
  90          * zero operands before converting x to long double and then
  91          * to code the comparison in line rather than calling _Q_cmp.
  92          * However, since this code probably won't get used much,
  93          * I'm opting in favor of simplicity instead.
  94          */
  95         lx = xx.d = x;
  96         hx = (xx.i[0] & ~0x80000000) | xx.i[1];
  97 
  98         /* check for each of four possible orderings */
  99         rel = _Q_cmp(&lx, &y);
 100         if (rel == fcc_unordered)
 101                 return (qnan);
 102 
 103         if (rel == fcc_equal) {
 104                 if (hx == 0) {  /* x is zero; return zero with y's sign */
 105                         yy.q = y;
 106                         xx.i[0] = yy.i[0];
 107                         return (xx.d);
 108                 }
 109                 return (x);
 110         }
 111 
 112         if (rel == fcc_less) {
 113                 if (hx == 0) {  /* x is zero */
 114                         xx.i[0] = 0;
 115                         xx.i[1] = 0x00000001;
 116                 } else if ((int)xx.i[0] >= 0) {      /* x is positive */
 117                         if (++xx.i[1] == 0)
 118                                 xx.i[0]++;
 119                 } else {
 120                         if (xx.i[1]-- == 0)
 121                                 xx.i[0]--;
 122                 }
 123         } else {
 124                 if (hx == 0) {  /* x is zero */
 125                         xx.i[0] = 0x80000000;
 126                         xx.i[1] = 0x00000001;
 127                 } else if ((int)xx.i[0] >= 0) {      /* x is positive */
 128                         if (xx.i[1]-- == 0)
 129                                 xx.i[0]--;
 130                 } else {
 131                         if (++xx.i[1] == 0)
 132                                 xx.i[0]++;
 133                 }
 134         }
 135 
 136         /* raise exceptions as needed */
 137         hx = xx.i[0] & ~0x80000000;
 138         if (hx == 0x7ff00000) {
 139                 dummy = huge;
 140                 dummy *= huge;
 141         } else if (hx < 0x00100000) {
 142                 dummy = tiny;
 143                 dummy *= tiny;
 144         }
 145 
 146         return (xx.d);
 147 }
 148 
 149 #elif defined(__x86)
 150 
 151 static union {
 152         unsigned i[2];
 153         double d;
 154 } C[] = {
 155         0, 0x00100000,
 156         0, 0x7fe00000,
 157 };
 158 
 159 #define tiny    C[0].d
 160 #define huge    C[1].d
 161 
 162 double
 163 __nexttoward(double x, long double y) {
 164         union {
 165                 unsigned i[2];
 166                 double d;
 167         } xx;
 168         unsigned hx;
 169         long double lx;
 170         volatile double dummy;
 171 
 172         lx = xx.d = x;
 173         hx = (xx.i[1] & ~0x80000000) | xx.i[0];
 174 
 175         /* check for each of four possible orderings */
 176         if (isunordered(lx, y))
 177                 return ((double) (lx + y));
 178 
 179         if (lx == y)
 180                 return ((double) y);
 181 
 182         if (lx < y) {
 183                 if (hx == 0) {  /* x is zero */
 184                         xx.i[0] = 0x00000001;
 185                         xx.i[1] = 0;
 186                 } else if ((int)xx.i[1] >= 0) {      /* x is positive */
 187                         if (++xx.i[0] == 0)
 188                                 xx.i[1]++;
 189                 } else {
 190                         if (xx.i[0]-- == 0)
 191                                 xx.i[1]--;
 192                 }
 193         } else {
 194                 if (hx == 0) {  /* x is zero */
 195                         xx.i[0] = 0x00000001;
 196                         xx.i[1] = 0x80000000;
 197                 } else if ((int)xx.i[1] >= 0) {      /* x is positive */
 198                         if (xx.i[0]-- == 0)
 199                                 xx.i[1]--;
 200                 } else {
 201                         if (++xx.i[0] == 0)
 202                                 xx.i[1]++;
 203                 }
 204         }
 205 
 206         /* raise exceptions as needed */
 207         hx = xx.i[1] & ~0x80000000;
 208         if (hx == 0x7ff00000) {
 209                 dummy = huge;
 210                 dummy *= huge;
 211         } else if (hx < 0x00100000) {
 212                 dummy = tiny;
 213                 dummy *= tiny;
 214         }
 215 
 216         return (xx.d);
 217 }
 218 
 219 #else
 220 #error Unknown architecture
 221 #endif