# Negative false no longer acts as a strong zero

**URL:** <https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506>\
**Category:** General Usage\
**Created:** [April 28, 2025, 11:35pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506 "2025-04-28T23:35:48Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![lance\_xwq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lance_xwq/32/36647_2.png) [@lance\_xwq](https://discourse.julialang.org/u/lance_xwq)\
**Post date:** [April 28, 2025, 11:35pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/1 "2025-04-28T23:35:48Z")

</div>

[Julia documentation](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Arithmetic-Operators) states that `false` acts like a strong zero in multiplication, such that `NaN * false` produces `0.0`. However, [Julia also defines](https://github.com/JuliaLang/julia/blob/59e9ada533850a0c15850644c1936d253aa2d8e7/base/bool.jl#L166) `-(x::Bool) = -Int(x)`, which seems to indicate `-false` is no longer a strong zero.

Personally, I find it a bit confusing, as:

```julia
julia> -NaN * false
-0.0

julia> NaN * -false
NaN

```

and

```julia
julia> 1 - NaN * false
1.0

julia> 1 - false * NaN
1.0

julia> - false * NaN + 1
NaN

julia> - NaN * false + 1
1.0

```

IMHO, this behavior may lead to some inconsistency and unpredictability. For example, as mentioned in [`rmul!` does not respect "strong zero": `NaN*false=0.0` · Issue #2607 · JuliaGPU/CUDA.jl · GitHub](https://github.com/JuliaGPU/CUDA.jl/issues/2607#issuecomment-2573015555),

```julia
julia> using LinearAlgebra

julia> rotate!([NaN], [NaN], false, false) # rotate!(x, y, c, s) means: x = c*x + s*y and y = -conj(s)*x + c*y
([0.0], [NaN])

```

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [April 29, 2025, 6:51am UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/2 "2025-04-29T06:51:55Z")

</div>

I’m not sure I agree that’s really a problem. `false` is a strong zero. `-false` is a different value of a different type. Why would that be a strong zero? Isn’t that exactly like how `false + 1` is not a strong zero?

---

<div class="post-metadata">

**Author:** ![albheim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albheim/32/34660_2.png) [@albheim](https://discourse.julialang.org/u/albheim)\
**Post date:** [April 29, 2025, 6:57am UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/3 "2025-04-29T06:57:28Z")

</div>

But is `-false` not more like `-1 * false`? Which then should be a strong zero. Or at least that I would think of it more like that than `0-false`, though maybe that is not warranted.

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [April 29, 2025, 6:59am UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/4 "2025-04-29T06:59:11Z")

</div>

Why would `-1 * false` be a strong zero? It’s not even a zero? It’s a different type.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 29, 2025, 7:10am UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/5 "2025-04-29T07:10:20Z")

</div>

One thing is `-false`, which could, arguably, in isolation, be equal to `false`, (just like `-0 == 0`) and thus a strong zero.

But what should `-true` be then?

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [April 29, 2025, 7:15am UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/6 "2025-04-29T07:15:36Z")

</div>

It’s not obvious to me what they should do — is there a reason why `-(::Bool)` or `-1 * false` need to be defined at all?

---

<div class="post-metadata">

**Author:** ![lance\_xwq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lance_xwq/32/36647_2.png) [@lance\_xwq](https://discourse.julialang.org/u/lance_xwq)\
**Post date:** [April 29, 2025, 7:50am UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/7 "2025-04-29T07:50:34Z")

</div>

I agree that `-false` does not need to be a strong zero. I am more curious about the best practice when using or writing code. 😃 If I write something similar to `rotate!`, how should I choose between `y = -conj(s)*x + c*y` and `y = c*y - conj(s)*x`, as they are not equivalent given `s==false` and `x==NaN` (or `Inf`)? It could be helpful if there were a convention I could follow.

Another question that just occurred to me 😅 is the behavior of `+false`. Julia documentation also describes the unitary plus as the identity operation. But

```julia
julia> identity(false)
false

julia> +false
0

```

---

<div class="post-metadata">

**Author:** ![araujoms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/araujoms/32/217734_2.png) [@araujoms](https://discourse.julialang.org/u/araujoms)\
**Post date:** [April 29, 2025, 10:36am UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/8 "2025-04-29T10:36:41Z")

</div>

`-false` needs to be an Integer because `-true` is an integer. Otherwise the function `-(x::Bool)`wouldn’t be type stable. On the other hand, the unary plus could be defined as `+(x::Bool) = x`, I don’t think that would cause any problems.

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [April 29, 2025, 11:41am UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/9 "2025-04-29T11:41:50Z")

</div>

> [@araujoms](#):
>
> On the other hand, the unary plus could be defined as `+ (x::Bool) = x`, I don’t think that would cause any problems.

I wonder what the reason is for the method `+(x::Bool) = int(x)`. It was added in [small tweaks to some scalar operators · JuliaLang/julia@d2f319f · GitHub](https://github.com/JuliaLang/julia/commit/d2f319f1c6a5193fe068c5a1d057f70899d58b5c) without much explanation. One would expect x \cdot y = x \cdot (+y) holds for any numbers x, y, but it clearly doesn’t hold with this method in place (`NaN * false == 0.0` and `NaN * (+false) == NaN * 0 == NaN`).

---

<div class="post-metadata">

**Author:** ![araujoms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/araujoms/32/217734_2.png) [@araujoms](https://discourse.julialang.org/u/araujoms)\
**Post date:** [April 29, 2025, 12:12pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/10 "2025-04-29T12:12:03Z")

</div>

Wow that’s 2013, it’s the stone age of Julia. I guess there wasn’t any reason. You could ask @jeff.bezanson, though.

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [April 29, 2025, 1:19pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/11 "2025-04-29T13:19:35Z")

</div>

I think that the current behavior is consisent, if one considers the rules of operator precedence, and that the “strong-zeroness” of `false` is not propagated to zeros of other types (even if derived from operating with `false`). Going through the examples given by the OP and other participants of this thread:

```julia
julia> -NaN * false # NaN * strong zero = normal zero promoted to `Float64`
-0.0

julia> -false # additive inverse of strong zero = normal zero of default integer type
0

julia> -1 * false # -1 * strong zero = normal zero promoted to Int, same as before
0

julia> NaN * -false # NaN * (-false = 0) = NaN
NaN

julia> 1 - NaN * false # 1 - (NaN * false = 0.0) = 1.0
1.0

julia> 1 - false * NaN # 1 - (false * NaN = 0.0) = 1.0
1.0

julia> - false * NaN + 1 # ((-false = 0.0) * NaN = NaN ) + 1 = NaN
NaN

julia> - NaN * false + 1 # (-NaN * false = 0.0) + 1 = 1.0
1.0

```

---

<div class="post-metadata">

**Author:** ![albheim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albheim/32/34660_2.png) [@albheim](https://discourse.julialang.org/u/albheim)\
**Post date:** [April 29, 2025, 1:28pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/12 "2025-04-29T13:28:57Z")

</div>

Somehow thought a strong zero meant result for multiplication should also be strong zero, not sure where I got that from… 😅

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [April 29, 2025, 1:57pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/13 "2025-04-29T13:57:57Z")

</div>

> [@barucden](#):
>
> I wonder what the reason is for the method `+(x::Bool) = int(x)`

Every other non-Boolean operation also promotes `Bool` to `Int`, e.g.

```julia
julia> true - true # integer 0, not false
0

```

So I’d say that it is for the sake of consistency - although that is an exception to the [definition of unary plus as identity of operator for primitive types](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Arithmetic-Operators). Should that exception be explicitly mentioned?

---

<div class="post-metadata">

**Author:** ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)\
**Post date:** [April 29, 2025, 4:52pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/14 "2025-04-29T16:52:04Z")

</div>

Yes, as best as I can remember that is the reason: all arithmetic operations promote Bool to Int. So `+x` isn’t the identity function exactly, but I’m not sure what to call it. Arithmetic identity? Identity except for Bool 😂 ? I wonder if there are other types in the ecosystem like Bool in this way?

Looking through our methods, I would say this is wrong:

```julia
-(A::AbstractArray) = broadcast_preserving_zero_d(-, A)

+(x::AbstractArray{<:Number}) = x

```

the second method should look like the first IMO.

---

<div class="post-metadata">

**Author:** ![lance\_xwq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lance_xwq/32/36647_2.png) [@lance\_xwq](https://discourse.julialang.org/u/lance_xwq)\
**Post date:** [April 29, 2025, 6:32pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/15 "2025-04-29T18:32:40Z")

</div>

I like the current way of achieving consistency in Julia @heliosdrm, @jeff.bezanson, just wondering if I should now always write `a - b * c` rather than `-b * c + a` (or the other way around) to be consistent in my code. 😅 And if it is too much to expect other packages to pick a convention (at least within that package). 🤔

---

<div class="post-metadata">

**Author:** ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)\
**Post date:** [April 29, 2025, 7:03pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/16 "2025-04-29T19:03:34Z")

</div>

You should write `fma(-b, c, a)` 😉  
Yeah, this is a tradeoff in allowing false to be a “strong zero”. `NaN*im` works, but some identities no longer hold. I would probably prefer forms with fewer operations. Other than that just don’t worry about NaNs too much 🙂

---

<div class="post-metadata">

**Author:** ![lance\_xwq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lance_xwq/32/36647_2.png) [@lance\_xwq](https://discourse.julialang.org/u/lance_xwq)\
**Post date:** [April 29, 2025, 7:27pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/17 "2025-04-29T19:27:04Z")

</div>

Thanks!

And just for the sake of reference…😂

```julia
julia> fma(false, NaN, 1)
NaN

julia> muladd(false, NaN, 1)
NaN

julia> false * NaN + 1
1.0

```

---

<div class="post-metadata">

**Author:** ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)\
**Post date:** [April 29, 2025, 7:42pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/18 "2025-04-29T19:42:25Z")

</div>

Yeah it might make sense to add methods for those. Some might argue that you only use fma if you know you have floats, but it can be debated in an issue or PR.

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [April 29, 2025, 8:27pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/19 "2025-04-29T20:27:56Z")

</div>

In case this detail is deemed worth to be explained in the manual:

> <https://github.com/JuliaLang/julia/pull/58281>
>
> Clarify the points discussed in https://discourse.julialang.org/t/negative-false…-no-longer-acts-as-a-strong-zero/128506/13

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [May 1, 2025, 12:42pm UTC](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506/20 "2025-05-01T12:42:42Z")

</div>

I’ve just created a tangentially related issue about unary `+` for arrays with `Bool` values:

> <https://github.com/JuliaLang/julia/issues/58295>
>
> (This issue is tangentially related to #58281.)
> 
> The return type of unary \`+\` wi…th \`Bool\` argument is not the same for arrays and views:
> \`\`\`
> julia\> v = \[true, false\]; +v
> 2-element Vector{Int64}:
> 1
> 0
> 
> julia\> w = view(v, :); +w
> 2-element view(::Vector{Bool}, :) with eltype Bool:
> 1
> 0
> \`\`\`
> The reason is that unary \`+\` for \`AbstractArray\` is simply the identity map:
> 
> https://github.com/JuliaLang/julia/blob/748775b5689deaa4acac7929e0a31a80d1c564f4/base/abstractarraymath.jl#L285
> 
> Hence it misses the convention that \`+\` transforms \`Bool\` to \`Int\`.
> 
> Another consequence of this definition is that one doesn't know whether \`+v\` is identical to \`v\` for mutable \`v\`:
> \`\`\`
> julia\> v = \[1, 2\]; +v === v
> false
> 
> julia\> w = view(v, :); +w === w
> true
> \`\`\`
> In my opinion, it would be good to have a consistent answer. However, it may be to late for that.

[Next page](https://discourse.julialang.org/t/negative-false-no-longer-acts-as-a-strong-zero/128506.md?page=2)
