1d59437c0Smrg /* mpfr_ui_div -- divide a machine integer by a floating-point number
2d59437c0Smrg
3ba125506Smrg Copyright 2000-2023 Free Software Foundation, Inc.
4efdec83bSmrg Contributed by the AriC and Caramba projects, INRIA.
5d59437c0Smrg
6d59437c0Smrg This file is part of the GNU MPFR Library.
7d59437c0Smrg
8d59437c0Smrg The GNU MPFR Library is free software; you can redistribute it and/or modify
9d59437c0Smrg it under the terms of the GNU Lesser General Public License as published by
10d59437c0Smrg the Free Software Foundation; either version 3 of the License, or (at your
11d59437c0Smrg option) any later version.
12d59437c0Smrg
13d59437c0Smrg The GNU MPFR Library is distributed in the hope that it will be useful, but
14d59437c0Smrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15d59437c0Smrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16d59437c0Smrg License for more details.
17d59437c0Smrg
18d59437c0Smrg You should have received a copy of the GNU Lesser General Public License
19d59437c0Smrg along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
202ba2404bSmrg https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21d59437c0Smrg 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22d59437c0Smrg
23d59437c0Smrg
24d59437c0Smrg #define MPFR_NEED_LONGLONG_H
25d59437c0Smrg #include "mpfr-impl.h"
26d59437c0Smrg
27d59437c0Smrg int
mpfr_ui_div(mpfr_ptr y,unsigned long int u,mpfr_srcptr x,mpfr_rnd_t rnd_mode)28d59437c0Smrg mpfr_ui_div (mpfr_ptr y, unsigned long int u, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
29d59437c0Smrg {
30d59437c0Smrg MPFR_LOG_FUNC
31*ec6772edSmrg (("u=%lu x[%Pd]=%.*Rg rnd=%d",
32d59437c0Smrg u, mpfr_get_prec(x), mpfr_log_prec, x, rnd_mode),
33*ec6772edSmrg ("y[%Pd]=%.*Rg", mpfr_get_prec(y), mpfr_log_prec, y));
34d59437c0Smrg
35d59437c0Smrg if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(x)))
36d59437c0Smrg {
37d59437c0Smrg if (MPFR_IS_NAN(x))
38d59437c0Smrg {
39d59437c0Smrg MPFR_SET_NAN(y);
40d59437c0Smrg MPFR_RET_NAN;
41d59437c0Smrg }
42d59437c0Smrg else if (MPFR_IS_INF(x)) /* u/Inf = 0 */
43d59437c0Smrg {
44d59437c0Smrg MPFR_SET_ZERO(y);
45d59437c0Smrg MPFR_SET_SAME_SIGN(y,x);
46d59437c0Smrg MPFR_RET(0);
47d59437c0Smrg }
48d59437c0Smrg else /* u / 0 */
49d59437c0Smrg {
50d59437c0Smrg MPFR_ASSERTD(MPFR_IS_ZERO(x));
51d59437c0Smrg if (u)
52d59437c0Smrg {
53d59437c0Smrg /* u > 0, so y = sign(x) * Inf */
54d59437c0Smrg MPFR_SET_SAME_SIGN(y, x);
55d59437c0Smrg MPFR_SET_INF(y);
56299c6f0cSmrg MPFR_SET_DIVBY0 ();
57d59437c0Smrg MPFR_RET(0);
58d59437c0Smrg }
59d59437c0Smrg else
60d59437c0Smrg {
61d59437c0Smrg /* 0 / 0 */
62d59437c0Smrg MPFR_SET_NAN(y);
63d59437c0Smrg MPFR_RET_NAN;
64d59437c0Smrg }
65d59437c0Smrg }
66d59437c0Smrg }
67d59437c0Smrg else if (MPFR_LIKELY(u != 0))
68d59437c0Smrg {
692ba2404bSmrg int inex;
702ba2404bSmrg MPFR_SAVE_EXPO_DECL (expo);
712ba2404bSmrg
722ba2404bSmrg /* Optimization note: Exponent save/restore operations may be
732ba2404bSmrg removed if mpfr_div works even when uu is out-of-range. */
742ba2404bSmrg MPFR_SAVE_EXPO_MARK (expo);
752ba2404bSmrg
762ba2404bSmrg #ifdef MPFR_LONG_WITHIN_LIMB
772ba2404bSmrg {
78efdec83bSmrg mpfr_t uu;
79efdec83bSmrg mp_limb_t up[1];
80efdec83bSmrg int cnt;
81efdec83bSmrg
82d59437c0Smrg MPFR_TMP_INIT1(up, uu, GMP_NUMB_BITS);
83d59437c0Smrg MPFR_ASSERTN(u == (mp_limb_t) u);
84d59437c0Smrg count_leading_zeros(cnt, (mp_limb_t) u);
85d59437c0Smrg up[0] = (mp_limb_t) u << cnt;
86efdec83bSmrg
87d59437c0Smrg MPFR_SET_EXP (uu, GMP_NUMB_BITS - cnt);
88efdec83bSmrg inex = mpfr_div (y, uu, x, rnd_mode);
892ba2404bSmrg }
902ba2404bSmrg #else
912ba2404bSmrg {
922ba2404bSmrg mpfr_t uu;
932ba2404bSmrg
942ba2404bSmrg mpfr_init2 (uu, sizeof (unsigned long) * CHAR_BIT);
952ba2404bSmrg mpfr_set_ui (uu, u, MPFR_RNDZ);
962ba2404bSmrg inex = mpfr_div (y, uu, x, rnd_mode);
972ba2404bSmrg mpfr_clear (uu);
982ba2404bSmrg }
992ba2404bSmrg #endif
1002ba2404bSmrg
101efdec83bSmrg MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, __gmpfr_flags);
102efdec83bSmrg MPFR_SAVE_EXPO_FREE (expo);
103efdec83bSmrg return mpfr_check_range (y, inex, rnd_mode);
104d59437c0Smrg }
105d59437c0Smrg else /* u = 0, and x != 0 */
106d59437c0Smrg {
107d59437c0Smrg MPFR_SET_ZERO(y); /* if u=0, then set y to 0 */
108d59437c0Smrg MPFR_SET_SAME_SIGN(y, x); /* u considered as +0: sign(+0/x) = sign(x) */
109d59437c0Smrg MPFR_RET(0);
110d59437c0Smrg }
111d59437c0Smrg }
112