diff options
author | Jaime <jaime.frio@gmail.com> | 2014-09-24 15:30:28 -0700 |
---|---|---|
committer | Jaime <jaime.frio@gmail.com> | 2014-09-24 15:30:28 -0700 |
commit | 5140ce73e3a79c238ee6226d6f3ef5336ee89215 (patch) | |
tree | 1235caf0ed1d31c1a5e36e041bc8bd4ca8fb5200 /numpy/core | |
parent | 27d73bf3295df59bd0e2d31605b0cbfc2a69f12d (diff) | |
parent | f2ab1fb607a9f931bc5633ca92f789d0d03af582 (diff) | |
download | numpy-5140ce73e3a79c238ee6226d6f3ef5336ee89215.tar.gz |
Merge pull request #5111 from larsmans/fast-bool
ENH: faster (branchless) logical_xor
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/src/umath/loops.c.src | 16 | ||||
-rw-r--r-- | numpy/core/tests/test_umath.py | 42 |
2 files changed, 40 insertions, 18 deletions
diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index d747864f8..14076f3fa 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -838,9 +838,9 @@ NPY_NO_EXPORT void @TYPE@_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { BINARY_LOOP { - const @type@ in1 = *(@type@ *)ip1; - const @type@ in2 = *(@type@ *)ip2; - *((npy_bool *)op1)= (in1 && !in2) || (!in1 && in2); + const int t1 = !!*(@type@ *)ip1; + const int t2 = !!*(@type@ *)ip2; + *((npy_bool *)op1) = (t1 != t2); } } @@ -1515,9 +1515,9 @@ NPY_NO_EXPORT void @TYPE@_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { BINARY_LOOP { - const @type@ in1 = *(@type@ *)ip1; - const @type@ in2 = *(@type@ *)ip2; - *((npy_bool *)op1)= (in1 && !in2) || (!in1 && in2); + const int t1 = !!*(@type@ *)ip1; + const int t2 = !!*(@type@ *)ip2; + *((npy_bool *)op1) = (t1 != t2); } } @@ -1864,7 +1864,7 @@ HALF_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_U BINARY_LOOP { const int in1 = !npy_half_iszero(*(npy_half *)ip1); const int in2 = !npy_half_iszero(*(npy_half *)ip2); - *((npy_bool *)op1)= (in1 && !in2) || (!in1 && in2); + *((npy_bool *)op1) = (in1 != in2); } } @@ -2346,7 +2346,7 @@ NPY_NO_EXPORT void const @ftype@ in2i = ((@ftype@ *)ip2)[1]; const npy_bool tmp1 = (in1r || in1i); const npy_bool tmp2 = (in2r || in2i); - *((npy_bool *)op1) = (tmp1 && !tmp2) || (!tmp1 && tmp2); + *((npy_bool *)op1) = tmp1 != tmp2; } } diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index 1cba24d06..4bbf5601a 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -720,21 +720,43 @@ class TestFmin(_FilterInvalids): class TestBool(TestCase): - def test_truth_table(self): + def test_truth_table_logical(self): + # 2, 3 and 4 serves as true values + input1 = [0, 0, 3, 2] + input2 = [0, 4, 0, 2] + + typecodes = (np.typecodes['AllFloat'] + + np.typecodes['AllInteger'] + + '?') # boolean + for dtype in map(np.dtype, typecodes): + arg1 = np.asarray(input1, dtype=dtype) + arg2 = np.asarray(input2, dtype=dtype) + + # OR + out = [False, True, True, True] + for func in (np.logical_or, np.maximum): + assert_equal(func(arg1, arg2).astype(bool), out) + # AND + out = [False, False, False, True] + for func in (np.logical_and, np.minimum): + assert_equal(func(arg1, arg2).astype(bool), out) + # XOR + out = [False, True, True, False] + for func in (np.logical_xor, np.not_equal): + assert_equal(func(arg1, arg2).astype(bool), out) + + def test_truth_table_bitwise(self): arg1 = [False, False, True, True] arg2 = [False, True, False, True] - # OR + out = [False, True, True, True] - for func in (np.logical_or, np.bitwise_or, np.maximum): - assert_equal(func(arg1, arg2), out) - # AND + assert_equal(np.bitwise_or(arg1, arg2), out) + out = [False, False, False, True] - for func in (np.logical_and, np.bitwise_and, np.minimum): - assert_equal(func(arg1, arg2), out) - # XOR + assert_equal(np.bitwise_and(arg1, arg2), out) + out = [False, True, True, False] - for func in (np.logical_xor, np.bitwise_xor, np.not_equal): - assert_equal(func(arg1, arg2), out) + assert_equal(np.bitwise_xor(arg1, arg2), out) class TestFloatingPoint(TestCase): |