Skip to content

Commit e468261

Browse files
authored
Add missing comparison functions for imaginary numbers (#29083)
Adds missing comparison numbers for imaginary numbers, both at runtime and compile time Also makes sure to implement min/max for imaginary numbers (at runtime and compile time), as well as `isFinite`, `isInf`, and `isNan` Built on #29081 Resolves #29051 - [x] paratest [Reviewed by @benharsh]
2 parents 642f897 + dca6c34 commit e468261

15 files changed

Lines changed: 332 additions & 0 deletions

doc/rst/technotes/editions.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,6 @@ remain in the preview until they are deemed sufficiently complete.
181181
are defined using tertiary methods. In such cases, a default
182182
comparison operator will now be available in scopes that do not have
183183
access to the tertiary method.
184+
185+
- The ``isFinite()``, ``isInf()``, and ``isNan()`` functions are now defined
186+
for ``imag`` values, in addition to ``real`` values.

modules/internal/ChapelBase.chpl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,10 @@ module ChapelBase {
321321
inline operator <=(a: uint(64), b: uint(64)) do return __primitive("<=", a, b);
322322
inline operator <=(a: real(32), b: real(32)) do return __primitive("<=", a, b);
323323
inline operator <=(a: real(64), b: real(64)) do return __primitive("<=", a, b);
324+
inline operator <=(a: imag(32), b: imag(32)) do return __primitive("<=", _i2r(a), _i2r(b));
325+
inline operator <=(a: imag(64), b: imag(64)) do return __primitive("<=", _i2r(a), _i2r(b));
326+
inline operator <=(a: complex(64), b: complex(64)) do compilerError("ordered comparison of complex numbers is not supported");
327+
inline operator <=(a: complex(128), b: complex(128)) do compilerError("ordered comparison of complex numbers is not supported");
324328
operator <=(a: enum, b: enum) where (a.type == b.type) do
325329
return __primitive("<=", chpl__enumToOrder(a), chpl__enumToOrder(b));
326330
pragma "last resort"
@@ -339,6 +343,10 @@ module ChapelBase {
339343
inline operator >=(a: uint(64), b: uint(64)) do return __primitive(">=", a, b);
340344
inline operator >=(a: real(32), b: real(32)) do return __primitive(">=", a, b);
341345
inline operator >=(a: real(64), b: real(64)) do return __primitive(">=", a, b);
346+
inline operator >=(a: imag(32), b: imag(32)) do return __primitive(">=", _i2r(a), _i2r(b));
347+
inline operator >=(a: imag(64), b: imag(64)) do return __primitive(">=", _i2r(a), _i2r(b));
348+
inline operator >=(a: complex(64), b: complex(64)) do compilerError("ordered comparison of complex numbers is not supported");
349+
inline operator >=(a: complex(128), b: complex(128)) do compilerError("ordered comparison of complex numbers is not supported");
342350
operator >=(a: enum, b: enum) where (a.type == b.type) do
343351
return __primitive(">=", chpl__enumToOrder(a), chpl__enumToOrder(b));
344352
pragma "last resort"
@@ -357,6 +365,10 @@ module ChapelBase {
357365
inline operator <(a: uint(64), b: uint(64)) do return __primitive("<", a, b);
358366
inline operator <(a: real(32), b: real(32)) do return __primitive("<", a, b);
359367
inline operator <(a: real(64), b: real(64)) do return __primitive("<", a, b);
368+
inline operator <(a: imag(32), b: imag(32)) do return __primitive("<", _i2r(a), _i2r(b));
369+
inline operator <(a: imag(64), b: imag(64)) do return __primitive("<", _i2r(a), _i2r(b));
370+
inline operator <(a: complex(64), b: complex(64)) do compilerError("ordered comparison of complex numbers is not supported");
371+
inline operator <(a: complex(128), b: complex(128)) do compilerError("ordered comparison of complex numbers is not supported");
360372
operator <(a: enum, b: enum) where (a.type == b.type) do
361373
return __primitive("<", chpl__enumToOrder(a), chpl__enumToOrder(b));
362374
pragma "last resort"
@@ -375,6 +387,10 @@ module ChapelBase {
375387
inline operator >(a: uint(64), b: uint(64)) do return __primitive(">", a, b);
376388
inline operator >(a: real(32), b: real(32)) do return __primitive(">", a, b);
377389
inline operator >(a: real(64), b: real(64)) do return __primitive(">", a, b);
390+
inline operator >(a: imag(32), b: imag(32)) do return __primitive(">", _i2r(a), _i2r(b));
391+
inline operator >(a: imag(64), b: imag(64)) do return __primitive(">", _i2r(a), _i2r(b));
392+
inline operator >(a: complex(64), b: complex(64)) do compilerError("ordered comparison of complex numbers is not supported");
393+
inline operator >(a: complex(128), b: complex(128)) do compilerError("ordered comparison of complex numbers is not supported");
378394
operator >(a: enum, b: enum) where (a.type == b.type) do
379395
return __primitive(">", chpl__enumToOrder(a), chpl__enumToOrder(b));
380396
pragma "last resort"
@@ -394,6 +410,10 @@ module ChapelBase {
394410
inline operator <=(param a: enum, param b: enum) param where (a.type == b.type) do return __primitive("<=", chpl__enumToOrder(a), chpl__enumToOrder(b));
395411
inline operator <=(param a: real(32), param b: real(32)) param do return __primitive("<=", a, b);
396412
inline operator <=(param a: real(64), param b: real(64)) param do return __primitive("<=", a, b);
413+
inline operator <=(param a: imag(32), param b: imag(32)) param do return __primitive("<=", _i2r(a), _i2r(b));
414+
inline operator <=(param a: imag(64), param b: imag(64)) param do return __primitive("<=", _i2r(a), _i2r(b));
415+
inline operator <=(param a: complex(64), param b: complex(64)) param do compilerError("ordered comparison of complex numbers is not supported");
416+
inline operator <=(param a: complex(128), param b: complex(128)) param do compilerError("ordered comparison of complex numbers is not supported");
397417

398418
inline operator >=(param a: int(8), param b: int(8)) param do return __primitive(">=", a, b);
399419
inline operator >=(param a: int(16), param b: int(16)) param do return __primitive(">=", a, b);
@@ -406,6 +426,10 @@ module ChapelBase {
406426
inline operator >=(param a: enum, param b: enum) param where (a.type == b.type) do return __primitive(">=", chpl__enumToOrder(a), chpl__enumToOrder(b));
407427
inline operator >=(param a: real(32), param b: real(32)) param do return __primitive(">=", a, b);
408428
inline operator >=(param a: real(64), param b: real(64)) param do return __primitive(">=", a, b);
429+
inline operator >=(param a: imag(32), param b: imag(32)) param do return __primitive(">=", _i2r(a), _i2r(b));
430+
inline operator >=(param a: imag(64), param b: imag(64)) param do return __primitive(">=", _i2r(a), _i2r(b));
431+
inline operator >=(param a: complex(64), param b: complex(64)) param do compilerError("ordered comparison of complex numbers is not supported");
432+
inline operator >=(param a: complex(128), param b: complex(128)) param do compilerError("ordered comparison of complex numbers is not supported");
409433

410434
inline operator <(param a: int(8), param b: int(8)) param do return __primitive("<", a, b);
411435
inline operator <(param a: int(16), param b: int(16)) param do return __primitive("<", a, b);
@@ -418,6 +442,10 @@ module ChapelBase {
418442
inline operator <(param a: enum, param b: enum) param where (a.type == b.type) do return __primitive("<", chpl__enumToOrder(a), chpl__enumToOrder(b));
419443
inline operator <(param a: real(32), param b: real(32)) param do return __primitive("<", a, b);
420444
inline operator <(param a: real(64), param b: real(64)) param do return __primitive("<", a, b);
445+
inline operator <(param a: imag(32), param b: imag(32)) param do return __primitive("<", _i2r(a), _i2r(b));
446+
inline operator <(param a: imag(64), param b: imag(64)) param do return __primitive("<", _i2r(a), _i2r(b));
447+
inline operator <(param a: complex(64), param b: complex(64)) param do compilerError("ordered comparison of complex numbers is not supported");
448+
inline operator <(param a: complex(128), param b: complex(128)) param do compilerError("ordered comparison of complex numbers is not supported");
421449

422450
inline operator >(param a: int(8), param b: int(8)) param do return __primitive(">", a, b);
423451
inline operator >(param a: int(16), param b: int(16)) param do return __primitive(">", a, b);
@@ -430,6 +458,10 @@ module ChapelBase {
430458
inline operator >(param a: enum, param b: enum) param where (a.type == b.type) do return __primitive(">", chpl__enumToOrder(a), chpl__enumToOrder(b));
431459
inline operator >(param a: real(32), param b: real(32)) param do return __primitive(">", a, b);
432460
inline operator >(param a: real(64), param b: real(64)) param do return __primitive(">", a, b);
461+
inline operator >(param a: imag(32), param b: imag(32)) param do return __primitive(">", _i2r(a), _i2r(b));
462+
inline operator >(param a: imag(64), param b: imag(64)) param do return __primitive(">", _i2r(a), _i2r(b));
463+
inline operator >(param a: complex(64), param b: complex(64)) param do compilerError("ordered comparison of complex numbers is not supported");
464+
inline operator >(param a: complex(128), param b: complex(128)) param do compilerError("ordered comparison of complex numbers is not supported");
433465

434466
//
435467
// unary + and - on primitive types

modules/standard/AutoMath.chpl

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,28 @@ module AutoMath {
295295
`false` otherwise. */
296296
inline proc isFinite(x: real(32)): bool do return chpl_macro_float_isfinite(x):bool;
297297

298+
/* Returns `true` if the argument `x` is a representation of a finite value;
299+
`false` otherwise. */
300+
@edition(first="preview")
301+
inline proc isFinite(x: imag(64)): bool do return isFinite(x:real(64));
302+
303+
/* Returns `true` if the argument `x` is a representation of a finite value;
304+
`false` otherwise. */
305+
@edition(first="preview")
306+
inline proc isFinite(x: imag(32)): bool do return isFinite(x:real(32));
307+
308+
/* Returns `true` if the argument `x` is a representation of a finite value;
309+
`false` otherwise. */
310+
@edition(last="2.0")
311+
@unstable("isFinite is unstable pending review and will be stabilized in a future edition")
312+
inline proc isFinite(x: imag(64)): bool do return isFinite(x:real(64));
313+
314+
/* Returns `true` if the argument `x` is a representation of a finite value;
315+
`false` otherwise. */
316+
@edition(last="2.0")
317+
@unstable("isFinite is unstable pending review and will be stabilized in a future edition")
318+
inline proc isFinite(x: imag(32)): bool do return isFinite(x:real(32));
319+
298320
/* Returns `true` if the argument `x` is a representation of *infinity*;
299321
`false` otherwise. */
300322
inline proc isInf(x: real(64)): bool do return chpl_macro_double_isinf(x):bool;
@@ -303,6 +325,28 @@ module AutoMath {
303325
`false` otherwise. */
304326
inline proc isInf(x: real(32)): bool do return chpl_macro_float_isinf(x):bool;
305327

328+
/* Returns `true` if the argument `x` is a representation of *infinity*;
329+
`false` otherwise. */
330+
@edition(first="preview")
331+
inline proc isInf(x: imag(64)): bool do return isInf(x:real(64));
332+
333+
/* Returns `true` if the argument `x` is a representation of *infinity*;
334+
`false` otherwise. */
335+
@edition(first="preview")
336+
inline proc isInf(x: imag(32)): bool do return isInf(x:real(32));
337+
338+
/* Returns `true` if the argument `x` is a representation of *infinity*;
339+
`false` otherwise. */
340+
@edition(last="2.0")
341+
@unstable("isInf is unstable pending review and will be stabilized in a future edition")
342+
inline proc isInf(x: imag(64)): bool do return isInf(x:real(64));
343+
344+
/* Returns `true` if the argument `x` is a representation of *infinity*;
345+
`false` otherwise. */
346+
@edition(last="2.0")
347+
@unstable("isInf is unstable pending review and will be stabilized in a future edition")
348+
inline proc isInf(x: imag(32)): bool do return isInf(x:real(32));
349+
306350
/* Returns `true` if the argument `x` does not represent a valid number;
307351
`false` otherwise. */
308352
inline proc isNan(x: real(64)): bool do return chpl_macro_double_isnan(x):bool;
@@ -311,6 +355,28 @@ module AutoMath {
311355
`false` otherwise. */
312356
inline proc isNan(x: real(32)): bool do return chpl_macro_float_isnan(x):bool;
313357

358+
/* Returns `true` if the argument `x` does not represent a valid number;
359+
`false` otherwise. */
360+
@edition(first="preview")
361+
inline proc isNan(x: imag(64)): bool do return isNan(x:real(64));
362+
363+
/* Returns `true` if the argument `x` does not represent a valid number;
364+
`false` otherwise. */
365+
@edition(first="preview")
366+
inline proc isNan(x: imag(32)): bool do return isNan(x:real(32));
367+
368+
/* Returns `true` if the argument `x` does not represent a valid number;
369+
`false` otherwise. */
370+
@edition(last="2.0")
371+
@unstable("isNan is unstable pending review and will be stabilized in a future edition")
372+
inline proc isNan(x: imag(64)): bool do return isNan(x:real(64));
373+
374+
/* Returns `true` if the argument `x` does not represent a valid number;
375+
`false` otherwise. */
376+
@edition(last="2.0")
377+
@unstable("isNan is unstable pending review and will be stabilized in a future edition")
378+
inline proc isNan(x: imag(32)): bool do return isNan(x:real(32));
379+
314380
//
315381
// min and max
316382
//
@@ -338,6 +404,11 @@ module AutoMath {
338404
@chpldoc.nodoc
339405
inline proc max(x: real(64), y: real(64)) do return if (x > y) || isNan(x) then x else y;
340406

407+
@chpldoc.nodoc
408+
inline proc max(x: imag(32), y: imag(32)) do return if (x > y) || isNan(x) then x else y;
409+
@chpldoc.nodoc
410+
inline proc max(x: imag(64), y: imag(64)) do return if (x > y) || isNan(x) then x else y;
411+
341412
@chpldoc.nodoc
342413
inline proc max(x: int(8), y: uint(8)) do return if x > y then x : uint(8) else y;
343414
@chpldoc.nodoc
@@ -362,6 +433,11 @@ module AutoMath {
362433
compilerError("min() and max() are not supported for atomic arguments - apply read() to those arguments first");
363434
}
364435

436+
pragma "last resort"
437+
@chpldoc.nodoc
438+
proc max(x, y) where isComplexType(x.type) || isComplexType(y.type) do
439+
compilerError("min() and max() are not supported for complex arguments");
440+
365441
/* Returns the maximum value of two arguments using the ``>`` operator
366442
for comparison.
367443
If one of the arguments is :proc:`Math.nan`, the result is also nan.
@@ -385,6 +461,12 @@ module AutoMath {
385461
return if x > y then x else y;
386462
}
387463

464+
// pragma "last resort"
465+
@chpldoc.nodoc
466+
inline proc max(param x: numeric, param y: numeric) param
467+
where isComplex(x) || isComplex(y) do
468+
compilerError("min() and max() are not supported for complex arguments");
469+
388470
@chpldoc.nodoc
389471
inline proc min(x: int(8), y: int(8)) do return if x < y then x else y;
390472
@chpldoc.nodoc
@@ -408,6 +490,11 @@ module AutoMath {
408490
@chpldoc.nodoc
409491
inline proc min(x: real(64), y: real(64)) do return if (x < y) || isNan(x) then x else y;
410492

493+
@chpldoc.nodoc
494+
inline proc min(x: imag(32), y: imag(32)) do return if (x < y) || isNan(x) then x else y;
495+
@chpldoc.nodoc
496+
inline proc min(x: imag(64), y: imag(64)) do return if (x < y) || isNan(x) then x else y;
497+
411498
@chpldoc.nodoc
412499
inline proc min(x: int(8), y: uint(8)) do return if x < y then x else y : int(8);
413500
@chpldoc.nodoc
@@ -432,6 +519,11 @@ module AutoMath {
432519
compilerError("min() and max() are not supported for atomic arguments - apply read() to those arguments first");
433520
}
434521

522+
pragma "last resort"
523+
@chpldoc.nodoc
524+
proc min(x, y) where isComplexType(x.type) || isComplexType(y.type) do
525+
compilerError("min() and max() are not supported for complex arguments");
526+
435527

436528
/* Returns the minimum value of two arguments using the ``<`` operator
437529
for comparison.
@@ -457,6 +549,12 @@ module AutoMath {
457549
return if x < y then x else y;
458550
}
459551

552+
// pragma "last resort"
553+
@chpldoc.nodoc
554+
inline proc min(param x: numeric, param y: numeric) param
555+
where isComplex(x) || isComplex(y) do
556+
compilerError("min() and max() are not supported for complex arguments");
557+
460558
/* Computes the mod operator on the two arguments, defined as
461559
``mod(x,y) = x - y * floor(x / y)``.
462560
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
enum testCases {
2+
compare,
3+
compareParam,
4+
min,
5+
maxParam
6+
}
7+
config param testCase = testCases.compare;
8+
9+
if testCase == testCases.compare {
10+
const x: complex = 1.0 + 2.0i;
11+
const y: complex = 4.0 + 3.0i;
12+
writeln("x < y: ", x < y);
13+
} else if testCase == testCases.compareParam {
14+
param x: complex = 1.0 + 2.0i;
15+
param y: complex = 4.0 + 3.0i;
16+
param z = x >= y;
17+
writeln("x >= y: ", z);
18+
} else if testCase == testCases.min {
19+
const x: complex = 1.0 + 2.0i;
20+
const y: complex = 4.0 + 3.0i;
21+
writeln("min(x, y): ", min(x, y));
22+
} else if testCase == testCases.maxParam {
23+
param x: complex = 1.0 + 2.0i;
24+
param y: complex = 4.0 + 3.0i;
25+
param z = max(x, y);
26+
writeln("max(x, y): ", z);
27+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
complexOrderedCompareErrors.chpl:12: error: ordered comparison of complex numbers is not supported
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
complexOrderedCompareErrors.chpl:16: error: ordered comparison of complex numbers is not supported
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-stestCase=testCases.compare # complexOrderedCompareErrors.compare.good
2+
-stestCase=testCases.compareParam # complexOrderedCompareErrors.compareParam.good
3+
-stestCase=testCases.min # complexOrderedCompareErrors.min.good
4+
-stestCase=testCases.maxParam # complexOrderedCompareErrors.maxParam.good
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
complexOrderedCompareErrors.chpl:25: error: min() and max() are not supported for complex arguments
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
complexOrderedCompareErrors.chpl:21: error: min() and max() are not supported for complex arguments
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
config const verbose = false;
2+
type types = (imag(32), imag(64));
3+
4+
inline proc vals(param idx) param {
5+
select idx {
6+
when 0 do return 0.0i;
7+
when 1 do return 1.0i;
8+
when 2 do return -2.0i;
9+
when 3 do return 4.0i;
10+
when 4 do return -8.0i;
11+
when 5 do return 0.5i;
12+
when 6 do return 0.125i;
13+
when 7 do return 16.0i;
14+
otherwise compilerError("Invalid index");
15+
}
16+
}
17+
param vals_size = 8;
18+
19+
20+
for param i in 0..<types.size {
21+
type t = types(i);
22+
23+
for param m in 0..<vals_size {
24+
for param n in 0..<vals_size {
25+
param a = vals(m):t;
26+
param b = vals(n):t;
27+
28+
param lt = a < b;
29+
param gt = a > b;
30+
param le = a <= b;
31+
param ge = a >= b;
32+
param eq = a == b;
33+
param ne = a != b;
34+
param minVal = min(a, b);
35+
param maxVal = max(a, b);
36+
37+
const aa = a;
38+
const bb = b;
39+
const lt2 = aa < bb;
40+
const gt2 = aa > bb;
41+
const le2 = aa <= bb;
42+
const ge2 = aa >= bb;
43+
const eq2 = aa == bb;
44+
const ne2 = aa != bb;
45+
const minVal2 = min(aa, bb);
46+
const maxVal2 = max(aa, bb);
47+
48+
if verbose then
49+
writeln(a, " X ", b, ": ",
50+
"a < b = ", lt, ", ",
51+
"a > b = ", gt, ", ",
52+
"a <= b = ", le, ", ",
53+
"a >= b = ", ge, ", ",
54+
"a == b = ", eq, ", ",
55+
"a != b = ", ne, ", ",
56+
"min(a, b) = ", minVal, ", ",
57+
"max(a, b) = ", maxVal);
58+
59+
// check for consistency between param and non-param versions of the comparisons
60+
if lt != lt2 then
61+
writeln("ERROR: ", a, " < ", b, " = ", lt, " != ", lt2);
62+
if gt != gt2 then
63+
writeln("ERROR: ", a, " > ", b, " = ", gt, " != ", gt2);
64+
if le != le2 then
65+
writeln("ERROR: ", a, " <= ", b, " = ", le, " != ", le2);
66+
if ge != ge2 then
67+
writeln("ERROR: ", a, " >= ", b, " = ", ge, " != ", ge2);
68+
if eq != eq2 then
69+
writeln("ERROR: ", a, " == ", b, " = ", eq, " != ", eq2);
70+
if ne != ne2 then
71+
writeln("ERROR: ", a, " != ", b, " = ", ne, " != ", ne2);
72+
if minVal != minVal2 then
73+
writeln("ERROR: min(", a, ", ", b, ") = ", minVal, " != ", minVal2);
74+
if maxVal != maxVal2 then
75+
writeln("ERROR: max(", a, ", ", b, ") = ", maxVal, " != ", maxVal2);
76+
77+
// check that the values are correct by casting to real and comparing to the real values
78+
if lt != (a:real < b:real) then
79+
writeln("ERROR: ", a, " < ", b, " = ", lt, " != ", (a:real < b:real));
80+
if gt != (a:real > b:real) then
81+
writeln("ERROR: ", a, " > ", b, " = ", gt, " != ", (a:real > b:real));
82+
if le != (a:real <= b:real) then
83+
writeln("ERROR: ", a, " <= ", b, " = ", le, " != ", (a:real <= b:real));
84+
if ge != (a:real >= b:real) then
85+
writeln("ERROR: ", a, " >= ", b, " = ", ge, " != ", (a:real >= b:real));
86+
if eq != (a:real == b:real) then
87+
writeln("ERROR: ", a, " == ", b, " = ", eq, " != ", (a:real == b:real));
88+
if ne != (a:real != b:real) then
89+
writeln("ERROR: ", a, " != ", b, " = ", ne, " != ", (a:real != b:real));
90+
if minVal:real != min(a:real, b:real) then
91+
writeln("ERROR: min(", a, ", ", b, ") = ", minVal, " != ", min(a:real, b:real));
92+
if maxVal:real != max(a:real, b:real) then
93+
writeln("ERROR: max(", a, ", ", b, ") = ", maxVal, " != ", max(a:real, b:real));
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)