diff --git a/base/bitarray.jl b/base/bitarray.jl index 6175a492cac75..1db84cad37a1c 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1707,6 +1707,8 @@ map!(::typeof(identity), dest::BitArray, A::BitArray) = copyto!(dest, A) for (T, f) in ((:(Union{typeof(&), typeof(*), typeof(min)}), :(&)), (:(Union{typeof(|), typeof(max)}), :(|)), (:(Union{typeof(xor), typeof(!=)}), :xor), + (:(typeof(nand)), :nand), + (:(typeof(nor)), :nor), (:(Union{typeof(>=), typeof(^)}), :((p, q) -> p | ~q)), (:(typeof(<=)), :((p, q) -> ~p | q)), (:(typeof(==)), :((p, q) -> ~xor(p, q))), diff --git a/base/bool.jl b/base/bool.jl index 92a27543d2fbc..297aa1863a64e 100644 --- a/base/bool.jl +++ b/base/bool.jl @@ -70,6 +70,74 @@ julia> [true; true; false] .⊻ [true; false; false] """ xor(x::Bool, y::Bool) = (x != y) +""" + nand(x, y) + ⊼(x, y) + +Bitwise nand (not and) of `x` and `y`. Implements +[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic), +returning [`missing`](@ref) if one of the arguments is `missing`. + +The infix operation `a ⊼ b` is a synonym for `nand(a,b)`, and +`⊼` can be typed by tab-completing `\\nand` or `\\barwedge` in the Julia REPL. + +# Examples +```jldoctest +julia> nand(true, false) +true + +julia> nand(true, true) +false + +julia> nand(true, missing) +missing + +julia> false ⊼ false +true + +julia> [true; true; false] .⊼ [true; false; false] +3-element BitVector: + 0 + 1 + 1 +``` +""" +nand(x...) = ~(&)(x...) + +""" + nor(x, y) + ⊽(x, y) + +Bitwise nor (not or) of `x` and `y`. Implements +[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic), +returning [`missing`](@ref) if one of the arguments is `missing`. + +The infix operation `a ⊽ b` is a synonym for `nor(a,b)`, and +`⊽` can be typed by tab-completing `\\nor` or `\\veebar` in the Julia REPL. + +# Examples +```jldoctest +julia> nor(true, false) +false + +julia> nor(true, true) +false + +julia> nor(true, missing) +false + +julia> false ⊽ false +true + +julia> [true; true; false] .⊽ [true; false; false] +3-element BitVector: + 0 + 0 + 1 +``` +""" +nor(x...) = ~(|)(x...) + >>(x::Bool, c::UInt) = Int(x) >> c <<(x::Bool, c::UInt) = Int(x) << c >>>(x::Bool, c::UInt) = Int(x) >>> c diff --git a/base/exports.jl b/base/exports.jl index 2a8ed97d4598f..9a6cdce86b38c 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -169,6 +169,10 @@ export ≢, xor, ⊻, + nand, + nor, + ⊼, + ⊽, %, ÷, &, diff --git a/base/gmp.jl b/base/gmp.jl index d0446e7d3d169..b957ab22a4bea 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -4,7 +4,7 @@ module GMP export BigInt -import .Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), xor, +import .Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), xor, nand, nor, binomial, cmp, convert, div, divrem, factorial, cld, fld, gcd, gcdx, lcm, mod, ndigits, promote_rule, rem, show, isqrt, string, powermod, sum, trailing_zeros, trailing_ones, count_ones, tryparse_internal, diff --git a/base/operators.jl b/base/operators.jl index 58f6024f71176..8d7d8180c5cde 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -578,6 +578,8 @@ identity(x) = x xor(x::Integer) = x const ⊻ = xor +const ⊼ = nand +const ⊽ = nor # foldl for argument lists. expand fully up to a point, then # switch to a loop. this allows small cases like `a+b+c+d` to be managed diff --git a/doc/src/base/math.md b/doc/src/base/math.md index e0f094572a398..8f8a038df83c0 100644 --- a/doc/src/base/math.md +++ b/doc/src/base/math.md @@ -49,6 +49,8 @@ Base.:(~) Base.:(&) Base.:(|) Base.xor +Base.nand +Base.nor Base.:(!) && || diff --git a/doc/src/manual/mathematical-operations.md b/doc/src/manual/mathematical-operations.md index 850c1f15bbd17..8df8505ac5cc6 100644 --- a/doc/src/manual/mathematical-operations.md +++ b/doc/src/manual/mathematical-operations.md @@ -82,6 +82,8 @@ are supported on all primitive integer types: | `x & y` | bitwise and | | `x \| y` | bitwise or | | `x ⊻ y` | bitwise xor (exclusive or) | +| `x ⊼ y` | bitwise nand (not and) | +| `x ⊽ y` | bitwise nor (not or) | | `x >>> y` | [logical shift](https://en.wikipedia.org/wiki/Logical_shift) right | | `x >> y` | [arithmetic shift](https://en.wikipedia.org/wiki/Arithmetic_shift) right | | `x << y` | logical/arithmetic shift left | @@ -104,6 +106,18 @@ julia> 123 ⊻ 234 julia> xor(123, 234) 145 +julia> nand(123, 123) +-124 + +julia> 123 ⊼ 123 +-124 + +julia> nor(123, 124) +-128 + +julia> 123 ⊽ 124 +-128 + julia> ~UInt32(123) 0xffffff84 diff --git a/stdlib/REPL/src/latex_symbols.jl b/stdlib/REPL/src/latex_symbols.jl index 57e41ed670538..bfd2e1fbbb015 100644 --- a/stdlib/REPL/src/latex_symbols.jl +++ b/stdlib/REPL/src/latex_symbols.jl @@ -110,6 +110,8 @@ const latex_symbols = Dict( "\\backpprime" => "‶", "\\backppprime" => "‷", "\\xor" => "⊻", + "\\nand" => "⊼", + "\\nor" => "⊽", "\\iff" => "⟺", "\\implies" => "⟹", "\\impliedby" => "⟸", @@ -2651,4 +2653,6 @@ const symbols_latex_canonical = Dict( "→" => "\\to", "ε" => "\\varepsilon", "⊻" => "\\xor", + "⊼" => "\\nand", + "⊽" => "\\nor", ) diff --git a/test/bitarray.jl b/test/bitarray.jl index a5591fca26de7..cee7624d9a81a 100644 --- a/test/bitarray.jl +++ b/test/bitarray.jl @@ -832,6 +832,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b1, b2) BitMatrix @check_bit_operation broadcast(|, b1, b2) BitMatrix @check_bit_operation broadcast(xor, b1, b2) BitMatrix + @check_bit_operation broadcast(nand, b1, b2) BitMatrix + @check_bit_operation broadcast(nor, b1, b2) BitMatrix @check_bit_operation (+)(b1, b2) Matrix{Int} @check_bit_operation (-)(b1, b2) Matrix{Int} @check_bit_operation broadcast(*, b1, b2) BitMatrix @@ -861,6 +863,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b0, b0) BitVector @check_bit_operation broadcast(|, b0, b0) BitVector @check_bit_operation broadcast(xor, b0, b0) BitVector + @check_bit_operation broadcast(nand, b0, b0) BitVector + @check_bit_operation broadcast(nor, b0, b0) BitVector @check_bit_operation broadcast(*, b0, b0) BitVector @check_bit_operation (*)(b0, b0') BitMatrix end @@ -871,6 +875,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b1, i2) Matrix{Int} @check_bit_operation broadcast(|, b1, i2) Matrix{Int} @check_bit_operation broadcast(xor, b1, i2) Matrix{Int} + @check_bit_operation broadcast(nand, b1, i2) Matrix{Int} + @check_bit_operation broadcast(nor, b1, i2) Matrix{Int} @check_bit_operation (+)(b1, i2) Matrix{Int} @check_bit_operation (-)(b1, i2) Matrix{Int} @check_bit_operation broadcast(*, b1, i2) Matrix{Int} @@ -902,6 +908,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, i1, b2) Matrix{Int} @check_bit_operation broadcast(|, i1, b2) Matrix{Int} @check_bit_operation broadcast(xor, i1, b2) Matrix{Int} + @check_bit_operation broadcast(nand, i1, b2) Matrix{Int} + @check_bit_operation broadcast(nor, i1, b2) Matrix{Int} @check_bit_operation broadcast(+, i1, b2) Matrix{Int} @check_bit_operation broadcast(-, i1, b2) Matrix{Int} @check_bit_operation broadcast(*, i1, b2) Matrix{Int} @@ -909,6 +917,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(|, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(xor, u1, b2) Matrix{UInt8} + @check_bit_operation broadcast(nand, u1, b2) Matrix{UInt8} + @check_bit_operation broadcast(nor, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(+, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(-, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(*, u1, b2) Matrix{UInt8} @@ -986,6 +996,14 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(xor, b1, false) BitMatrix @check_bit_operation broadcast(xor, true, b1) BitMatrix @check_bit_operation broadcast(xor, false, b1) BitMatrix + @check_bit_operation broadcast(nand, b1, true) BitMatrix + @check_bit_operation broadcast(nand, b1, false) BitMatrix + @check_bit_operation broadcast(nand, true, b1) BitMatrix + @check_bit_operation broadcast(nand, false, b1) BitMatrix + @check_bit_operation broadcast(nor, b1, true) BitMatrix + @check_bit_operation broadcast(nor, b1, false) BitMatrix + @check_bit_operation broadcast(nor, true, b1) BitMatrix + @check_bit_operation broadcast(nor, false, b1) BitMatrix @check_bit_operation broadcast(+, b1, true) Matrix{Int} @check_bit_operation broadcast(+, b1, false) Matrix{Int} @check_bit_operation broadcast(-, b1, true) Matrix{Int} @@ -1002,12 +1020,18 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b1, b2) BitMatrix @check_bit_operation broadcast(|, b1, b2) BitMatrix @check_bit_operation broadcast(xor, b1, b2) BitMatrix + @check_bit_operation broadcast(nand, b1, b2) BitMatrix + @check_bit_operation broadcast(nor, b1, b2) BitMatrix @check_bit_operation broadcast(&, b2, b1) BitMatrix @check_bit_operation broadcast(|, b2, b1) BitMatrix @check_bit_operation broadcast(xor, b2, b1) BitMatrix + @check_bit_operation broadcast(nand, b2, b1) BitMatrix + @check_bit_operation broadcast(nor, b2, b1) BitMatrix @check_bit_operation broadcast(&, b1, i2) Matrix{Int} @check_bit_operation broadcast(|, b1, i2) Matrix{Int} @check_bit_operation broadcast(xor, b1, i2) Matrix{Int} + @check_bit_operation broadcast(nand, b1, i2) Matrix{Int} + @check_bit_operation broadcast(nor, b1, i2) Matrix{Int} @check_bit_operation broadcast(+, b1, i2) Matrix{Int} @check_bit_operation broadcast(-, b1, i2) Matrix{Int} @check_bit_operation broadcast(*, b1, i2) Matrix{Int} @@ -1018,6 +1042,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(|, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(xor, b1, u2) Matrix{UInt8} + @check_bit_operation broadcast(nand, b1, u2) Matrix{UInt8} + @check_bit_operation broadcast(nor, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(+, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(-, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(*, b1, u2) Matrix{UInt8} @@ -1086,6 +1112,14 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(xor, b1, transpose(b3)) BitMatrix @check_bit_operation broadcast(xor, b2, b1) BitMatrix @check_bit_operation broadcast(xor, transpose(b3), b1) BitMatrix + @check_bit_operation broadcast(nand, b1, b2) BitMatrix + @check_bit_operation broadcast(nand, b1, transpose(b3)) BitMatrix + @check_bit_operation broadcast(nand, b2, b1) BitMatrix + @check_bit_operation broadcast(nand, transpose(b3), b1) BitMatrix + @check_bit_operation broadcast(nor, b1, b2) BitMatrix + @check_bit_operation broadcast(nor, b1, transpose(b3)) BitMatrix + @check_bit_operation broadcast(nor, b2, b1) BitMatrix + @check_bit_operation broadcast(nor, transpose(b3), b1) BitMatrix @check_bit_operation broadcast(+, b1, b2) Matrix{Int} @check_bit_operation broadcast(+, b1, transpose(b3)) Matrix{Int} @check_bit_operation broadcast(+, b2, b1) Matrix{Int} @@ -1390,6 +1424,8 @@ timesofar("reductions") @test map(&, b1, b2) == map((x,y)->x&y, b1, b2) == broadcast(&, b1, b2) @test map(|, b1, b2) == map((x,y)->x|y, b1, b2) == broadcast(|, b1, b2) @test map(⊻, b1, b2) == map((x,y)->x⊻y, b1, b2) == broadcast(⊻, b1, b2) == broadcast(xor, b1, b2) + @test map(⊼, b1, b2) == map((x,y)->x⊼y, b1, b2) == broadcast(⊼, b1, b2) == broadcast(nand, b1, b2) + @test map(⊽, b1, b2) == map((x,y)->x⊽y, b1, b2) == broadcast(⊽, b1, b2) == broadcast(nor, b1, b2) @test map(^, b1, b2) == map((x,y)->x^y, b1, b2) == b1 .^ b2 @test map(*, b1, b2) == map((x,y)->x*y, b1, b2) == b1 .* b2 diff --git a/test/gmp.jl b/test/gmp.jl index 96ffdedb7a93c..3d7317b37bacc 100644 --- a/test/gmp.jl +++ b/test/gmp.jl @@ -241,6 +241,12 @@ end @test xor(a, b, c, d, f) == parse(BigInt,"-2413804710837418037418307081437316711364709261074607933698") @test xor(a, b, c, d, f, g) == parse(BigInt,"2413804710837418037418307081437316711364709261074607933697") + @test nand(a, b) == parse(BigInt,"-125") + @test ⊼(a, b) == parse(BigInt,"-125") + + @test nor(a, b) == parse(BigInt,"-327424") + @test ⊽(a, b) == parse(BigInt,"-327424") + @test (&)(a, b) == parse(BigInt,"124") @test (&)(a, b, c) == parse(BigInt,"72") @test (&)(a, b, c, d) == parse(BigInt,"8") diff --git a/test/missing.jl b/test/missing.jl index 4c704c4ce64f8..c20395b70b564 100644 --- a/test/missing.jl +++ b/test/missing.jl @@ -83,7 +83,7 @@ end arithmetic_operators = [+, -, *, /, ^, Base.div, Base.mod, Base.fld, Base.rem] # All unary operators return missing when evaluating missing - for f in [!, ~, +, -, *, &, |, xor] + for f in [!, ~, +, -, *, &, |, xor, nand, nor] @test ismissing(f(missing)) end @@ -128,6 +128,22 @@ end @test ismissing(xor(true, missing)) @test ismissing(xor(missing, false)) @test ismissing(xor(false, missing)) + @test ismissing(nand(missing, true)) + @test ismissing(nand(true, missing)) + @test nand(missing, false) == true + @test nand(false, missing) == true + @test ismissing(⊼(missing, true)) + @test ismissing(⊼(true, missing)) + @test ⊼(missing, false) == true + @test ⊼(false, missing) == true + @test nor(missing, true) == false + @test nor(true, missing) == false + @test ismissing(nor(missing, false)) + @test ismissing(nor(false, missing)) + @test ⊽(missing, true) == false + @test ⊽(true, missing) == false + @test ismissing(⊽(missing, false)) + @test ismissing(⊽(false, missing)) @test ismissing(missing & 1) @test ismissing(1 & missing) @@ -135,6 +151,14 @@ end @test ismissing(1 | missing) @test ismissing(xor(missing, 1)) @test ismissing(xor(1, missing)) + @test ismissing(nand(missing, 1)) + @test ismissing(nand(1, missing)) + @test ismissing(⊼(missing, 1)) + @test ismissing(⊼(1, missing)) + @test ismissing(nor(missing, 1)) + @test ismissing(nor(1, missing)) + @test ismissing(⊽(missing, 1)) + @test ismissing(⊽(1, missing)) end @testset "* string concatenation" begin diff --git a/test/numbers.jl b/test/numbers.jl index a76f5726492df..e62e1a798221d 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -38,6 +38,24 @@ const ≣ = isequal # convenient for comparing NaNs @test xor(true, false) == true @test xor(false, true) == true @test xor(true, true) == false + + @test false ⊼ false == true + @test true ⊼ false == true + @test false ⊼ true == true + @test true ⊼ true == false + @test nand(false, false) == true + @test nand(true, false) == true + @test nand(false, true) == true + @test nand(true, true) == false + + @test false ⊽ false == true + @test true ⊽ false == false + @test false ⊽ true == false + @test true ⊽ true == false + @test nor(false, false) == true + @test nor(true, false) == false + @test nor(false, true) == false + @test nor(true, true) == false end @testset "bool operator" begin @test Bool(false) == false