1*ace5b9b5Schristos /* $NetBSD: compat_modf_ieee754.c,v 1.6 2024/01/20 14:52:45 christos Exp $ */
200483774Sdrochner
300483774Sdrochner /*
400483774Sdrochner * Copyright (c) 1994, 1995 Carnegie-Mellon University.
500483774Sdrochner * All rights reserved.
600483774Sdrochner *
700483774Sdrochner * Author: Chris G. Demetriou
800483774Sdrochner *
900483774Sdrochner * Permission to use, copy, modify and distribute this software and
1000483774Sdrochner * its documentation is hereby granted, provided that both the copyright
1100483774Sdrochner * notice and this permission notice appear in all copies of the
1200483774Sdrochner * software, derivative works or modified versions, and any portions
1300483774Sdrochner * thereof, and that both notices appear in supporting documentation.
1400483774Sdrochner *
1500483774Sdrochner * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1600483774Sdrochner * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
1700483774Sdrochner * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1800483774Sdrochner *
1900483774Sdrochner * Carnegie Mellon requests users of this software to return to
2000483774Sdrochner *
2100483774Sdrochner * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
2200483774Sdrochner * School of Computer Science
2300483774Sdrochner * Carnegie Mellon University
2400483774Sdrochner * Pittsburgh PA 15213-3890
2500483774Sdrochner *
2600483774Sdrochner * any improvements or extensions that they make and grant Carnegie the
2700483774Sdrochner * rights to redistribute these changes.
2800483774Sdrochner */
2900483774Sdrochner
3000483774Sdrochner #include <sys/types.h>
3100483774Sdrochner #include <machine/ieee.h>
3200483774Sdrochner #include <errno.h>
33*ace5b9b5Schristos #include <math.h>
3400483774Sdrochner
3500483774Sdrochner /*
3600483774Sdrochner * double modf(double val, double *iptr)
3700483774Sdrochner * returns: f and i such that |f| < 1.0, (f + i) = val, and
3800483774Sdrochner * sign(f) == sign(i) == sign(val).
3900483774Sdrochner *
4000483774Sdrochner * Beware signedness when doing subtraction, and also operand size!
4100483774Sdrochner */
4200483774Sdrochner double
modf(double val,double * iptr)4300483774Sdrochner modf(double val, double *iptr)
4400483774Sdrochner {
4500483774Sdrochner union ieee_double_u u, v;
4600483774Sdrochner u_int64_t frac;
4700483774Sdrochner
4800483774Sdrochner /*
496cbc5cbfSdrochner * If input is +/-Inf or NaN, return +/-0 or NaN.
5000483774Sdrochner */
5100483774Sdrochner u.dblu_d = val;
526cbc5cbfSdrochner if (u.dblu_dbl.dbl_exp == DBL_EXP_INFNAN) {
536cbc5cbfSdrochner *iptr = u.dblu_d;
546cbc5cbfSdrochner return (0.0 / u.dblu_d);
556cbc5cbfSdrochner }
5600483774Sdrochner
5700483774Sdrochner /*
5800483774Sdrochner * If input can't have a fractional part, return
5900483774Sdrochner * (appropriately signed) zero, and make i be the input.
6000483774Sdrochner */
6100483774Sdrochner if ((int)u.dblu_dbl.dbl_exp - DBL_EXP_BIAS > DBL_FRACBITS - 1) {
6200483774Sdrochner *iptr = u.dblu_d;
6300483774Sdrochner v.dblu_d = 0.0;
6400483774Sdrochner v.dblu_dbl.dbl_sign = u.dblu_dbl.dbl_sign;
6500483774Sdrochner return (v.dblu_d);
6600483774Sdrochner }
6700483774Sdrochner
6800483774Sdrochner /*
6900483774Sdrochner * If |input| < 1.0, return it, and set i to the appropriately
7000483774Sdrochner * signed zero.
7100483774Sdrochner */
7200483774Sdrochner if (u.dblu_dbl.dbl_exp < DBL_EXP_BIAS) {
7300483774Sdrochner v.dblu_d = 0.0;
7400483774Sdrochner v.dblu_dbl.dbl_sign = u.dblu_dbl.dbl_sign;
7500483774Sdrochner *iptr = v.dblu_d;
7600483774Sdrochner return (u.dblu_d);
7700483774Sdrochner }
7800483774Sdrochner
7900483774Sdrochner /*
8000483774Sdrochner * There can be a fractional part of the input.
8100483774Sdrochner * If you look at the math involved for a few seconds, it's
8200483774Sdrochner * plain to see that the integral part is the input, with the
8300483774Sdrochner * low (DBL_FRACBITS - (exponent - DBL_EXP_BIAS)) bits zeroed,
8400483774Sdrochner * the fractional part is the part with the rest of the
8500483774Sdrochner * bits zeroed. Just zeroing the high bits to get the
8600483774Sdrochner * fractional part would yield a fraction in need of
8700483774Sdrochner * normalization. Therefore, we take the easy way out, and
8800483774Sdrochner * just use subtraction to get the fractional part.
8900483774Sdrochner */
9000483774Sdrochner v.dblu_d = u.dblu_d;
9100483774Sdrochner /* Zero the low bits of the fraction, the sleazy way. */
9200483774Sdrochner frac = ((u_int64_t)v.dblu_dbl.dbl_frach << 32) + v.dblu_dbl.dbl_fracl;
9300483774Sdrochner frac >>= DBL_FRACBITS - (u.dblu_dbl.dbl_exp - DBL_EXP_BIAS);
9400483774Sdrochner frac <<= DBL_FRACBITS - (u.dblu_dbl.dbl_exp - DBL_EXP_BIAS);
951acb507cSchristos v.dblu_dbl.dbl_fracl = (unsigned int)(frac & 0xffffffffULL);
9600483774Sdrochner v.dblu_dbl.dbl_frach = (unsigned int)(frac >> 32);
9700483774Sdrochner *iptr = v.dblu_d;
9800483774Sdrochner
9900483774Sdrochner u.dblu_d -= v.dblu_d;
10000483774Sdrochner u.dblu_dbl.dbl_sign = v.dblu_dbl.dbl_sign;
10100483774Sdrochner return (u.dblu_d);
10200483774Sdrochner }
103