Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/parisc/math-emu/dfsub.c
26288 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Linux/PA-RISC Project (http://www.parisc-linux.org/)
4
*
5
* Floating-point emulation code
6
* Copyright (C) 2001 Hewlett-Packard (Paul Bame) <[email protected]>
7
*/
8
/*
9
* BEGIN_DESC
10
*
11
* File:
12
* @(#) pa/spmath/dfsub.c $Revision: 1.1 $
13
*
14
* Purpose:
15
* Double_subtract: subtract two double precision values.
16
*
17
* External Interfaces:
18
* dbl_fsub(leftptr, rightptr, dstptr, status)
19
*
20
* Internal Interfaces:
21
*
22
* Theory:
23
* <<please update with a overview of the operation of this file>>
24
*
25
* END_DESC
26
*/
27
28
29
#include "float.h"
30
#include "dbl_float.h"
31
32
/*
33
* Double_subtract: subtract two double precision values.
34
*/
35
int
36
dbl_fsub(
37
dbl_floating_point *leftptr,
38
dbl_floating_point *rightptr,
39
dbl_floating_point *dstptr,
40
unsigned int *status)
41
{
42
register unsigned int signless_upper_left, signless_upper_right, save;
43
register unsigned int leftp1, leftp2, rightp1, rightp2, extent;
44
register unsigned int resultp1 = 0, resultp2 = 0;
45
46
register int result_exponent, right_exponent, diff_exponent;
47
register int sign_save, jumpsize;
48
register boolean inexact = FALSE, underflowtrap;
49
50
/* Create local copies of the numbers */
51
Dbl_copyfromptr(leftptr,leftp1,leftp2);
52
Dbl_copyfromptr(rightptr,rightp1,rightp2);
53
54
/* A zero "save" helps discover equal operands (for later), *
55
* and is used in swapping operands (if needed). */
56
Dbl_xortointp1(leftp1,rightp1,/*to*/save);
57
58
/*
59
* check first operand for NaN's or infinity
60
*/
61
if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)
62
{
63
if (Dbl_iszero_mantissa(leftp1,leftp2))
64
{
65
if (Dbl_isnotnan(rightp1,rightp2))
66
{
67
if (Dbl_isinfinity(rightp1,rightp2) && save==0)
68
{
69
/*
70
* invalid since operands are same signed infinity's
71
*/
72
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
73
Set_invalidflag();
74
Dbl_makequietnan(resultp1,resultp2);
75
Dbl_copytoptr(resultp1,resultp2,dstptr);
76
return(NOEXCEPTION);
77
}
78
/*
79
* return infinity
80
*/
81
Dbl_copytoptr(leftp1,leftp2,dstptr);
82
return(NOEXCEPTION);
83
}
84
}
85
else
86
{
87
/*
88
* is NaN; signaling or quiet?
89
*/
90
if (Dbl_isone_signaling(leftp1))
91
{
92
/* trap if INVALIDTRAP enabled */
93
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
94
/* make NaN quiet */
95
Set_invalidflag();
96
Dbl_set_quiet(leftp1);
97
}
98
/*
99
* is second operand a signaling NaN?
100
*/
101
else if (Dbl_is_signalingnan(rightp1))
102
{
103
/* trap if INVALIDTRAP enabled */
104
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
105
/* make NaN quiet */
106
Set_invalidflag();
107
Dbl_set_quiet(rightp1);
108
Dbl_copytoptr(rightp1,rightp2,dstptr);
109
return(NOEXCEPTION);
110
}
111
/*
112
* return quiet NaN
113
*/
114
Dbl_copytoptr(leftp1,leftp2,dstptr);
115
return(NOEXCEPTION);
116
}
117
} /* End left NaN or Infinity processing */
118
/*
119
* check second operand for NaN's or infinity
120
*/
121
if (Dbl_isinfinity_exponent(rightp1))
122
{
123
if (Dbl_iszero_mantissa(rightp1,rightp2))
124
{
125
/* return infinity */
126
Dbl_invert_sign(rightp1);
127
Dbl_copytoptr(rightp1,rightp2,dstptr);
128
return(NOEXCEPTION);
129
}
130
/*
131
* is NaN; signaling or quiet?
132
*/
133
if (Dbl_isone_signaling(rightp1))
134
{
135
/* trap if INVALIDTRAP enabled */
136
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
137
/* make NaN quiet */
138
Set_invalidflag();
139
Dbl_set_quiet(rightp1);
140
}
141
/*
142
* return quiet NaN
143
*/
144
Dbl_copytoptr(rightp1,rightp2,dstptr);
145
return(NOEXCEPTION);
146
} /* End right NaN or Infinity processing */
147
148
/* Invariant: Must be dealing with finite numbers */
149
150
/* Compare operands by removing the sign */
151
Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);
152
Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);
153
154
/* sign difference selects add or sub operation. */
155
if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))
156
{
157
/* Set the left operand to the larger one by XOR swap *
158
* First finish the first word using "save" */
159
Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);
160
Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);
161
Dbl_swap_lower(leftp2,rightp2);
162
result_exponent = Dbl_exponent(leftp1);
163
Dbl_invert_sign(leftp1);
164
}
165
/* Invariant: left is not smaller than right. */
166
167
if((right_exponent = Dbl_exponent(rightp1)) == 0)
168
{
169
/* Denormalized operands. First look for zeroes */
170
if(Dbl_iszero_mantissa(rightp1,rightp2))
171
{
172
/* right is zero */
173
if(Dbl_iszero_exponentmantissa(leftp1,leftp2))
174
{
175
/* Both operands are zeros */
176
Dbl_invert_sign(rightp1);
177
if(Is_rounding_mode(ROUNDMINUS))
178
{
179
Dbl_or_signs(leftp1,/*with*/rightp1);
180
}
181
else
182
{
183
Dbl_and_signs(leftp1,/*with*/rightp1);
184
}
185
}
186
else
187
{
188
/* Left is not a zero and must be the result. Trapped
189
* underflows are signaled if left is denormalized. Result
190
* is always exact. */
191
if( (result_exponent == 0) && Is_underflowtrap_enabled() )
192
{
193
/* need to normalize results mantissa */
194
sign_save = Dbl_signextendedsign(leftp1);
195
Dbl_leftshiftby1(leftp1,leftp2);
196
Dbl_normalize(leftp1,leftp2,result_exponent);
197
Dbl_set_sign(leftp1,/*using*/sign_save);
198
Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);
199
Dbl_copytoptr(leftp1,leftp2,dstptr);
200
/* inexact = FALSE */
201
return(UNDERFLOWEXCEPTION);
202
}
203
}
204
Dbl_copytoptr(leftp1,leftp2,dstptr);
205
return(NOEXCEPTION);
206
}
207
208
/* Neither are zeroes */
209
Dbl_clear_sign(rightp1); /* Exponent is already cleared */
210
if(result_exponent == 0 )
211
{
212
/* Both operands are denormalized. The result must be exact
213
* and is simply calculated. A sum could become normalized and a
214
* difference could cancel to a true zero. */
215
if( (/*signed*/int) save >= 0 )
216
{
217
Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,
218
/*into*/resultp1,resultp2);
219
if(Dbl_iszero_mantissa(resultp1,resultp2))
220
{
221
if(Is_rounding_mode(ROUNDMINUS))
222
{
223
Dbl_setone_sign(resultp1);
224
}
225
else
226
{
227
Dbl_setzero_sign(resultp1);
228
}
229
Dbl_copytoptr(resultp1,resultp2,dstptr);
230
return(NOEXCEPTION);
231
}
232
}
233
else
234
{
235
Dbl_addition(leftp1,leftp2,rightp1,rightp2,
236
/*into*/resultp1,resultp2);
237
if(Dbl_isone_hidden(resultp1))
238
{
239
Dbl_copytoptr(resultp1,resultp2,dstptr);
240
return(NOEXCEPTION);
241
}
242
}
243
if(Is_underflowtrap_enabled())
244
{
245
/* need to normalize result */
246
sign_save = Dbl_signextendedsign(resultp1);
247
Dbl_leftshiftby1(resultp1,resultp2);
248
Dbl_normalize(resultp1,resultp2,result_exponent);
249
Dbl_set_sign(resultp1,/*using*/sign_save);
250
Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
251
Dbl_copytoptr(resultp1,resultp2,dstptr);
252
/* inexact = FALSE */
253
return(UNDERFLOWEXCEPTION);
254
}
255
Dbl_copytoptr(resultp1,resultp2,dstptr);
256
return(NOEXCEPTION);
257
}
258
right_exponent = 1; /* Set exponent to reflect different bias
259
* with denormalized numbers. */
260
}
261
else
262
{
263
Dbl_clear_signexponent_set_hidden(rightp1);
264
}
265
Dbl_clear_exponent_set_hidden(leftp1);
266
diff_exponent = result_exponent - right_exponent;
267
268
/*
269
* Special case alignment of operands that would force alignment
270
* beyond the extent of the extension. A further optimization
271
* could special case this but only reduces the path length for this
272
* infrequent case.
273
*/
274
if(diff_exponent > DBL_THRESHOLD)
275
{
276
diff_exponent = DBL_THRESHOLD;
277
}
278
279
/* Align right operand by shifting to right */
280
Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,
281
/*and lower to*/extent);
282
283
/* Treat sum and difference of the operands separately. */
284
if( (/*signed*/int) save >= 0 )
285
{
286
/*
287
* Difference of the two operands. Their can be no overflow. A
288
* borrow can occur out of the hidden bit and force a post
289
* normalization phase.
290
*/
291
Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,
292
/*with*/extent,/*into*/resultp1,resultp2);
293
if(Dbl_iszero_hidden(resultp1))
294
{
295
/* Handle normalization */
296
/* A straight forward algorithm would now shift the result
297
* and extension left until the hidden bit becomes one. Not
298
* all of the extension bits need participate in the shift.
299
* Only the two most significant bits (round and guard) are
300
* needed. If only a single shift is needed then the guard
301
* bit becomes a significant low order bit and the extension
302
* must participate in the rounding. If more than a single
303
* shift is needed, then all bits to the right of the guard
304
* bit are zeros, and the guard bit may or may not be zero. */
305
sign_save = Dbl_signextendedsign(resultp1);
306
Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);
307
308
/* Need to check for a zero result. The sign and exponent
309
* fields have already been zeroed. The more efficient test
310
* of the full object can be used.
311
*/
312
if(Dbl_iszero(resultp1,resultp2))
313
/* Must have been "x-x" or "x+(-x)". */
314
{
315
if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);
316
Dbl_copytoptr(resultp1,resultp2,dstptr);
317
return(NOEXCEPTION);
318
}
319
result_exponent--;
320
/* Look to see if normalization is finished. */
321
if(Dbl_isone_hidden(resultp1))
322
{
323
if(result_exponent==0)
324
{
325
/* Denormalized, exponent should be zero. Left operand *
326
* was normalized, so extent (guard, round) was zero */
327
goto underflow;
328
}
329
else
330
{
331
/* No further normalization is needed. */
332
Dbl_set_sign(resultp1,/*using*/sign_save);
333
Ext_leftshiftby1(extent);
334
goto round;
335
}
336
}
337
338
/* Check for denormalized, exponent should be zero. Left *
339
* operand was normalized, so extent (guard, round) was zero */
340
if(!(underflowtrap = Is_underflowtrap_enabled()) &&
341
result_exponent==0) goto underflow;
342
343
/* Shift extension to complete one bit of normalization and
344
* update exponent. */
345
Ext_leftshiftby1(extent);
346
347
/* Discover first one bit to determine shift amount. Use a
348
* modified binary search. We have already shifted the result
349
* one position right and still not found a one so the remainder
350
* of the extension must be zero and simplifies rounding. */
351
/* Scan bytes */
352
while(Dbl_iszero_hiddenhigh7mantissa(resultp1))
353
{
354
Dbl_leftshiftby8(resultp1,resultp2);
355
if((result_exponent -= 8) <= 0 && !underflowtrap)
356
goto underflow;
357
}
358
/* Now narrow it down to the nibble */
359
if(Dbl_iszero_hiddenhigh3mantissa(resultp1))
360
{
361
/* The lower nibble contains the normalizing one */
362
Dbl_leftshiftby4(resultp1,resultp2);
363
if((result_exponent -= 4) <= 0 && !underflowtrap)
364
goto underflow;
365
}
366
/* Select case were first bit is set (already normalized)
367
* otherwise select the proper shift. */
368
if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)
369
{
370
/* Already normalized */
371
if(result_exponent <= 0) goto underflow;
372
Dbl_set_sign(resultp1,/*using*/sign_save);
373
Dbl_set_exponent(resultp1,/*using*/result_exponent);
374
Dbl_copytoptr(resultp1,resultp2,dstptr);
375
return(NOEXCEPTION);
376
}
377
Dbl_sethigh4bits(resultp1,/*using*/sign_save);
378
switch(jumpsize)
379
{
380
case 1:
381
{
382
Dbl_leftshiftby3(resultp1,resultp2);
383
result_exponent -= 3;
384
break;
385
}
386
case 2:
387
case 3:
388
{
389
Dbl_leftshiftby2(resultp1,resultp2);
390
result_exponent -= 2;
391
break;
392
}
393
case 4:
394
case 5:
395
case 6:
396
case 7:
397
{
398
Dbl_leftshiftby1(resultp1,resultp2);
399
result_exponent -= 1;
400
break;
401
}
402
}
403
if(result_exponent > 0)
404
{
405
Dbl_set_exponent(resultp1,/*using*/result_exponent);
406
Dbl_copytoptr(resultp1,resultp2,dstptr);
407
return(NOEXCEPTION); /* Sign bit is already set */
408
}
409
/* Fixup potential underflows */
410
underflow:
411
if(Is_underflowtrap_enabled())
412
{
413
Dbl_set_sign(resultp1,sign_save);
414
Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
415
Dbl_copytoptr(resultp1,resultp2,dstptr);
416
/* inexact = FALSE */
417
return(UNDERFLOWEXCEPTION);
418
}
419
/*
420
* Since we cannot get an inexact denormalized result,
421
* we can now return.
422
*/
423
Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);
424
Dbl_clear_signexponent(resultp1);
425
Dbl_set_sign(resultp1,sign_save);
426
Dbl_copytoptr(resultp1,resultp2,dstptr);
427
return(NOEXCEPTION);
428
} /* end if(hidden...)... */
429
/* Fall through and round */
430
} /* end if(save >= 0)... */
431
else
432
{
433
/* Subtract magnitudes */
434
Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);
435
if(Dbl_isone_hiddenoverflow(resultp1))
436
{
437
/* Prenormalization required. */
438
Dbl_rightshiftby1_withextent(resultp2,extent,extent);
439
Dbl_arithrightshiftby1(resultp1,resultp2);
440
result_exponent++;
441
} /* end if hiddenoverflow... */
442
} /* end else ...subtract magnitudes... */
443
444
/* Round the result. If the extension is all zeros,then the result is
445
* exact. Otherwise round in the correct direction. No underflow is
446
* possible. If a postnormalization is necessary, then the mantissa is
447
* all zeros so no shift is needed. */
448
round:
449
if(Ext_isnotzero(extent))
450
{
451
inexact = TRUE;
452
switch(Rounding_mode())
453
{
454
case ROUNDNEAREST: /* The default. */
455
if(Ext_isone_sign(extent))
456
{
457
/* at least 1/2 ulp */
458
if(Ext_isnotzero_lower(extent) ||
459
Dbl_isone_lowmantissap2(resultp2))
460
{
461
/* either exactly half way and odd or more than 1/2ulp */
462
Dbl_increment(resultp1,resultp2);
463
}
464
}
465
break;
466
467
case ROUNDPLUS:
468
if(Dbl_iszero_sign(resultp1))
469
{
470
/* Round up positive results */
471
Dbl_increment(resultp1,resultp2);
472
}
473
break;
474
475
case ROUNDMINUS:
476
if(Dbl_isone_sign(resultp1))
477
{
478
/* Round down negative results */
479
Dbl_increment(resultp1,resultp2);
480
}
481
482
case ROUNDZERO:;
483
/* truncate is simple */
484
} /* end switch... */
485
if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
486
}
487
if(result_exponent == DBL_INFINITY_EXPONENT)
488
{
489
/* Overflow */
490
if(Is_overflowtrap_enabled())
491
{
492
Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
493
Dbl_copytoptr(resultp1,resultp2,dstptr);
494
if (inexact)
495
if (Is_inexacttrap_enabled())
496
return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
497
else Set_inexactflag();
498
return(OVERFLOWEXCEPTION);
499
}
500
else
501
{
502
inexact = TRUE;
503
Set_overflowflag();
504
Dbl_setoverflow(resultp1,resultp2);
505
}
506
}
507
else Dbl_set_exponent(resultp1,result_exponent);
508
Dbl_copytoptr(resultp1,resultp2,dstptr);
509
if(inexact)
510
if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
511
else Set_inexactflag();
512
return(NOEXCEPTION);
513
}
514
515