source: mainline/uspace/lib/softfloat/generic/mul.c@ 41455a22

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 41455a22 was 88d5c1e, checked in by Martin Decky <martin@…>, 13 years ago

softfloat redesign

  • avoid hardwired type sizes, actual sizes are determined at compile-time
  • add basic support for x87 extended-precision data types (stored as 96bit long double)
  • a lot of coding style changes (removal of CamelCase, etc.)
  • Property mode set to 100644
File size: 9.2 KB
RevLine 
[b5440cf]1/*
[df4ed85]2 * Copyright (c) 2005 Josef Cejka
[c67aff2]3 * Copyright (c) 2011 Petr Koupy
[b5440cf]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[750636a]30/** @addtogroup softfloat
[846848a6]31 * @{
32 */
[c67aff2]33/** @file Multiplication functions.
[846848a6]34 */
35
[750636a]36#include <sftypes.h>
37#include <mul.h>
38#include <comparison.h>
39#include <common.h>
[b5440cf]40
[88d5c1e]41/** Multiply two single-precision floats.
[3af72dc]42 *
[c67aff2]43 * @param a First input operand.
44 * @param b Second input operand.
[88d5c1e]45 *
[c67aff2]46 * @return Result of multiplication.
[88d5c1e]47 *
[3af72dc]48 */
[88d5c1e]49float32 mul_float32(float32 a, float32 b)
[3af72dc]50{
51 float32 result;
[aa59fa0]52 uint64_t frac1, frac2;
53 int32_t exp;
[88d5c1e]54
[3af72dc]55 result.parts.sign = a.parts.sign ^ b.parts.sign;
56
[88d5c1e]57 if (is_float32_nan(a) || is_float32_nan(b)) {
[3af72dc]58 /* TODO: fix SigNaNs */
[88d5c1e]59 if (is_float32_signan(a)) {
[1266543]60 result.parts.fraction = a.parts.fraction;
[3af72dc]61 result.parts.exp = a.parts.exp;
62 return result;
[c67aff2]63 }
[88d5c1e]64 if (is_float32_signan(b)) { /* TODO: fix SigNaN */
[1266543]65 result.parts.fraction = b.parts.fraction;
[3af72dc]66 result.parts.exp = b.parts.exp;
67 return result;
[c67aff2]68 }
[3af72dc]69 /* set NaN as result */
[88d5c1e]70 result.bin = FLOAT32_NAN;
[3af72dc]71 return result;
[c67aff2]72 }
[88d5c1e]73
74 if (is_float32_infinity(a)) {
75 if (is_float32_zero(b)) {
[3af72dc]76 /* FIXME: zero * infinity */
[88d5c1e]77 result.bin = FLOAT32_NAN;
[3af72dc]78 return result;
79 }
[1266543]80 result.parts.fraction = a.parts.fraction;
[3af72dc]81 result.parts.exp = a.parts.exp;
82 return result;
83 }
[88d5c1e]84
85 if (is_float32_infinity(b)) {
86 if (is_float32_zero(a)) {
[3af72dc]87 /* FIXME: zero * infinity */
[88d5c1e]88 result.bin = FLOAT32_NAN;
[3af72dc]89 return result;
90 }
[1266543]91 result.parts.fraction = b.parts.fraction;
[3af72dc]92 result.parts.exp = b.parts.exp;
93 return result;
94 }
[88d5c1e]95
[3af72dc]96 /* exp is signed so we can easy detect underflow */
97 exp = a.parts.exp + b.parts.exp;
98 exp -= FLOAT32_BIAS;
99
[bff16dd]100 if (exp >= FLOAT32_MAX_EXPONENT) {
[3af72dc]101 /* FIXME: overflow */
102 /* set infinity as result */
[88d5c1e]103 result.bin = FLOAT32_INF;
[bff16dd]104 result.parts.sign = a.parts.sign ^ b.parts.sign;
[3af72dc]105 return result;
[c67aff2]106 }
[3af72dc]107
108 if (exp < 0) {
109 /* FIXME: underflow */
110 /* return signed zero */
[1266543]111 result.parts.fraction = 0x0;
[3af72dc]112 result.parts.exp = 0x0;
113 return result;
[c67aff2]114 }
[3af72dc]115
[1266543]116 frac1 = a.parts.fraction;
[bff16dd]117 if (a.parts.exp > 0) {
[1266543]118 frac1 |= FLOAT32_HIDDEN_BIT_MASK;
[3af72dc]119 } else {
120 ++exp;
[c67aff2]121 }
[3af72dc]122
[1266543]123 frac2 = b.parts.fraction;
[88d5c1e]124
[bff16dd]125 if (b.parts.exp > 0) {
[1266543]126 frac2 |= FLOAT32_HIDDEN_BIT_MASK;
[3af72dc]127 } else {
128 ++exp;
[c67aff2]129 }
[88d5c1e]130
[1266543]131 frac1 <<= 1; /* one bit space for rounding */
[88d5c1e]132
[1266543]133 frac1 = frac1 * frac2;
[88d5c1e]134
[c67aff2]135 /* round and return */
[88d5c1e]136 while ((exp < FLOAT32_MAX_EXPONENT) &&
137 (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 2)))) {
[c67aff2]138 /* 23 bits of fraction + one more for hidden bit (all shifted 1 bit left) */
[3af72dc]139 ++exp;
[1266543]140 frac1 >>= 1;
[c67aff2]141 }
[88d5c1e]142
[3af72dc]143 /* rounding */
[1266543]144 /* ++frac1; FIXME: not works - without it is ok */
145 frac1 >>= 1; /* shift off rounding space */
[3af72dc]146
[88d5c1e]147 if ((exp < FLOAT32_MAX_EXPONENT) &&
148 (frac1 >= (1 << (FLOAT32_FRACTION_SIZE + 1)))) {
[3af72dc]149 ++exp;
[1266543]150 frac1 >>= 1;
[c67aff2]151 }
[88d5c1e]152
153 if (exp >= FLOAT32_MAX_EXPONENT) {
[3af72dc]154 /* TODO: fix overflow */
155 /* return infinity*/
[bff16dd]156 result.parts.exp = FLOAT32_MAX_EXPONENT;
[1266543]157 result.parts.fraction = 0x0;
[3af72dc]158 return result;
159 }
160
[1266543]161 exp -= FLOAT32_FRACTION_SIZE;
[88d5c1e]162
163 if (exp <= FLOAT32_FRACTION_SIZE) {
[3af72dc]164 /* denormalized number */
[1266543]165 frac1 >>= 1; /* denormalize */
166 while ((frac1 > 0) && (exp < 0)) {
167 frac1 >>= 1;
[3af72dc]168 ++exp;
[c67aff2]169 }
[1266543]170 if (frac1 == 0) {
[3af72dc]171 /* FIXME : underflow */
[c67aff2]172 result.parts.exp = 0;
173 result.parts.fraction = 0;
174 return result;
175 }
176 }
[3af72dc]177 result.parts.exp = exp;
[c67aff2]178 result.parts.fraction = frac1 & ((1 << FLOAT32_FRACTION_SIZE) - 1);
[bff16dd]179
[88d5c1e]180 return result;
[bff16dd]181}
182
[88d5c1e]183/** Multiply two double-precision floats.
[bff16dd]184 *
[c67aff2]185 * @param a First input operand.
186 * @param b Second input operand.
[88d5c1e]187 *
[c67aff2]188 * @return Result of multiplication.
[88d5c1e]189 *
[bff16dd]190 */
[88d5c1e]191float64 mul_float64(float64 a, float64 b)
[bff16dd]192{
193 float64 result;
[aa59fa0]194 uint64_t frac1, frac2;
195 int32_t exp;
[88d5c1e]196
[bff16dd]197 result.parts.sign = a.parts.sign ^ b.parts.sign;
198
[88d5c1e]199 if (is_float64_nan(a) || is_float64_nan(b)) {
[bff16dd]200 /* TODO: fix SigNaNs */
[88d5c1e]201 if (is_float64_signan(a)) {
[1266543]202 result.parts.fraction = a.parts.fraction;
[bff16dd]203 result.parts.exp = a.parts.exp;
204 return result;
[c67aff2]205 }
[88d5c1e]206 if (is_float64_signan(b)) { /* TODO: fix SigNaN */
[1266543]207 result.parts.fraction = b.parts.fraction;
[bff16dd]208 result.parts.exp = b.parts.exp;
209 return result;
[c67aff2]210 }
[bff16dd]211 /* set NaN as result */
[88d5c1e]212 result.bin = FLOAT64_NAN;
[bff16dd]213 return result;
[c67aff2]214 }
[88d5c1e]215
216 if (is_float64_infinity(a)) {
217 if (is_float64_zero(b)) {
[bff16dd]218 /* FIXME: zero * infinity */
[88d5c1e]219 result.bin = FLOAT64_NAN;
[bff16dd]220 return result;
221 }
[1266543]222 result.parts.fraction = a.parts.fraction;
[bff16dd]223 result.parts.exp = a.parts.exp;
224 return result;
225 }
[88d5c1e]226
227 if (is_float64_infinity(b)) {
228 if (is_float64_zero(a)) {
[bff16dd]229 /* FIXME: zero * infinity */
[88d5c1e]230 result.bin = FLOAT64_NAN;
[bff16dd]231 return result;
232 }
[1266543]233 result.parts.fraction = b.parts.fraction;
[bff16dd]234 result.parts.exp = b.parts.exp;
235 return result;
236 }
[88d5c1e]237
[bff16dd]238 /* exp is signed so we can easy detect underflow */
[e979fea]239 exp = a.parts.exp + b.parts.exp - FLOAT64_BIAS;
[bff16dd]240
[1266543]241 frac1 = a.parts.fraction;
[88d5c1e]242
[bff16dd]243 if (a.parts.exp > 0) {
[1266543]244 frac1 |= FLOAT64_HIDDEN_BIT_MASK;
[bff16dd]245 } else {
246 ++exp;
[c67aff2]247 }
[bff16dd]248
[1266543]249 frac2 = b.parts.fraction;
[88d5c1e]250
[bff16dd]251 if (b.parts.exp > 0) {
[1266543]252 frac2 |= FLOAT64_HIDDEN_BIT_MASK;
[bff16dd]253 } else {
254 ++exp;
[c67aff2]255 }
[88d5c1e]256
[e979fea]257 frac1 <<= (64 - FLOAT64_FRACTION_SIZE - 1);
258 frac2 <<= (64 - FLOAT64_FRACTION_SIZE - 2);
[88d5c1e]259
[c67aff2]260 mul64(frac1, frac2, &frac1, &frac2);
[88d5c1e]261
[c67aff2]262 frac1 |= (frac2 != 0);
263 if (frac1 & (0x1ll << 62)) {
264 frac1 <<= 1;
[e979fea]265 exp--;
[bff16dd]266 }
[88d5c1e]267
268 result = finish_float64(exp, frac1, result.parts.sign);
[e979fea]269 return result;
[12c6f2d]270}
271
[88d5c1e]272/** Multiply two quadruple-precision floats.
[c67aff2]273 *
274 * @param a First input operand.
275 * @param b Second input operand.
[88d5c1e]276 *
[c67aff2]277 * @return Result of multiplication.
[88d5c1e]278 *
[bff16dd]279 */
[88d5c1e]280float128 mul_float128(float128 a, float128 b)
[bff16dd]281{
[c67aff2]282 float128 result;
283 uint64_t frac1_hi, frac1_lo, frac2_hi, frac2_lo, tmp_hi, tmp_lo;
284 int32_t exp;
[88d5c1e]285
[c67aff2]286 result.parts.sign = a.parts.sign ^ b.parts.sign;
[88d5c1e]287
288 if (is_float128_nan(a) || is_float128_nan(b)) {
[c67aff2]289 /* TODO: fix SigNaNs */
[88d5c1e]290 if (is_float128_signan(a)) {
[c67aff2]291 result.parts.frac_hi = a.parts.frac_hi;
292 result.parts.frac_lo = a.parts.frac_lo;
293 result.parts.exp = a.parts.exp;
294 return result;
295 }
[88d5c1e]296 if (is_float128_signan(b)) { /* TODO: fix SigNaN */
[c67aff2]297 result.parts.frac_hi = b.parts.frac_hi;
298 result.parts.frac_lo = b.parts.frac_lo;
299 result.parts.exp = b.parts.exp;
300 return result;
301 }
302 /* set NaN as result */
[88d5c1e]303 result.bin.hi = FLOAT128_NAN_HI;
304 result.bin.lo = FLOAT128_NAN_LO;
[c67aff2]305 return result;
306 }
[88d5c1e]307
308 if (is_float128_infinity(a)) {
309 if (is_float128_zero(b)) {
[c67aff2]310 /* FIXME: zero * infinity */
[88d5c1e]311 result.bin.hi = FLOAT128_NAN_HI;
312 result.bin.lo = FLOAT128_NAN_LO;
[c67aff2]313 return result;
314 }
315 result.parts.frac_hi = a.parts.frac_hi;
316 result.parts.frac_lo = a.parts.frac_lo;
317 result.parts.exp = a.parts.exp;
318 return result;
319 }
[88d5c1e]320
321 if (is_float128_infinity(b)) {
322 if (is_float128_zero(a)) {
[c67aff2]323 /* FIXME: zero * infinity */
[88d5c1e]324 result.bin.hi = FLOAT128_NAN_HI;
325 result.bin.lo = FLOAT128_NAN_LO;
[c67aff2]326 return result;
327 }
328 result.parts.frac_hi = b.parts.frac_hi;
329 result.parts.frac_lo = b.parts.frac_lo;
330 result.parts.exp = b.parts.exp;
331 return result;
332 }
[88d5c1e]333
[c67aff2]334 /* exp is signed so we can easy detect underflow */
335 exp = a.parts.exp + b.parts.exp - FLOAT128_BIAS - 1;
[88d5c1e]336
[c67aff2]337 frac1_hi = a.parts.frac_hi;
338 frac1_lo = a.parts.frac_lo;
[88d5c1e]339
[c67aff2]340 if (a.parts.exp > 0) {
341 or128(frac1_hi, frac1_lo,
[88d5c1e]342 FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
343 &frac1_hi, &frac1_lo);
[c67aff2]344 } else {
345 ++exp;
346 }
[88d5c1e]347
[c67aff2]348 frac2_hi = b.parts.frac_hi;
349 frac2_lo = b.parts.frac_lo;
[88d5c1e]350
[c67aff2]351 if (b.parts.exp > 0) {
352 or128(frac2_hi, frac2_lo,
353 FLOAT128_HIDDEN_BIT_MASK_HI, FLOAT128_HIDDEN_BIT_MASK_LO,
354 &frac2_hi, &frac2_lo);
355 } else {
356 ++exp;
357 }
[88d5c1e]358
[c67aff2]359 lshift128(frac2_hi, frac2_lo,
360 128 - FLOAT128_FRACTION_SIZE, &frac2_hi, &frac2_lo);
[88d5c1e]361
[c67aff2]362 tmp_hi = frac1_hi;
363 tmp_lo = frac1_lo;
364 mul128(frac1_hi, frac1_lo, frac2_hi, frac2_lo,
365 &frac1_hi, &frac1_lo, &frac2_hi, &frac2_lo);
366 add128(frac1_hi, frac1_lo, tmp_hi, tmp_lo, &frac1_hi, &frac1_lo);
367 frac2_hi |= (frac2_lo != 0x0ll);
[88d5c1e]368
[c67aff2]369 if ((FLOAT128_HIDDEN_BIT_MASK_HI << 1) <= frac1_hi) {
370 frac2_hi >>= 1;
371 if (frac1_lo & 0x1ll) {
372 frac2_hi |= (0x1ull < 64);
373 }
374 rshift128(frac1_hi, frac1_lo, 1, &frac1_hi, &frac1_lo);
375 ++exp;
376 }
[88d5c1e]377
378 result = finish_float128(exp, frac1_hi, frac1_lo, result.parts.sign, frac2_hi);
[c67aff2]379 return result;
[bff16dd]380}
[3af72dc]381
[231a60a]382/** @}
[846848a6]383 */
Note: See TracBrowser for help on using the repository browser.