1 //------------------------------------------------------------------------------
2 // GB_math.h: definitions for complex types, and mathematical operators
3 //------------------------------------------------------------------------------
4
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7
8 //------------------------------------------------------------------------------
9
10 #ifndef GB_MATH_H
11 #define GB_MATH_H
12
13 //------------------------------------------------------------------------------
14 // complex macros
15 //------------------------------------------------------------------------------
16
17 #if ( _MSC_VER && !__INTEL_COMPILER )
18
19 //--------------------------------------------------------------------------
20 // Microsoft Visual Studio compiler with its own complex type
21 //--------------------------------------------------------------------------
22
23 // complex-complex multiply: z = x*y where both x and y are complex
24 #define GB_FC32_mul(x,y) (_FCmulcc (x, y))
25 #define GB_FC64_mul(x,y) ( _Cmulcc (x, y))
26
27 // complex-real multiply: z = x*y where x is complex and y is real
28 #define GB_FC32_rmul(x,y) (_FCmulcr (x, y))
29 #define GB_FC64_rmul(x,y) ( _Cmulcr (x, y))
30
31 // complex-complex addition: z = x+y where both x and y are complex
32 #define GB_FC32_add(x,y) \
33 GxB_CMPLXF (crealf (x) + crealf (y), cimagf (x) + cimagf (y))
34 #define GB_FC64_add(x,y) \
35 GxB_CMPLX (creal (x) + creal (y), cimag (x) + cimag (y))
36
37 // complex-complex subtraction: z = x-y where both x and y are complex
38 #define GB_FC32_minus(x,y) \
39 GxB_CMPLXF (crealf (x) - crealf (y), cimagf (x) - cimagf (y))
40 #define GB_FC64_minus(x,y) \
41 GxB_CMPLX (creal (x) - creal (y), cimag (x) - cimag (y))
42
43 // complex negation: z = -x
44 #define GB_FC32_ainv(x) GxB_CMPLXF (-crealf (x), -cimagf (x))
45 #define GB_FC64_ainv(x) GxB_CMPLX (-creal (x), -cimag (x))
46
47 #else
48
49 //--------------------------------------------------------------------------
50 // native complex type support
51 //--------------------------------------------------------------------------
52
53 // complex-complex multiply: z = x*y where both x and y are complex
54 #define GB_FC32_mul(x,y) ((x) * (y))
55 #define GB_FC64_mul(x,y) ((x) * (y))
56
57 // complex-real multiply: z = x*y where x is complex and y is real
58 #define GB_FC32_rmul(x,y) ((x) * (y))
59 #define GB_FC64_rmul(x,y) ((x) * (y))
60
61 // complex-complex addition: z = x+y where both x and y are complex
62 #define GB_FC32_add(x,y) ((x) + (y))
63 #define GB_FC64_add(x,y) ((x) + (y))
64
65 // complex-complex subtraction: z = x-y where both x and y are complex
66 #define GB_FC32_minus(x,y) ((x) - (y))
67 #define GB_FC64_minus(x,y) ((x) - (y))
68
69 // complex negation
70 #define GB_FC32_ainv(x) (-(x))
71 #define GB_FC64_ainv(x) (-(x))
72
73 #endif
74
75 // complex inverse: z = 1/x
76 #define GB_FC32_minv(x) GB_FC32_div (GxB_CMPLXF (1,0), x)
77 #define GB_FC64_minv(x) GB_FC64_div (GxB_CMPLX (1,0), x)
78
79 // complex comparisons
80 #define GB_FC32_eq(x,y) ((crealf(x) == crealf(y)) && (cimagf(x) == cimagf(y)))
81 #define GB_FC64_eq(x,y) ((creal (x) == creal (y)) && (cimag (x) == cimag (y)))
82
83 #define GB_FC32_ne(x,y) ((crealf(x) != crealf(y)) || (cimagf(x) != cimagf(y)))
84 #define GB_FC64_ne(x,y) ((creal (x) != creal (y)) || (cimag (x) != cimag (y)))
85
86 #define GB_FC32_iseq(x,y) GxB_CMPLXF ((float) GB_FC32_eq (x,y), 0)
87 #define GB_FC64_iseq(x,y) GxB_CMPLX ((double) GB_FC64_eq (x,y), 0)
88
89 #define GB_FC32_isne(x,y) GxB_CMPLXF ((float) GB_FC32_ne (x,y), 0)
90 #define GB_FC64_isne(x,y) GxB_CMPLX ((double) GB_FC64_ne (x,y), 0)
91
92 #define GB_FC32_eq0(x) ((crealf(x) == 0) && (cimagf(x) == 0))
93 #define GB_FC64_eq0(x) ((creal (x) == 0) && (cimag (x) == 0))
94
95 #define GB_FC32_ne0(x) ((crealf(x) != 0) || (cimagf(x) != 0))
96 #define GB_FC64_ne0(x) ((creal (x) != 0) || (cimag (x) != 0))
97
98 //------------------------------------------------------------------------------
99 // min, max, and NaN handling
100 //------------------------------------------------------------------------------
101
102 // For floating-point computations, SuiteSparse:GraphBLAS relies on the IEEE
103 // 754 standard for the basic operations (+ - / *). Comparison operators also
104 // work as they should; any comparison with NaN is always false, even
105 // eq(NaN,NaN) is false. This follows the IEEE 754 standard.
106
107 // For integer MIN and MAX, SuiteSparse:GraphBLAS relies on one comparison:
108
109 // z = min(x,y) = (x < y) ? x : y
110 // z = max(x,y) = (x > y) ? x : y
111
112 // However, this is not suitable for floating-point x and y. Comparisons with
113 // NaN always return false, so if either x or y are NaN, then z = y, for both
114 // min(x,y) and max(x,y). In MATLAB, min(3,NaN), min(NaN,3), max(3,NaN), and
115 // max(NaN,3) are all 3, which is another interpretation. The MATLAB min and
116 // max functions have a 3rd argument that specifies how NaNs are handled:
117 // 'omitnan' (default) and 'includenan'. In SuiteSparse:GraphBLAS 2.2.* and
118 // earlier, the min and max functions were the same as 'includenan' in MATLAB.
119 // As of version 2.3 and later, they are 'omitnan', to facilitate the terminal
120 // exit of the MIN and MAX monoids for floating-point values.
121
122 // The ANSI C11 fmin, fminf, fmax, and fmaxf functions have the 'omitnan'
123 // behavior. These are used in SuiteSparse:GraphBLAS v2.3.0 and later.
124
125 // Below is a complete comparison of MATLAB and GraphBLAS. Both tables are the
126 // results for both min and max (they return the same results in these cases):
127
128 // x y MATLAB MATLAB (x<y)?x:y SuiteSparse: SuiteSparse: ANSI
129 // omitnan includenan GraphBLAS GraphBLAS fmin
130 // v 2.2.x this version
131 //
132 // 3 3 3 3 3 3 3 3
133 // 3 NaN 3 NaN NaN NaN 3 3
134 // NaN 3 3 NaN 3 NaN 3 3
135 // NaN NaN NaN NaN NaN NaN NaN NaN
136
137 // for integers only:
138 #define GB_IABS(x) (((x) >= 0) ? (x) : (-(x)))
139
140 // suitable for integers, and non-NaN floating point:
141 #include "GB_imin.h"
142
143 // ceiling of a/b for two integers a and b
144 #define GB_ICEIL(a,b) (((a) + (b) - 1) / (b))
145
146 //------------------------------------------------------------------------------
147 // division by zero
148 //------------------------------------------------------------------------------
149
150 // Integer division by zero is done the same way it's done in MATLAB. This
151 // approach allows GraphBLAS to not terminate the user's application on
152 // divide-by-zero, and allows GraphBLAS results to be tested against MATLAB.
153 // To compute X/0: if X is zero, the result is zero (like NaN). if X is
154 // negative, the result is the negative integer with biggest magnitude (like
155 // -infinity). if X is positive, the result is the biggest positive integer
156 // (like +infinity).
157
158 // For places affected by this decision in the code do:
159 // grep "integer division"
160
161 // Signed and unsigned integer division, z = x/y. The bits parameter can be 8,
162 // 16, 32, or 64.
163 #define GB_INT_MIN(bits) INT ## bits ## _MIN
164 #define GB_INT_MAX(bits) INT ## bits ## _MAX
165 #define GB_UINT_MAX(bits) UINT ## bits ## _MAX
166
167 // x/y when x and y are signed integers
168 #define GB_IDIV_SIGNED(x,y,bits) \
169 ( \
170 ((y) == -1) ? \
171 ( \
172 /* INT32_MIN/(-1) causes floating point exception; avoid it */ \
173 -(x) \
174 ) \
175 : \
176 ( \
177 ((y) == 0) ? \
178 ( \
179 /* x/0 */ \
180 ((x) == 0) ? \
181 ( \
182 /* zero divided by zero gives 'Nan' */ \
183 0 \
184 ) \
185 : \
186 ( \
187 /* x/0 and x is nonzero */ \
188 ((x) < 0) ? \
189 ( \
190 /* x is negative: x/0 gives '-Inf' */ \
191 GB_INT_MIN (bits) \
192 ) \
193 : \
194 ( \
195 /* x is positive: x/0 gives '+Inf' */ \
196 GB_INT_MAX (bits) \
197 ) \
198 ) \
199 ) \
200 : \
201 ( \
202 /* normal case for signed integer division */ \
203 (x) / (y) \
204 ) \
205 ) \
206 )
207
208 // x/y when x and y are unsigned integers
209 #define GB_IDIV_UNSIGNED(x,y,bits) \
210 ( \
211 ((y) == 0) ? \
212 ( \
213 /* x/0 */ \
214 ((x) == 0) ? \
215 ( \
216 /* zero divided by zero gives 'Nan' */ \
217 0 \
218 ) \
219 : \
220 ( \
221 /* x is positive: x/0 gives '+Inf' */ \
222 GB_UINT_MAX (bits) \
223 ) \
224 ) \
225 : \
226 ( \
227 /* normal case for unsigned integer division */ \
228 (x) / (y) \
229 ) \
230 )
231
232 // 1/y when y is a signed integer
233 #define GB_IMINV_SIGNED(y,bits) \
234 ( \
235 ((y) == -1) ? \
236 ( \
237 -1 \
238 ) \
239 : \
240 ( \
241 ((y) == 0) ? \
242 ( \
243 GB_INT_MAX (bits) \
244 ) \
245 : \
246 ( \
247 ((y) == 1) ? \
248 ( \
249 1 \
250 ) \
251 : \
252 ( \
253 0 \
254 ) \
255 ) \
256 ) \
257 )
258
259 // 1/y when y is an unsigned integer
260 #define GB_IMINV_UNSIGNED(y,bits) \
261 ( \
262 ((y) == 0) ? \
263 ( \
264 GB_UINT_MAX (bits) \
265 ) \
266 : \
267 ( \
268 ((y) == 1) ? \
269 ( \
270 1 \
271 ) \
272 : \
273 ( \
274 0 \
275 ) \
276 ) \
277 ) \
278
279 // GraphBLAS includes a built-in GrB_DIV_BOOL operator, so boolean division
280 // must be defined. There is no MATLAB equivalent since x/y for logical x and
281 // y is not permitted in MATLAB. ANSI C11 does not provide a definition
282 // either, and dividing by zero (boolean false) will typically terminate an
283 // application. In this GraphBLAS implementation, boolean division is treated
284 // as if it were int1, where 1/1 = 1, 0/1 = 0, 0/0 = integer NaN = 0, 1/0 =
285 // +infinity = 1. Thus Z=X/Y is Z=X. This is arbitrary, but it allows all
286 // operators to work on all types without causing run time exceptions. It also
287 // means that GrB_DIV(x,y) is the same as GrB_FIRST(x,y) for boolean x and y.
288 // See for example GB_boolean_rename and Template/GB_ops_template.c.
289 // Similarly, GrB_MINV_BOOL, which is 1/x, is simply 'true' for all x.
290
291 //------------------------------------------------------------------------------
292 // complex division
293 //------------------------------------------------------------------------------
294
295 // z = x/y where z, x, and y are double complex. The real and imaginary parts
296 // are passed as separate arguments to this routine. The NaN case is ignored
297 // for the double relop yr >= yi. Returns 1 if the denominator is zero, 0
298 // otherwise.
299 //
300 // This uses ACM Algo 116, by R. L. Smith, 1962, which tries to avoid underflow
301 // and overflow.
302 //
303 // z can be the same variable as x or y.
304 //
305 // Note that this function has the same signature as SuiteSparse_divcomplex.
306
GB_divcomplex(double xr,double xi,double yr,double yi,double * zr,double * zi)307 inline int GB_divcomplex
308 (
309 double xr, double xi, // real and imaginary parts of x
310 double yr, double yi, // real and imaginary parts of y
311 double *zr, double *zi // real and imaginary parts of z
312 )
313 {
314 double tr, ti, r, den ;
315
316 int yr_class = fpclassify (yr) ;
317 int yi_class = fpclassify (yi) ;
318
319 if (yi_class == FP_ZERO)
320 {
321 den = yr ;
322 if (xi == 0)
323 {
324 tr = xr / den ;
325 ti = 0 ;
326 }
327 else if (xr == 0)
328 {
329 tr = 0 ;
330 ti = xi / den ;
331 }
332 else
333 {
334 tr = xr / den ;
335 ti = xi / den ;
336 }
337 }
338 else if (yr_class == FP_ZERO)
339 {
340 den = yi ;
341 if (xr == 0)
342 {
343 tr = xi / den ;
344 ti = 0 ;
345 }
346 else if (xi == 0)
347 {
348 tr = 0 ;
349 ti = -xr / den ;
350 }
351 else
352 {
353 tr = xi / den ;
354 ti = -xr / den ;
355 }
356 }
357 else if (yi_class == FP_INFINITE && yr_class == FP_INFINITE)
358 {
359 r = (signbit (yr) == signbit (yi)) ? (1) : (-1) ;
360 den = yr + r * yi ;
361 tr = (xr + xi * r) / den ;
362 ti = (xi - xr * r) / den ;
363 }
364 else if (fabs (yr) >= fabs (yi))
365 {
366 r = yi / yr ;
367 den = yr + r * yi ;
368 tr = (xr + xi * r) / den ;
369 ti = (xi - xr * r) / den ;
370 }
371 else
372 {
373 r = yr / yi ;
374 den = r * yr + yi ;
375 tr = (xr * r + xi) / den ;
376 ti = (xi * r - xr) / den ;
377 }
378 (*zr) = tr ;
379 (*zi) = ti ;
380 return (den == 0) ;
381 }
382
GB_FC64_div(GxB_FC64_t x,GxB_FC64_t y)383 inline GxB_FC64_t GB_FC64_div (GxB_FC64_t x, GxB_FC64_t y)
384 {
385 double zr, zi ;
386 GB_divcomplex (creal (x), cimag (x), creal (y), cimag (y), &zr, &zi) ;
387 return (GxB_CMPLX (zr, zi)) ;
388 }
389
GB_FC32_div(GxB_FC32_t x,GxB_FC32_t y)390 inline GxB_FC32_t GB_FC32_div (GxB_FC32_t x, GxB_FC32_t y)
391 {
392 // single complex division: typecast to double complex, do the division,
393 // and then typecast back to single complex
394 double zr, zi ;
395 GB_divcomplex ((double) crealf (x), (double) cimagf (x),
396 (double) crealf (y), (double) cimagf (y), &zr, &zi) ;
397 return (GxB_CMPLXF ((float) zr, (float) zi)) ;
398 }
399
400 //------------------------------------------------------------------------------
401 // z = x^y: wrappers for pow, powf, cpow, and cpowf
402 //------------------------------------------------------------------------------
403
404 // The following rules are used to try to align the results with what MATLAB
405 // computes for x^y:
406
407 // if x or y are NaN, then z is NaN
408 // if y is zero, then z is 1
409 // if (x and y are complex but with zero imaginary parts, and
410 // (x >= 0 or if y is an integer, NaN, or Inf)), then z is real
411 // else use the built-in C library function, z = pow (x,y)
412
GB_powf(float x,float y)413 inline float GB_powf (float x, float y)
414 {
415 int xr_class = fpclassify (x) ;
416 int yr_class = fpclassify (y) ;
417 if (xr_class == FP_NAN || yr_class == FP_NAN)
418 {
419 // z is nan if either x or y are nan
420 return (NAN) ;
421 }
422 if (yr_class == FP_ZERO)
423 {
424 // z is 1 if y is zero
425 return (1) ;
426 }
427 // otherwise, z = powf (x,y)
428 return (powf (x, y)) ;
429 }
430
GB_pow(double x,double y)431 inline double GB_pow (double x, double y)
432 {
433 int xr_class = fpclassify (x) ;
434 int yr_class = fpclassify (y) ;
435 if (xr_class == FP_NAN || yr_class == FP_NAN)
436 {
437 // z is nan if either x or y are nan
438 return (NAN) ;
439 }
440 if (yr_class == FP_ZERO)
441 {
442 // z is 1 if y is zero
443 return (1) ;
444 }
445 // otherwise, z = pow (x,y)
446 return (pow (x, y)) ;
447 }
448
GB_cpowf(GxB_FC32_t x,GxB_FC32_t y)449 inline GxB_FC32_t GB_cpowf (GxB_FC32_t x, GxB_FC32_t y)
450 {
451 float xr = crealf (x) ;
452 float yr = crealf (y) ;
453 int xr_class = fpclassify (xr) ;
454 int yr_class = fpclassify (yr) ;
455 int xi_class = fpclassify (cimagf (x)) ;
456 int yi_class = fpclassify (cimagf (y)) ;
457 if (xi_class == FP_ZERO && yi_class == FP_ZERO)
458 {
459 // both x and y are real; see if z should be real
460 if (xr >= 0 || yr_class == FP_NAN || yr_class == FP_INFINITE ||
461 yr == truncf (yr))
462 {
463 // z is real if x >= 0, or if y is an integer, NaN, or Inf
464 return (GxB_CMPLXF (GB_powf (xr, yr), 0)) ;
465 }
466 }
467 if (xr_class == FP_NAN || xi_class == FP_NAN ||
468 yr_class == FP_NAN || yi_class == FP_NAN)
469 {
470 // z is (nan,nan) if any part of x or y are nan
471 return (GxB_CMPLXF (NAN, NAN)) ;
472 }
473 if (yr_class == FP_ZERO && yi_class == FP_ZERO)
474 {
475 // z is (1,0) if y is (0,0)
476 return (GxB_CMPLXF (1, 0)) ;
477 }
478 return (cpowf (x, y)) ;
479 }
480
GB_cpow(GxB_FC64_t x,GxB_FC64_t y)481 inline GxB_FC64_t GB_cpow (GxB_FC64_t x, GxB_FC64_t y)
482 {
483 double xr = creal (x) ;
484 double yr = creal (y) ;
485 int xr_class = fpclassify (xr) ;
486 int yr_class = fpclassify (yr) ;
487 int xi_class = fpclassify (cimag (x)) ;
488 int yi_class = fpclassify (cimag (y)) ;
489 if (xi_class == FP_ZERO && yi_class == FP_ZERO)
490 {
491 // both x and y are real; see if z should be real
492 if (xr >= 0 || yr_class == FP_NAN || yr_class == FP_INFINITE ||
493 yr == trunc (yr))
494 {
495 // z is real if x >= 0, or if y is an integer, NaN, or Inf
496 return (GxB_CMPLX (GB_pow (xr, yr), 0)) ;
497 }
498 }
499 if (xr_class == FP_NAN || xi_class == FP_NAN ||
500 yr_class == FP_NAN || yi_class == FP_NAN)
501 {
502 // z is (nan,nan) if any part of x or y are nan
503 return (GxB_CMPLX (NAN, NAN)) ;
504 }
505 if (yr_class == FP_ZERO && yi_class == FP_ZERO)
506 {
507 // z is (1,0) if y is (0,0)
508 return (GxB_CMPLX (1, 0)) ;
509 }
510 return (cpow (x, y)) ;
511 }
512
GB_pow_int8(int8_t x,int8_t y)513 inline int8_t GB_pow_int8 (int8_t x, int8_t y)
514 {
515 return (GB_cast_to_int8_t (GB_pow ((double) x, (double) y))) ;
516 }
517
GB_pow_int16(int16_t x,int16_t y)518 inline int16_t GB_pow_int16 (int16_t x, int16_t y)
519 {
520 return (GB_cast_to_int16_t (GB_pow ((double) x, (double) y))) ;
521 }
522
GB_pow_int32(int32_t x,int32_t y)523 inline int32_t GB_pow_int32 (int32_t x, int32_t y)
524 {
525 return (GB_cast_to_int32_t (GB_pow ((double) x, (double) y))) ;
526 }
527
GB_pow_int64(int64_t x,int64_t y)528 inline int64_t GB_pow_int64 (int64_t x, int64_t y)
529 {
530 return (GB_cast_to_int64_t (GB_pow ((double) x, (double) y))) ;
531 }
532
GB_pow_uint8(uint8_t x,uint8_t y)533 inline uint8_t GB_pow_uint8 (uint8_t x, uint8_t y)
534 {
535 return (GB_cast_to_uint8_t (GB_pow ((double) x, (double) y))) ;
536 }
537
GB_pow_uint16(uint16_t x,uint16_t y)538 inline uint16_t GB_pow_uint16 (uint16_t x, uint16_t y)
539 {
540 return (GB_cast_to_uint16_t (GB_pow ((double) x, (double) y))) ;
541 }
542
GB_pow_uint32(uint32_t x,uint32_t y)543 inline uint32_t GB_pow_uint32 (uint32_t x, uint32_t y)
544 {
545 return (GB_cast_to_uint32_t (GB_pow ((double) x, (double) y))) ;
546 }
547
GB_pow_uint64(uint64_t x,uint64_t y)548 inline uint64_t GB_pow_uint64 (uint64_t x, uint64_t y)
549 {
550 return (GB_cast_to_uint64_t (GB_pow ((double) x, (double) y))) ;
551 }
552
553 //------------------------------------------------------------------------------
554 // frexp for float and double
555 //------------------------------------------------------------------------------
556
GB_frexpxf(float x)557 inline float GB_frexpxf (float x)
558 {
559 int exp_ignored ;
560 return (frexpf (x, &exp_ignored)) ;
561 }
562
GB_frexpef(float x)563 inline float GB_frexpef (float x)
564 {
565 int exp ;
566 float mantissa_ignored = frexpf (x, &exp) ;
567 return ((float) exp) ;
568 }
569
GB_frexpx(double x)570 inline double GB_frexpx (double x)
571 {
572 int exp_ignored ;
573 return (frexp (x, &exp_ignored)) ;
574 }
575
GB_frexpe(double x)576 inline double GB_frexpe (double x)
577 {
578 int exp ;
579 double mantissa_ignored = frexp (x, &exp) ;
580 return ((double) exp) ;
581 }
582
583 //------------------------------------------------------------------------------
584 // signum functions
585 //------------------------------------------------------------------------------
586
GB_signumf(float x)587 inline float GB_signumf (float x)
588 {
589 if (isnan (x)) return (x) ;
590 return ((float) ((x < 0) ? (-1) : ((x > 0) ? 1 : 0))) ;
591 }
592
GB_signum(double x)593 inline double GB_signum (double x)
594 {
595 if (isnan (x)) return (x) ;
596 return ((double) ((x < 0) ? (-1) : ((x > 0) ? 1 : 0))) ;
597 }
598
GB_csignumf(GxB_FC32_t x)599 inline GxB_FC32_t GB_csignumf (GxB_FC32_t x)
600 {
601 if (crealf (x) == 0 && cimagf (x) == 0) return (GxB_CMPLXF (0,0)) ;
602 float y = cabsf (x) ;
603 return (GxB_CMPLXF (crealf (x) / y, cimagf (x) / y)) ;
604 }
605
GB_csignum(GxB_FC64_t x)606 inline GxB_FC64_t GB_csignum (GxB_FC64_t x)
607 {
608 if (creal (x) == 0 && cimag (x) == 0) return (GxB_CMPLX (0,0)) ;
609 double y = cabs (x) ;
610 return (GxB_CMPLX (creal (x) / y, cimag (x) / y)) ;
611 }
612
613 //------------------------------------------------------------------------------
614 // complex functions
615 //------------------------------------------------------------------------------
616
617 // The ANSI C11 math.h header defines the ceil, floor, round, trunc,
618 // exp2, expm1, log10, log1pm, or log2 functions for float and double,
619 // but the corresponding functions do not appear in the ANSI C11 complex.h.
620 // These functions are used instead, for float complex and double complex.
621
622 //------------------------------------------------------------------------------
623 // z = ceil (x) for float complex
624 //------------------------------------------------------------------------------
625
GB_cceilf(GxB_FC32_t x)626 inline GxB_FC32_t GB_cceilf (GxB_FC32_t x)
627 {
628 return (GxB_CMPLXF (ceilf (crealf (x)), ceilf (cimagf (x)))) ;
629 }
630
631 //------------------------------------------------------------------------------
632 // z = ceil (x) for double complex
633 //------------------------------------------------------------------------------
634
GB_cceil(GxB_FC64_t x)635 inline GxB_FC64_t GB_cceil (GxB_FC64_t x)
636 {
637 return (GxB_CMPLX (ceil (creal (x)), ceil (cimag (x)))) ;
638 }
639
640 //------------------------------------------------------------------------------
641 // z = floor (x) for float complex
642 //------------------------------------------------------------------------------
643
GB_cfloorf(GxB_FC32_t x)644 inline GxB_FC32_t GB_cfloorf (GxB_FC32_t x)
645 {
646 return (GxB_CMPLXF (floorf (crealf (x)), floorf (cimagf (x)))) ;
647 }
648
649 //------------------------------------------------------------------------------
650 // z = floor (x) for double complex
651 //------------------------------------------------------------------------------
652
GB_cfloor(GxB_FC64_t x)653 inline GxB_FC64_t GB_cfloor (GxB_FC64_t x)
654 {
655 return (GxB_CMPLX (floor (creal (x)), floor (cimag (x)))) ;
656 }
657
658 //------------------------------------------------------------------------------
659 // z = round (x) for float complex
660 //------------------------------------------------------------------------------
661
GB_croundf(GxB_FC32_t x)662 inline GxB_FC32_t GB_croundf (GxB_FC32_t x)
663 {
664 return (GxB_CMPLXF (roundf (crealf (x)), roundf (cimagf (x)))) ;
665 }
666
667 //------------------------------------------------------------------------------
668 // z = round (x) for double complex
669 //------------------------------------------------------------------------------
670
GB_cround(GxB_FC64_t x)671 inline GxB_FC64_t GB_cround (GxB_FC64_t x)
672 {
673 return (GxB_CMPLX (round (creal (x)), round (cimag (x)))) ;
674 }
675
676 //------------------------------------------------------------------------------
677 // z = trunc (x) for float complex
678 //------------------------------------------------------------------------------
679
GB_ctruncf(GxB_FC32_t x)680 inline GxB_FC32_t GB_ctruncf (GxB_FC32_t x)
681 {
682 return (GxB_CMPLXF (truncf (crealf (x)), truncf (cimagf (x)))) ;
683 }
684
685 //------------------------------------------------------------------------------
686 // z = trunc (x) for double complex
687 //------------------------------------------------------------------------------
688
GB_ctrunc(GxB_FC64_t x)689 inline GxB_FC64_t GB_ctrunc (GxB_FC64_t x)
690 {
691 return (GxB_CMPLX (trunc (creal (x)), trunc (cimag (x)))) ;
692 }
693
694 //------------------------------------------------------------------------------
695 // z = exp2 (x) for float complex
696 //------------------------------------------------------------------------------
697
GB_cexp2f(GxB_FC32_t x)698 inline GxB_FC32_t GB_cexp2f (GxB_FC32_t x)
699 {
700 if (fpclassify (cimagf (x)) == FP_ZERO)
701 {
702 // x is real, use exp2f
703 return (GxB_CMPLXF (exp2f (crealf (x)), 0)) ;
704 }
705 return (GB_cpowf (GxB_CMPLXF (2,0), x)) ; // z = 2^x
706 }
707
708 //------------------------------------------------------------------------------
709 // z = exp2 (x) for double complex
710 //------------------------------------------------------------------------------
711
GB_cexp2(GxB_FC64_t x)712 inline GxB_FC64_t GB_cexp2 (GxB_FC64_t x)
713 {
714 if (fpclassify (cimag (x)) == FP_ZERO)
715 {
716 // x is real, use exp2
717 return (GxB_CMPLX (exp2 (creal (x)), 0)) ;
718 }
719 return (GB_cpow (GxB_CMPLX (2,0), x)) ; // z = 2^x
720 }
721
722 //------------------------------------------------------------------------------
723 // z = expm1 (x) for double complex
724 //------------------------------------------------------------------------------
725
GB_cexpm1(GxB_FC64_t x)726 inline GxB_FC64_t GB_cexpm1 (GxB_FC64_t x)
727 {
728 // FUTURE: GB_cexpm1 is not accurate
729 // z = cexp (x) - 1
730 GxB_FC64_t z = cexp (x) ;
731 return (GxB_CMPLX (creal (z) - 1, cimag (z))) ;
732 }
733
734 //------------------------------------------------------------------------------
735 // z = expm1 (x) for float complex
736 //------------------------------------------------------------------------------
737
GB_cexpm1f(GxB_FC32_t x)738 inline GxB_FC32_t GB_cexpm1f (GxB_FC32_t x)
739 {
740 // typecast to double and use GB_cexpm1
741 GxB_FC64_t z = GxB_CMPLX ((double) crealf (x), (double) cimagf (x)) ;
742 z = GB_cexpm1 (z) ;
743 return (GxB_CMPLXF ((float) creal (z), (float) cimag (z))) ;
744 }
745
746 //------------------------------------------------------------------------------
747 // z = log1p (x) for double complex
748 //------------------------------------------------------------------------------
749
GB_clog1p(GxB_FC64_t x)750 inline GxB_FC64_t GB_clog1p (GxB_FC64_t x)
751 {
752 // FUTURE: GB_clog1p is not accurate
753 // z = clog (1+x)
754 return (clog (GxB_CMPLX (creal (x) + 1, cimag (x)))) ;
755 }
756
757 //------------------------------------------------------------------------------
758 // z = log1p (x) for float complex
759 //------------------------------------------------------------------------------
760
GB_clog1pf(GxB_FC32_t x)761 inline GxB_FC32_t GB_clog1pf (GxB_FC32_t x)
762 {
763 // typecast to double and use GB_clog1p
764 GxB_FC64_t z = GxB_CMPLX ((double) crealf (x), (double) cimagf (x)) ;
765 z = GB_clog1p (z) ;
766 return (GxB_CMPLXF ((float) creal (z), (float) cimag (z))) ;
767 }
768
769 //------------------------------------------------------------------------------
770 // z = log10 (x) for float complex
771 //------------------------------------------------------------------------------
772
773 // log_e (10) in single precision
774 #define GB_LOG10EF 2.3025851f
775
GB_clog10f(GxB_FC32_t x)776 inline GxB_FC32_t GB_clog10f (GxB_FC32_t x)
777 {
778 // z = log (x) / log (10)
779 return (GB_FC32_div (clogf (x), GxB_CMPLXF (GB_LOG10EF, 0))) ;
780 }
781
782 //------------------------------------------------------------------------------
783 // z = log10 (x) for double complex
784 //------------------------------------------------------------------------------
785
786 // log_e (10) in double precision
787 #define GB_LOG10E 2.302585092994045901
788
GB_clog10(GxB_FC64_t x)789 inline GxB_FC64_t GB_clog10 (GxB_FC64_t x)
790 {
791 // z = log (x) / log (10)
792 return (GB_FC64_div (clog (x), GxB_CMPLX (GB_LOG10E, 0))) ;
793 }
794
795 //------------------------------------------------------------------------------
796 // z = log2 (x) for float complex
797 //------------------------------------------------------------------------------
798
799 // log_e (2) in single precision
800 #define GB_LOG2EF 0.69314718f
801
GB_clog2f(GxB_FC32_t x)802 inline GxB_FC32_t GB_clog2f (GxB_FC32_t x)
803 {
804 // z = log (x) / log (2)
805 return (GB_FC32_div (clogf (x), GxB_CMPLXF (GB_LOG2EF, 0))) ;
806 }
807
808 //------------------------------------------------------------------------------
809 // z = log2 (x) for double complex
810 //------------------------------------------------------------------------------
811
812 // log_e (2) in double precision
813 #define GB_LOG2E 0.693147180559945286
814
GB_clog2(GxB_FC64_t x)815 inline GxB_FC64_t GB_clog2 (GxB_FC64_t x)
816 {
817 // z = log (x) / log (2)
818 return (GB_FC64_div (clog (x), GxB_CMPLX (GB_LOG2E, 0))) ;
819 }
820
821 //------------------------------------------------------------------------------
822 // z = isinf (x) for float complex
823 //------------------------------------------------------------------------------
824
GB_cisinff(GxB_FC32_t x)825 inline bool GB_cisinff (GxB_FC32_t x)
826 {
827 return (isinf (crealf (x)) || isinf (cimagf (x))) ;
828 }
829
830 //------------------------------------------------------------------------------
831 // z = isinf (x) for double complex
832 //------------------------------------------------------------------------------
833
GB_cisinf(GxB_FC64_t x)834 inline bool GB_cisinf (GxB_FC64_t x)
835 {
836 return (isinf (creal (x)) || isinf (cimag (x))) ;
837 }
838
839 //------------------------------------------------------------------------------
840 // z = isnan (x) for float complex
841 //------------------------------------------------------------------------------
842
GB_cisnanf(GxB_FC32_t x)843 inline bool GB_cisnanf (GxB_FC32_t x)
844 {
845 return (isnan (crealf (x)) || isnan (cimagf (x))) ;
846 }
847
848 //------------------------------------------------------------------------------
849 // z = isnan (x) for double complex
850 //------------------------------------------------------------------------------
851
GB_cisnan(GxB_FC64_t x)852 inline bool GB_cisnan (GxB_FC64_t x)
853 {
854 return (isnan (creal (x)) || isnan (cimag (x))) ;
855 }
856
857 //------------------------------------------------------------------------------
858 // z = isfinite (x) for float complex
859 //------------------------------------------------------------------------------
860
GB_cisfinitef(GxB_FC32_t x)861 inline bool GB_cisfinitef (GxB_FC32_t x)
862 {
863 return (isfinite (crealf (x)) && isfinite (cimagf (x))) ;
864 }
865
866 //------------------------------------------------------------------------------
867 // z = isfinite (x) for double complex
868 //------------------------------------------------------------------------------
869
GB_cisfinite(GxB_FC64_t x)870 inline bool GB_cisfinite (GxB_FC64_t x)
871 {
872 return (isfinite (creal (x)) && isfinite (cimag (x))) ;
873 }
874
875 #endif
876
877