Skip to content

Commit

Permalink
Implemented bitwise nand and nor (JuliaLang#40339)
Browse files Browse the repository at this point in the history
  • Loading branch information
arvganesh authored and johanmon committed Jul 5, 2021
1 parent 05c9c25 commit 828f2e9
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 2 deletions.
2 changes: 2 additions & 0 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))),
Expand Down
68 changes: 68 additions & 0 deletions base/bool.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ export
,
xor,
,
nand,
nor,
,
,
%,
÷,
&,
Expand Down
2 changes: 1 addition & 1 deletion base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions doc/src/base/math.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Base.:(~)
Base.:(&)
Base.:(|)
Base.xor
Base.nand
Base.nor
Base.:(!)
&&
||
Expand Down
14 changes: 14 additions & 0 deletions doc/src/manual/mathematical-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,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 |
Expand All @@ -106,6 +108,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
Expand Down
4 changes: 4 additions & 0 deletions stdlib/REPL/src/latex_symbols.jl
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ const latex_symbols = Dict(
"\\backpprime" => "",
"\\backppprime" => "",
"\\xor" => "",
"\\nand" => "",
"\\nor" => "",
"\\iff" => "",
"\\implies" => "",
"\\impliedby" => "",
Expand Down Expand Up @@ -2651,4 +2653,6 @@ const symbols_latex_canonical = Dict(
"" => "\\to",
"ε" => "\\varepsilon",
"" => "\\xor",
"" => "\\nand",
"" => "\\nor",
)
36 changes: 36 additions & 0 deletions test/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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}
Expand Down Expand Up @@ -902,13 +908,17 @@ 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}

@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}
Expand Down Expand Up @@ -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}
Expand All @@ -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}
Expand All @@ -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}
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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)->xy, b1, b2) == broadcast(, b1, b2) == broadcast(xor, b1, b2)
@test map(, b1, b2) == map((x,y)->xy, b1, b2) == broadcast(, b1, b2) == broadcast(nand, b1, b2)
@test map(, b1, b2) == map((x,y)->xy, 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
Expand Down
6 changes: 6 additions & 0 deletions test/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
26 changes: 25 additions & 1 deletion test/missing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,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

Expand Down Expand Up @@ -131,13 +131,37 @@ 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)
@test ismissing(missing | 1)
@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
Expand Down
18 changes: 18 additions & 0 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 828f2e9

Please sign in to comment.