source: mainline/uspace/lib/math/generic/nearbyint.c@ 241ab7e

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 241ab7e was 516e780, checked in by GitHub <noreply@…>, 7 years ago

Strip down libmath. (#45)

libmath is mostly unused (except for trunc(), sin() and cos()), and most functions in it are either very imprecise or downright broken. Additionally, it is implemented in manner that conflicts with C standard. Instead of trying to fix all the shortcomings while maintaining unused functionality, I'm opting to simply remove most of it and only keep the parts that are currently necessary.

Later readdition of the removed functions is possible, but there needs to be a reliable way to evaluate their quality first.

  • Property mode set to 100644
File size: 4.4 KB
Line 
1/*
2 * Copyright (c) 2018 CZ.NIC, z.s.p.o.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libmath
30 * @{
31 */
32/** @file
33 */
34
35#include <assert.h>
36#include <math.h>
37#include <fenv.h>
38#include <float.h>
39#include <stdbool.h>
40#include <stdint.h>
41
42static float _roundf_even(float val)
43{
44 assert(!signbit(val));
45
46 /* Get some special cases out of the way first. */
47
48 if (islessequal(val, 0.5f))
49 return 0.0f;
50
51 if (isless(val, 1.5f))
52 return 1.0f;
53
54 if (islessequal(val, 2.5f))
55 return 2.0f;
56
57 const int exp_bias = FLT_MAX_EXP - 1;
58 const int mant_bits = FLT_MANT_DIG - 1;
59 const uint32_t mant_mask = (UINT32_C(1) << mant_bits) - 1;
60
61 union {
62 float f;
63 uint32_t i;
64 } u = { .f = val };
65
66 int exp = (u.i >> mant_bits) - exp_bias;
67 assert(exp > 0);
68
69 /* Mantissa has no fractional places. */
70 if (exp >= mant_bits)
71 return val;
72
73 /* Check whether we are rounding up or down. */
74 uint32_t first = (UINT32_C(1) << (mant_bits - exp));
75 uint32_t midpoint = first >> 1;
76 uint32_t frac = u.i & (mant_mask >> exp);
77
78 bool up;
79 if (frac == midpoint) {
80 up = (u.i & first);
81 } else {
82 up = (frac > midpoint);
83 }
84
85 u.i &= ~(mant_mask >> exp);
86 if (up) {
87 u.i += first;
88 }
89 return copysignf(u.f, val);
90}
91
92static float _round_even(float val)
93{
94 assert(!signbit(val));
95
96 /* Get some special cases out of the way first. */
97
98 if (islessequal(val, 0.5))
99 return 0.0;
100
101 if (isless(val, 1.5))
102 return 1.0;
103
104 if (islessequal(val, 2.5))
105 return 2.0;
106
107 const int exp_bias = DBL_MAX_EXP - 1;
108 const int mant_bits = DBL_MANT_DIG - 1;
109 const uint64_t mant_mask = (UINT64_C(1) << mant_bits) - 1;
110
111 union {
112 double f;
113 uint64_t i;
114 } u = { .f = val };
115
116 int exp = (u.i >> mant_bits) - exp_bias;
117 assert(exp > 0);
118
119 /* Mantissa has no fractional places. */
120 if (exp >= mant_bits)
121 return val;
122
123 /* Check whether we are rounding up or down. */
124 uint64_t first = (UINT64_C(1) << (mant_bits - exp));
125 uint64_t midpoint = first >> 1;
126 uint64_t frac = u.i & (mant_mask >> exp);
127
128 bool up;
129 if (frac == midpoint) {
130 up = (u.i & first);
131 } else {
132 up = (frac > midpoint);
133 }
134
135 u.i &= ~(mant_mask >> exp);
136 if (up) {
137 u.i += first;
138 }
139 return copysignf(u.f, val);
140}
141
142/**
143 * Rounds its argument to the nearest integer value in floating-point format,
144 * using the current rounding direction and without raising the inexact
145 * floating-point exception.
146 */
147float nearbyintf(float val)
148{
149 switch (fegetround()) {
150 case FE_DOWNWARD:
151 return floorf(val);
152 case FE_UPWARD:
153 return ceilf(val);
154 case FE_TOWARDZERO:
155 return truncf(val);
156 case FE_TONEAREST:
157 return copysignf(_roundf_even(fabsf(val)), val);
158 }
159
160 assert(false);
161}
162
163/**
164 * Rounds its argument to the nearest integer value in floating-point format,
165 * using the current rounding direction and without raising the inexact
166 * floating-point exception.
167 */
168double nearbyint(double val)
169{
170 switch (fegetround()) {
171 case FE_DOWNWARD:
172 return floor(val);
173 case FE_UPWARD:
174 return ceil(val);
175 case FE_TOWARDZERO:
176 return trunc(val);
177 case FE_TONEAREST:
178 return copysign(_round_even(fabs(val)), val);
179 }
180
181 assert(false);
182}
183
184/** @}
185 */
Note: See TracBrowser for help on using the repository browser.