xref: /illumos-gate/usr/src/lib/libnsl/rpc/xdr_float.c (revision a07094369b21309434206d9b3601d162693466fc)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30 /*
31  * Portions of this source code were derived from Berkeley
32  * 4.3 BSD under license from the Regents of the University of
33  * California.
34  */
35 
36 #pragma ident	"%Z%%M%	%I%	%E% SMI"
37 
38 /*
39  * Generic XDR routines impelmentation.
40  *
41  * These are the "floating point" xdr routines used to (de)serialize
42  * most common data items.  See xdr.h for more info on the interface to
43  * xdr.
44  */
45 
46 #include "mt.h"
47 #include <sys/types.h>
48 #include <stdio.h>
49 #include <rpc/types.h>
50 #include <rpc/xdr.h>
51 
52 /*
53  * This routine works on Suns, 3b2, 68000s, 386 and Vaxen in a manner
54  * which is very efficient as bit twiddling is all that is needed.  All
55  * other machines can use this code but the code is inefficient as
56  * various mathematical operations are used to generate the ieee format.
57  * In addition rounding errors may occur due to the calculations involved.
58  * To be most efficient, new machines should have their own ifdefs.
59  * The encoding routines will fail if the machines try to encode a
60  * float/double whose value can not be represented by the ieee format,
61  * e.g. the exponent is too big/small.
62  *	ieee largest  float  = (2 ^ 128)  * 0x1.fffff
63  *	ieee smallest float  = (2 ^ -127) * 0x1.00000
64  *	ieee largest  double = (2 ^ 1024)  * 0x1.fffff
65  *	ieee smallest double = (2 ^ -1023) * 0x1.00000
66  * The decoding routines assumes that the receiving machine can handle
67  * floats/doubles as large/small as the values stated above.  If you
68  * use a machine which can not represent these values, you will need
69  * to put ifdefs in the decode sections to identify areas of failure.
70  */
71 
72 #if defined(vax)
73 
74 /*
75  * What IEEE single precision floating point looks like this on a
76  * vax.
77  */
78 
79 struct	ieee_single {
80 	unsigned int	mantissa: 23;
81 	unsigned int	exp	: 8;
82 	unsigned int	sign    : 1;
83 };
84 
85 #define	IEEE_SNG_BIAS	0x7f
86 #define	VAX_SNG_BIAS    0x81
87 
88 
89 /* Vax single precision floating point */
90 struct	vax_single {
91 	unsigned int	mantissa1 : 7;
92 	unsigned int	exp	: 8;
93 	unsigned int	sign	: 1;
94 	unsigned int	mantissa2 : 16;
95 };
96 
97 #define	VAX_SNG_BIAS	0x81
98 
99 static struct sgl_limits {
100 	struct vax_single s;
101 	struct ieee_single ieee;
102 } sgl_limits[2] = {
103 	{{ 0x7f, 0xff, 0x0, 0xffff },	/* Max Vax */
104 	{ 0x0, 0xff, 0x0 }},		/* Max IEEE */
105 	{{ 0x0, 0x0, 0x0, 0x0 },	/* Min Vax */
106 	{ 0x0, 0x0, 0x0 }}		/* Min IEEE */
107 };
108 #endif /* vax */
109 
110 bool_t
111 xdr_float(XDR *xdrs, float *fp)
112 {
113 #if defined(vax)
114 	struct ieee_single is;
115 	struct vax_single vs, *vsp;
116 	struct sgl_limits *lim;
117 	size_t i;
118 #endif
119 
120 	switch (xdrs->x_op) {
121 
122 	case XDR_ENCODE:
123 #if defined(mc68000) || defined(sparc) || defined(u3b2) || \
124 	defined(u3b15) || defined(i386)
125 		return (XDR_PUTINT32(xdrs, (int *)fp));
126 #else
127 #if defined(vax)
128 		vs = *((struct vax_single *)fp);
129 		if ((vs.exp == 1) || (vs.exp == 2)) {
130 			/* map these to subnormals */
131 			is.exp = 0;
132 			is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
133 			/* lose some precision */
134 			is.mantissa >>= 3 - vs.exp;
135 			is.mantissa += (1 << (20 + vs.exp));
136 			goto shipit;
137 		}
138 		for (i = 0, lim = sgl_limits;
139 			i < (int)(sizeof (sgl_limits) /
140 					sizeof (struct sgl_limits));
141 			i++, lim++) {
142 			if ((vs.mantissa2 == lim->s.mantissa2) &&
143 				(vs.exp == lim->s.exp) &&
144 				(vs.mantissa1 == lim->s.mantissa1)) {
145 				is = lim->ieee;
146 				goto shipit;
147 			}
148 		}
149 		is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
150 		is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
151 	shipit:
152 		is.sign = vs.sign;
153 		return (XDR_PUTINT32(xdrs, (int32_t *)&is));
154 #else
155 		{
156 		/*
157 		 * Every machine can do this, its just not very efficient.
158 		 * In addtion, some rounding errors may occur do to the
159 		 * calculations involved.
160 		 */
161 		float f;
162 		int neg = 0;
163 		int exp = 0;
164 		int32_t val;
165 
166 		f = *fp;
167 		if (f == 0) {
168 			val = 0;
169 			return (XDR_PUTINT32(xdrs, &val));
170 		}
171 		if (f < 0) {
172 			f = 0 - f;
173 			neg = 1;
174 		}
175 		while (f < 1) {
176 			f = f * 2;
177 			--exp;
178 		}
179 		while (f >= 2) {
180 			f = f/2;
181 			++exp;
182 		}
183 		if ((exp > 128) || (exp < -127)) {
184 			/* over or under flowing ieee exponent */
185 			return (FALSE);
186 		}
187 		val = neg;
188 		val = val << 8;		/* for the exponent */
189 		val += 127 + exp;	/* 127 is the bias */
190 		val = val << 23;	/* for the mantissa */
191 		val += (int32_t)((f - 1) * 8388608);	/* 2 ^ 23 */
192 		return (XDR_PUTINT32(xdrs, &val));
193 		}
194 #endif
195 #endif
196 
197 	case XDR_DECODE:
198 #if defined(mc68000) || defined(sparc) || defined(u3b2) || \
199 	defined(u3b15) || defined(i386)
200 		return (XDR_GETINT32(xdrs, (int *)fp));
201 #else
202 #if defined(vax)
203 		vsp = (struct vax_single *)fp;
204 		if (!XDR_GETINT32(xdrs, (int32_t *)&is))
205 			return (FALSE);
206 
207 		for (i = 0, lim = sgl_limits;
208 			i < (int)(sizeof (sgl_limits) /
209 					sizeof (struct sgl_limits));
210 			i++, lim++) {
211 			if ((is.exp == lim->ieee.exp) &&
212 				(is.mantissa == lim->ieee.mantissa)) {
213 				*vsp = lim->s;
214 				goto doneit;
215 			} else if ((is.exp == 0) && (lim->ieee.exp == 0)) {
216 			    /* Special Case */
217 			    unsigned tmp = is.mantissa >> 20;
218 			    if (tmp >= 4) {
219 			    vsp->exp = 2;
220 			    } else if (tmp >= 2) {
221 			    vsp->exp = 1;
222 			    } else {
223 				*vsp = min.s;
224 				break;
225 			    }	/* else */
226 			    tmp = is.mantissa - (1 << (20 + vsp->exp));
227 			    tmp <<= 3 - vsp->exp;
228 			    vsp->mantissa2 = tmp;
229 			    vsp->mantissa1 = (tmp >> 16);
230 			    goto doneit;
231 		    }
232 		vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
233 		vsp->mantissa2 = is.mantissa;
234 		vsp->mantissa1 = (is.mantissa >> 16);
235 	doneit:
236 		vsp->sign = is.sign;
237 		return (TRUE);
238 #else
239 		{
240 		/*
241 		 * Every machine can do this, its just not very
242 		 * efficient.  It assumes that the decoding machine's
243 		 * float can represent any value in the range of
244 		 *	ieee largest  float  = (2 ^ 128)  * 0x1.fffff
245 		 *	to
246 		 *	ieee smallest float  = (2 ^ -127) * 0x1.00000
247 		 * In addtion, some rounding errors may occur do to the
248 		 * calculations involved.
249 		 */
250 		float f;
251 		int neg = 0;
252 		int exp = 0;
253 		int32_t val;
254 
255 		if (!XDR_GETINT32(xdrs, (int32_t *)&val))
256 			return (FALSE);
257 		neg = val & 0x80000000;
258 		exp = (val & 0x7f800000) >> 23;
259 		exp -= 127;		/* subtract exponent base */
260 		f = (val & 0x007fffff) * 0.00000011920928955078125;
261 		/* 2 ^ -23 */
262 		f++;
263 		while (exp != 0) {
264 			if (exp < 0) {
265 				f = f/2.0;
266 				++exp;
267 			} else {
268 				f = f * 2.0;
269 				--exp;
270 			}
271 		}
272 		if (neg)
273 			f = 0 - f;
274 		*fp = f;
275 		}
276 		return (TRUE);
277 #endif
278 #endif
279 
280 	case XDR_FREE:
281 		return (TRUE);
282 	}
283 	return (FALSE);
284 }
285 
286 /*
287  * This routine works on Suns (Sky / 68000's) and Vaxen.
288  */
289 
290 #if defined(vax)
291 /* What IEEE double precision floating point looks like on a Vax */
292 struct	ieee_double {
293 	unsigned int	mantissa1 : 20;
294 	unsigned int	exp	  : 11;
295 	unsigned int	sign	  : 1;
296 	unsigned int	mantissa2 : 32;
297 };
298 
299 /* Vax double precision floating point */
300 struct  vax_double {
301 	unsigned int	mantissa1 : 7;
302 	unsigned int	exp	  : 8;
303 	unsigned int	sign	  : 1;
304 	unsigned int	mantissa2 : 16;
305 	unsigned int	mantissa3 : 16;
306 	unsigned int	mantissa4 : 16;
307 };
308 
309 #define	VAX_DBL_BIAS	0x81
310 #define	IEEE_DBL_BIAS	0x3ff
311 #define	MASK(nbits)	((1 << nbits) - 1)
312 
313 static struct dbl_limits {
314 	struct	vax_double d;
315 	struct	ieee_double ieee;
316 } dbl_limits[2] = {
317 	{{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff },	/* Max Vax */
318 	{ 0x0, 0x7ff, 0x0, 0x0 }},			/* Max IEEE */
319 	{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},		/* Min Vax */
320 	{ 0x0, 0x0, 0x0, 0x0 }}				/* Min IEEE */
321 };
322 
323 #endif /* vax */
324 
325 
326 bool_t
327 xdr_double(XDR *xdrs, double *dp)
328 {
329 	int *lp;
330 #if defined(vax)
331 	struct	ieee_double id;
332 	struct	vax_double vd;
333 	struct dbl_limits *lim;
334 	size_t i;
335 #endif
336 
337 	switch (xdrs->x_op) {
338 
339 	case XDR_ENCODE:
340 #if defined(mc68000) || defined(u3b2) || defined(u3b15) || \
341 	defined(_LONG_LONG_HTOL)
342 		lp = (int *)dp;
343 		return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
344 #else
345 #if defined(_LONG_LONG_LTOH)
346 		lp = (int *)dp;
347 		lp++;
348 		return (XDR_PUTINT32(xdrs, lp--) && XDR_PUTINT32(xdrs, lp));
349 #else
350 #if defined(vax)
351 		vd = *((struct vax_double *)dp);
352 		for (i = 0, lim = dbl_limits;
353 			i < (int)(sizeof (dbl_limits) /
354 					sizeof (struct dbl_limits));
355 			i++, lim++) {
356 			if ((vd.mantissa4 == lim->d.mantissa4) &&
357 				(vd.mantissa3 == lim->d.mantissa3) &&
358 				(vd.mantissa2 == lim->d.mantissa2) &&
359 				(vd.mantissa1 == lim->d.mantissa1) &&
360 				(vd.exp == lim->d.exp)) {
361 				id = lim->ieee;
362 				goto shipit;
363 			}
364 		}
365 		id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
366 		id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
367 		id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
368 				(vd.mantissa3 << 13) |
369 				((vd.mantissa4 >> 3) & MASK(13));
370 	shipit:
371 		id.sign = vd.sign;
372 		lp = (int32_t *)&id;
373 #else
374 		{
375 		/*
376 		 * Every machine can do this, its just not very efficient.
377 		 * In addtion, some rounding errors may occur do to the
378 		 * calculations involved.
379 		 */
380 		double d;
381 		int neg = 0;
382 		int exp = 0;
383 		int32_t val[2];
384 
385 		d = *dp;
386 		if (d == 0) {
387 			val[0] = 0;
388 			val[1] = 0;
389 			lp = val;
390 			return (XDR_PUTINT32(xdrs, lp++) &&
391 				XDR_PUTINT32(xdrs, lp));
392 		}
393 		if (d < 0) {
394 			d = 0 - d;
395 			neg = 1;
396 		}
397 		while (d < 1) {
398 			d = d * 2;
399 			--exp;
400 		}
401 		while (d >= 2) {
402 			d = d/2;
403 			++exp;
404 		}
405 		if ((exp > 1024) || (exp < -1023)) {
406 			/* over or under flowing ieee exponent */
407 			return (FALSE);
408 		}
409 		val[0] = neg;
410 		val[0] = val[0] << 11;	/* for the exponent */
411 		val[0] += 1023 + exp;	/* 1023 is the bias */
412 		val[0] = val[0] << 20;	/* for the mantissa */
413 		val[0] += (int32_t)((d - 1) * 1048576);	/* 2 ^ 20 */
414 		val[1] += (int32_t)((((d - 1) * 1048576) - val[0])
415 							* 4294967296);
416 		/* 2 ^ 32 */
417 		lp = val;
418 		}
419 #endif
420 		return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
421 #endif
422 #endif
423 
424 	case XDR_DECODE:
425 #if defined(mc68000) || defined(u3b2) || defined(u3b15) || \
426 	defined(_LONG_LONG_HTOL)
427 		lp = (int *)dp;
428 		return (XDR_GETINT32(xdrs, lp++) && XDR_GETINT32(xdrs, lp));
429 #else
430 #if defined(_LONG_LONG_LTOH)
431 		lp = (int *)dp;
432 		lp++;
433 		return (XDR_GETINT32(xdrs, lp--) && XDR_GETINT32(xdrs, lp));
434 #else
435 #if defined(vax)
436 		lp = (int32_t *)&id;
437 		if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
438 			return (FALSE);
439 		for (i = 0, lim = dbl_limits;
440 			i < sizeof (dbl_limits)/sizeof (struct dbl_limits);
441 			i++, lim++) {
442 			if ((id.mantissa2 == lim->ieee.mantissa2) &&
443 				(id.mantissa1 == lim->ieee.mantissa1) &&
444 				(id.exp == lim->ieee.exp)) {
445 				vd = lim->d;
446 				goto doneit;
447 			}
448 		}
449 		vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
450 		vd.mantissa1 = (id.mantissa1 >> 13);
451 		vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
452 				(id.mantissa2 >> 29);
453 		vd.mantissa3 = (id.mantissa2 >> 13);
454 		vd.mantissa4 = (id.mantissa2 << 3);
455 	doneit:
456 		vd.sign = id.sign;
457 		*dp = *((double *)&vd);
458 		return (TRUE);
459 #else
460 		{
461 		/*
462 		 * Every machine can do this, its just not very
463 		 * efficient.  It assumes that the decoding machine's
464 		 * double can represent any value in the range of
465 		 *	ieee largest  double  = (2 ^ 1024)  * 0x1.fffffffffffff
466 		 *	to
467 		 *	ieee smallest double  = (2 ^ -1023) * 0x1.0000000000000
468 		 * In addtion, some rounding errors may occur do to the
469 		 * calculations involved.
470 		 */
471 		double d;
472 		int neg = 0;
473 		int exp = 0;
474 		int32_t val[2];
475 
476 		lp = val;
477 		if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
478 			return (FALSE);
479 		neg = val[0] & 0x80000000;
480 		exp = (val[0] & 0x7ff00000) >> 20;
481 		exp -= 1023;		/* subtract exponent base */
482 		d = (val[0] & 0x000fffff) * 0.00000095367431640625;
483 		/* 2 ^ -20 */
484 		d += (val[1] * 0.0000000000000002220446049250313);
485 		/* 2 ^ -52 */
486 		d++;
487 		while (exp != 0) {
488 			if (exp < 0) {
489 				d = d/2.0;
490 				++exp;
491 			} else {
492 				d = d * 2.0;
493 				--exp;
494 			}
495 		}
496 		if (neg)
497 			d = 0 - d;
498 		*dp = d;
499 		}
500 #endif
501 #endif
502 #endif
503 
504 	case XDR_FREE:
505 		return (TRUE);
506 	}
507 	return (FALSE);
508 }
509 
510 /* ARGSUSED */
511 bool_t
512 xdr_quadruple(XDR *xdrs, long double *fp)
513 {
514 /*
515  * The Sparc uses IEEE FP encoding, so just do a byte copy
516  */
517 
518 #if !defined(sparc)
519 	return (FALSE);
520 #else
521 	switch (xdrs->x_op) {
522 	case XDR_ENCODE:
523 		return (XDR_PUTBYTES(xdrs, (char *)fp, sizeof (long double)));
524 	case XDR_DECODE:
525 		return (XDR_GETBYTES(xdrs, (char *)fp, sizeof (long double)));
526 	case XDR_FREE:
527 		return (TRUE);
528 	}
529 	return (FALSE);
530 #endif
531 }
532