xref: /illumos-gate/usr/src/lib/libnsl/rpc/xdr_float.c (revision 7f93f875323d3870ccfa2f3df6aad7f2edecbafe)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55f9e186fSgt29601  * Common Development and Distribution License (the "License").
65f9e186fSgt29601  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
2061961e0fSrobinson  */
2161961e0fSrobinson 
2261961e0fSrobinson /*
23e8031f0aSraf  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
26e8031f0aSraf 
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
287c478bd9Sstevel@tonic-gate /* All Rights Reserved */
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley
317c478bd9Sstevel@tonic-gate  * 4.3 BSD under license from the Regents of the University of
327c478bd9Sstevel@tonic-gate  * California.
337c478bd9Sstevel@tonic-gate  */
344b05e997SJason King /*
354b05e997SJason King  * Copyright 2011 Jason King.  All rights reserved
364b05e997SJason King  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
39e8031f0aSraf  * Generic XDR routines impelmentation.
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * These are the "floating point" xdr routines used to (de)serialize
427c478bd9Sstevel@tonic-gate  * most common data items.  See xdr.h for more info on the interface to
437c478bd9Sstevel@tonic-gate  * xdr.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
46e8031f0aSraf #include "mt.h"
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <stdio.h>
49*7f93f875SJason King #include <values.h>
507c478bd9Sstevel@tonic-gate #include <rpc/types.h>
517c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
52*7f93f875SJason King #include <sys/byteorder.h>
537c478bd9Sstevel@tonic-gate 
54*7f93f875SJason King #ifdef _IEEE_754
557c478bd9Sstevel@tonic-gate 
56*7f93f875SJason King /*
57*7f93f875SJason King  * The OTW format is IEEE 754 with big endian ordering.
58*7f93f875SJason King  */
597c478bd9Sstevel@tonic-gate bool_t
xdr_float(XDR * xdrs,float * fp)607c478bd9Sstevel@tonic-gate xdr_float(XDR *xdrs, float *fp)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate 	switch (xdrs->x_op) {
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	case XDR_ENCODE:
65*7f93f875SJason King 		return (XDR_PUTINT32(xdrs, (int *)fp));
664b05e997SJason King 
674b05e997SJason King 	case XDR_DECODE:
68*7f93f875SJason King 		return (XDR_GETINT32(xdrs, (int *)fp));
694b05e997SJason King 
704b05e997SJason King 	case XDR_FREE:
714b05e997SJason King 		return (TRUE);
724b05e997SJason King 	}
734b05e997SJason King 	return (FALSE);
744b05e997SJason King }
754b05e997SJason King 
764b05e997SJason King bool_t
xdr_double(XDR * xdrs,double * dp)774b05e997SJason King xdr_double(XDR *xdrs, double *dp)
784b05e997SJason King {
79*7f93f875SJason King 	int64_t *i64p = (int64_t *)dp;
80*7f93f875SJason King 	int64_t val;
81*7f93f875SJason King 	bool_t ret;
82*7f93f875SJason King 
834b05e997SJason King 	switch (xdrs->x_op) {
844b05e997SJason King 
854b05e997SJason King 	case XDR_ENCODE:
86*7f93f875SJason King 		val = BE_64(*i64p);
87*7f93f875SJason King 		return (XDR_PUTBYTES(xdrs, (char *)&val, sizeof (val)));
884b05e997SJason King 
894b05e997SJason King 	case XDR_DECODE:
90*7f93f875SJason King 		ret = XDR_GETBYTES(xdrs, (char *)dp, sizeof (double));
91*7f93f875SJason King 		if (ret)
92*7f93f875SJason King 			*i64p = BE_64(*i64p);
93*7f93f875SJason King 		return (ret);
944b05e997SJason King 
954b05e997SJason King 	case XDR_FREE:
964b05e997SJason King 		return (TRUE);
974b05e997SJason King 	}
984b05e997SJason King 
994b05e997SJason King 	return (FALSE);
1004b05e997SJason King }
1014b05e997SJason King 
1024b05e997SJason King /* ARGSUSED */
1034b05e997SJason King bool_t
xdr_quadruple(XDR * xdrs,long double * fp)1044b05e997SJason King xdr_quadruple(XDR *xdrs, long double *fp)
1054b05e997SJason King {
1064b05e997SJason King /*
1074b05e997SJason King  * The Sparc uses IEEE FP encoding, so just do a byte copy
1084b05e997SJason King  */
1094b05e997SJason King 
1104b05e997SJason King #if !defined(sparc)
1114b05e997SJason King 	return (FALSE);
1127c478bd9Sstevel@tonic-gate #else
1134b05e997SJason King 	switch (xdrs->x_op) {
1144b05e997SJason King 	case XDR_ENCODE:
1154b05e997SJason King 		return (XDR_PUTBYTES(xdrs, (char *)fp, sizeof (long double)));
1164b05e997SJason King 	case XDR_DECODE:
1174b05e997SJason King 		return (XDR_GETBYTES(xdrs, (char *)fp, sizeof (long double)));
1184b05e997SJason King 	case XDR_FREE:
1194b05e997SJason King 		return (TRUE);
1207c478bd9Sstevel@tonic-gate 	}
1214b05e997SJason King 	return (FALSE);
1224b05e997SJason King #endif
1237c478bd9Sstevel@tonic-gate }
1244b05e997SJason King 
125*7f93f875SJason King #else
1264b05e997SJason King 
127*7f93f875SJason King #warn No platform specific implementation defined for floats
1284b05e997SJason King 
129*7f93f875SJason King bool_t
xdr_float(XDR * xdrs,float * fp)130*7f93f875SJason King xdr_float(XDR *xdrs, float *fp)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	/*
1337c478bd9Sstevel@tonic-gate 	 * Every machine can do this, its just not very efficient.
1347c478bd9Sstevel@tonic-gate 	 * In addtion, some rounding errors may occur do to the
1357c478bd9Sstevel@tonic-gate 	 * calculations involved.
1367c478bd9Sstevel@tonic-gate 	 */
1377c478bd9Sstevel@tonic-gate 	float f;
1387c478bd9Sstevel@tonic-gate 	int neg = 0;
1397c478bd9Sstevel@tonic-gate 	int exp = 0;
1407c478bd9Sstevel@tonic-gate 	int32_t val;
1417c478bd9Sstevel@tonic-gate 
142*7f93f875SJason King 	switch (xdrs->x_op) {
143*7f93f875SJason King 	case XDR_ENCODE:
1447c478bd9Sstevel@tonic-gate 		f = *fp;
1457c478bd9Sstevel@tonic-gate 		if (f == 0) {
1467c478bd9Sstevel@tonic-gate 			val = 0;
14761961e0fSrobinson 			return (XDR_PUTINT32(xdrs, &val));
1487c478bd9Sstevel@tonic-gate 		}
1497c478bd9Sstevel@tonic-gate 		if (f < 0) {
1507c478bd9Sstevel@tonic-gate 			f = 0 - f;
1517c478bd9Sstevel@tonic-gate 			neg = 1;
1527c478bd9Sstevel@tonic-gate 		}
1537c478bd9Sstevel@tonic-gate 		while (f < 1) {
1547c478bd9Sstevel@tonic-gate 			f = f * 2;
1557c478bd9Sstevel@tonic-gate 			--exp;
1567c478bd9Sstevel@tonic-gate 		}
1577c478bd9Sstevel@tonic-gate 		while (f >= 2) {
1587c478bd9Sstevel@tonic-gate 			f = f/2;
1597c478bd9Sstevel@tonic-gate 			++exp;
1607c478bd9Sstevel@tonic-gate 		}
1617c478bd9Sstevel@tonic-gate 		if ((exp > 128) || (exp < -127)) {
1627c478bd9Sstevel@tonic-gate 			/* over or under flowing ieee exponent */
1637c478bd9Sstevel@tonic-gate 			return (FALSE);
1647c478bd9Sstevel@tonic-gate 		}
1657c478bd9Sstevel@tonic-gate 		val = neg;
1667c478bd9Sstevel@tonic-gate 		val = val << 8;		/* for the exponent */
1677c478bd9Sstevel@tonic-gate 		val += 127 + exp;	/* 127 is the bias */
1687c478bd9Sstevel@tonic-gate 		val = val << 23;	/* for the mantissa */
1697c478bd9Sstevel@tonic-gate 		val += (int32_t)((f - 1) * 8388608);	/* 2 ^ 23 */
17061961e0fSrobinson 		return (XDR_PUTINT32(xdrs, &val));
1717c478bd9Sstevel@tonic-gate 
172*7f93f875SJason King 	case XDR_DECODE:
1737c478bd9Sstevel@tonic-gate 		/*
174*7f93f875SJason King 		 * It assumes that the decoding machine's float can represent
175*7f93f875SJason King 		 * any value in the range of
1767c478bd9Sstevel@tonic-gate 		 *	ieee largest  float  = (2 ^ 128)  * 0x1.fffff
1777c478bd9Sstevel@tonic-gate 		 *	to
1787c478bd9Sstevel@tonic-gate 		 *	ieee smallest float  = (2 ^ -127) * 0x1.00000
1797c478bd9Sstevel@tonic-gate 		 * In addtion, some rounding errors may occur do to the
1807c478bd9Sstevel@tonic-gate 		 * calculations involved.
1817c478bd9Sstevel@tonic-gate 		 */
1827c478bd9Sstevel@tonic-gate 
18361961e0fSrobinson 		if (!XDR_GETINT32(xdrs, (int32_t *)&val))
1847c478bd9Sstevel@tonic-gate 			return (FALSE);
1857c478bd9Sstevel@tonic-gate 		neg = val & 0x80000000;
1867c478bd9Sstevel@tonic-gate 		exp = (val & 0x7f800000) >> 23;
1877c478bd9Sstevel@tonic-gate 		exp -= 127;		/* subtract exponent base */
1887c478bd9Sstevel@tonic-gate 		f = (val & 0x007fffff) * 0.00000011920928955078125;
1897c478bd9Sstevel@tonic-gate 		/* 2 ^ -23 */
1907c478bd9Sstevel@tonic-gate 		f++;
1914b05e997SJason King 
1927c478bd9Sstevel@tonic-gate 		while (exp != 0) {
1937c478bd9Sstevel@tonic-gate 			if (exp < 0) {
1947c478bd9Sstevel@tonic-gate 				f = f/2.0;
1957c478bd9Sstevel@tonic-gate 				++exp;
1967c478bd9Sstevel@tonic-gate 			} else {
1977c478bd9Sstevel@tonic-gate 				f = f * 2.0;
1987c478bd9Sstevel@tonic-gate 				--exp;
1997c478bd9Sstevel@tonic-gate 			}
2007c478bd9Sstevel@tonic-gate 		}
2014b05e997SJason King 
2027c478bd9Sstevel@tonic-gate 		if (neg)
2037c478bd9Sstevel@tonic-gate 			f = 0 - f;
2044b05e997SJason King 
2057c478bd9Sstevel@tonic-gate 		*fp = f;
2067c478bd9Sstevel@tonic-gate 		return (TRUE);
207*7f93f875SJason King 
208*7f93f875SJason King 	case XDR_FREE:
209*7f93f875SJason King 		return (TRUE);
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 
212*7f93f875SJason King 	return (FALSE);
213*7f93f875SJason King }
214*7f93f875SJason King 
215*7f93f875SJason King bool_t
xdr_double(XDR * xdrs,double * dp)216*7f93f875SJason King xdr_double(XDR *xdrs, double *dp)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	/*
2197c478bd9Sstevel@tonic-gate 	 * Every machine can do this, its just not very efficient.
2207c478bd9Sstevel@tonic-gate 	 * In addtion, some rounding errors may occur do to the
2217c478bd9Sstevel@tonic-gate 	 * calculations involved.
2227c478bd9Sstevel@tonic-gate 	 */
2234b05e997SJason King 
2244b05e997SJason King 	int *lp;
2257c478bd9Sstevel@tonic-gate 	double d;
2267c478bd9Sstevel@tonic-gate 	int neg = 0;
2277c478bd9Sstevel@tonic-gate 	int exp = 0;
2287c478bd9Sstevel@tonic-gate 	int32_t val[2];
2297c478bd9Sstevel@tonic-gate 
230*7f93f875SJason King 	switch (xdrs->x_op) {
231*7f93f875SJason King 	case XDR_ENCODE:
2327c478bd9Sstevel@tonic-gate 		d = *dp;
2337c478bd9Sstevel@tonic-gate 		if (d == 0) {
2347c478bd9Sstevel@tonic-gate 			val[0] = 0;
2357c478bd9Sstevel@tonic-gate 			val[1] = 0;
2367c478bd9Sstevel@tonic-gate 			lp = val;
237*7f93f875SJason King 			return (XDR_PUTINT32(xdrs, lp++) &&
238*7f93f875SJason King 			    XDR_PUTINT32(xdrs, lp));
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 		if (d < 0) {
2417c478bd9Sstevel@tonic-gate 			d = 0 - d;
2427c478bd9Sstevel@tonic-gate 			neg = 1;
2437c478bd9Sstevel@tonic-gate 		}
2447c478bd9Sstevel@tonic-gate 		while (d < 1) {
2457c478bd9Sstevel@tonic-gate 			d = d * 2;
2467c478bd9Sstevel@tonic-gate 			--exp;
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 		while (d >= 2) {
2497c478bd9Sstevel@tonic-gate 			d = d/2;
2507c478bd9Sstevel@tonic-gate 			++exp;
2517c478bd9Sstevel@tonic-gate 		}
2527c478bd9Sstevel@tonic-gate 		if ((exp > 1024) || (exp < -1023)) {
2537c478bd9Sstevel@tonic-gate 			/* over or under flowing ieee exponent */
2547c478bd9Sstevel@tonic-gate 			return (FALSE);
2557c478bd9Sstevel@tonic-gate 		}
256*7f93f875SJason King 		val[0] = (neg << 11);	/* for the exponent */
2577c478bd9Sstevel@tonic-gate 		val[0] += 1023 + exp;	/* 1023 is the bias */
2587c478bd9Sstevel@tonic-gate 		val[0] = val[0] << 20;	/* for the mantissa */
2597c478bd9Sstevel@tonic-gate 		val[0] += (int32_t)((d - 1) * 1048576);	/* 2 ^ 20 */
260*7f93f875SJason King 		val[1] += (uint32_t)((((d - 1) * 1048576) - val[0]) *
261*7f93f875SJason King 		    4294967296); /* 2 ^ 32 */
2627c478bd9Sstevel@tonic-gate 		lp = val;
2637c478bd9Sstevel@tonic-gate 
2644b05e997SJason King 		return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
2654b05e997SJason King 
266*7f93f875SJason King 	case XDR_DECODE:
2677c478bd9Sstevel@tonic-gate 		/*
268*7f93f875SJason King 		 * It assumes that the decoding machine's
2697c478bd9Sstevel@tonic-gate 		 * double can represent any value in the range of
2707c478bd9Sstevel@tonic-gate 		 *	ieee largest  double  = (2 ^ 1024)  * 0x1.fffffffffffff
2717c478bd9Sstevel@tonic-gate 		 *	to
2727c478bd9Sstevel@tonic-gate 		 *	ieee smallest double  = (2 ^ -1023) * 0x1.0000000000000
2737c478bd9Sstevel@tonic-gate 		 * In addtion, some rounding errors may occur do to the
2747c478bd9Sstevel@tonic-gate 		 * calculations involved.
2757c478bd9Sstevel@tonic-gate 		 */
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		lp = val;
27861961e0fSrobinson 		if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
2797c478bd9Sstevel@tonic-gate 			return (FALSE);
2807c478bd9Sstevel@tonic-gate 		neg = val[0] & 0x80000000;
2817c478bd9Sstevel@tonic-gate 		exp = (val[0] & 0x7ff00000) >> 20;
2827c478bd9Sstevel@tonic-gate 		exp -= 1023;		/* subtract exponent base */
2837c478bd9Sstevel@tonic-gate 		d = (val[0] & 0x000fffff) * 0.00000095367431640625;
2847c478bd9Sstevel@tonic-gate 		/* 2 ^ -20 */
2857c478bd9Sstevel@tonic-gate 		d += (val[1] * 0.0000000000000002220446049250313);
2867c478bd9Sstevel@tonic-gate 		/* 2 ^ -52 */
2877c478bd9Sstevel@tonic-gate 		d++;
2887c478bd9Sstevel@tonic-gate 		while (exp != 0) {
2897c478bd9Sstevel@tonic-gate 			if (exp < 0) {
2907c478bd9Sstevel@tonic-gate 				d = d/2.0;
2917c478bd9Sstevel@tonic-gate 				++exp;
2927c478bd9Sstevel@tonic-gate 			} else {
2937c478bd9Sstevel@tonic-gate 				d = d * 2.0;
2947c478bd9Sstevel@tonic-gate 				--exp;
2957c478bd9Sstevel@tonic-gate 			}
2967c478bd9Sstevel@tonic-gate 		}
2977c478bd9Sstevel@tonic-gate 		if (neg)
2987c478bd9Sstevel@tonic-gate 			d = 0 - d;
2994b05e997SJason King 
3007c478bd9Sstevel@tonic-gate 		*dp = d;
3017c478bd9Sstevel@tonic-gate 		return (TRUE);
302*7f93f875SJason King 
303*7f93f875SJason King 	case XDR_FREE:
304*7f93f875SJason King 		return (TRUE);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
307*7f93f875SJason King 	return (FALSE);
308*7f93f875SJason King }
309*7f93f875SJason King 
310*7f93f875SJason King bool_t
xdr_quadruple(XDR * xdrs,long double * fp)311*7f93f875SJason King xdr_quadruple(XDR *xdrs, long double *fp)
312*7f93f875SJason King {
313*7f93f875SJason King 	return (FALSE);
314*7f93f875SJason King }
315*7f93f875SJason King 
316*7f93f875SJason King #endif /* _IEEE_754 */
317